@twentyhq/call-recorder 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/manifest.json +297 -0
- package/package.json +2 -2
- package/src/front-components/calendar-event-recording.front-component.mjs +269 -0
- package/src/front-components/calendar-event-recording.front-component.mjs.map +7 -0
- package/src/logic-functions/process-recall-webhook.mjs +1744 -0
- package/src/logic-functions/process-recall-webhook.mjs.map +7 -0
- package/src/logic-functions/recall-webhook.mjs +391 -0
- package/src/logic-functions/recall-webhook.mjs.map +7 -0
- package/src/logic-functions/reconcile-call-recorder-calendar-event.mjs +1602 -0
- package/src/logic-functions/reconcile-call-recorder-calendar-event.mjs.map +7 -0
- package/src/logic-functions/reconcile-stale-bot-state.mjs +2268 -0
- package/src/logic-functions/reconcile-stale-bot-state.mjs.map +7 -0
- package/.env.example +0 -5
- package/.nvmrc +0 -1
- package/.oxlintrc.json +0 -20
- package/AGENTS.md +0 -67
- package/CLAUDE.md +0 -67
- package/README.md +0 -24
- package/SETUP.md +0 -95
- package/src/__tests__/global-setup.ts +0 -100
- package/src/__tests__/schema.integration-test.ts +0 -104
- package/src/application-config.ts +0 -96
- package/src/constants/__tests__/call-recording-field-universal-identifiers.test.ts +0 -19
- package/src/constants/app-description.ts +0 -2
- package/src/constants/app-display-name.ts +0 -1
- package/src/constants/application-universal-identifier.ts +0 -2
- package/src/constants/calendar-event-reconciliation-logic-function-universal-identifier.ts +0 -2
- package/src/constants/calendar-event-record-page-layout-universal-identifier.ts +0 -2
- package/src/constants/calendar-event-recording-front-component-universal-identifier.ts +0 -2
- package/src/constants/calendar-event-recording-page-layout-tab-universal-identifier.ts +0 -2
- package/src/constants/calendar-event-recording-page-layout-widget-universal-identifier.ts +0 -2
- package/src/constants/call-recorder-everyone-left-timeout-seconds-app-variable-universal-identifier.ts +0 -2
- package/src/constants/call-recorder-failure-reason-on-call-recording-field-universal-identifier.ts +0 -2
- package/src/constants/call-recorder-join-early-minutes-app-variable-universal-identifier.ts +0 -2
- package/src/constants/call-recorder-name-app-variable-universal-identifier.ts +0 -2
- package/src/constants/call-recorder-noone-joined-timeout-seconds-app-variable-universal-identifier.ts +0 -2
- package/src/constants/call-recorder-preference-off-option-id.ts +0 -2
- package/src/constants/call-recorder-preference-on-calendar-event-field-universal-identifier.ts +0 -2
- package/src/constants/call-recorder-preference-on-calendar-event-view-field-universal-identifier.ts +0 -2
- package/src/constants/call-recorder-preference-on-option-id.ts +0 -2
- package/src/constants/call-recorder-preference.ts +0 -4
- package/src/constants/call-recorder-waiting-room-timeout-seconds-app-variable-universal-identifier.ts +0 -2
- package/src/constants/call-recording-audio-field-universal-identifier.ts +0 -2
- package/src/constants/call-recording-video-field-universal-identifier.ts +0 -2
- package/src/constants/default-role-universal-identifier.ts +0 -2
- package/src/constants/process-recall-webhook-logic-function-universal-identifier.ts +0 -2
- package/src/constants/recall-webhook-logic-function-universal-identifier.ts +0 -2
- package/src/constants/stale-bot-state-logic-function-universal-identifier.ts +0 -2
- package/src/default-role.ts +0 -69
- package/src/fields/call-recorder-failure-reason-on-call-recording.field.ts +0 -22
- package/src/fields/call-recorder-preference-on-calendar-event.field.ts +0 -41
- package/src/front-components/calendar-event-recording.front-component.tsx +0 -13
- package/src/front-components/components/CalendarEventRecording.tsx +0 -39
- package/src/front-components/components/CalendarEventRecordingBody.tsx +0 -96
- package/src/front-components/components/CalendarEventRecordingContent.tsx +0 -111
- package/src/front-components/components/RecordingTranscript.tsx +0 -92
- package/src/front-components/components/RecordingVideoPlayer.tsx +0 -52
- package/src/front-components/components/TranscriptEntryList.tsx +0 -61
- package/src/front-components/components/TranscriptEntryListItem.tsx +0 -115
- package/src/front-components/components/TranscriptErrorBox.tsx +0 -48
- package/src/front-components/components/TranscriptSpeakerAvatar.tsx +0 -141
- package/src/front-components/components/TranscriptSpeakerChip.tsx +0 -51
- package/src/front-components/constants/recording-theme-css-variables.ts +0 -40
- package/src/front-components/hooks/use-calendar-event-participants.ts +0 -172
- package/src/front-components/hooks/use-calendar-event-recording.ts +0 -155
- package/src/front-components/types/calendar-event-participant-by-speaker-name.type.ts +0 -6
- package/src/front-components/types/calendar-event-recording-participant.type.ts +0 -7
- package/src/front-components/types/transcript-entry.type.ts +0 -13
- package/src/front-components/utils/__tests__/find-active-transcript-entry-index.test.ts +0 -66
- package/src/front-components/utils/__tests__/format-transcript-timestamp.test.ts +0 -29
- package/src/front-components/utils/__tests__/get-speaker-name-match-keys.test.ts +0 -22
- package/src/front-components/utils/__tests__/parse-transcript-entries.test.ts +0 -162
- package/src/front-components/utils/build-calendar-event-participant-by-speaker-name.util.ts +0 -45
- package/src/front-components/utils/find-active-transcript-entry-index.util.ts +0 -77
- package/src/front-components/utils/format-transcript-timestamp.util.ts +0 -16
- package/src/front-components/utils/get-absolute-avatar-url.util.ts +0 -48
- package/src/front-components/utils/get-calendar-event-participant-for-speaker-name.util.ts +0 -24
- package/src/front-components/utils/get-speaker-name-match-keys.util.ts +0 -64
- package/src/front-components/utils/get-video-file-extension.util.ts +0 -23
- package/src/front-components/utils/parse-transcript-entries.util.ts +0 -85
- package/src/logic-functions/__tests__/process-recall-webhook.test.ts +0 -62
- package/src/logic-functions/__tests__/recall-webhook.test.ts +0 -180
- package/src/logic-functions/constants/call-recorder-everyone-left-timeout-seconds-env-var-name.ts +0 -2
- package/src/logic-functions/constants/call-recorder-everyone-left-timeout-seconds.ts +0 -1
- package/src/logic-functions/constants/call-recorder-join-early-minutes-env-var-name.ts +0 -2
- package/src/logic-functions/constants/call-recorder-name-env-var-name.ts +0 -1
- package/src/logic-functions/constants/call-recorder-noone-joined-timeout-seconds-env-var-name.ts +0 -2
- package/src/logic-functions/constants/call-recorder-noone-joined-timeout-seconds.ts +0 -1
- package/src/logic-functions/constants/call-recorder-recording-retention-hours-env-var-name.ts +0 -2
- package/src/logic-functions/constants/call-recorder-waiting-room-timeout-seconds-env-var-name.ts +0 -2
- package/src/logic-functions/constants/call-recorder-waiting-room-timeout-seconds.ts +0 -1
- package/src/logic-functions/constants/call-recording-micro-credits-per-hour.ts +0 -1
- package/src/logic-functions/constants/call-recording-request-status.ts +0 -5
- package/src/logic-functions/constants/call-recording-status.ts +0 -9
- package/src/logic-functions/constants/default-call-recorder-join-early-minutes.ts +0 -1
- package/src/logic-functions/constants/default-call-recorder-name.ts +0 -1
- package/src/logic-functions/constants/default-call-recorder-recording-retention-hours.ts +0 -2
- package/src/logic-functions/constants/default-recall-region.ts +0 -1
- package/src/logic-functions/constants/milliseconds-per-minute.ts +0 -1
- package/src/logic-functions/constants/non-terminal-call-recording-statuses.ts +0 -8
- package/src/logic-functions/constants/recall-api-key-env-var-name.ts +0 -1
- package/src/logic-functions/constants/recall-api-max-attempts.ts +0 -1
- package/src/logic-functions/constants/recall-api-retry-delay-ms.ts +0 -1
- package/src/logic-functions/constants/recall-bot-automatic-leave.ts +0 -74
- package/src/logic-functions/constants/recall-bot-everyone-left-min-activate-after-seconds.ts +0 -1
- package/src/logic-functions/constants/recall-bot-recording-config.ts +0 -34
- package/src/logic-functions/constants/recall-region-env-var-name.ts +0 -1
- package/src/logic-functions/constants/recall-webhook-secret-env-var-name.ts +0 -1
- package/src/logic-functions/constants/restricted-field-placeholder.ts +0 -3
- package/src/logic-functions/constants/stale-bot-state-cron-pattern.ts +0 -1
- package/src/logic-functions/constants/twenty-page-size.ts +0 -1
- package/src/logic-functions/data/__tests__/complete-call-recording-ingestion.test.ts +0 -55
- package/src/logic-functions/data/__tests__/fetch-all-nodes.test.ts +0 -43
- package/src/logic-functions/data/__tests__/get-current-workspace-id.test.ts +0 -38
- package/src/logic-functions/data/__tests__/strip-restricted-field-value.test.ts +0 -22
- package/src/logic-functions/data/complete-call-recording-ingestion.util.ts +0 -24
- package/src/logic-functions/data/create-call-recording.util.ts +0 -41
- package/src/logic-functions/data/fetch-all-nodes.util.ts +0 -44
- package/src/logic-functions/data/fetch-calendar-events-by-filter.util.ts +0 -80
- package/src/logic-functions/data/fetch-calendar-events-by-ids.util.ts +0 -20
- package/src/logic-functions/data/fetch-calendar-events-by-starts-at-values.util.ts +0 -19
- package/src/logic-functions/data/find-call-recordings-by-calendar-event-ids.util.ts +0 -17
- package/src/logic-functions/data/find-call-recordings-by-filter.util.ts +0 -102
- package/src/logic-functions/data/find-call-recordings-by-ids.util.ts +0 -17
- package/src/logic-functions/data/find-open-scheduled-call-recordings.util.ts +0 -14
- package/src/logic-functions/data/get-current-workspace-id.util.ts +0 -36
- package/src/logic-functions/data/strip-restricted-field-value.util.ts +0 -6
- package/src/logic-functions/data/update-call-recording.util.ts +0 -24
- package/src/logic-functions/domain/__tests__/build-call-recorder-policy-result.test.ts +0 -47
- package/src/logic-functions/domain/__tests__/compute-call-recording-charge.test.ts +0 -71
- package/src/logic-functions/domain/__tests__/compute-call-recording-id-for-meeting.test.ts +0 -37
- package/src/logic-functions/domain/__tests__/compute-real-meeting-key.test.ts +0 -88
- package/src/logic-functions/domain/__tests__/is-call-recording-ingestion-complete.test.ts +0 -59
- package/src/logic-functions/domain/__tests__/is-call-recording-status-downgrade.test.ts +0 -37
- package/src/logic-functions/domain/__tests__/resolve-call-recorder-policy-result.test.ts +0 -120
- package/src/logic-functions/domain/__tests__/should-complete-call-recording-ingestion.test.ts +0 -102
- package/src/logic-functions/domain/aggregate-call-recorder-policy-results-by-meeting.util.ts +0 -42
- package/src/logic-functions/domain/build-call-recorder-policy-result.util.ts +0 -53
- package/src/logic-functions/domain/build-failed-transcript-marker.util.ts +0 -13
- package/src/logic-functions/domain/build-pending-transcript-marker.util.ts +0 -13
- package/src/logic-functions/domain/build-recall-routing-metadata.util.ts +0 -12
- package/src/logic-functions/domain/build-transcript-failure-reason.util.ts +0 -7
- package/src/logic-functions/domain/compute-call-recording-charge.util.ts +0 -41
- package/src/logic-functions/domain/compute-call-recording-id-for-meeting.util.ts +0 -16
- package/src/logic-functions/domain/compute-real-meeting-key.util.ts +0 -48
- package/src/logic-functions/domain/compute-recall-bot-join-at.util.ts +0 -34
- package/src/logic-functions/domain/is-call-recording-ingestion-complete.util.ts +0 -19
- package/src/logic-functions/domain/is-call-recording-status-downgrade.util.ts +0 -37
- package/src/logic-functions/domain/is-recall-recording-done-signal.util.ts +0 -13
- package/src/logic-functions/domain/map-recall-status-code-to-call-recording-status.util.ts +0 -26
- package/src/logic-functions/domain/parse-transcript-marker.util.ts +0 -29
- package/src/logic-functions/domain/resolve-call-recorder-policy-result.util.ts +0 -72
- package/src/logic-functions/domain/should-complete-call-recording-ingestion.util.ts +0 -32
- package/src/logic-functions/flows/__tests__/charge-completed-call-recording.test.ts +0 -45
- package/src/logic-functions/flows/__tests__/complete-and-charge-call-recording.test.ts +0 -61
- package/src/logic-functions/flows/__tests__/converge-diverged-call-recordings.test.ts +0 -727
- package/src/logic-functions/flows/__tests__/download-transcript.test.ts +0 -74
- package/src/logic-functions/flows/__tests__/handle-recall-webhook.test.ts +0 -1301
- package/src/logic-functions/flows/__tests__/heal-call-recordings-missing-bot.test.ts +0 -225
- package/src/logic-functions/flows/__tests__/ingest-call-recording-media.test.ts +0 -153
- package/src/logic-functions/flows/__tests__/reap-orphaned-call-recorders.test.ts +0 -425
- package/src/logic-functions/flows/__tests__/reconcile-call-recorder.test.ts +0 -1007
- package/src/logic-functions/flows/cancel-call-recording-request.util.ts +0 -46
- package/src/logic-functions/flows/charge-completed-call-recording.util.ts +0 -31
- package/src/logic-functions/flows/complete-and-charge-call-recording.util.ts +0 -29
- package/src/logic-functions/flows/converge-diverged-call-recordings-result.type.ts +0 -8
- package/src/logic-functions/flows/converge-diverged-call-recordings.util.ts +0 -447
- package/src/logic-functions/flows/download-transcript.util.ts +0 -67
- package/src/logic-functions/flows/ensure-call-recorder.util.ts +0 -73
- package/src/logic-functions/flows/handle-recall-webhook.util.ts +0 -672
- package/src/logic-functions/flows/heal-call-recordings-missing-bot.util.ts +0 -82
- package/src/logic-functions/flows/ingest-call-recording-media.util.ts +0 -128
- package/src/logic-functions/flows/persist-call-recording-progress.util.ts +0 -58
- package/src/logic-functions/flows/reap-orphaned-call-recorders.util.ts +0 -183
- package/src/logic-functions/flows/reconcile-call-recorder.util.ts +0 -495
- package/src/logic-functions/flows/reconcile-call-recording-transcript-artifact-result.type.ts +0 -11
- package/src/logic-functions/flows/reconcile-call-recording-transcript-artifact.util.ts +0 -182
- package/src/logic-functions/flows/reschedule-call-recording-bot.util.ts +0 -69
- package/src/logic-functions/process-recall-webhook.ts +0 -23
- package/src/logic-functions/recall-api/__tests__/extract-recall-bot-convergence.test.ts +0 -153
- package/src/logic-functions/recall-api/__tests__/extract-recall-media-urls.test.ts +0 -67
- package/src/logic-functions/recall-api/__tests__/recall-bot-api.test.ts +0 -744
- package/src/logic-functions/recall-api/__tests__/verify-recall-webhook-signature.test.ts +0 -122
- package/src/logic-functions/recall-api/cancel-recall-bot.util.ts +0 -28
- package/src/logic-functions/recall-api/create-async-recall-transcript.util.ts +0 -47
- package/src/logic-functions/recall-api/eject-recall-bot.util.ts +0 -28
- package/src/logic-functions/recall-api/extract-recall-bot-convergence.util.ts +0 -149
- package/src/logic-functions/recall-api/extract-recall-bot-id.util.ts +0 -10
- package/src/logic-functions/recall-api/extract-recall-media-urls.util.ts +0 -30
- package/src/logic-functions/recall-api/extract-twenty-workspace-id-from-recall-webhook.util.ts +0 -8
- package/src/logic-functions/recall-api/get-recall-api-config.util.ts +0 -59
- package/src/logic-functions/recall-api/get-recall-bot.util.ts +0 -42
- package/src/logic-functions/recall-api/get-recall-recording.util.ts +0 -31
- package/src/logic-functions/recall-api/get-recall-webhook-bot-metadata.util.ts +0 -18
- package/src/logic-functions/recall-api/list-recall-transcripts.util.ts +0 -141
- package/src/logic-functions/recall-api/list-scheduled-recall-bots.util.ts +0 -106
- package/src/logic-functions/recall-api/normalize-recall-timestamp.util.ts +0 -14
- package/src/logic-functions/recall-api/parse-recall-webhook-event.util.ts +0 -88
- package/src/logic-functions/recall-api/recall-bot-api-request.util.ts +0 -165
- package/src/logic-functions/recall-api/recall-transcript-summary.type.ts +0 -5
- package/src/logic-functions/recall-api/reschedule-recall-bot.util.ts +0 -56
- package/src/logic-functions/recall-api/retrieve-recall-transcript.util.ts +0 -71
- package/src/logic-functions/recall-api/schedule-recall-bot.util.ts +0 -68
- package/src/logic-functions/recall-api/verify-recall-webhook-signature.util.ts +0 -109
- package/src/logic-functions/recall-webhook.ts +0 -90
- package/src/logic-functions/reconcile-call-recorder-calendar-event.ts +0 -178
- package/src/logic-functions/reconcile-stale-bot-state.ts +0 -106
- package/src/logic-functions/types/calendar-event-record.type.ts +0 -5
- package/src/logic-functions/types/call-recorder-policy-calendar-event-input.type.ts +0 -10
- package/src/logic-functions/types/call-recorder-policy-input.type.ts +0 -9
- package/src/logic-functions/types/call-recorder-policy-not-required-reason.type.ts +0 -5
- package/src/logic-functions/types/call-recorder-policy-required-reason.type.ts +0 -1
- package/src/logic-functions/types/call-recorder-policy-result-for-calendar-event.type.ts +0 -9
- package/src/logic-functions/types/call-recorder-policy-result-for-meeting.type.ts +0 -6
- package/src/logic-functions/types/call-recorder-policy-result.type.ts +0 -12
- package/src/logic-functions/types/call-recorder-reconciliation-result.type.ts +0 -16
- package/src/logic-functions/types/call-recording-media-file.type.ts +0 -1
- package/src/logic-functions/types/call-recording-record.type.ts +0 -15
- package/src/logic-functions/types/call-recording-update-fields.type.ts +0 -20
- package/src/logic-functions/types/files-field-value.type.ts +0 -1
- package/src/logic-functions/types/meeting-recording.type.ts +0 -7
- package/src/logic-functions/types/recall-bot-operation-result.type.ts +0 -19
- package/src/logic-functions/types/recall-routing-metadata.type.ts +0 -4
- package/src/logic-functions/types/removed-call-recorder-occurrence.type.ts +0 -6
- package/src/logic-functions/types/transcript-marker.type.ts +0 -6
- package/src/logic-functions/utils/as-record.util.ts +0 -6
- package/src/logic-functions/utils/get-application-variable-value.util.ts +0 -3
- package/src/logic-functions/utils/get-record-at-path.util.ts +0 -10
- package/src/logic-functions/utils/get-string.util.ts +0 -4
- package/src/logic-functions/utils/get-unique-sorted-ids.util.ts +0 -8
- package/src/logic-functions/utils/is-non-empty-string.util.ts +0 -5
- package/src/page-layouts/calendar-event-recording-tab.ts +0 -33
- package/src/view-fields/call-recorder-preference-on-calendar-event.view-field.ts +0 -27
- package/tsconfig.json +0 -42
- package/tsconfig.spec.json +0 -9
- package/vitest.config.ts +0 -31
- package/vitest.unit.config.ts +0 -14
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
defineField,
|
|
3
|
-
FieldType,
|
|
4
|
-
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
|
5
|
-
} from 'twenty-sdk/define';
|
|
6
|
-
|
|
7
|
-
import { CallRecorderPreference } from 'src/constants/call-recorder-preference';
|
|
8
|
-
import { CALL_RECORDER_PREFERENCE_OFF_OPTION_ID } from 'src/constants/call-recorder-preference-off-option-id';
|
|
9
|
-
import { CALL_RECORDER_PREFERENCE_ON_OPTION_ID } from 'src/constants/call-recorder-preference-on-option-id';
|
|
10
|
-
import { CALL_RECORDER_PREFERENCE_ON_CALENDAR_EVENT_FIELD_UNIVERSAL_IDENTIFIER } from 'src/constants/call-recorder-preference-on-calendar-event-field-universal-identifier';
|
|
11
|
-
|
|
12
|
-
export default defineField({
|
|
13
|
-
universalIdentifier:
|
|
14
|
-
CALL_RECORDER_PREFERENCE_ON_CALENDAR_EVENT_FIELD_UNIVERSAL_IDENTIFIER,
|
|
15
|
-
objectUniversalIdentifier:
|
|
16
|
-
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.calendarEvent.universalIdentifier,
|
|
17
|
-
type: FieldType.SELECT,
|
|
18
|
-
name: 'callRecorderPreference',
|
|
19
|
-
label: 'Recording Bot',
|
|
20
|
-
description:
|
|
21
|
-
'Call recording is on by default when the app is installed. Turn it off for this event when needed.',
|
|
22
|
-
icon: 'IconRobot',
|
|
23
|
-
isNullable: false,
|
|
24
|
-
defaultValue: `'${CallRecorderPreference.ON}'`,
|
|
25
|
-
options: [
|
|
26
|
-
{
|
|
27
|
-
id: CALL_RECORDER_PREFERENCE_ON_OPTION_ID,
|
|
28
|
-
value: CallRecorderPreference.ON,
|
|
29
|
-
label: 'On',
|
|
30
|
-
position: 0,
|
|
31
|
-
color: 'green',
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
id: CALL_RECORDER_PREFERENCE_OFF_OPTION_ID,
|
|
35
|
-
value: CallRecorderPreference.OFF,
|
|
36
|
-
label: 'Off',
|
|
37
|
-
position: 1,
|
|
38
|
-
color: 'red',
|
|
39
|
-
},
|
|
40
|
-
],
|
|
41
|
-
});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { defineFrontComponent } from 'twenty-sdk/define';
|
|
2
|
-
|
|
3
|
-
import { CALENDAR_EVENT_RECORDING_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER } from 'src/constants/calendar-event-recording-front-component-universal-identifier';
|
|
4
|
-
import { CalendarEventRecording } from 'src/front-components/components/CalendarEventRecording';
|
|
5
|
-
|
|
6
|
-
export default defineFrontComponent({
|
|
7
|
-
universalIdentifier:
|
|
8
|
-
CALENDAR_EVENT_RECORDING_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER,
|
|
9
|
-
name: 'calendar-event-recording',
|
|
10
|
-
description:
|
|
11
|
-
'Read-only recording viewer with synced transcript for the calendar event record page.',
|
|
12
|
-
component: CalendarEventRecording,
|
|
13
|
-
});
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import styled from '@emotion/styled';
|
|
2
|
-
import { isUndefined } from '@sniptt/guards';
|
|
3
|
-
import { useSelectedRecordIds } from 'twenty-sdk/front-component';
|
|
4
|
-
|
|
5
|
-
import { CalendarEventRecordingContent } from 'src/front-components/components/CalendarEventRecordingContent';
|
|
6
|
-
import { recordingThemeCssVariables } from 'src/front-components/constants/recording-theme-css-variables';
|
|
7
|
-
|
|
8
|
-
const StyledCenteredState = styled.div`
|
|
9
|
-
align-items: center;
|
|
10
|
-
box-sizing: border-box;
|
|
11
|
-
color: ${recordingThemeCssVariables.font.colorTertiary};
|
|
12
|
-
display: flex;
|
|
13
|
-
font-family: ${recordingThemeCssVariables.font.family};
|
|
14
|
-
font-size: ${recordingThemeCssVariables.font.sizeSm};
|
|
15
|
-
height: 100%;
|
|
16
|
-
justify-content: center;
|
|
17
|
-
padding: ${recordingThemeCssVariables.spacing[4]};
|
|
18
|
-
`;
|
|
19
|
-
|
|
20
|
-
export const CalendarEventRecording = () => {
|
|
21
|
-
const selectedRecordIds = useSelectedRecordIds();
|
|
22
|
-
const calendarEventId =
|
|
23
|
-
selectedRecordIds.length === 1 ? selectedRecordIds[0] : undefined;
|
|
24
|
-
|
|
25
|
-
if (isUndefined(calendarEventId)) {
|
|
26
|
-
return (
|
|
27
|
-
<StyledCenteredState>
|
|
28
|
-
Open a calendar event to see its recording.
|
|
29
|
-
</StyledCenteredState>
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return (
|
|
34
|
-
<CalendarEventRecordingContent
|
|
35
|
-
key={calendarEventId}
|
|
36
|
-
calendarEventId={calendarEventId}
|
|
37
|
-
/>
|
|
38
|
-
);
|
|
39
|
-
};
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import styled from '@emotion/styled';
|
|
2
|
-
import { isUndefined } from '@sniptt/guards';
|
|
3
|
-
|
|
4
|
-
import { RecordingTranscript } from 'src/front-components/components/RecordingTranscript';
|
|
5
|
-
import { RecordingVideoPlayer } from 'src/front-components/components/RecordingVideoPlayer';
|
|
6
|
-
import { TranscriptErrorBox } from 'src/front-components/components/TranscriptErrorBox';
|
|
7
|
-
import { recordingThemeCssVariables } from 'src/front-components/constants/recording-theme-css-variables';
|
|
8
|
-
import { type CalendarEventRecordingParticipant } from 'src/front-components/types/calendar-event-recording-participant.type';
|
|
9
|
-
|
|
10
|
-
const StyledCenteredState = styled.div`
|
|
11
|
-
align-items: center;
|
|
12
|
-
box-sizing: border-box;
|
|
13
|
-
color: ${recordingThemeCssVariables.font.colorTertiary};
|
|
14
|
-
display: flex;
|
|
15
|
-
font-family: ${recordingThemeCssVariables.font.family};
|
|
16
|
-
font-size: ${recordingThemeCssVariables.font.sizeSm};
|
|
17
|
-
justify-content: center;
|
|
18
|
-
min-height: 240px;
|
|
19
|
-
padding: ${recordingThemeCssVariables.spacing[4]};
|
|
20
|
-
`;
|
|
21
|
-
|
|
22
|
-
const StyledRecordingContainer = styled.div<{
|
|
23
|
-
$hasVideo?: boolean;
|
|
24
|
-
}>`
|
|
25
|
-
display: grid;
|
|
26
|
-
gap: ${recordingThemeCssVariables.spacing[2]};
|
|
27
|
-
grid-template-rows: ${({ $hasVideo }) =>
|
|
28
|
-
$hasVideo ? 'auto minmax(0, 1fr)' : 'minmax(0, 1fr)'};
|
|
29
|
-
min-height: 0;
|
|
30
|
-
`;
|
|
31
|
-
|
|
32
|
-
type CalendarEventRecordingBodyProps = {
|
|
33
|
-
transcript: unknown;
|
|
34
|
-
videoFileUrl: string | undefined;
|
|
35
|
-
isCalendarEventRecordingQueryLoading: boolean;
|
|
36
|
-
errorMessage: string | undefined;
|
|
37
|
-
currentTimeSeconds: number;
|
|
38
|
-
calendarEventParticipants: CalendarEventRecordingParticipant[];
|
|
39
|
-
onVideoTimeUpdate: (videoCurrentTimeSeconds: number) => void;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export const CalendarEventRecordingBody = ({
|
|
43
|
-
transcript,
|
|
44
|
-
videoFileUrl,
|
|
45
|
-
isCalendarEventRecordingQueryLoading,
|
|
46
|
-
errorMessage,
|
|
47
|
-
currentTimeSeconds,
|
|
48
|
-
calendarEventParticipants,
|
|
49
|
-
onVideoTimeUpdate,
|
|
50
|
-
}: CalendarEventRecordingBodyProps) => {
|
|
51
|
-
const hasVideo = !isUndefined(videoFileUrl);
|
|
52
|
-
|
|
53
|
-
if (!isUndefined(errorMessage)) {
|
|
54
|
-
return (
|
|
55
|
-
<TranscriptErrorBox
|
|
56
|
-
title="Failed to load the recording"
|
|
57
|
-
description={errorMessage}
|
|
58
|
-
/>
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (isCalendarEventRecordingQueryLoading) {
|
|
63
|
-
return (
|
|
64
|
-
<StyledRecordingContainer $hasVideo={false}>
|
|
65
|
-
<RecordingVideoPlayer
|
|
66
|
-
src={undefined}
|
|
67
|
-
onTimeUpdate={onVideoTimeUpdate}
|
|
68
|
-
/>
|
|
69
|
-
</StyledRecordingContainer>
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (isUndefined(transcript) && !hasVideo) {
|
|
74
|
-
return (
|
|
75
|
-
<StyledCenteredState>
|
|
76
|
-
No recording for this calendar event yet.
|
|
77
|
-
</StyledCenteredState>
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return (
|
|
82
|
-
<StyledRecordingContainer $hasVideo={hasVideo}>
|
|
83
|
-
{hasVideo && (
|
|
84
|
-
<RecordingVideoPlayer
|
|
85
|
-
src={videoFileUrl}
|
|
86
|
-
onTimeUpdate={onVideoTimeUpdate}
|
|
87
|
-
/>
|
|
88
|
-
)}
|
|
89
|
-
<RecordingTranscript
|
|
90
|
-
transcript={transcript}
|
|
91
|
-
currentTimeSeconds={currentTimeSeconds}
|
|
92
|
-
calendarEventParticipants={calendarEventParticipants}
|
|
93
|
-
/>
|
|
94
|
-
</StyledRecordingContainer>
|
|
95
|
-
);
|
|
96
|
-
};
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import styled from '@emotion/styled';
|
|
2
|
-
import { useCallback, useState } from 'react';
|
|
3
|
-
|
|
4
|
-
import { CalendarEventRecordingBody } from 'src/front-components/components/CalendarEventRecordingBody';
|
|
5
|
-
import { recordingThemeCssVariables } from 'src/front-components/constants/recording-theme-css-variables';
|
|
6
|
-
import { useCalendarEventParticipants } from 'src/front-components/hooks/use-calendar-event-participants';
|
|
7
|
-
import { useCalendarEventRecording } from 'src/front-components/hooks/use-calendar-event-recording';
|
|
8
|
-
|
|
9
|
-
const TRANSCRIPT_TIME_UPDATE_INTERVAL_SECONDS = 0.25;
|
|
10
|
-
|
|
11
|
-
const StyledRecordingShell = styled.div`
|
|
12
|
-
background: ${recordingThemeCssVariables.background.primary};
|
|
13
|
-
border: 1px solid transparent;
|
|
14
|
-
border-bottom: 1px solid transparent;
|
|
15
|
-
border-radius: ${recordingThemeCssVariables.border.radiusMd};
|
|
16
|
-
box-sizing: border-box;
|
|
17
|
-
font-family: ${recordingThemeCssVariables.font.family};
|
|
18
|
-
padding: ${recordingThemeCssVariables.spacing[4]};
|
|
19
|
-
position: relative;
|
|
20
|
-
width: 100%;
|
|
21
|
-
`;
|
|
22
|
-
|
|
23
|
-
const StyledRecordingHeader = styled.div`
|
|
24
|
-
align-items: center;
|
|
25
|
-
box-sizing: border-box;
|
|
26
|
-
display: flex;
|
|
27
|
-
height: ${recordingThemeCssVariables.spacing[6]};
|
|
28
|
-
`;
|
|
29
|
-
|
|
30
|
-
const StyledRecordingTitle = styled.h2`
|
|
31
|
-
color: ${recordingThemeCssVariables.font.colorPrimary};
|
|
32
|
-
flex: 1;
|
|
33
|
-
font-size: ${recordingThemeCssVariables.font.sizeMd};
|
|
34
|
-
font-weight: ${recordingThemeCssVariables.font.weightMedium};
|
|
35
|
-
margin: 0;
|
|
36
|
-
overflow: hidden;
|
|
37
|
-
padding-inline: ${recordingThemeCssVariables.spacing[1]};
|
|
38
|
-
user-select: none;
|
|
39
|
-
`;
|
|
40
|
-
|
|
41
|
-
const StyledRecordingBody = styled.div`
|
|
42
|
-
box-sizing: border-box;
|
|
43
|
-
margin-top: ${recordingThemeCssVariables.spacing[2]};
|
|
44
|
-
`;
|
|
45
|
-
|
|
46
|
-
const StyledRecordingContentFrame = styled.div`
|
|
47
|
-
background-color: ${recordingThemeCssVariables.background.secondary};
|
|
48
|
-
border: 1px solid ${recordingThemeCssVariables.border.colorMedium};
|
|
49
|
-
border-radius: ${recordingThemeCssVariables.border.radiusMd};
|
|
50
|
-
box-sizing: border-box;
|
|
51
|
-
padding: ${recordingThemeCssVariables.spacing[2]};
|
|
52
|
-
`;
|
|
53
|
-
|
|
54
|
-
type CalendarEventRecordingContentProps = {
|
|
55
|
-
calendarEventId: string;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
export const CalendarEventRecordingContent = ({
|
|
59
|
-
calendarEventId,
|
|
60
|
-
}: CalendarEventRecordingContentProps) => {
|
|
61
|
-
const [currentTimeSeconds, setCurrentTimeSeconds] = useState(0);
|
|
62
|
-
const updateCurrentTimeSeconds = useCallback(
|
|
63
|
-
(videoCurrentTimeSeconds: number) => {
|
|
64
|
-
const nextCurrentTimeSeconds =
|
|
65
|
-
Math.floor(
|
|
66
|
-
videoCurrentTimeSeconds / TRANSCRIPT_TIME_UPDATE_INTERVAL_SECONDS,
|
|
67
|
-
) * TRANSCRIPT_TIME_UPDATE_INTERVAL_SECONDS;
|
|
68
|
-
|
|
69
|
-
setCurrentTimeSeconds((previousCurrentTimeSeconds) =>
|
|
70
|
-
previousCurrentTimeSeconds === nextCurrentTimeSeconds
|
|
71
|
-
? previousCurrentTimeSeconds
|
|
72
|
-
: nextCurrentTimeSeconds,
|
|
73
|
-
);
|
|
74
|
-
},
|
|
75
|
-
[],
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
const {
|
|
79
|
-
transcript,
|
|
80
|
-
videoFile,
|
|
81
|
-
isCalendarEventRecordingQueryLoading,
|
|
82
|
-
errorMessage,
|
|
83
|
-
} = useCalendarEventRecording(calendarEventId);
|
|
84
|
-
const { calendarEventParticipants } =
|
|
85
|
-
useCalendarEventParticipants(calendarEventId);
|
|
86
|
-
|
|
87
|
-
const videoFileUrl = videoFile?.url ?? undefined;
|
|
88
|
-
|
|
89
|
-
return (
|
|
90
|
-
<StyledRecordingShell>
|
|
91
|
-
<StyledRecordingHeader>
|
|
92
|
-
<StyledRecordingTitle>Recording and Transcript</StyledRecordingTitle>
|
|
93
|
-
</StyledRecordingHeader>
|
|
94
|
-
<StyledRecordingBody>
|
|
95
|
-
<StyledRecordingContentFrame>
|
|
96
|
-
<CalendarEventRecordingBody
|
|
97
|
-
transcript={transcript}
|
|
98
|
-
videoFileUrl={videoFileUrl}
|
|
99
|
-
isCalendarEventRecordingQueryLoading={
|
|
100
|
-
isCalendarEventRecordingQueryLoading
|
|
101
|
-
}
|
|
102
|
-
errorMessage={errorMessage}
|
|
103
|
-
currentTimeSeconds={currentTimeSeconds}
|
|
104
|
-
calendarEventParticipants={calendarEventParticipants}
|
|
105
|
-
onVideoTimeUpdate={updateCurrentTimeSeconds}
|
|
106
|
-
/>
|
|
107
|
-
</StyledRecordingContentFrame>
|
|
108
|
-
</StyledRecordingBody>
|
|
109
|
-
</StyledRecordingShell>
|
|
110
|
-
);
|
|
111
|
-
};
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import styled from '@emotion/styled';
|
|
2
|
-
import { isUndefined } from '@sniptt/guards';
|
|
3
|
-
import { useMemo } from 'react';
|
|
4
|
-
|
|
5
|
-
import { TranscriptEntryList } from 'src/front-components/components/TranscriptEntryList';
|
|
6
|
-
import { TranscriptErrorBox } from 'src/front-components/components/TranscriptErrorBox';
|
|
7
|
-
import { recordingThemeCssVariables } from 'src/front-components/constants/recording-theme-css-variables';
|
|
8
|
-
import { type CalendarEventRecordingParticipant } from 'src/front-components/types/calendar-event-recording-participant.type';
|
|
9
|
-
import { parseTranscriptEntries } from 'src/front-components/utils/parse-transcript-entries.util';
|
|
10
|
-
import { parseTranscriptMarker } from 'src/logic-functions/domain/parse-transcript-marker.util';
|
|
11
|
-
import { isNonEmptyString } from 'src/logic-functions/utils/is-non-empty-string.util';
|
|
12
|
-
|
|
13
|
-
const StyledTranscriptCenteredState = styled.div`
|
|
14
|
-
align-items: center;
|
|
15
|
-
color: ${recordingThemeCssVariables.font.colorTertiary};
|
|
16
|
-
display: flex;
|
|
17
|
-
flex: 1;
|
|
18
|
-
font-size: ${recordingThemeCssVariables.font.sizeSm};
|
|
19
|
-
justify-content: center;
|
|
20
|
-
`;
|
|
21
|
-
|
|
22
|
-
type RecordingTranscriptProps = {
|
|
23
|
-
transcript: unknown;
|
|
24
|
-
currentTimeSeconds: number;
|
|
25
|
-
calendarEventParticipants: CalendarEventRecordingParticipant[];
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export const RecordingTranscript = ({
|
|
29
|
-
transcript,
|
|
30
|
-
currentTimeSeconds,
|
|
31
|
-
calendarEventParticipants,
|
|
32
|
-
}: RecordingTranscriptProps) => {
|
|
33
|
-
const marker = useMemo(() => parseTranscriptMarker(transcript), [transcript]);
|
|
34
|
-
const entries = useMemo(
|
|
35
|
-
() => parseTranscriptEntries(transcript),
|
|
36
|
-
[transcript],
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
if (isUndefined(transcript)) {
|
|
40
|
-
return (
|
|
41
|
-
<StyledTranscriptCenteredState>
|
|
42
|
-
No transcript for this calendar event yet.
|
|
43
|
-
</StyledTranscriptCenteredState>
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (marker?.status === 'PENDING') {
|
|
48
|
-
return (
|
|
49
|
-
<StyledTranscriptCenteredState>
|
|
50
|
-
The transcript is being generated. Check back in a few minutes.
|
|
51
|
-
</StyledTranscriptCenteredState>
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (marker?.status === 'FAILED') {
|
|
56
|
-
return (
|
|
57
|
-
<TranscriptErrorBox
|
|
58
|
-
title="Transcription failed"
|
|
59
|
-
description={
|
|
60
|
-
isNonEmptyString(marker.subCode)
|
|
61
|
-
? `The transcription provider could not process this recording (${marker.subCode}).`
|
|
62
|
-
: 'The transcription provider could not process this recording.'
|
|
63
|
-
}
|
|
64
|
-
/>
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (isUndefined(entries)) {
|
|
69
|
-
return (
|
|
70
|
-
<TranscriptErrorBox
|
|
71
|
-
title="Unrecognized transcript format"
|
|
72
|
-
description="The stored transcript does not match the expected diarized format."
|
|
73
|
-
/>
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (entries.length === 0) {
|
|
78
|
-
return (
|
|
79
|
-
<StyledTranscriptCenteredState>
|
|
80
|
-
The transcript is empty.
|
|
81
|
-
</StyledTranscriptCenteredState>
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return (
|
|
86
|
-
<TranscriptEntryList
|
|
87
|
-
entries={entries}
|
|
88
|
-
currentTimeSeconds={currentTimeSeconds}
|
|
89
|
-
calendarEventParticipants={calendarEventParticipants}
|
|
90
|
-
/>
|
|
91
|
-
);
|
|
92
|
-
};
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import styled from '@emotion/styled';
|
|
2
|
-
import { memo, type SyntheticEvent } from 'react';
|
|
3
|
-
|
|
4
|
-
import { recordingThemeCssVariables } from 'src/front-components/constants/recording-theme-css-variables';
|
|
5
|
-
|
|
6
|
-
const DEFAULT_VIDEO_ASPECT_RATIO = '16 / 9';
|
|
7
|
-
|
|
8
|
-
const StyledVideoViewport = styled.div`
|
|
9
|
-
aspect-ratio: ${DEFAULT_VIDEO_ASPECT_RATIO};
|
|
10
|
-
background: ${recordingThemeCssVariables.background.primary};
|
|
11
|
-
border-radius: ${recordingThemeCssVariables.border.radiusSm};
|
|
12
|
-
overflow: hidden;
|
|
13
|
-
width: 100%;
|
|
14
|
-
`;
|
|
15
|
-
|
|
16
|
-
const StyledVideo = styled.video`
|
|
17
|
-
accent-color: ${recordingThemeCssVariables.accent.primary};
|
|
18
|
-
background: ${recordingThemeCssVariables.background.primary};
|
|
19
|
-
color-scheme: light dark;
|
|
20
|
-
display: block;
|
|
21
|
-
height: 100%;
|
|
22
|
-
object-fit: contain;
|
|
23
|
-
width: 100%;
|
|
24
|
-
`;
|
|
25
|
-
|
|
26
|
-
type RecordingVideoPlayerProps = {
|
|
27
|
-
src: string | undefined;
|
|
28
|
-
onTimeUpdate: (currentTimeSeconds: number) => void;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const RecordingVideoPlayerComponent = ({
|
|
32
|
-
src,
|
|
33
|
-
onTimeUpdate,
|
|
34
|
-
}: RecordingVideoPlayerProps) => {
|
|
35
|
-
const handleTimeUpdate = (event: SyntheticEvent<HTMLVideoElement>) => {
|
|
36
|
-
onTimeUpdate(event.currentTarget.currentTime);
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
return (
|
|
40
|
-
<StyledVideoViewport>
|
|
41
|
-
<StyledVideo
|
|
42
|
-
controls
|
|
43
|
-
playsInline
|
|
44
|
-
preload="metadata"
|
|
45
|
-
src={src}
|
|
46
|
-
onTimeUpdate={handleTimeUpdate}
|
|
47
|
-
/>
|
|
48
|
-
</StyledVideoViewport>
|
|
49
|
-
);
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
export const RecordingVideoPlayer = memo(RecordingVideoPlayerComponent);
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import styled from '@emotion/styled';
|
|
2
|
-
import { useMemo } from 'react';
|
|
3
|
-
|
|
4
|
-
import { TranscriptEntryListItem } from 'src/front-components/components/TranscriptEntryListItem';
|
|
5
|
-
import { recordingThemeCssVariables } from 'src/front-components/constants/recording-theme-css-variables';
|
|
6
|
-
import { type CalendarEventRecordingParticipant } from 'src/front-components/types/calendar-event-recording-participant.type';
|
|
7
|
-
import { type TranscriptEntry } from 'src/front-components/types/transcript-entry.type';
|
|
8
|
-
import { buildCalendarEventParticipantBySpeakerName } from 'src/front-components/utils/build-calendar-event-participant-by-speaker-name.util';
|
|
9
|
-
import { findActiveTranscriptEntryIndex } from 'src/front-components/utils/find-active-transcript-entry-index.util';
|
|
10
|
-
import { getCalendarEventParticipantForSpeakerName } from 'src/front-components/utils/get-calendar-event-participant-for-speaker-name.util';
|
|
11
|
-
|
|
12
|
-
const StyledTranscriptContainer = styled.div`
|
|
13
|
-
display: flex;
|
|
14
|
-
flex: 1;
|
|
15
|
-
flex-direction: column;
|
|
16
|
-
gap: ${recordingThemeCssVariables.spacing[2]};
|
|
17
|
-
min-height: 0;
|
|
18
|
-
`;
|
|
19
|
-
|
|
20
|
-
type TranscriptEntryListProps = {
|
|
21
|
-
entries: TranscriptEntry[];
|
|
22
|
-
currentTimeSeconds: number;
|
|
23
|
-
calendarEventParticipants: CalendarEventRecordingParticipant[];
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export const TranscriptEntryList = ({
|
|
27
|
-
entries,
|
|
28
|
-
currentTimeSeconds,
|
|
29
|
-
calendarEventParticipants,
|
|
30
|
-
}: TranscriptEntryListProps) => {
|
|
31
|
-
const activeEntryIndex = findActiveTranscriptEntryIndex(
|
|
32
|
-
entries,
|
|
33
|
-
currentTimeSeconds,
|
|
34
|
-
);
|
|
35
|
-
const calendarEventParticipantBySpeakerName = useMemo(
|
|
36
|
-
() => buildCalendarEventParticipantBySpeakerName(calendarEventParticipants),
|
|
37
|
-
[calendarEventParticipants],
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
return (
|
|
41
|
-
<StyledTranscriptContainer>
|
|
42
|
-
{entries.map((entry, entryIndex) => {
|
|
43
|
-
const calendarEventParticipant =
|
|
44
|
-
getCalendarEventParticipantForSpeakerName({
|
|
45
|
-
speakerName: entry.speakerName,
|
|
46
|
-
calendarEventParticipantBySpeakerName,
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
return (
|
|
50
|
-
<TranscriptEntryListItem
|
|
51
|
-
key={entryIndex}
|
|
52
|
-
entry={entry}
|
|
53
|
-
isActive={entryIndex === activeEntryIndex}
|
|
54
|
-
currentTimeSeconds={currentTimeSeconds}
|
|
55
|
-
calendarEventParticipant={calendarEventParticipant}
|
|
56
|
-
/>
|
|
57
|
-
);
|
|
58
|
-
})}
|
|
59
|
-
</StyledTranscriptContainer>
|
|
60
|
-
);
|
|
61
|
-
};
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import styled from '@emotion/styled';
|
|
2
|
-
import { isUndefined } from '@sniptt/guards';
|
|
3
|
-
|
|
4
|
-
import { TranscriptSpeakerChip } from 'src/front-components/components/TranscriptSpeakerChip';
|
|
5
|
-
import { recordingThemeCssVariables } from 'src/front-components/constants/recording-theme-css-variables';
|
|
6
|
-
import { type CalendarEventRecordingParticipant } from 'src/front-components/types/calendar-event-recording-participant.type';
|
|
7
|
-
import {
|
|
8
|
-
type TranscriptEntry,
|
|
9
|
-
type TranscriptWord,
|
|
10
|
-
} from 'src/front-components/types/transcript-entry.type';
|
|
11
|
-
import { formatTranscriptTimestamp } from 'src/front-components/utils/format-transcript-timestamp.util';
|
|
12
|
-
|
|
13
|
-
const StyledEntry = styled.div<{ $isActive: boolean }>`
|
|
14
|
-
align-items: flex-start;
|
|
15
|
-
background: ${({ $isActive }) =>
|
|
16
|
-
$isActive
|
|
17
|
-
? recordingThemeCssVariables.background.transparentBlue
|
|
18
|
-
: 'transparent'};
|
|
19
|
-
border-radius: ${recordingThemeCssVariables.border.radiusSm};
|
|
20
|
-
box-sizing: border-box;
|
|
21
|
-
display: flex;
|
|
22
|
-
flex-direction: column;
|
|
23
|
-
gap: ${recordingThemeCssVariables.spacing[2]};
|
|
24
|
-
justify-content: center;
|
|
25
|
-
padding: ${recordingThemeCssVariables.spacing[2]};
|
|
26
|
-
width: 100%;
|
|
27
|
-
`;
|
|
28
|
-
|
|
29
|
-
const StyledEntryHeader = styled.div`
|
|
30
|
-
align-items: center;
|
|
31
|
-
align-self: stretch;
|
|
32
|
-
display: flex;
|
|
33
|
-
gap: ${recordingThemeCssVariables.spacing[2]};
|
|
34
|
-
min-height: ${recordingThemeCssVariables.spacing[6]};
|
|
35
|
-
min-width: 0;
|
|
36
|
-
`;
|
|
37
|
-
|
|
38
|
-
const StyledTimestamp = styled.span`
|
|
39
|
-
color: ${recordingThemeCssVariables.font.colorTertiary};
|
|
40
|
-
font-size: ${recordingThemeCssVariables.font.sizeXs};
|
|
41
|
-
line-height: 1.4;
|
|
42
|
-
`;
|
|
43
|
-
|
|
44
|
-
const StyledEntryText = styled.p`
|
|
45
|
-
align-self: stretch;
|
|
46
|
-
color: ${recordingThemeCssVariables.font.colorSecondary};
|
|
47
|
-
font-size: ${recordingThemeCssVariables.font.sizeSm};
|
|
48
|
-
line-height: 1.4;
|
|
49
|
-
margin: 0;
|
|
50
|
-
`;
|
|
51
|
-
|
|
52
|
-
const StyledWord = styled.span<{ $isSpoken: boolean }>`
|
|
53
|
-
color: ${({ $isSpoken }) =>
|
|
54
|
-
$isSpoken
|
|
55
|
-
? recordingThemeCssVariables.font.colorPrimary
|
|
56
|
-
: recordingThemeCssVariables.font.colorSecondary};
|
|
57
|
-
line-height: 1.4;
|
|
58
|
-
transition: color 0.15s ease;
|
|
59
|
-
`;
|
|
60
|
-
|
|
61
|
-
type TranscriptEntryListItemProps = {
|
|
62
|
-
entry: TranscriptEntry;
|
|
63
|
-
isActive: boolean;
|
|
64
|
-
currentTimeSeconds: number;
|
|
65
|
-
calendarEventParticipant: CalendarEventRecordingParticipant | undefined;
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
export const TranscriptEntryListItem = ({
|
|
69
|
-
entry,
|
|
70
|
-
isActive,
|
|
71
|
-
currentTimeSeconds,
|
|
72
|
-
calendarEventParticipant,
|
|
73
|
-
}: TranscriptEntryListItemProps) => {
|
|
74
|
-
const speakerDisplayName =
|
|
75
|
-
calendarEventParticipant?.displayName ?? entry.speakerName;
|
|
76
|
-
|
|
77
|
-
return (
|
|
78
|
-
<StyledEntry $isActive={isActive}>
|
|
79
|
-
<StyledEntryHeader>
|
|
80
|
-
<TranscriptSpeakerChip
|
|
81
|
-
speakerName={speakerDisplayName}
|
|
82
|
-
avatarUrl={calendarEventParticipant?.avatarUrl}
|
|
83
|
-
placeholderColorSeed={
|
|
84
|
-
calendarEventParticipant?.placeholderColorSeed ?? speakerDisplayName
|
|
85
|
-
}
|
|
86
|
-
/>
|
|
87
|
-
{!isUndefined(entry.startSeconds) && (
|
|
88
|
-
<StyledTimestamp>
|
|
89
|
-
{formatTranscriptTimestamp(entry.startSeconds)}
|
|
90
|
-
</StyledTimestamp>
|
|
91
|
-
)}
|
|
92
|
-
</StyledEntryHeader>
|
|
93
|
-
<StyledEntryText>
|
|
94
|
-
{entry.words.map((word, wordIndex) => (
|
|
95
|
-
<StyledWord
|
|
96
|
-
key={wordIndex}
|
|
97
|
-
$isSpoken={isWordSpoken({ word, currentTimeSeconds })}
|
|
98
|
-
>
|
|
99
|
-
{wordIndex > 0 ? ' ' : ''}
|
|
100
|
-
{word.text}
|
|
101
|
-
</StyledWord>
|
|
102
|
-
))}
|
|
103
|
-
</StyledEntryText>
|
|
104
|
-
</StyledEntry>
|
|
105
|
-
);
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
const isWordSpoken = ({
|
|
109
|
-
word,
|
|
110
|
-
currentTimeSeconds,
|
|
111
|
-
}: {
|
|
112
|
-
word: TranscriptWord;
|
|
113
|
-
currentTimeSeconds: number;
|
|
114
|
-
}): boolean =>
|
|
115
|
-
!isUndefined(word.startSeconds) && currentTimeSeconds >= word.startSeconds;
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import styled from '@emotion/styled';
|
|
2
|
-
|
|
3
|
-
import { recordingThemeCssVariables } from 'src/front-components/constants/recording-theme-css-variables';
|
|
4
|
-
|
|
5
|
-
const StyledStateContainer = styled.div`
|
|
6
|
-
box-sizing: border-box;
|
|
7
|
-
font-family: ${recordingThemeCssVariables.font.family};
|
|
8
|
-
height: 100%;
|
|
9
|
-
padding: ${recordingThemeCssVariables.spacing[4]};
|
|
10
|
-
`;
|
|
11
|
-
|
|
12
|
-
const StyledErrorBox = styled.div`
|
|
13
|
-
background: ${recordingThemeCssVariables.background.transparentDanger};
|
|
14
|
-
border: 1px solid ${recordingThemeCssVariables.border.colorDanger};
|
|
15
|
-
border-radius: ${recordingThemeCssVariables.border.radiusMd};
|
|
16
|
-
display: flex;
|
|
17
|
-
flex-direction: column;
|
|
18
|
-
gap: ${recordingThemeCssVariables.spacing[1]};
|
|
19
|
-
padding: ${recordingThemeCssVariables.spacing[3]};
|
|
20
|
-
`;
|
|
21
|
-
|
|
22
|
-
const StyledErrorTitle = styled.span`
|
|
23
|
-
color: ${recordingThemeCssVariables.font.colorDanger};
|
|
24
|
-
font-size: ${recordingThemeCssVariables.font.sizeSm};
|
|
25
|
-
font-weight: ${recordingThemeCssVariables.font.weightMedium};
|
|
26
|
-
`;
|
|
27
|
-
|
|
28
|
-
const StyledErrorDescription = styled.span`
|
|
29
|
-
color: ${recordingThemeCssVariables.font.colorSecondary};
|
|
30
|
-
font-size: ${recordingThemeCssVariables.font.sizeSm};
|
|
31
|
-
`;
|
|
32
|
-
|
|
33
|
-
type TranscriptErrorBoxProps = {
|
|
34
|
-
title: string;
|
|
35
|
-
description: string;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export const TranscriptErrorBox = ({
|
|
39
|
-
title,
|
|
40
|
-
description,
|
|
41
|
-
}: TranscriptErrorBoxProps) => (
|
|
42
|
-
<StyledStateContainer>
|
|
43
|
-
<StyledErrorBox>
|
|
44
|
-
<StyledErrorTitle>{title}</StyledErrorTitle>
|
|
45
|
-
<StyledErrorDescription>{description}</StyledErrorDescription>
|
|
46
|
-
</StyledErrorBox>
|
|
47
|
-
</StyledStateContainer>
|
|
48
|
-
);
|