@100mslive/roomkit-react 0.2.7-alpha.1 → 0.2.7-alpha.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. package/dist/{HLSView-4B5MUDFR.js → HLSView-NDCESLVD.js} +2 -2
  2. package/dist/Prebuilt/common/constants.d.ts +5 -0
  3. package/dist/Prebuilt/components/AppData/useSheet.d.ts +4 -0
  4. package/dist/Prebuilt/components/Header/RoomDetailsHeader.d.ts +2 -0
  5. package/dist/Prebuilt/components/Polls/common/utils.d.ts +1 -1
  6. package/dist/Prebuilt/components/RoomDetails/Duration.d.ts +4 -0
  7. package/dist/Prebuilt/components/RoomDetails/RoomDetailsPane.d.ts +2 -0
  8. package/dist/Prebuilt/components/RoomDetails/RoomDetailsRow.d.ts +4 -0
  9. package/dist/Prebuilt/components/RoomDetails/RoomDetailsSheet.d.ts +2 -0
  10. package/dist/Prebuilt/layouts/Sheet.d.ts +2 -0
  11. package/dist/Prebuilt/provider/roomLayoutProvider/hooks/useRoomLayoutScreen.d.ts +5 -0
  12. package/dist/{chunk-KST24BRA.js → chunk-AGREPSFA.js} +1514 -1311
  13. package/dist/chunk-AGREPSFA.js.map +7 -0
  14. package/dist/index.cjs.js +2849 -2581
  15. package/dist/index.cjs.js.map +4 -4
  16. package/dist/index.js +1 -1
  17. package/dist/meta.cjs.json +502 -59
  18. package/dist/meta.esbuild.json +511 -68
  19. package/package.json +7 -7
  20. package/src/Prebuilt/App.tsx +2 -0
  21. package/src/Prebuilt/common/constants.ts +6 -0
  22. package/src/Prebuilt/components/AppData/AppData.tsx +1 -0
  23. package/src/Prebuilt/components/AppData/useSheet.ts +33 -0
  24. package/src/Prebuilt/components/AppData/useUISettings.js +1 -1
  25. package/src/Prebuilt/components/AudioVideoToggle.tsx +31 -27
  26. package/src/Prebuilt/components/Chat/ChatFooter.tsx +0 -1
  27. package/src/Prebuilt/components/Header/Header.tsx +2 -0
  28. package/src/Prebuilt/components/Header/RoomDetailsHeader.tsx +51 -0
  29. package/src/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.tsx +18 -2
  30. package/src/Prebuilt/components/Notifications/HandRaisedNotifications.tsx +4 -8
  31. package/src/Prebuilt/components/Notifications/Notifications.tsx +15 -2
  32. package/src/Prebuilt/components/Polls/common/utils.ts +15 -9
  33. package/src/Prebuilt/components/RoomDetails/Duration.tsx +26 -0
  34. package/src/Prebuilt/components/RoomDetails/RoomDetailsPane.tsx +36 -0
  35. package/src/Prebuilt/components/RoomDetails/RoomDetailsRow.tsx +23 -0
  36. package/src/Prebuilt/components/RoomDetails/RoomDetailsSheet.tsx +45 -0
  37. package/src/Prebuilt/components/ScreenShareToggle.jsx +5 -3
  38. package/src/Prebuilt/layouts/Sheet.tsx +14 -0
  39. package/src/Prebuilt/layouts/SidePane.tsx +4 -0
  40. package/src/Prebuilt/provider/roomLayoutProvider/hooks/useRoomLayoutScreen.ts +40 -0
  41. package/dist/chunk-KST24BRA.js.map +0 -7
  42. /package/dist/{HLSView-4B5MUDFR.js.map → HLSView-NDCESLVD.js.map} +0 -0
package/package.json CHANGED
@@ -10,7 +10,7 @@
10
10
  "prebuilt",
11
11
  "roomkit"
12
12
  ],
13
- "version": "0.2.7-alpha.1",
13
+ "version": "0.2.7-alpha.3",
14
14
  "author": "100ms",
15
15
  "license": "MIT",
16
16
  "repository": {
@@ -82,12 +82,12 @@
82
82
  "react": ">=17.0.2 <19.0.0"
83
83
  },
84
84
  "dependencies": {
85
- "@100mslive/hls-player": "0.2.7-alpha.1",
85
+ "@100mslive/hls-player": "0.2.7-alpha.3",
86
86
  "@100mslive/hms-noise-cancellation": "0.0.0-alpha.1",
87
- "@100mslive/hms-virtual-background": "1.12.7-alpha.1",
88
- "@100mslive/react-icons": "0.9.7-alpha.1",
89
- "@100mslive/react-sdk": "0.9.7-alpha.1",
90
- "@100mslive/types-prebuilt": "0.12.6",
87
+ "@100mslive/hms-virtual-background": "1.12.7-alpha.3",
88
+ "@100mslive/react-icons": "0.9.7-alpha.3",
89
+ "@100mslive/react-sdk": "0.9.7-alpha.3",
90
+ "@100mslive/types-prebuilt": "0.12.7",
91
91
  "@emoji-mart/data": "^1.0.6",
92
92
  "@emoji-mart/react": "^1.0.1",
93
93
  "@radix-ui/react-accordion": "1.0.0",
@@ -121,5 +121,5 @@
121
121
  "uuid": "^8.3.2",
122
122
  "worker-timers": "^7.0.40"
123
123
  },
124
- "gitHead": "d9ed012d59612c39bc68dc427b5749405e4eeb38"
124
+ "gitHead": "696d255e5bbde485a185ef420c2f00fefdb85426"
125
125
  }
@@ -26,6 +26,7 @@ import { PreviewScreen } from './components/Preview/PreviewScreen';
26
26
  // @ts-ignore: No implicit Any
27
27
  import { ToastContainer } from './components/Toast/ToastContainer';
28
28
  import { VBHandler } from './components/VirtualBackground/VBHandler';
29
+ import { Sheet } from './layouts/Sheet';
29
30
  import { RoomLayoutContext, RoomLayoutProvider, useRoomLayout } from './provider/roomLayoutProvider';
30
31
  import { DialogContainerProvider } from '../context/DialogContext';
31
32
  import { Box } from '../Layout';
@@ -293,6 +294,7 @@ function AppRoutes({
293
294
  <ToastContainer />
294
295
  <Notifications />
295
296
  <MwebLandscapePrompt />
297
+ <Sheet />
296
298
  <BackSwipe />
297
299
  {!isNotificationsDisabled && <FlyingEmoji />}
298
300
  <RemoteStopScreenshare />
@@ -46,6 +46,7 @@ export const APP_DATA = {
46
46
  disableNotifications: 'disableNotifications',
47
47
  pollState: 'pollState',
48
48
  background: 'background',
49
+ sheet: 'sheet',
49
50
  };
50
51
 
51
52
  export const UI_SETTINGS = {
@@ -64,6 +65,11 @@ export const SIDE_PANE_OPTIONS = {
64
65
  STREAMING: 'STREAMING',
65
66
  POLLS: 'POLLS',
66
67
  VB: 'VB',
68
+ ROOM_DETAILS: 'ROOM_DETAILS',
69
+ };
70
+
71
+ export const SHEET_OPTIONS = {
72
+ ROOM_DETAILS: 'ROOM_DETAILS',
67
73
  };
68
74
 
69
75
  export const POLL_STATE = {
@@ -54,6 +54,7 @@ const initialAppData = {
54
54
  },
55
55
  [APP_DATA.chatDraft]: '',
56
56
  [APP_DATA.sidePane]: '',
57
+ [APP_DATA.sheet]: '',
57
58
  [APP_DATA.hlsStarted]: false,
58
59
  [APP_DATA.rtmpStarted]: false,
59
60
  [APP_DATA.recordingStarted]: false,
@@ -0,0 +1,33 @@
1
+ import { useCallback } from 'react';
2
+ import { selectAppData, useHMSActions, useHMSStore, useHMSVanillaStore } from '@100mslive/react-sdk';
3
+ import { APP_DATA } from '../../common/constants';
4
+
5
+ export const useIsSheetTypeOpen = (sheetType: string) => {
6
+ if (!sheetType) {
7
+ throw Error('Pass one of the sheet options');
8
+ }
9
+ return useHMSStore(selectAppData(APP_DATA.sheet)) === sheetType;
10
+ };
11
+
12
+ export const useSheetState = () => {
13
+ const sheet = useHMSStore(selectAppData(APP_DATA.sheet));
14
+ return sheet;
15
+ };
16
+
17
+ export const useSheetToggle = (sheetType: string) => {
18
+ const hmsActions = useHMSActions();
19
+ const vanillaStore = useHMSVanillaStore();
20
+ const toggleSheet = useCallback(() => {
21
+ const isOpen = vanillaStore.getState(selectAppData(APP_DATA.sheet)) === sheetType;
22
+ hmsActions.setAppData(APP_DATA.sheet, !isOpen ? sheetType : '');
23
+ }, [vanillaStore, hmsActions, sheetType]);
24
+ return toggleSheet;
25
+ };
26
+
27
+ export const useSheetReset = () => {
28
+ const hmsActions = useHMSActions();
29
+ const resetSheet = useCallback(() => {
30
+ hmsActions.setAppData(APP_DATA.sheet, '');
31
+ }, [hmsActions]);
32
+ return resetSheet;
33
+ };
@@ -90,7 +90,7 @@ export const usePinnedTrack = () => {
90
90
 
91
91
  export const useSubscribedNotifications = notificationKey => {
92
92
  const notificationPreference = useHMSStore(selectAppDataByPath(APP_DATA.subscribedNotifications, notificationKey));
93
- return notificationPreference || {};
93
+ return notificationPreference;
94
94
  };
95
95
 
96
96
  export const useIsNotificationDisabled = () => {
@@ -6,6 +6,7 @@ import {
6
6
  selectIsLocalAudioPluginPresent,
7
7
  selectLocalAudioTrackID,
8
8
  selectLocalVideoTrackID,
9
+ selectRoom,
9
10
  selectRoomState,
10
11
  selectVideoTrackByID,
11
12
  useAVToggle,
@@ -99,6 +100,7 @@ const NoiseCancellation = () => {
99
100
  const [active, setActive] = useState(isPluginAdded);
100
101
  const [inProgress, setInProgress] = useState(false);
101
102
  const actions = useHMSActions();
103
+ const room = useHMSStore(selectRoom);
102
104
 
103
105
  useEffect(() => {
104
106
  (async () => {
@@ -113,37 +115,40 @@ const NoiseCancellation = () => {
113
115
  })();
114
116
  }, [actions, active, isPluginAdded]);
115
117
 
116
- if (!plugin.isSupported() || !localPeerAudioTrackID) {
118
+ if (!plugin.isSupported() || !room.isNoiseCancellationEnabled || !localPeerAudioTrackID) {
117
119
  return null;
118
120
  }
119
121
 
120
122
  return (
121
- <Dropdown.Item
122
- css={{
123
- p: '$4 $8',
124
- h: '$15',
125
- fontSize: '$xs',
126
- justifyContent: 'space-between',
127
- }}
128
- onClick={e => {
129
- e.preventDefault();
130
- setActive(value => !value);
131
- }}
132
- >
133
- <Text css={{ display: 'flex', alignItems: 'center', gap: '$2', fontSize: '$xs', '& svg': { size: '$8' } }}>
134
- <AudioLevelIcon />
135
- Reduce Noise
136
- </Text>
137
- <Switch
138
- id="noise_cancellation"
139
- checked={active}
140
- disabled={inProgress}
141
- onClick={e => e.stopPropagation()}
142
- onCheckedChange={value => {
143
- setActive(value);
123
+ <>
124
+ <Dropdown.Item
125
+ css={{
126
+ p: '$4 $8',
127
+ h: '$15',
128
+ fontSize: '$xs',
129
+ justifyContent: 'space-between',
144
130
  }}
145
- />
146
- </Dropdown.Item>
131
+ onClick={e => {
132
+ e.preventDefault();
133
+ setActive(value => !value);
134
+ }}
135
+ >
136
+ <Text css={{ display: 'flex', alignItems: 'center', gap: '$2', fontSize: '$xs', '& svg': { size: '$8' } }}>
137
+ <AudioLevelIcon />
138
+ Reduce Noise
139
+ </Text>
140
+ <Switch
141
+ id="noise_cancellation"
142
+ checked={active}
143
+ disabled={inProgress}
144
+ onClick={e => e.stopPropagation()}
145
+ onCheckedChange={value => {
146
+ setActive(value);
147
+ }}
148
+ />
149
+ </Dropdown.Item>
150
+ <Dropdown.ItemSeparator css={{ mx: 0 }} />
151
+ </>
147
152
  );
148
153
  };
149
154
 
@@ -252,7 +257,6 @@ export const AudioVideoToggle = ({ hideOptions = false }) => {
252
257
  )}
253
258
  <Dropdown.ItemSeparator css={{ mx: 0 }} />
254
259
  <NoiseCancellation />
255
- <Dropdown.ItemSeparator css={{ mx: 0 }} />
256
260
  <AudioSettings onClick={() => setShowSettings(true)} />
257
261
  </IconButtonWithOptions>
258
262
  ) : null}
@@ -219,7 +219,6 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
219
219
  placeholder={message_placeholder}
220
220
  ref={inputRef}
221
221
  required
222
- autoFocus={!isMobile}
223
222
  onKeyPress={async event => {
224
223
  if (event.key === 'Enter') {
225
224
  if (!event.shiftKey) {
@@ -5,6 +5,7 @@ import { config as cssConfig, Flex } from '../../..';
5
5
  // @ts-ignore: No implicit any
6
6
  import { Logo, SpeakerTag } from './HeaderComponents';
7
7
  // @ts-ignore: No implicit any
8
+ import { RoomDetailsHeader } from './RoomDetailsHeader';
8
9
  import { LiveStatus, RecordingPauseStatus, RecordingStatus, StreamActions } from './StreamActions';
9
10
  // @ts-ignore: No implicit any
10
11
  import { AudioActions, CamaraFlipActions } from './common';
@@ -20,6 +21,7 @@ export const Header = () => {
20
21
  <Flex justify="between" align="center" css={{ position: 'relative', height: '100%' }}>
21
22
  <Flex align="center" gap="2" css={{ position: 'absolute', left: '$10' }}>
22
23
  <Logo />
24
+ <RoomDetailsHeader />
23
25
  <SpeakerTag />
24
26
  {isMobile && (
25
27
  <Flex align="center" css={{ gap: '$4' }}>
@@ -0,0 +1,51 @@
1
+ import React from 'react';
2
+ import { useMedia } from 'react-use';
3
+ import { ChevronRightIcon } from '@100mslive/react-icons';
4
+ import { Flex } from '../../../Layout';
5
+ import { Text } from '../../../Text';
6
+ import { config as cssConfig } from '../../../Theme';
7
+ import { useRoomLayoutHeader } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
8
+ import { useSheetToggle } from '../AppData/useSheet';
9
+ // @ts-ignore
10
+ import { useSidepaneToggle } from '../AppData/useSidepane';
11
+ import { SHEET_OPTIONS, SIDE_PANE_OPTIONS } from '../../common/constants';
12
+
13
+ export const RoomDetailsHeader = () => {
14
+ const { title, description } = useRoomLayoutHeader();
15
+ const isMobile = useMedia(cssConfig.media.md);
16
+ const clipLength = 80;
17
+ const toggleDetailsPane = useSidepaneToggle(SIDE_PANE_OPTIONS.ROOM_DETAILS);
18
+ const toggleDetailsSheet = useSheetToggle(SHEET_OPTIONS.ROOM_DETAILS);
19
+
20
+ if ((!title && !description) || (isMobile && !title)) {
21
+ return null;
22
+ }
23
+
24
+ return (
25
+ <Flex direction={isMobile ? 'row' : 'column'} css={{ ml: '$8', alignItems: isMobile ? 'center' : 'start' }}>
26
+ <Text variant="sm" css={{ c: '$on_surface_high', fontWeight: '$semiBold' }}>
27
+ {title}
28
+ </Text>
29
+ {!isMobile && (
30
+ <Flex align="end" css={{ color: '$on_surface_high' }}>
31
+ <Text variant="xs" css={{ c: '$on_surface_medium' }}>
32
+ {description.slice(0, clipLength)}
33
+ </Text>
34
+ {description.length > clipLength ? (
35
+ <span
36
+ style={{ fontWeight: '600', fontSize: '12px', cursor: 'pointer', lineHeight: '1rem' }}
37
+ onClick={toggleDetailsPane}
38
+ >
39
+ &nbsp;...more
40
+ </span>
41
+ ) : null}
42
+ </Flex>
43
+ )}
44
+ {isMobile && description ? (
45
+ <Flex css={{ color: '$on_surface_medium' }}>
46
+ <ChevronRightIcon height={16} width={16} onClick={toggleDetailsSheet} />
47
+ </Flex>
48
+ ) : null}
49
+ </Flex>
50
+ );
51
+ };
@@ -17,6 +17,7 @@ import {
17
17
  HamburgerMenuIcon,
18
18
  HandIcon,
19
19
  HandRaiseSlashedIcon,
20
+ InfoIcon,
20
21
  PeopleIcon,
21
22
  QuizActiveIcon,
22
23
  QuizIcon,
@@ -41,6 +42,8 @@ import { ActionTile } from '../ActionTile';
41
42
  import { ChangeNameModal } from '../ChangeNameModal';
42
43
  // @ts-ignore: No implicit any
43
44
  import { MuteAllModal } from '../MuteAllModal';
45
+ import { useRoomLayoutHeader } from '../../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
46
+ import { useSheetToggle } from '../../AppData/useSheet';
44
47
  // @ts-ignore: No implicit any
45
48
  import { usePollViewToggle, useSidepaneToggle } from '../../AppData/useSidepane';
46
49
  // @ts-ignore: No implicit Any
@@ -53,7 +56,7 @@ import { useUnreadPollQuizPresent } from '../../hooks/useUnreadPollQuizPresent';
53
56
  // @ts-ignore: No implicit any
54
57
  import { getFormattedCount } from '../../../common/utils';
55
58
  // @ts-ignore: No implicit any
56
- import { SIDE_PANE_OPTIONS } from '../../../common/constants';
59
+ import { SHEET_OPTIONS, SIDE_PANE_OPTIONS } from '../../../common/constants';
57
60
 
58
61
  const MODALS = {
59
62
  CHANGE_NAME: 'changeName',
@@ -93,7 +96,8 @@ export const MwebOptions = ({
93
96
  const { toggleAudio, toggleVideo } = useAVToggle();
94
97
  const noAVPermissions = !(toggleAudio || toggleVideo);
95
98
  const { unreadPollQuiz, setUnreadPollQuiz } = useUnreadPollQuizPresent();
96
- // const toggleVB = useSidepaneToggle(SIDE_PANE_OPTIONS.VB);
99
+ const { title, description } = useRoomLayoutHeader();
100
+ const toggleDetailsSheet = useSheetToggle(SHEET_OPTIONS.ROOM_DETAILS);
97
101
 
98
102
  useDropdownList({ open: openModals.size > 0 || openOptionsSheet || openSettingsSheet, name: 'MoreSettings' });
99
103
 
@@ -291,6 +295,18 @@ export const MwebOptions = ({
291
295
  </ActionTile.Title>
292
296
  </ActionTile.Root>
293
297
  ) : null}
298
+
299
+ {title || description ? (
300
+ <ActionTile.Root
301
+ onClick={() => {
302
+ setOpenOptionsSheet(false);
303
+ toggleDetailsSheet();
304
+ }}
305
+ >
306
+ <InfoIcon />
307
+ <ActionTile.Title>About Session</ActionTile.Title>
308
+ </ActionTile.Root>
309
+ ) : null}
294
310
  </Box>
295
311
  </Sheet.Content>
296
312
  </Sheet.Root>
@@ -13,13 +13,14 @@ import { ToastBatcher } from '../Toast/ToastBatcher';
13
13
  import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
14
14
  // @ts-ignore: No implicit Any
15
15
  import { useSubscribedNotifications } from '../AppData/useUISettings';
16
+ import { SUBSCRIBED_NOTIFICATIONS } from '../../common/constants';
16
17
 
17
18
  export const HandRaisedNotifications = () => {
18
19
  const notification = useHMSNotifications(HMSNotificationTypes.HAND_RAISE_CHANGED);
19
20
  const roomState = useHMSStore(selectRoomState);
20
21
  const vanillaStore = useHMSVanillaStore();
21
22
  const { on_stage_exp } = useRoomLayoutConferencingScreen().elements || {};
22
- const subscribedNotifications = useSubscribedNotifications();
23
+ const isSubscribing = !!useSubscribedNotifications(SUBSCRIBED_NOTIFICATIONS.METADATA_UPDATED);
23
24
 
24
25
  useEffect(() => {
25
26
  if (!notification?.data) {
@@ -27,12 +28,7 @@ export const HandRaisedNotifications = () => {
27
28
  }
28
29
 
29
30
  // Don't show toast message in case of local peer.
30
- if (
31
- roomState !== HMSRoomState.Connected ||
32
- notification.data.isLocal ||
33
- !on_stage_exp ||
34
- !subscribedNotifications.METADATA_UPDATED
35
- ) {
31
+ if (roomState !== HMSRoomState.Connected || notification.data.isLocal || !on_stage_exp || !isSubscribing) {
36
32
  return;
37
33
  }
38
34
  const hasPeerHandRaised = vanillaStore.getState(selectHasPeerHandRaised(notification.data.id));
@@ -40,7 +36,7 @@ export const HandRaisedNotifications = () => {
40
36
  ToastBatcher.showToast({ notification, type: 'RAISE_HAND' });
41
37
  console.debug('Metadata updated', notification.data);
42
38
  }
43
- }, [notification, on_stage_exp, roomState, subscribedNotifications.METADATA_UPDATED, vanillaStore]);
39
+ }, [isSubscribing, notification, on_stage_exp, roomState, vanillaStore]);
44
40
 
45
41
  return null;
46
42
  };
@@ -4,9 +4,11 @@ import {
4
4
  HMSNotificationTypes,
5
5
  HMSRoleChangeRequest,
6
6
  HMSRoomState,
7
+ selectIsLocalScreenShared,
7
8
  selectLocalPeerID,
8
9
  selectPeerNameByID,
9
10
  selectRoomState,
11
+ useAwayNotifications,
10
12
  useCustomEvent,
11
13
  useHMSNotifications,
12
14
  useHMSStore,
@@ -14,7 +16,7 @@ import {
14
16
  } from '@100mslive/react-sdk';
15
17
  import { GroupIcon } from '@100mslive/react-icons';
16
18
  import { Box, Button } from '../../..';
17
- import { useUpdateRoomLayout } from '../../provider/roomLayoutProvider';
19
+ import { useRoomLayout, useUpdateRoomLayout } from '../../provider/roomLayoutProvider';
18
20
  // @ts-ignore: No implicit Any
19
21
  import { ToastManager } from '../Toast/ToastManager';
20
22
  import { AutoplayBlockedModal } from './AutoplayBlockedModal';
@@ -39,13 +41,16 @@ const pollToastKey: Record<string, string> = {};
39
41
  export function Notifications() {
40
42
  const localPeerID = useHMSStore(selectLocalPeerID);
41
43
  const notification = useHMSNotifications();
42
- const subscribedNotifications = useSubscribedNotifications();
44
+ const subscribedNotifications = useSubscribedNotifications() || {};
43
45
  const roomState = useHMSStore(selectRoomState);
44
46
  const updateRoomLayoutForRole = useUpdateRoomLayout();
45
47
  const isNotificationDisabled = useIsNotificationDisabled();
46
48
  const screenProps = useRoomLayoutConferencingScreen();
47
49
  const vanillaStore = useHMSVanillaStore();
48
50
  const togglePollView = usePollViewToggle();
51
+ const { showNotification } = useAwayNotifications();
52
+ const amIScreenSharing = useHMSStore(selectIsLocalScreenShared);
53
+ const logoURL = useRoomLayout()?.logo?.url;
49
54
 
50
55
  const handleRoleChangeDenied = useCallback((request: HMSRoleChangeRequest & { peerName: string }) => {
51
56
  ToastManager.addToast({
@@ -165,6 +170,14 @@ export function Notifications() {
165
170
  delete pollToastKey[notification?.data.id];
166
171
  }
167
172
  break;
173
+ case HMSNotificationTypes.NEW_MESSAGE:
174
+ if (amIScreenSharing) {
175
+ showNotification(`New message from ${notification.data.senderName}`, {
176
+ body: notification.data.message,
177
+ icon: logoURL,
178
+ });
179
+ }
180
+ break;
168
181
  default:
169
182
  break;
170
183
  }
@@ -1,16 +1,22 @@
1
- export const getFormattedTime = (milliseconds: number | undefined) => {
1
+ export const getFormattedTime = (milliseconds: number | undefined, precise = true) => {
2
2
  if (!milliseconds) return '-';
3
3
 
4
4
  const totalSeconds = milliseconds / 1000;
5
- const minutes = Math.floor(totalSeconds / 60);
6
- const seconds = totalSeconds % 60;
5
+ const hours = Math.floor(totalSeconds / 3600);
6
+ const minutes = Math.floor((totalSeconds % 3600) / 60);
7
+ const seconds = precise ? totalSeconds % 60 : Math.floor(totalSeconds % 60);
7
8
 
8
- let formattedSeconds = '';
9
- if (Number.isInteger(seconds) || minutes) {
10
- formattedSeconds = seconds.toFixed(0);
11
- } else {
12
- formattedSeconds = seconds.toFixed(1);
9
+ let formattedTime = '';
10
+ if (hours) {
11
+ formattedTime += `${hours}h `;
13
12
  }
13
+ if (minutes || hours) {
14
+ formattedTime += `${minutes}m `;
15
+ }
16
+ if (!precise && (hours || minutes)) {
17
+ return formattedTime;
18
+ }
19
+ formattedTime += `${seconds}s`;
14
20
 
15
- return `${minutes ? `${minutes}m ` : ''}${formattedSeconds}s`;
21
+ return formattedTime;
16
22
  };
@@ -0,0 +1,26 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { Flex } from '../../../Layout';
3
+ import { Text } from '../../../Text';
4
+ import { getFormattedTime } from '../Polls/common/utils';
5
+
6
+ export const Duration = ({ timestamp }: { timestamp: Date }) => {
7
+ const [elapsedTime, setElapsedTime] = useState(getFormattedTime(Date.now() - timestamp.getTime(), false));
8
+
9
+ useEffect(() => {
10
+ const timerAdded = setInterval(() => {
11
+ setElapsedTime(getFormattedTime(Date.now() - timestamp.getTime(), false));
12
+ }, 1000);
13
+
14
+ return () => {
15
+ clearInterval(timerAdded);
16
+ };
17
+ }, [timestamp]);
18
+
19
+ return (
20
+ <Flex css={{ color: '$on_surface_medium' }}>
21
+ <Text variant="xs" css={{ color: 'inherit' }}>
22
+ Started {elapsedTime} ago
23
+ </Text>
24
+ </Flex>
25
+ );
26
+ };
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+ import { CrossIcon } from '@100mslive/react-icons';
3
+ import { Box, Flex } from '../../../Layout';
4
+ import { Text } from '../../../Text';
5
+ import { RoomDetailsRow } from './RoomDetailsRow';
6
+ import { useRoomLayoutHeader } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
7
+ // @ts-ignore
8
+ import { useSidepaneToggle } from '../AppData/useSidepane';
9
+ import { SIDE_PANE_OPTIONS } from '../../common/constants';
10
+
11
+ export const RoomDetailsPane = () => {
12
+ const { title, description, details } = useRoomLayoutHeader();
13
+ const toggleDetailsPane = useSidepaneToggle(SIDE_PANE_OPTIONS.ROOM_DETAILS);
14
+ return (
15
+ <Box css={{ flex: '1 1 0' }}>
16
+ <Flex justify="between" align="center" css={{ w: '100%' }}>
17
+ <Text variant="h6">{title}</Text>
18
+ <Flex
19
+ onClick={toggleDetailsPane}
20
+ css={{ color: '$on_surface_high', cursor: 'pointer', '&:hover': { opacity: '0.8' } }}
21
+ >
22
+ <CrossIcon />
23
+ </Flex>
24
+ </Flex>
25
+
26
+ <RoomDetailsRow details={details} />
27
+
28
+ <Box css={{ mt: '$10' }}>
29
+ <Text css={{ color: '$on_surface_high', fontWeight: '$semiBold' }}>Description</Text>
30
+ <Text variant="sm" css={{ c: '$on_surface_medium' }}>
31
+ {description}
32
+ </Text>
33
+ </Box>
34
+ </Box>
35
+ );
36
+ };
@@ -0,0 +1,23 @@
1
+ import React from 'react';
2
+ import { Box, Flex } from '../../../Layout';
3
+ import { Text } from '../../../Text';
4
+ import { Duration } from './Duration';
5
+
6
+ export const RoomDetailsRow = ({ details }: { details: (string | Date)[] }) => {
7
+ return (
8
+ <Flex align="center" css={{ w: '100%' }}>
9
+ {details.map((detail, index) => (
10
+ <React.Fragment key={detail.toString()}>
11
+ {index > 0 && <Box css={{ h: '$2', w: '$2', r: '$round', bg: '$on_surface_medium', m: '0 $2' }} />}
12
+ {typeof detail !== 'string' ? (
13
+ <Duration timestamp={detail} />
14
+ ) : (
15
+ <Text variant="xs" css={{ c: '$on_surface_medium' }}>
16
+ {detail}
17
+ </Text>
18
+ )}
19
+ </React.Fragment>
20
+ ))}
21
+ </Flex>
22
+ );
23
+ };
@@ -0,0 +1,45 @@
1
+ import React from 'react';
2
+ import { CrossIcon } from '@100mslive/react-icons';
3
+ import { Box, Flex } from '../../../Layout';
4
+ import { Sheet } from '../../../Sheet';
5
+ import { Text } from '../../../Text';
6
+ // @ts-ignore
7
+ import { Logo } from '../Header/HeaderComponents';
8
+ import { RoomDetailsRow } from './RoomDetailsRow';
9
+ import { useRoomLayoutHeader } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
10
+ import { useIsSheetTypeOpen, useSheetToggle } from '../AppData/useSheet';
11
+ import { SHEET_OPTIONS } from '../../common/constants';
12
+
13
+ export const RoomDetailsSheet = () => {
14
+ const { title, description, details } = useRoomLayoutHeader();
15
+ const toggleSheet = useSheetToggle(SHEET_OPTIONS.ROOM_DETAILS);
16
+ const showRoomDetailsSheet = useIsSheetTypeOpen(SHEET_OPTIONS.ROOM_DETAILS);
17
+ return (
18
+ <Sheet.Root open={showRoomDetailsSheet} onOpenChange={toggleSheet}>
19
+ <Sheet.Content css={{ py: '$8', pb: '$12' }}>
20
+ <Flex
21
+ justify="between"
22
+ align="center"
23
+ css={{ w: '100%', borderBottom: '1px solid $border_bright', pb: '$4', mb: '$4', px: '$8' }}
24
+ >
25
+ <Text css={{ fontWeight: '$semiBold', color: '$on_surface_high' }}>Description</Text>
26
+ <Sheet.Close css={{ color: '$on_surface_high' }}>
27
+ <CrossIcon />
28
+ </Sheet.Close>
29
+ </Flex>
30
+ <Flex align="center" css={{ w: '100%', gap: '$4', pb: '$8', px: '$8' }}>
31
+ <Logo />
32
+ <Box>
33
+ <Text variant="sm" css={{ c: '$on_secondary_high', fontWeight: '$semiBold' }}>
34
+ {title}
35
+ </Text>
36
+ <RoomDetailsRow details={details} />
37
+ </Box>
38
+ </Flex>
39
+ <Text variant="sm" css={{ color: '$on_surface_medium', px: '$8' }}>
40
+ {description}
41
+ </Text>
42
+ </Sheet.Content>
43
+ </Sheet.Root>
44
+ );
45
+ };
@@ -1,5 +1,5 @@
1
1
  import React, { Fragment } from 'react';
2
- import { selectIsAllowedToPublish, useHMSStore, useScreenShare } from '@100mslive/react-sdk';
2
+ import { selectIsAllowedToPublish, useAwayNotifications, useHMSStore, useScreenShare } from '@100mslive/react-sdk';
3
3
  import { ShareScreenIcon } from '@100mslive/react-icons';
4
4
  import { ShareScreenOptions } from './pdfAnnotator/shareScreenOptions';
5
5
  import { Box, Flex } from '../../Layout';
@@ -14,6 +14,7 @@ export const ScreenshareToggle = ({ css = {} }) => {
14
14
  const isAudioOnly = useUISettings(UI_SETTINGS.isAudioOnly);
15
15
 
16
16
  const { amIScreenSharing, screenShareVideoTrackId: video, toggleScreenShare } = useScreenShare();
17
+ const { requestPermission } = useAwayNotifications();
17
18
  const isVideoScreenshare = amIScreenSharing && !!video;
18
19
  if (!isAllowedToPublish.screen || !isScreenshareSupported()) {
19
20
  return null;
@@ -28,8 +29,9 @@ export const ScreenshareToggle = ({ css = {} }) => {
28
29
  active={!isVideoScreenshare}
29
30
  css={css}
30
31
  disabled={isAudioOnly}
31
- onClick={() => {
32
- toggleScreenShare();
32
+ onClick={async () => {
33
+ await toggleScreenShare();
34
+ await requestPermission();
33
35
  }}
34
36
  >
35
37
  <Tooltip title={`${!isVideoScreenshare ? 'Start' : 'Stop'} screen sharing`}>
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import { selectAppData, useHMSStore } from '@100mslive/react-sdk';
3
+ import { RoomDetailsSheet } from '../components/RoomDetails/RoomDetailsSheet';
4
+ import { Box } from '../../Layout';
5
+ import { APP_DATA, SHEET_OPTIONS } from '../common/constants';
6
+
7
+ export const Sheet = () => {
8
+ const sheet = useHMSStore(selectAppData(APP_DATA.sheet));
9
+ let ViewComponent;
10
+ if (sheet === SHEET_OPTIONS.ROOM_DETAILS) {
11
+ ViewComponent = <RoomDetailsSheet />;
12
+ }
13
+ return <Box>{ViewComponent}</Box>;
14
+ };