🚸(frontend) add notification with recording handling details
Display notification clarifying recording is processing and show which email will receive completion notification. Reduces user mental load per @sampaccoud's feedback.
This commit is contained in:
committed by
aleb_the_flash
parent
29a46a413e
commit
8d1f01645a
@@ -11,5 +11,6 @@ export const NotificationDuration = {
|
||||
PARTICIPANT_JOINED: ToastDuration.LONG,
|
||||
HAND_RAISED: ToastDuration.LONG,
|
||||
LOWER_HAND: ToastDuration.EXTRA_LONG,
|
||||
RECORDING_SAVING: ToastDuration.EXTRA_LONG,
|
||||
REACTION_RECEIVED: ToastDuration.SHORT,
|
||||
} as const
|
||||
|
||||
@@ -10,4 +10,5 @@ export enum NotificationType {
|
||||
TranscriptionStopped = 'transcriptionStopped',
|
||||
ScreenRecordingStarted = 'screenRecordingStarted',
|
||||
ScreenRecordingStopped = 'screenRecordingStopped',
|
||||
RecordingSaving = 'recordingSaving',
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ export interface ToastData {
|
||||
participant: Participant
|
||||
type: NotificationType
|
||||
message?: string
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
// Using a global queue for toasts allows for centralized management and queuing of notifications
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import { useToast } from '@react-aria/toast'
|
||||
import { useMemo, useRef } from 'react'
|
||||
import { Text } from '@/primitives'
|
||||
|
||||
import { StyledToastContainer, ToastProps } from './Toast'
|
||||
import { HStack } from '@/styled-system/jsx'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useUser } from '@/features/auth'
|
||||
import { css } from '@/styled-system/css'
|
||||
import { RecordingMode } from '@/features/recording'
|
||||
|
||||
export function ToastRecordingSaving({ state, ...props }: ToastProps) {
|
||||
const { t } = useTranslation('notifications', { keyPrefix: 'recordingSave' })
|
||||
const ref = useRef(null)
|
||||
const { toastProps, contentProps } = useToast(props, state, ref)
|
||||
|
||||
const { user } = useUser()
|
||||
|
||||
const modeLabel = useMemo(() => {
|
||||
const mode = props.toast.content.mode as RecordingMode
|
||||
switch (mode) {
|
||||
case RecordingMode.Transcript:
|
||||
return 'transcript'
|
||||
case RecordingMode.ScreenRecording:
|
||||
return 'screenRecording'
|
||||
}
|
||||
}, [props.toast.content])
|
||||
|
||||
return (
|
||||
<StyledToastContainer {...toastProps} ref={ref}>
|
||||
<HStack
|
||||
justify="center"
|
||||
alignItems="center"
|
||||
{...contentProps}
|
||||
padding={14}
|
||||
gap={1}
|
||||
>
|
||||
<Text
|
||||
margin={false}
|
||||
className={css({
|
||||
maxWidth: '22rem',
|
||||
wordBreak: 'break-word',
|
||||
overflowWrap: 'break-word',
|
||||
whiteSpace: 'normal',
|
||||
})}
|
||||
>
|
||||
{user?.email ? (
|
||||
<span
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: t(`${modeLabel}.message`, {
|
||||
email: user.email,
|
||||
}),
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
t(`${modeLabel}.default`)
|
||||
)}
|
||||
</Text>
|
||||
</HStack>
|
||||
</StyledToastContainer>
|
||||
)
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import { ToastMuted } from './ToastMuted'
|
||||
import { ToastMessageReceived } from './ToastMessageReceived'
|
||||
import { ToastLowerHand } from './ToastLowerHand'
|
||||
import { ToastAnyRecording } from './ToastAnyRecording'
|
||||
import { ToastRecordingSaving } from './ToastRecordingSaving'
|
||||
|
||||
interface ToastRegionProps extends AriaToastRegionProps {
|
||||
state: ToastState<ToastData>
|
||||
@@ -43,6 +44,11 @@ const renderToast = (
|
||||
case NotificationType.ScreenRecordingStopped:
|
||||
return <ToastAnyRecording key={toast.key} toast={toast} state={state} />
|
||||
|
||||
case NotificationType.RecordingSaving:
|
||||
return (
|
||||
<ToastRecordingSaving key={toast.key} toast={toast} state={state} />
|
||||
)
|
||||
|
||||
default:
|
||||
return <Toast key={toast.key} toast={toast} state={state} />
|
||||
}
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export { useNotifyParticipants } from './hooks/useNotifyParticipants'
|
||||
export { NotificationType } from './NotificationType'
|
||||
export { notifyRecordingSaveInProgress } from './utils'
|
||||
|
||||
@@ -3,6 +3,7 @@ import { NotificationType } from './NotificationType'
|
||||
import { NotificationDuration } from './NotificationDuration'
|
||||
import { Participant } from 'livekit-client'
|
||||
import { NotificationPayload } from './NotificationPayload'
|
||||
import { RecordingMode } from '@/features/recording'
|
||||
|
||||
export const showLowerHandToast = (
|
||||
participant: Participant,
|
||||
@@ -49,3 +50,17 @@ export const decodeNotificationDataReceived = (
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
export const notifyRecordingSaveInProgress = (
|
||||
mode: RecordingMode,
|
||||
participant: Participant
|
||||
) => {
|
||||
toastQueue.add(
|
||||
{
|
||||
participant,
|
||||
mode,
|
||||
type: NotificationType.RecordingSaving,
|
||||
},
|
||||
{ timeout: NotificationDuration.RECORDING_SAVING }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -106,14 +106,10 @@ export const RecordingStateToast = () => {
|
||||
switch (recordingSnap.status) {
|
||||
case RecordingStatus.TRANSCRIPT_STARTED:
|
||||
return 'transcript.started'
|
||||
case RecordingStatus.TRANSCRIPT_STOPPING:
|
||||
return 'transcript.stopping'
|
||||
case RecordingStatus.TRANSCRIPT_STARTING:
|
||||
return 'transcript.starting'
|
||||
case RecordingStatus.SCREEN_RECORDING_STARTED:
|
||||
return 'screenRecording.started'
|
||||
case RecordingStatus.SCREEN_RECORDING_STOPPING:
|
||||
return 'screenRecording.stopping'
|
||||
case RecordingStatus.SCREEN_RECORDING_STARTING:
|
||||
return 'screenRecording.starting'
|
||||
case RecordingStatus.ANY_STARTED:
|
||||
|
||||
@@ -18,6 +18,7 @@ import { CRISP_HELP_ARTICLE_RECORDING } from '@/utils/constants'
|
||||
|
||||
import {
|
||||
NotificationType,
|
||||
notifyRecordingSaveInProgress,
|
||||
useNotifyParticipants,
|
||||
} from '@/features/notifications'
|
||||
import posthog from 'posthog-js'
|
||||
@@ -84,6 +85,10 @@ export const ScreenRecordingSidePanel = () => {
|
||||
await notifyParticipants({
|
||||
type: NotificationType.ScreenRecordingStopped,
|
||||
})
|
||||
notifyRecordingSaveInProgress(
|
||||
RecordingMode.ScreenRecording,
|
||||
room.localParticipant
|
||||
)
|
||||
} else {
|
||||
await startRecordingRoom({
|
||||
id: roomId,
|
||||
|
||||
@@ -24,6 +24,7 @@ import { FeatureFlags } from '@/features/analytics/enums'
|
||||
import {
|
||||
NotificationType,
|
||||
useNotifyParticipants,
|
||||
notifyRecordingSaveInProgress,
|
||||
} from '@/features/notifications'
|
||||
import posthog from 'posthog-js'
|
||||
import { useSnapshot } from 'valtio/index'
|
||||
@@ -99,6 +100,10 @@ export const TranscriptSidePanel = () => {
|
||||
await notifyParticipants({
|
||||
type: NotificationType.TranscriptionStopped,
|
||||
})
|
||||
notifyRecordingSaveInProgress(
|
||||
RecordingMode.Transcript,
|
||||
room.localParticipant
|
||||
)
|
||||
} else {
|
||||
await startRecordingRoom({ id: roomId, mode: RecordingMode.Transcript })
|
||||
recordingStore.status = RecordingStatus.TRANSCRIPT_STARTING
|
||||
|
||||
@@ -29,5 +29,15 @@
|
||||
"screenRecording": {
|
||||
"started": "{{name}} hat die Aufzeichnung des Treffens gestartet.",
|
||||
"stopped": "{{name}} hat die Aufzeichnung des Treffens gestoppt."
|
||||
},
|
||||
"recordingSave": {
|
||||
"transcript": {
|
||||
"message": "Wir finalisieren Ihre Aufnahme! Sie erhalten eine E-Mail an <strong>{{email}}</strong>, sobald die Transkription fertig ist.",
|
||||
"default": "Wir finalisieren Ihre Aufnahme! Sie erhalten eine E-Mail, sobald die Transkription fertig ist."
|
||||
},
|
||||
"screenRecording": {
|
||||
"message": "Wir finalisieren Ihre Aufnahme! Sie erhalten eine E-Mail an <strong>{{email}}</strong>, sobald sie fertig ist.",
|
||||
"default": "Wir finalisieren Ihre Aufnahme! Sie erhalten eine E-Mail, sobald sie fertig ist."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,5 +29,15 @@
|
||||
"screenRecording": {
|
||||
"started": "{{name}} started the meeting recording.",
|
||||
"stopped": "{{name}} stopped the meeting recording."
|
||||
},
|
||||
"recordingSave": {
|
||||
"transcript": {
|
||||
"message": "Your recording is being saved! We’ll send the transcript to <strong>{{email}}</strong> as soon as it’s ready.",
|
||||
"default": "Your recording is being saved! We’ll send the transcript to your email as soon as it’s ready."
|
||||
},
|
||||
"screenRecording": {
|
||||
"message": "Your recording is being saved! We’ll send a notification to <strong>{{email}}</strong> as soon as it’s ready.",
|
||||
"default": "Your recording is being saved! We’ll send a notification to your email as soon as it’s ready."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,5 +29,15 @@
|
||||
"screenRecording": {
|
||||
"started": "{{name}} a démarré l'enregistrement de la réunion.",
|
||||
"stopped": "{{name}} a arrêté l'enregistrement de la réunion."
|
||||
},
|
||||
"recordingSave": {
|
||||
"transcript": {
|
||||
"message": "Nous finalisons votre enregistrement ! Vous recevrez un e-mail à <strong>{{email}}</strong> dès que la transcription sera prête.",
|
||||
"default": "Nous finalisons votre enregistrement ! Vous recevrez un e-mail dès que la transcription sera prête."
|
||||
},
|
||||
"screenRecording": {
|
||||
"message": "Nous finalisons votre enregistrement ! Vous recevrez un e-mail à <strong>{{email}}</strong> dès qu’il sera prêt.",
|
||||
"default": "Nous finalisons votre enregistrement ! Vous recevrez un e-mail dès qu’il sera prêt."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,5 +29,15 @@
|
||||
"screenRecording": {
|
||||
"started": "{{name}} is begonnen met het opnemen van de vergadering.",
|
||||
"stopped": "{{name}} is gestopt met het opnemen van de vergadering."
|
||||
},
|
||||
"recordingSave": {
|
||||
"transcript": {
|
||||
"message": "We zijn uw opname aan het voltooien! U ontvangt een e-mail op <strong>{{email}}</strong> zodra de transcriptie klaar is.",
|
||||
"default": "We zijn uw opname aan het voltooien! U ontvangt een e-mail zodra de transcriptie klaar is."
|
||||
},
|
||||
"screenRecording": {
|
||||
"message": "We zijn uw opname aan het voltooien! U ontvangt een e-mail op <strong>{{email}}</strong> zodra deze klaar is.",
|
||||
"default": "We zijn uw opname aan het voltooien! U ontvangt een e-mail zodra deze klaar is."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user