🚸(frontend) inform user when recording is saving

Saving a recording can take a bit of time, display a clear message to
inform user it can takes few minutes.
This commit is contained in:
lebaudantoine
2025-04-10 20:08:28 +02:00
committed by aleb_the_flash
parent f0742a0978
commit a079ceef71
8 changed files with 166 additions and 92 deletions

View File

@@ -14,20 +14,18 @@ import { RoomEvent } from 'livekit-client'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { RecordingStatus, recordingStore } from '@/stores/recording' import { RecordingStatus, recordingStore } from '@/stores/recording'
import { CRISP_HELP_ARTICLE_RECORDING } from '@/utils/constants' import { CRISP_HELP_ARTICLE_RECORDING } from '@/utils/constants'
import { import { useIsRecordingTransitioning } from '@/features/recording'
useIsRecordingTransitioning,
useIsScreenRecordingStarted,
useIsTranscriptStarted,
} from '@/features/recording'
import { import {
useNotifyParticipants, useNotifyParticipants,
NotificationType, NotificationType,
} from '@/features/notifications' } from '@/features/notifications'
import posthog from 'posthog-js' import posthog from 'posthog-js'
import { useSnapshot } from 'valtio/index'
export const ScreenRecordingSidePanel = () => { export const ScreenRecordingSidePanel = () => {
const [isLoading, setIsLoading] = useState(false) const [isLoading, setIsLoading] = useState(false)
const recordingSnap = useSnapshot(recordingStore)
const { t } = useTranslation('rooms', { keyPrefix: 'screenRecording' }) const { t } = useTranslation('rooms', { keyPrefix: 'screenRecording' })
const { notifyParticipants } = useNotifyParticipants() const { notifyParticipants } = useNotifyParticipants()
@@ -37,8 +35,16 @@ export const ScreenRecordingSidePanel = () => {
const { mutateAsync: startRecordingRoom } = useStartRecording() const { mutateAsync: startRecordingRoom } = useStartRecording()
const { mutateAsync: stopRecordingRoom } = useStopRecording() const { mutateAsync: stopRecordingRoom } = useStopRecording()
const isScreenRecordingStarted = useIsScreenRecordingStarted() const statuses = useMemo(() => {
const isTranscriptStarted = useIsTranscriptStarted() return {
isAnotherModeStarted:
recordingSnap.status == RecordingStatus.TRANSCRIPT_STARTED,
isStarted:
recordingSnap.status == RecordingStatus.SCREEN_RECORDING_STARTED,
isStopping:
recordingSnap.status == RecordingStatus.SCREEN_RECORDING_STOPPING,
}
}, [recordingSnap])
const room = useRoomContext() const room = useRoomContext()
const isRecordingTransitioning = useIsRecordingTransitioning() const isRecordingTransitioning = useIsRecordingTransitioning()
@@ -84,8 +90,9 @@ export const ScreenRecordingSidePanel = () => {
} }
const isDisabled = useMemo( const isDisabled = useMemo(
() => isLoading || isRecordingTransitioning || isTranscriptStarted, () =>
[isLoading, isRecordingTransitioning, isTranscriptStarted] isLoading || isRecordingTransitioning || statuses.isAnotherModeStarted,
[isLoading, isRecordingTransitioning, statuses]
) )
return ( return (
@@ -106,7 +113,7 @@ export const ScreenRecordingSidePanel = () => {
})} })}
/> />
{isScreenRecordingStarted ? ( {statuses.isStarted ? (
<> <>
<H lvl={3} margin={false}> <H lvl={3} margin={false}>
{t('stop.heading')} {t('stop.heading')}
@@ -135,34 +142,57 @@ export const ScreenRecordingSidePanel = () => {
</> </>
) : ( ) : (
<> <>
<H lvl={3} margin={false}> {statuses.isStopping ? (
{t('start.heading')} <>
</H> <H lvl={3} margin={false}>
<Text {t('stopping.heading')}
variant="note" </H>
wrap={'pretty'} <Text
centered variant="note"
className={css({ wrap={'pretty'}
textStyle: 'sm', centered
maxWidth: '90%', className={css({
marginBottom: '2.5rem', textStyle: 'sm',
marginTop: '0.25rem', maxWidth: '90%',
})} marginBottom: '2.5rem',
> marginTop: '0.25rem',
{t('start.body')} <br />{' '} })}
<A href={CRISP_HELP_ARTICLE_RECORDING} target="_blank"> >
{t('start.linkMore')} {t('stopping.body')}
</A> </Text>
</Text> </>
<Button ) : (
isDisabled={isDisabled} <>
onPress={() => handleScreenRecording()} <H lvl={3} margin={false}>
data-attr="start-screen-recording" {t('start.heading')}
size="sm" </H>
variant="tertiary" <Text
> variant="note"
{t('start.button')} wrap={'pretty'}
</Button> centered
className={css({
textStyle: 'sm',
maxWidth: '90%',
marginBottom: '2.5rem',
marginTop: '0.25rem',
})}
>
{t('start.body')} <br />{' '}
<A href={CRISP_HELP_ARTICLE_RECORDING} target="_blank">
{t('start.linkMore')}
</A>
</Text>
<Button
isDisabled={isDisabled}
onPress={() => handleScreenRecording()}
data-attr="start-screen-recording"
size="sm"
variant="tertiary"
>
{t('start.button')}
</Button>
</>
)}
</> </>
)} )}
</Div> </Div>

View File

@@ -6,12 +6,10 @@ import { useRoomId } from '@/features/rooms/livekit/hooks/useRoomId'
import { useRoomContext } from '@livekit/components-react' import { useRoomContext } from '@livekit/components-react'
import { import {
RecordingMode, RecordingMode,
useHasRecordingAccess,
useIsRecordingTransitioning,
useStartRecording, useStartRecording,
useStopRecording, useStopRecording,
useIsScreenRecordingStarted,
useIsTranscriptStarted,
useIsRecordingTransitioning,
useHasRecordingAccess,
} from '../index' } from '../index'
import { useEffect, useMemo, useState } from 'react' import { useEffect, useMemo, useState } from 'react'
import { RoomEvent } from 'livekit-client' import { RoomEvent } from 'livekit-client'
@@ -23,15 +21,18 @@ import {
} from '@/utils/constants' } from '@/utils/constants'
import { FeatureFlags } from '@/features/analytics/enums' import { FeatureFlags } from '@/features/analytics/enums'
import { import {
useNotifyParticipants,
NotificationType, NotificationType,
useNotifyParticipants,
} from '@/features/notifications' } from '@/features/notifications'
import posthog from 'posthog-js' import posthog from 'posthog-js'
import { useSnapshot } from 'valtio/index'
export const TranscriptSidePanel = () => { export const TranscriptSidePanel = () => {
const [isLoading, setIsLoading] = useState(false) const [isLoading, setIsLoading] = useState(false)
const { t } = useTranslation('rooms', { keyPrefix: 'transcript' }) const { t } = useTranslation('rooms', { keyPrefix: 'transcript' })
const recordingSnap = useSnapshot(recordingStore)
const { notifyParticipants } = useNotifyParticipants() const { notifyParticipants } = useNotifyParticipants()
const hasTranscriptAccess = useHasRecordingAccess( const hasTranscriptAccess = useHasRecordingAccess(
@@ -43,8 +44,15 @@ export const TranscriptSidePanel = () => {
const { mutateAsync: startRecordingRoom } = useStartRecording() const { mutateAsync: startRecordingRoom } = useStartRecording()
const { mutateAsync: stopRecordingRoom } = useStopRecording() const { mutateAsync: stopRecordingRoom } = useStopRecording()
const isScreenRecordingStarted = useIsScreenRecordingStarted() const statuses = useMemo(() => {
const isTranscriptStarted = useIsTranscriptStarted() return {
isAnotherModeStarted:
recordingSnap.status == RecordingStatus.SCREEN_RECORDING_STARTED,
isStarted: recordingSnap.status == RecordingStatus.TRANSCRIPT_STARTED,
isStopping: recordingSnap.status == RecordingStatus.TRANSCRIPT_STOPPING,
}
}, [recordingSnap])
const isRecordingTransitioning = useIsRecordingTransitioning() const isRecordingTransitioning = useIsRecordingTransitioning()
const room = useRoomContext() const room = useRoomContext()
@@ -87,8 +95,9 @@ export const TranscriptSidePanel = () => {
} }
const isDisabled = useMemo( const isDisabled = useMemo(
() => isLoading || isRecordingTransitioning || isScreenRecordingStarted, () =>
[isLoading, isRecordingTransitioning, isScreenRecordingStarted] isLoading || isRecordingTransitioning || statuses.isAnotherModeStarted,
[isLoading, isRecordingTransitioning, statuses]
) )
return ( return (
@@ -137,7 +146,7 @@ export const TranscriptSidePanel = () => {
</> </>
) : ( ) : (
<> <>
{isTranscriptStarted ? ( {statuses.isStarted ? (
<> <>
<H lvl={3} margin={false}> <H lvl={3} margin={false}>
{t('stop.heading')} {t('stop.heading')}
@@ -166,34 +175,57 @@ export const TranscriptSidePanel = () => {
</> </>
) : ( ) : (
<> <>
<H lvl={3} margin={false}> {statuses.isStopping ? (
{t('start.heading')} <>
</H> <H lvl={3} margin={false}>
<Text {t('stopping.heading')}
variant="note" </H>
wrap={'pretty'} <Text
centered variant="note"
className={css({ wrap={'pretty'}
textStyle: 'sm', centered
maxWidth: '90%', className={css({
marginBottom: '2.5rem', textStyle: 'sm',
marginTop: '0.25rem', maxWidth: '90%',
})} marginBottom: '2.5rem',
> marginTop: '0.25rem',
{t('start.body')} <br />{' '} })}
<A href={CRISP_HELP_ARTICLE_TRANSCRIPT} target="_blank"> >
{t('start.linkMore')} {t('stopping.body')}
</A> </Text>
</Text> </>
<Button ) : (
isDisabled={isDisabled} <>
onPress={() => handleTranscript()} <H lvl={3} margin={false}>
data-attr="start-transcript" {t('start.heading')}
size="sm" </H>
variant="tertiary" <Text
> variant="note"
{t('start.button')} wrap={'pretty'}
</Button> centered
className={css({
textStyle: 'sm',
maxWidth: '90%',
marginBottom: '2.5rem',
marginTop: '0.25rem',
})}
>
{t('start.body')} <br />{' '}
<A href={CRISP_HELP_ARTICLE_TRANSCRIPT} target="_blank">
{t('start.linkMore')}
</A>
</Text>
<Button
isDisabled={isDisabled}
onPress={() => handleTranscript()}
data-attr="start-transcript"
size="sm"
variant="tertiary"
>
{t('start.button')}
</Button>
</>
)}
</> </>
)} )}
</> </>

View File

@@ -1,12 +0,0 @@
import { useSnapshot } from 'valtio'
import { RecordingStatus, recordingStore } from '@/stores/recording'
export const useIsScreenRecordingStarted = () => {
const recordingSnap = useSnapshot(recordingStore)
return recordingSnap.status == RecordingStatus.SCREEN_RECORDING_STARTED
}
export const useIsTranscriptStarted = () => {
const recordingSnap = useSnapshot(recordingStore)
return recordingSnap.status == RecordingStatus.TRANSCRIPT_STARTED
}

View File

@@ -1,9 +1,5 @@
// hooks // hooks
export { useIsRecordingModeEnabled } from './hooks/useIsRecordingModeEnabled' export { useIsRecordingModeEnabled } from './hooks/useIsRecordingModeEnabled'
export {
useIsScreenRecordingStarted,
useIsTranscriptStarted,
} from './hooks/useIsRecordingStarted'
export { useIsRecordingTransitioning } from './hooks/useIsRecordingTransitioning' export { useIsRecordingTransitioning } from './hooks/useIsRecordingTransitioning'
export { useHasRecordingAccess } from './hooks/useHasRecordingAccess' export { useHasRecordingAccess } from './hooks/useHasRecordingAccess'

View File

@@ -207,6 +207,10 @@
"body": "", "body": "",
"button": "" "button": ""
}, },
"stopping": {
"heading": "",
"body": ""
},
"beta": { "beta": {
"heading": "", "heading": "",
"body": "", "body": "",

View File

@@ -212,6 +212,10 @@
"body": "The transcription of your meeting is in progress. You will receive the result by email once the meeting is finished.", "body": "The transcription of your meeting is in progress. You will receive the result by email once the meeting is finished.",
"button": "Stop transcription" "button": "Stop transcription"
}, },
"stopping": {
"heading": "Saving your data…",
"body": "This process may take a few minutes. Thank you for your patience."
},
"beta": { "beta": {
"heading": "Become a beta tester", "heading": "Become a beta tester",
"body": "Record your meeting for later. You will receive a summary by email once the meeting is finished.", "body": "Record your meeting for later. You will receive a summary by email once the meeting is finished.",
@@ -225,6 +229,10 @@
"button": "Start recording", "button": "Start recording",
"linkMore": "Learn more" "linkMore": "Learn more"
}, },
"stopping": {
"heading": "Saving your data…",
"body": "This process may take a few minutes. Thank you for your patience."
},
"stop": { "stop": {
"heading": "Recording in progress…", "heading": "Recording in progress…",
"body": "You will receive the result by email once the recording is complete.", "body": "You will receive the result by email once the recording is complete.",

View File

@@ -212,6 +212,10 @@
"body": "La transcription de votre réunion est en cours. Vous recevrez le resultat par email une fois la réunion terminée.", "body": "La transcription de votre réunion est en cours. Vous recevrez le resultat par email une fois la réunion terminée.",
"button": "Arrêter la transcription" "button": "Arrêter la transcription"
}, },
"stopping": {
"heading": "Sauvegarde de vos données…",
"body": "Cette opération peut durer quelques minutes. Merci de votre patience."
},
"beta": { "beta": {
"heading": "Devenez beta testeur", "heading": "Devenez beta testeur",
"body": "Enregistrer votre réunion pour plus tard. Vous recevrez un compte-rendu par email une fois la réunion terminée.", "body": "Enregistrer votre réunion pour plus tard. Vous recevrez un compte-rendu par email une fois la réunion terminée.",
@@ -225,6 +229,10 @@
"button": "Démarrer l'enregistrement", "button": "Démarrer l'enregistrement",
"linkMore": "En savoir plus" "linkMore": "En savoir plus"
}, },
"stopping": {
"heading": "Sauvegarde de vos données…",
"body": "Cette opération peut durer quelques minutes. Merci de votre patience."
},
"stop": { "stop": {
"heading": "Enregistrement en cours …", "heading": "Enregistrement en cours …",
"body": "Vous recevrez le resultat par email une fois l'enregistrement terminé.", "body": "Vous recevrez le resultat par email une fois l'enregistrement terminé.",

View File

@@ -212,6 +212,10 @@
"body": "De transcriptie van uw vergadering is bezig. U ontvangt het resultaat per e-mail zodra de vergadering is afgelopen.", "body": "De transcriptie van uw vergadering is bezig. U ontvangt het resultaat per e-mail zodra de vergadering is afgelopen.",
"button": "Transcriptie stoppen" "button": "Transcriptie stoppen"
}, },
"stopping": {
"heading": "Uw gegevens worden opgeslagen…",
"body": "Dit proces kan enkele minuten duren. Bedankt voor uw geduld."
},
"beta": { "beta": {
"heading": "Word betatester", "heading": "Word betatester",
"body": "Neem uw vergadering op voor later. U ontvangt een samenvatting per e-mail zodra de vergadering is afgelopen.", "body": "Neem uw vergadering op voor later. U ontvangt een samenvatting per e-mail zodra de vergadering is afgelopen.",
@@ -225,6 +229,10 @@
"button": "Opname starten", "button": "Opname starten",
"linkMore": "Meer informatie" "linkMore": "Meer informatie"
}, },
"stopping": {
"heading": "Uw gegevens worden opgeslagen…",
"body": "Dit proces kan enkele minuten duren. Bedankt voor uw geduld."
},
"stop": { "stop": {
"heading": "Opname bezig …", "heading": "Opname bezig …",
"body": "Je ontvangt het resultaat per e-mail zodra de opname is voltooid.", "body": "Je ontvangt het resultaat per e-mail zodra de opname is voltooid.",