@100mslive/roomkit-react 0.3.11 → 0.3.12-alpha.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -8,14 +8,17 @@ import { Text } from '../../../Text';
8
8
  // @ts-ignore: No implicit Any
9
9
  import { ToastManager } from '../Toast/ToastManager';
10
10
  // @ts-ignore: No implicit Any
11
- import { useSetIsCaptionEnabled } from '../AppData/useUISettings';
11
+ import { useSetAppDataByKey, useSetIsCaptionEnabled } from '../AppData/useUISettings';
12
+ import { CAPTION_TOAST } from '../../common/constants';
12
13
 
13
14
  export const CaptionContent = ({ isMobile, onExit }: { isMobile: boolean; onExit: () => void }) => {
14
15
  const DURATION = 2000;
15
16
  const actions = useHMSActions();
16
17
  const isTranscriptionEnabled = useHMSStore(selectIsTranscriptionEnabled);
18
+ const [toastId, setToastId] = useSetAppDataByKey(CAPTION_TOAST.captionToast);
17
19
 
18
20
  const [isCaptionEnabled, setIsCaptionEnabled] = useSetIsCaptionEnabled();
21
+
19
22
  return (
20
23
  <>
21
24
  <Text
@@ -90,30 +93,33 @@ export const CaptionContent = ({ isMobile, onExit }: { isMobile: boolean; onExit
90
93
  await actions.stopTranscription({
91
94
  mode: HMSTranscriptionMode.CAPTION,
92
95
  });
93
- ToastManager.addToast({
96
+ const id = ToastManager.replaceToast(toastId, {
94
97
  title: `Disabling Closed Caption for everyone.`,
95
98
  variant: 'standard',
96
99
  duration: DURATION,
97
100
  icon: <Loading color="currentColor" />,
98
101
  });
102
+ setToastId(id);
99
103
  onExit();
100
104
  return;
101
105
  }
102
106
  await actions.startTranscription({
103
107
  mode: HMSTranscriptionMode.CAPTION,
104
108
  });
105
- ToastManager.addToast({
109
+ const id = ToastManager.replaceToast(toastId, {
106
110
  title: `Enabling Closed Caption for everyone.`,
107
111
  variant: 'standard',
108
112
  duration: DURATION,
109
113
  icon: <Loading color="currentColor" />,
110
114
  });
115
+ setToastId(id);
111
116
  } catch (err) {
112
- ToastManager.addToast({
117
+ const id = ToastManager.replaceToast(toastId, {
113
118
  title: `Failed to ${isTranscriptionEnabled ? 'disabled' : 'enabled'} closed caption`,
114
119
  variant: 'error',
115
120
  icon: <AlertTriangleIcon style={{ marginRight: '0.5rem' }} />,
116
121
  });
122
+ setToastId(id);
117
123
  }
118
124
  onExit();
119
125
  }}
@@ -6,9 +6,25 @@ import {
6
6
  HLSLiveStreamingScreen_Elements,
7
7
  } from '@100mslive/types-prebuilt';
8
8
  import { match } from 'ts-pattern';
9
- import { selectAppData, selectLocalPeerID, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
10
- import { BrbIcon, CheckIcon, HamburgerMenuIcon, InfoIcon, PipIcon, SettingsIcon } from '@100mslive/react-icons';
11
- import { Checkbox, Dropdown, Flex, Text, Tooltip } from '../../../..';
9
+ import {
10
+ HMSTranscriptionMode,
11
+ selectAppData,
12
+ selectIsTranscriptionAllowedByMode,
13
+ selectIsTranscriptionEnabled,
14
+ selectLocalPeerID,
15
+ useHMSActions,
16
+ useHMSStore,
17
+ } from '@100mslive/react-sdk';
18
+ import {
19
+ BrbIcon,
20
+ CheckIcon,
21
+ HamburgerMenuIcon,
22
+ InfoIcon,
23
+ OpenCaptionIcon,
24
+ PipIcon,
25
+ SettingsIcon,
26
+ } from '@100mslive/react-icons';
27
+ import { Checkbox, Dropdown, Flex, Switch, Text, Tooltip } from '../../../..';
12
28
  import IconButton from '../../../IconButton';
13
29
  // @ts-ignore: No implicit any
14
30
  import { PIP } from '../../PIP';
@@ -61,6 +77,8 @@ export const DesktopOptions = ({
61
77
  const { isBRBOn, toggleBRB } = useMyMetadata();
62
78
  const isPipOn = PictureInPicture.isOn();
63
79
  const isBRBEnabled = !!elements?.brb;
80
+ const isTranscriptionAllowed = useHMSStore(selectIsTranscriptionAllowedByMode(HMSTranscriptionMode.CAPTION));
81
+ const isTranscriptionEnabled = useHMSStore(selectIsTranscriptionEnabled);
64
82
 
65
83
  useDropdownList({ open: openModals.size > 0, name: 'MoreSettings' });
66
84
 
@@ -116,6 +134,25 @@ export const DesktopOptions = ({
116
134
  </Flex>
117
135
  </Dropdown.Item>
118
136
  ) : null}
137
+ {isTranscriptionAllowed ? (
138
+ <Dropdown.Item
139
+ data-testid="closed_caption_admin"
140
+ onClick={() => {
141
+ updateState(MODALS.CAPTION, true);
142
+ }}
143
+ >
144
+ <OpenCaptionIcon />
145
+ <Flex direction="column" css={{ flexGrow: '1' }}>
146
+ <Text variant="sm" css={{ ml: '$4', color: '$on_surface_high' }}>
147
+ Closed Captions
148
+ </Text>
149
+ <Text variant="caption" css={{ ml: '$4', color: '$on_surface_medium' }}>
150
+ {isTranscriptionEnabled ? 'Enabled' : 'Disabled'}
151
+ </Text>
152
+ </Flex>
153
+ <Switch id="closed_caption_start_stop" checked={isTranscriptionEnabled} disabled={false} />
154
+ </Dropdown.Item>
155
+ ) : null}
119
156
  {screenType !== 'hls_live_streaming' ? (
120
157
  <Dropdown.Item css={{ p: 0, '&:empty': { display: 'none' } }}>
121
158
  <PIP
@@ -3,8 +3,11 @@ import { useClickAway } from 'react-use';
3
3
  import { ConferencingScreen, DefaultConferencingScreen_Elements } from '@100mslive/types-prebuilt';
4
4
  import { match } from 'ts-pattern';
5
5
  import {
6
+ HMSTranscriptionMode,
6
7
  selectIsConnectedToRoom,
7
8
  selectIsLocalVideoEnabled,
9
+ selectIsTranscriptionAllowedByMode,
10
+ selectIsTranscriptionEnabled,
8
11
  selectPeerCount,
9
12
  selectPermissions,
10
13
  useHMSActions,
@@ -13,12 +16,14 @@ import {
13
16
  } from '@100mslive/react-sdk';
14
17
  import {
15
18
  BrbIcon,
19
+ ClosedCaptionIcon,
16
20
  CrossIcon,
17
21
  EmojiIcon,
18
22
  HamburgerMenuIcon,
19
23
  HandIcon,
20
24
  HandRaiseSlashedIcon,
21
25
  InfoIcon,
26
+ OpenCaptionIcon,
22
27
  PeopleIcon,
23
28
  QuizActiveIcon,
24
29
  QuizIcon,
@@ -50,7 +55,7 @@ import { useSheetToggle } from '../../AppData/useSheet';
50
55
  // @ts-ignore: No implicit any
51
56
  import { usePollViewToggle, useSidepaneToggle } from '../../AppData/useSidepane';
52
57
  // @ts-ignore: No implicit Any
53
- import { useShowPolls } from '../../AppData/useUISettings';
58
+ import { useSetIsCaptionEnabled, useShowPolls } from '../../AppData/useUISettings';
54
59
  // @ts-ignore: No implicit any
55
60
  import { useDropdownList } from '../../hooks/useDropdownList';
56
61
  import { useMyMetadata } from '../../hooks/useMetadata';
@@ -104,7 +109,10 @@ export const MwebOptions = ({
104
109
  const toggleVB = useSidepaneToggle(SIDE_PANE_OPTIONS.VB);
105
110
  const isLocalVideoEnabled = useHMSStore(selectIsLocalVideoEnabled);
106
111
  const { startRecording, isRecordingLoading } = useRecordingHandler();
112
+ const isTranscriptionAllowed = useHMSStore(selectIsTranscriptionAllowedByMode(HMSTranscriptionMode.CAPTION));
113
+ const isTranscriptionEnabled = useHMSStore(selectIsTranscriptionEnabled);
107
114
 
115
+ const [isCaptionEnabled] = useSetIsCaptionEnabled();
108
116
  useDropdownList({ open: openModals.size > 0 || openOptionsSheet || openSettingsSheet, name: 'MoreSettings' });
109
117
 
110
118
  const updateState = (modalName: string, value: boolean) => {
@@ -189,6 +197,17 @@ export const MwebOptions = ({
189
197
  <ActionTile.Title>{isHandRaised ? 'Lower' : 'Raise'} Hand</ActionTile.Title>
190
198
  </ActionTile.Root>
191
199
  ) : null}
200
+ {isTranscriptionAllowed ? (
201
+ <ActionTile.Root
202
+ onClick={() => {
203
+ setOpenOptionsSheet(false);
204
+ updateState(MODALS.CAPTION, true);
205
+ }}
206
+ >
207
+ {isTranscriptionEnabled && isCaptionEnabled ? <ClosedCaptionIcon /> : <OpenCaptionIcon />}
208
+ <ActionTile.Title>Closed Caption</ActionTile.Title>
209
+ </ActionTile.Root>
210
+ ) : null}
192
211
  {isLocalVideoEnabled && !!elements?.virtual_background ? (
193
212
  <ActionTile.Root
194
213
  onClick={() => {
@@ -29,6 +29,7 @@ import { ReconnectNotifications } from './ReconnectNotifications';
29
29
  import { TrackBulkUnmuteModal } from './TrackBulkUnmuteModal';
30
30
  import { TrackNotifications } from './TrackNotifications';
31
31
  import { TrackUnmuteModal } from './TrackUnmuteModal';
32
+ import { TranscriptionNotifications } from './TranscriptionNotifications';
32
33
  import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
33
34
  // @ts-ignore: No implicit Any
34
35
  import { usePollViewToggle } from '../AppData/useSidepane';
@@ -200,6 +201,7 @@ export function Notifications() {
200
201
  <InitErrorModal />
201
202
  <ChatNotifications />
202
203
  <HandRaisedNotifications />
204
+ <TranscriptionNotifications />
203
205
  </>
204
206
  );
205
207
  }
@@ -0,0 +1,58 @@
1
+ import React, { useEffect } from 'react';
2
+ import { match } from 'ts-pattern';
3
+ import { HMSNotificationTypes, HMSTranscriptionState, useHMSNotifications } from '@100mslive/react-sdk';
4
+ import { AlertTriangleIcon, ClosedCaptionIcon, OpenCaptionIcon } from '@100mslive/react-icons';
5
+ // @ts-ignore: No implicit Any
6
+ import { ToastManager } from '../Toast/ToastManager';
7
+ // @ts-ignore: No implicit Any
8
+ import { useSetAppDataByKey } from '../AppData/useUISettings';
9
+ import { CAPTION_TOAST } from '../../common/constants';
10
+
11
+ export const TranscriptionNotifications = () => {
12
+ const notification = useHMSNotifications(HMSNotificationTypes.TRANSCRIPTION_STATE_UPDATED);
13
+ const [toastId, setToastId] = useSetAppDataByKey(CAPTION_TOAST.captionToast);
14
+
15
+ useEffect(() => {
16
+ if (!notification?.data) {
17
+ return;
18
+ }
19
+
20
+ console.debug(`[${notification.type}]`, notification);
21
+ const transcriptionStates = notification.data;
22
+ if (transcriptionStates.length > 0) {
23
+ let id = '';
24
+ match({ state: transcriptionStates[0].state, error: transcriptionStates[0].error })
25
+ .when(
26
+ ({ error }) => !!error,
27
+ () => {
28
+ id = ToastManager.replaceToast(toastId, {
29
+ title: `Failed to enable Closed Caption`,
30
+ variant: 'error',
31
+ icon: <AlertTriangleIcon style={{ marginRight: '0.5rem' }} />,
32
+ });
33
+ },
34
+ )
35
+ .with({ state: HMSTranscriptionState.STARTED }, () => {
36
+ id = ToastManager.replaceToast(toastId, {
37
+ title: `Closed Captioning enabled for everyone`,
38
+ variant: 'standard',
39
+ duration: 2000,
40
+ icon: <OpenCaptionIcon style={{ marginRight: '0.5rem' }} />,
41
+ });
42
+ })
43
+ .with({ state: HMSTranscriptionState.STOPPED }, () => {
44
+ id = ToastManager.replaceToast(toastId, {
45
+ title: `Closed Captioning disabled for everyone`,
46
+ variant: 'standard',
47
+ duration: 2000,
48
+ icon: <ClosedCaptionIcon style={{ marginRight: '0.5rem' }} />,
49
+ });
50
+ })
51
+ .otherwise(() => null);
52
+ setToastId(id);
53
+ }
54
+ // eslint-disable-next-line react-hooks/exhaustive-deps
55
+ }, [notification, setToastId]);
56
+
57
+ return null;
58
+ };
@@ -1,19 +1,15 @@
1
1
  import React, { useEffect, useMemo, useState } from 'react';
2
2
  import { GridVideoTileLayout } from '@100mslive/types-prebuilt/elements/video_tile_layout';
3
3
  import {
4
- HMSTranscriptionInfo,
5
4
  selectLocalPeerID,
6
5
  selectLocalPeerRoleName,
7
6
  selectPeers,
8
7
  selectPeerScreenSharing,
9
- selectTranscriptionsState,
10
8
  selectWhiteboard,
11
9
  useHMSStore,
12
10
  useHMSVanillaStore,
13
11
  } from '@100mslive/react-sdk';
14
- import { AlertTriangleIcon } from '@100mslive/react-icons';
15
12
  // @ts-ignore: No implicit Any
16
- import { ToastManager } from '../Toast/ToastManager';
17
13
  import { EqualProminence } from './EqualProminence';
18
14
  import { RoleProminence } from './RoleProminence';
19
15
  import { ScreenshareLayout } from './ScreenshareLayout';
@@ -99,18 +95,6 @@ export const GridLayout = ({
99
95
  objectFit: video_object_fit,
100
96
  };
101
97
 
102
- const transcriptionStates: HMSTranscriptionInfo[] | undefined = useHMSStore(selectTranscriptionsState);
103
-
104
- useEffect(() => {
105
- if (transcriptionStates && transcriptionStates.length > 0 && transcriptionStates[0].error) {
106
- ToastManager.addToast({
107
- title: `Failed to enable Closed Caption`,
108
- variant: 'error',
109
- icon: <AlertTriangleIcon style={{ marginRight: '0.5rem' }} />,
110
- });
111
- }
112
- }, [transcriptionStates]);
113
-
114
98
  useEffect(() => {
115
99
  if (mainPage !== 0) {
116
100
  return;
@@ -1,6 +1,12 @@
1
1
  import React, { useEffect, useState } from 'react';
2
2
  import { useMedia } from 'react-use';
3
- import { HMSTranscript, selectPeerNameByID, useHMSStore, useTranscript } from '@100mslive/react-sdk';
3
+ import {
4
+ HMSTranscript,
5
+ selectIsTranscriptionEnabled,
6
+ selectPeerNameByID,
7
+ useHMSStore,
8
+ useTranscript,
9
+ } from '@100mslive/react-sdk';
4
10
  import { Box, Flex } from '../../Layout';
5
11
  import { Text } from '../../Text';
6
12
  import { config } from '../../Theme';
@@ -170,6 +176,8 @@ export const CaptionsViewer = () => {
170
176
 
171
177
  const isCaptionEnabled = useIsCaptionEnabled();
172
178
 
179
+ const isTranscriptionEnabled = useHMSStore(selectIsTranscriptionEnabled);
180
+
173
181
  useEffect(() => {
174
182
  const timeInterval = setInterval(() => {
175
183
  if (!captionQueue) {
@@ -193,7 +201,7 @@ export const CaptionsViewer = () => {
193
201
  }
194
202
  return false;
195
203
  });
196
- if (dataToShow.length <= 0 || screenType === 'hls_live_streaming' || !isCaptionEnabled) {
204
+ if (dataToShow.length <= 0 || screenType === 'hls_live_streaming' || !isCaptionEnabled || !isTranscriptionEnabled) {
197
205
  return null;
198
206
  }
199
207
  return (