@100mslive/roomkit-react 0.1.6 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. package/dist/{HLSView-4NSE37G7.js → HLSView-3S74KF3A.js} +23 -4
  2. package/dist/HLSView-3S74KF3A.js.map +7 -0
  3. package/dist/Prebuilt/components/RoleChangeRequest/RequestPrompt.d.ts +9 -0
  4. package/dist/VideoTile/StyledVideoTile.d.ts +445 -3
  5. package/dist/{VirtualBackground-A5UM363O.js → VirtualBackground-3TI5NA4V.js} +3 -3
  6. package/dist/{chunk-BUWIMYLW.js → chunk-36X4ZCLC.js} +2 -2
  7. package/dist/{chunk-NMOZ33TX.js → chunk-5DQ3WTED.js} +3 -2
  8. package/dist/{chunk-NMOZ33TX.js.map → chunk-5DQ3WTED.js.map} +2 -2
  9. package/dist/{chunk-Q6U22HIE.js → chunk-Z7P5WITU.js} +223 -200
  10. package/dist/chunk-Z7P5WITU.js.map +7 -0
  11. package/dist/{conference-S7R3O4OC.js → conference-JNABIZBG.js} +534 -504
  12. package/dist/conference-JNABIZBG.js.map +7 -0
  13. package/dist/index.cjs.js +1011 -924
  14. package/dist/index.cjs.js.map +4 -4
  15. package/dist/index.js +2 -2
  16. package/dist/meta.cjs.json +241 -167
  17. package/dist/meta.esbuild.json +276 -203
  18. package/package.json +6 -6
  19. package/src/Input/Input.tsx +1 -1
  20. package/src/Prebuilt/common/hooks.js +1 -2
  21. package/src/Prebuilt/common/utils.js +7 -2
  22. package/src/Prebuilt/components/Chat/ChatBody.jsx +125 -106
  23. package/src/Prebuilt/components/Chat/ChatFooter.tsx +1 -0
  24. package/src/Prebuilt/components/Footer/Footer.tsx +4 -1
  25. package/src/Prebuilt/components/Footer/ParticipantList.jsx +8 -9
  26. package/src/Prebuilt/components/Header/ParticipantFilter.jsx +9 -12
  27. package/src/Prebuilt/components/Leave/DesktopLeaveRoom.tsx +36 -44
  28. package/src/Prebuilt/components/Leave/MwebLeaveRoom.tsx +23 -35
  29. package/src/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.tsx +4 -2
  30. package/src/Prebuilt/components/Notifications/Notifications.jsx +14 -1
  31. package/src/Prebuilt/components/Notifications/PeerNotifications.jsx +4 -15
  32. package/src/Prebuilt/components/Preview/PreviewJoin.tsx +12 -5
  33. package/src/Prebuilt/components/RaiseHand.jsx +3 -6
  34. package/src/Prebuilt/components/RoleChangeRequest/RequestPrompt.tsx +66 -0
  35. package/src/Prebuilt/components/RoleChangeRequest/RoleChangeRequestModal.tsx +89 -0
  36. package/src/Prebuilt/components/SidePaneTabs.tsx +21 -2
  37. package/src/Prebuilt/components/VideoTile.jsx +24 -15
  38. package/src/Prebuilt/components/conference.jsx +1 -1
  39. package/src/Prebuilt/components/hooks/useMetadata.jsx +15 -4
  40. package/src/Prebuilt/layouts/HLSView.jsx +20 -1
  41. package/src/Prebuilt/layouts/SidePane.tsx +0 -1
  42. package/src/Tooltip/Tooltip.tsx +1 -1
  43. package/src/VideoTile/StyledVideoTile.tsx +10 -14
  44. package/src/fixtures/peers.ts +5 -3
  45. package/dist/HLSView-4NSE37G7.js.map +0 -7
  46. package/dist/chunk-Q6U22HIE.js.map +0 -7
  47. package/dist/conference-S7R3O4OC.js.map +0 -7
  48. package/src/Prebuilt/components/RoleChangeRequestModal.tsx +0 -120
  49. /package/dist/Prebuilt/components/{RoleChangeRequestModal.d.ts → RoleChangeRequest/RoleChangeRequestModal.d.ts} +0 -0
  50. /package/dist/{VirtualBackground-A5UM363O.js.map → VirtualBackground-3TI5NA4V.js.map} +0 -0
  51. /package/dist/{chunk-BUWIMYLW.js.map → chunk-36X4ZCLC.js.map} +0 -0
@@ -30,6 +30,7 @@ export const MwebLeaveRoom = ({
30
30
  const permissions = useHMSStore(selectPermissions);
31
31
  const { isStreamingOn } = useRecordingStreaming();
32
32
  const showStream = screenType !== 'hls_live_streaming' && isStreamingOn;
33
+ const showLeaveOptions = (permissions?.hlsStreaming && isStreamingOn) || permissions?.endRoom;
33
34
 
34
35
  useDropdownList({ open, name: 'LeaveRoom' });
35
36
 
@@ -39,7 +40,7 @@ export const MwebLeaveRoom = ({
39
40
 
40
41
  return (
41
42
  <Fragment>
42
- {screenType !== 'hls_live_streaming' ? (
43
+ {showLeaveOptions ? (
43
44
  <Sheet.Root open={open} onOpenChange={setOpen}>
44
45
  <Sheet.Trigger asChild>
45
46
  <LeaveIconButton
@@ -70,36 +71,24 @@ export const MwebLeaveRoom = ({
70
71
  css={{ pt: 0, mt: '$10', color: '$on_surface_low', '&:hover': { color: '$on_surface_high' } }}
71
72
  />
72
73
 
73
- {permissions?.endRoom || permissions?.hlsStreaming ? (
74
- <LeaveCard
75
- title={showStream ? 'End Stream' : 'End Session'}
76
- subtitle={`The will end the ${
77
- showStream ? 'stream' : 'session'
78
- } for everyone. You can't undo this action.`}
79
- bg="$alert_error_dim"
80
- titleColor="$alert_error_brighter"
81
- css={{ color: '$alert_error_bright', '&:hover': { color: '$alert_error_brighter' } }}
82
- icon={<StopIcon height={24} width={24} />}
83
- onClick={() => {
84
- setOpen(false);
85
- setShowEndStreamAlert(true);
86
- }}
87
- />
88
- ) : null}
74
+ <LeaveCard
75
+ title={showStream ? 'End Stream' : 'End Session'}
76
+ subtitle={`The will end the ${
77
+ showStream ? 'stream' : 'session'
78
+ } for everyone. You can't undo this action.`}
79
+ bg="$alert_error_dim"
80
+ titleColor="$alert_error_brighter"
81
+ css={{ color: '$alert_error_bright', '&:hover': { color: '$alert_error_brighter' } }}
82
+ icon={<StopIcon height={24} width={24} />}
83
+ onClick={() => {
84
+ setOpen(false);
85
+ setShowEndStreamAlert(true);
86
+ }}
87
+ />
89
88
  </Sheet.Content>
90
89
  </Sheet.Root>
91
90
  ) : (
92
- <LeaveIconButton
93
- key="LeaveRoom"
94
- data-testid="leave_room_btn"
95
- onClick={() => {
96
- if (screenType === 'hls_live_streaming') {
97
- setShowLeaveRoomAlert(true);
98
- } else {
99
- leaveRoom({ endstream: false });
100
- }
101
- }}
102
- >
91
+ <LeaveIconButton key="LeaveRoom" data-testid="leave_room_btn" onClick={() => setShowLeaveRoomAlert(true)}>
103
92
  <Tooltip title="Leave Room">
104
93
  <Box>
105
94
  <ExitIcon style={{ transform: 'rotate(180deg)' }} />
@@ -116,13 +105,12 @@ export const MwebLeaveRoom = ({
116
105
  />
117
106
  </Sheet.Content>
118
107
  </Sheet.Root>
119
- {screenType === 'hls_live_streaming' ? (
120
- <Sheet.Root open={showLeaveRoomAlert} onOpenChange={setShowLeaveRoomAlert}>
121
- <Sheet.Content css={{ bg: '$surface_dim', p: '$10', pb: '$12' }}>
122
- <LeaveSessionContent setShowLeaveRoomAlert={setShowLeaveRoomAlert} leaveRoom={leaveRoom} />
123
- </Sheet.Content>
124
- </Sheet.Root>
125
- ) : null}
108
+
109
+ <Sheet.Root open={showLeaveRoomAlert} onOpenChange={setShowLeaveRoomAlert}>
110
+ <Sheet.Content css={{ bg: '$surface_dim', p: '$10', pb: '$12' }}>
111
+ <LeaveSessionContent setShowLeaveRoomAlert={setShowLeaveRoomAlert} leaveRoom={leaveRoom} />
112
+ </Sheet.Content>
113
+ </Sheet.Root>
126
114
  </Fragment>
127
115
  );
128
116
  };
@@ -5,6 +5,7 @@ import {
5
5
  selectIsConnectedToRoom,
6
6
  selectPeerCount,
7
7
  selectPermissions,
8
+ useAVToggle,
8
9
  useHMSActions,
9
10
  useHMSStore,
10
11
  useRecordingStreaming,
@@ -84,6 +85,8 @@ export const MwebOptions = ({
84
85
  const peerCount = useHMSStore(selectPeerCount);
85
86
  const emojiCardRef = useRef(null);
86
87
  const { isBRBOn, toggleBRB, isHandRaised, toggleHandRaise } = useMyMetadata();
88
+ const { toggleAudio, toggleVideo } = useAVToggle();
89
+ const noAVPermissions = !(toggleAudio || toggleVideo);
87
90
  // const isVideoOn = useHMSStore(selectIsLocalVideoEnabled);
88
91
 
89
92
  useDropdownList({ open: openModals.size > 0 || openOptionsSheet || openSettingsSheet, name: 'MoreSettings' });
@@ -158,7 +161,7 @@ export const MwebOptions = ({
158
161
  </ActionTile.Root>
159
162
  )}
160
163
 
161
- {screenType !== 'hls_live_streaming' ? (
164
+ {!noAVPermissions ? (
162
165
  <ActionTile.Root
163
166
  active={isHandRaised}
164
167
  onClick={() => {
@@ -279,7 +282,6 @@ export const MwebOptions = ({
279
282
 
280
283
  {showEmojiCard && (
281
284
  <Box
282
- onClick={() => setShowEmojiCard(false)}
283
285
  ref={emojiCardRef}
284
286
  css={{
285
287
  maxWidth: '100%',
@@ -4,10 +4,12 @@ import { useNavigate, useParams } from 'react-router-dom';
4
4
  import {
5
5
  HMSNotificationTypes,
6
6
  HMSRoomState,
7
+ selectHasPeerHandRaised,
7
8
  selectRoomState,
8
9
  useCustomEvent,
9
10
  useHMSNotifications,
10
11
  useHMSStore,
12
+ useHMSVanillaStore,
11
13
  } from '@100mslive/react-sdk';
12
14
  import { Button } from '../../../';
13
15
  import { useUpdateRoomLayout } from '../../provider/roomLayoutProvider';
@@ -34,6 +36,7 @@ export function Notifications() {
34
36
  const updateRoomLayoutForRole = useUpdateRoomLayout();
35
37
  const isNotificationDisabled = useIsNotificationDisabled();
36
38
  const { redirectToLeave } = useRedirectToLeave();
39
+ const vanillaStore = useHMSVanillaStore();
37
40
 
38
41
  const handleRoleChangeDenied = useCallback(request => {
39
42
  ToastManager.addToast({
@@ -49,6 +52,16 @@ export function Notifications() {
49
52
  return;
50
53
  }
51
54
  switch (notification.type) {
55
+ case HMSNotificationTypes.HAND_RAISE_CHANGED: {
56
+ if (roomState !== HMSRoomState.Connected || notification.data.isLocal) {
57
+ return;
58
+ }
59
+ const hasPeerHandRaised = vanillaStore.getState(selectHasPeerHandRaised(notification.data.id));
60
+ if (hasPeerHandRaised) {
61
+ ToastBatcher.showToast({ notification, type: 'RAISE_HAND' });
62
+ }
63
+ break;
64
+ }
52
65
  case HMSNotificationTypes.METADATA_UPDATED:
53
66
  if (roomState !== HMSRoomState.Connected) {
54
67
  return;
@@ -154,7 +167,7 @@ export function Notifications() {
154
167
  <TrackUnmuteModal />
155
168
  <TrackBulkUnmuteModal />
156
169
  <TrackNotifications />
157
- <PeerNotifications />
170
+ {roomState === HMSRoomState.Connected ? <PeerNotifications /> : null}
158
171
  <ReconnectNotifications />
159
172
  <AutoplayBlockedModal />
160
173
  <PermissionErrorModal />
@@ -1,14 +1,7 @@
1
1
  import { useEffect } from 'react';
2
- import {
3
- HMSNotificationTypes,
4
- HMSRoomState,
5
- selectRoomState,
6
- useHMSNotifications,
7
- useHMSStore,
8
- } from '@100mslive/react-sdk';
2
+ import { HMSNotificationTypes, useHMSNotifications } from '@100mslive/react-sdk';
9
3
  import { ToastBatcher } from '../Toast/ToastBatcher';
10
4
  import { useSubscribedNotifications } from '../AppData/useUISettings';
11
- import { isInternalRole } from '../../common/utils';
12
5
  import { SUBSCRIBED_NOTIFICATIONS } from '../../common/constants';
13
6
 
14
7
  const notificationTypes = [
@@ -21,19 +14,15 @@ export const PeerNotifications = () => {
21
14
  const notification = useHMSNotifications(notificationTypes);
22
15
  const isPeerJoinSubscribed = useSubscribedNotifications(SUBSCRIBED_NOTIFICATIONS.PEER_JOINED);
23
16
  const isPeerLeftSubscribed = useSubscribedNotifications(SUBSCRIBED_NOTIFICATIONS.PEER_LEFT);
24
- const roomState = useHMSStore(selectRoomState);
25
17
  useEffect(() => {
26
- if (roomState !== HMSRoomState.Connected) {
27
- return;
28
- }
29
- if (!notification || (notification?.data?.roleName && isInternalRole(notification.data.roleName))) {
18
+ if (!notification?.data) {
30
19
  return;
31
20
  }
32
21
 
33
22
  console.debug(`[${notification.type}]`, notification);
34
23
  switch (notification.type) {
35
24
  case HMSNotificationTypes.PEER_LIST:
36
- if (!isPeerJoinSubscribed || notification.data?.length === 0) {
25
+ if (!isPeerJoinSubscribed || notification.data.length === 0) {
37
26
  return;
38
27
  }
39
28
  break;
@@ -52,7 +41,7 @@ export const PeerNotifications = () => {
52
41
  }
53
42
 
54
43
  ToastBatcher.showToast({ notification });
55
- }, [notification, isPeerJoinSubscribed, isPeerLeftSubscribed, roomState]);
44
+ }, [notification, isPeerJoinSubscribed, isPeerLeftSubscribed]);
56
45
 
57
46
  return null;
58
47
  };
@@ -105,7 +105,11 @@ const PreviewJoin = ({
105
105
  const roomLayout = useRoomLayout();
106
106
 
107
107
  const { preview_header: previewHeader = {} } = roomLayout?.screens?.preview?.default?.elements || {};
108
-
108
+ const localPeer = useHMSStore(selectLocalPeer);
109
+ const videoTrack = useHMSStore(selectVideoTrackByID(localPeer?.videoTrack));
110
+ const isMobile = useMedia(cssConfig.media.md);
111
+ const aspectRatio =
112
+ videoTrack?.width && videoTrack?.height ? videoTrack.width / videoTrack.height : isMobile ? 9 / 16 : 16 / 9;
109
113
  useEffect(() => {
110
114
  if (authToken) {
111
115
  if (skipPreview) {
@@ -166,7 +170,7 @@ const PreviewJoin = ({
166
170
  <PreviewTile name={name} error={previewError} />
167
171
  </Flex>
168
172
  ) : null}
169
- <Box css={{ w: '100%', maxWidth: '640px' }}>
173
+ <Box css={{ w: '100%', maxWidth: `${Math.max(aspectRatio, 1) * 360}px` }}>
170
174
  <PreviewControls hideSettings={!toggleVideo && !toggleAudio} />
171
175
  <PreviewForm
172
176
  name={name}
@@ -202,12 +206,13 @@ export const PreviewTile = ({ name, error }: { name: string; error?: boolean })
202
206
  const isMobile = useMedia(cssConfig.media.md);
203
207
  const aspectRatio =
204
208
  videoTrack?.width && videoTrack?.height ? videoTrack.width / videoTrack.height : isMobile ? 9 / 16 : 16 / 9;
209
+
205
210
  return (
206
211
  <StyledVideoTile.Container
207
212
  css={{
208
213
  bg: '$surface_default',
209
214
  aspectRatio,
210
- height: 'min(640px, 40vh)',
215
+ height: 'min(360px, 70vh)',
211
216
  maxWidth: '640px',
212
217
  overflow: 'clip',
213
218
  '@md': {
@@ -225,6 +230,7 @@ export const PreviewTile = ({ name, error }: { name: string; error?: boolean })
225
230
  trackId={localPeer.videoTrack}
226
231
  data-testid="preview_tile"
227
232
  />
233
+
228
234
  {!isVideoOn ? (
229
235
  <StyledVideoTile.AvatarContainer>
230
236
  <Avatar name={name} data-testid="preview_avatar_tile" />
@@ -234,8 +240,9 @@ export const PreviewTile = ({ name, error }: { name: string; error?: boolean })
234
240
  ) : !error ? (
235
241
  <FullPageProgress />
236
242
  ) : null}
243
+
237
244
  {showMuteIcon ? (
238
- <StyledVideoTile.AudioIndicator size="medium">
245
+ <StyledVideoTile.AudioIndicator>
239
246
  <MicOffIcon />
240
247
  </StyledVideoTile.AudioIndicator>
241
248
  ) : (
@@ -250,7 +257,7 @@ export const PreviewControls = ({ hideSettings }: { hideSettings: boolean }) =>
250
257
 
251
258
  return (
252
259
  <Flex
253
- justify="between"
260
+ justify={hideSettings && isMobile ? 'center' : 'between'}
254
261
  css={{
255
262
  width: '100%',
256
263
  mt: '$8',
@@ -1,18 +1,15 @@
1
1
  import React from 'react';
2
- import { selectLocalPeer, selectPeerMetadata, useHMSStore } from '@100mslive/react-sdk';
3
2
  import { HandIcon } from '@100mslive/react-icons';
4
3
  import { Tooltip } from '../../Tooltip';
5
4
  import IconButton from '../IconButton';
5
+ // @ts-ignore: No implicit Any
6
6
  import { useMyMetadata } from './hooks/useMetadata';
7
7
 
8
8
  export const RaiseHand = () => {
9
- const { toggleHandRaise } = useMyMetadata();
10
- const localPeer = useHMSStore(selectLocalPeer);
11
- const isHandRaised = useHMSStore(selectPeerMetadata(localPeer.id))?.isHandRaised || false;
12
-
9
+ const { isHandRaised, toggleHandRaise } = useMyMetadata();
13
10
  return (
14
11
  <Tooltip title={isHandRaised ? 'Lower hand' : 'Raise hand'}>
15
- <IconButton active={!isHandRaised} onClick={toggleHandRaise}>
12
+ <IconButton active={!isHandRaised} onClick={async () => await toggleHandRaise()}>
16
13
  <HandIcon />
17
14
  </IconButton>
18
15
  </Tooltip>
@@ -0,0 +1,66 @@
1
+ import React from 'react';
2
+ import { useMedia } from 'react-use';
3
+ import { Box, Button, config as cssConfig, Dialog, Flex, Text } from '../../..';
4
+ import { Sheet } from '../../../Sheet';
5
+
6
+ export const RequestPrompt = ({
7
+ open = true,
8
+ onOpenChange,
9
+ title,
10
+ body,
11
+ actionText = 'Accept',
12
+ onAction,
13
+ }: {
14
+ open?: boolean;
15
+ onOpenChange: (value: boolean) => void;
16
+ title: string;
17
+ body: React.ReactNode;
18
+ actionText?: string;
19
+ onAction: () => void;
20
+ }) => {
21
+ const isMobile = useMedia(cssConfig.media.md);
22
+
23
+ if (isMobile) {
24
+ return (
25
+ <Sheet.Root open={open} onOpenChange={onOpenChange}>
26
+ <Sheet.Content css={{ py: '$8' }}>
27
+ <Text css={{ fontWeight: '$semiBold', c: '$on_surface_high', '@md': { px: '$8' } }}>{title}</Text>
28
+ {body}
29
+ <RequestActions actionText={actionText} onAction={onAction} />
30
+ </Sheet.Content>
31
+ </Sheet.Root>
32
+ );
33
+ }
34
+
35
+ return (
36
+ <Dialog.Root open={open} onOpenChange={onOpenChange}>
37
+ <Dialog.Portal>
38
+ <Dialog.Overlay />
39
+ <Dialog.Content css={{ p: '$10' }}>
40
+ <Dialog.Title css={{ p: 0, display: 'flex', flexDirection: 'row', gap: '$md', justifyContent: 'center' }}>
41
+ <Text variant="h6">{title}</Text>
42
+ </Dialog.Title>
43
+ <Box css={{ mt: '$4', mb: '$10' }}>{body}</Box>
44
+ <RequestActions actionText={actionText} onAction={onAction} />
45
+ </Dialog.Content>
46
+ </Dialog.Portal>
47
+ </Dialog.Root>
48
+ );
49
+ };
50
+
51
+ const RequestActions = ({ onAction, actionText }: { actionText?: string; onAction: () => void }) => (
52
+ <Flex justify="center" align="center" css={{ width: '100%', gap: '$md', '@md': { mt: '$8', px: '$8' } }}>
53
+ <Box css={{ width: '50%' }}>
54
+ <Dialog.Close css={{ width: '100%' }}>
55
+ <Button variant="standard" outlined css={{ width: '100%' }}>
56
+ Decline
57
+ </Button>
58
+ </Dialog.Close>
59
+ </Box>
60
+ <Box css={{ width: '50%' }}>
61
+ <Button variant="primary" css={{ width: '100%' }} onClick={onAction}>
62
+ {actionText}
63
+ </Button>
64
+ </Box>
65
+ </Flex>
66
+ );
@@ -0,0 +1,89 @@
1
+ import React, { useEffect } from 'react';
2
+ import {
3
+ selectLocalPeerName,
4
+ selectLocalPeerRoleName,
5
+ selectRoleChangeRequest,
6
+ useCustomEvent,
7
+ useHMSActions,
8
+ useHMSStore,
9
+ } from '@100mslive/react-sdk';
10
+ import { Flex, Text } from '../../..';
11
+ // @ts-ignore: No implicit Any
12
+ import { PreviewControls, PreviewTile } from '../Preview/PreviewJoin';
13
+ import { RequestPrompt } from './RequestPrompt';
14
+ // @ts-ignore: No implicit Any
15
+ import { useMyMetadata } from '../hooks/useMetadata';
16
+ // @ts-ignore: No implicit Any
17
+ import { ROLE_CHANGE_DECLINED } from '../../common/constants';
18
+
19
+ export const RoleChangeRequestModal = () => {
20
+ const hmsActions = useHMSActions();
21
+ const { updateMetaData } = useMyMetadata();
22
+ const currentRole = useHMSStore(selectLocalPeerRoleName);
23
+ const roleChangeRequest = useHMSStore(selectRoleChangeRequest);
24
+ const name = useHMSStore(selectLocalPeerName);
25
+ const { sendEvent } = useCustomEvent({ type: ROLE_CHANGE_DECLINED });
26
+
27
+ useEffect(() => {
28
+ if (!roleChangeRequest?.role) {
29
+ return;
30
+ }
31
+ (async () => {
32
+ await hmsActions.preview({ asRole: roleChangeRequest.role.name });
33
+ })();
34
+ }, [hmsActions, roleChangeRequest, currentRole, updateMetaData]);
35
+
36
+ if (!roleChangeRequest?.role) {
37
+ return null;
38
+ }
39
+
40
+ const body = (
41
+ <>
42
+ <Text
43
+ variant="xs"
44
+ css={{
45
+ c: '$on_surface_medium',
46
+ textAlign: 'center',
47
+ '@md': { textAlign: 'left', borderBottom: '1px solid $border_bright', pb: '$4', px: '$8' },
48
+ }}
49
+ >
50
+ Setup your audio and video before joining
51
+ </Text>
52
+ <Flex
53
+ align="center"
54
+ justify="center"
55
+ css={{
56
+ '@sm': { width: '100%' },
57
+ flexDirection: 'column',
58
+ mt: '$6',
59
+ '@md': { px: '$8' },
60
+ }}
61
+ >
62
+ <PreviewTile name={name || ''} />
63
+
64
+ <PreviewControls hideSettings={true} />
65
+ </Flex>
66
+ </>
67
+ );
68
+
69
+ return (
70
+ <RequestPrompt
71
+ title="You're invited to join the stage"
72
+ onOpenChange={async value => {
73
+ if (!value) {
74
+ hmsActions.rejectChangeRole(roleChangeRequest);
75
+ sendEvent({ ...roleChangeRequest, peerName: name }, { peerId: roleChangeRequest.requestedBy?.id });
76
+ await hmsActions.cancelMidCallPreview();
77
+ await hmsActions.lowerLocalPeerHand();
78
+ }
79
+ }}
80
+ body={body}
81
+ onAction={async () => {
82
+ await hmsActions.acceptChangeRole(roleChangeRequest);
83
+ await updateMetaData({ prevRole: currentRole });
84
+ await hmsActions.lowerLocalPeerHand();
85
+ }}
86
+ actionText="Accept"
87
+ />
88
+ );
89
+ };
@@ -8,11 +8,14 @@ import { Chat } from './Chat/Chat';
8
8
  // @ts-ignore: No implicit Any
9
9
  import { ParticipantList } from './Footer/ParticipantList';
10
10
  import { config as cssConfig, Flex, IconButton, Tabs, Text } from '../..';
11
+ import { Tooltip } from '../../Tooltip';
11
12
  // @ts-ignore: No implicit Any
12
13
  import { useRoomLayoutConferencingScreen } from '../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
13
14
  // @ts-ignore: No implicit Any
14
15
  import { useIsSidepaneTypeOpen, useSidepaneReset, useSidepaneToggle } from './AppData/useSidepane';
15
16
  // @ts-ignore: No implicit Any
17
+ import { getFormattedCount } from '../common/utils';
18
+ // @ts-ignore: No implicit Any
16
19
  import { SIDE_PANE_OPTIONS } from '../common/constants';
17
20
 
18
21
  const tabTriggerCSS = {
@@ -24,6 +27,16 @@ const tabTriggerCSS = {
24
27
  justifyContent: 'center',
25
28
  };
26
29
 
30
+ const ParticipantCount = ({ count }: { count: number }) => {
31
+ return count < 1000 ? (
32
+ <span>({count})</span>
33
+ ) : (
34
+ <Tooltip title={count}>
35
+ <span>({getFormattedCount(count)})</span>
36
+ </Tooltip>
37
+ );
38
+ };
39
+
27
40
  export const SidePaneTabs = React.memo<{
28
41
  active: 'Participants | Chat';
29
42
  screenType: keyof ConferencingScreen;
@@ -73,7 +86,13 @@ export const SidePaneTabs = React.memo<{
73
86
  {hideTabs ? (
74
87
  <>
75
88
  <Text variant="sm" css={{ fontWeight: '$semiBold', p: '$4', c: '$on_surface_high', pr: '$12' }}>
76
- {showChat ? 'Chat' : `Participants (${peerCount})`}
89
+ {showChat ? (
90
+ 'Chat'
91
+ ) : (
92
+ <span>
93
+ Participants <ParticipantCount count={peerCount} />
94
+ </span>
95
+ )}
77
96
  </Text>
78
97
 
79
98
  {showChat ? <Chat screenType={screenType} /> : <ParticipantList />}
@@ -106,7 +125,7 @@ export const SidePaneTabs = React.memo<{
106
125
  color: activeTab !== SIDE_PANE_OPTIONS.PARTICIPANTS ? '$on_surface_low' : '$on_surface_high',
107
126
  }}
108
127
  >
109
- Participants ({peerCount})
128
+ Participants <ParticipantCount count={peerCount} />
110
129
  </Tabs.Trigger>
111
130
  </Tabs.List>
112
131
  <Tabs.Content value={SIDE_PANE_OPTIONS.PARTICIPANTS} css={{ p: 0 }}>
@@ -1,6 +1,8 @@
1
1
  import React, { Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
+ import { useMedia } from 'react-use';
2
3
  import {
3
4
  selectAudioTrackByPeerID,
5
+ selectHasPeerHandRaised,
4
6
  selectIsPeerAudioEnabled,
5
7
  selectLocalPeerID,
6
8
  selectPeerMetadata,
@@ -18,11 +20,12 @@ import TileMenu, { isSameTile } from './TileMenu/TileMenu';
18
20
  import { Avatar } from '../../Avatar';
19
21
  import { Box, Flex } from '../../Layout';
20
22
  import { VideoTileStats } from '../../Stats';
21
- import { keyframes } from '../../Theme';
23
+ import { config as cssConfig, keyframes } from '../../Theme';
22
24
  import { Video } from '../../Video';
23
25
  import { StyledVideoTile } from '../../VideoTile';
24
26
  import { getVideoTileLabel } from './peerTileUtils';
25
27
  import { useSetAppDataByKey, useUISettings } from './AppData/useUISettings';
28
+ import { getAttributeBoxSize } from '../common/utils';
26
29
  import { APP_DATA, SESSION_STORE_KEY, UI_SETTINGS } from '../common/constants';
27
30
 
28
31
  const Tile = ({
@@ -43,6 +46,7 @@ const Tile = ({
43
46
  }) => {
44
47
  const trackSelector = trackId ? selectVideoTrackByID(trackId) : selectVideoTrackByPeerID(peerId);
45
48
  const track = useHMSStore(trackSelector);
49
+ const isMobile = useMedia(cssConfig.media.md);
46
50
  const peerName = useHMSStore(selectPeerNameByID(peerId));
47
51
  const audioTrack = useHMSStore(selectAudioTrackByPeerID(peerId));
48
52
  const localPeerID = useHMSStore(selectLocalPeerID);
@@ -69,21 +73,28 @@ const Tile = ({
69
73
  const onHoverHandler = useCallback(event => {
70
74
  setIsMouseHovered(event.type === 'mouseenter');
71
75
  }, []);
72
- const isTileBigEnoughToShowStats = height >= 180 && width >= 180;
76
+
77
+ const ref = useRef(null);
78
+ const calculatedHeight = ref.current?.clientHeight || '';
79
+ const calculatedWidth = ref.current?.clientWidth || '';
80
+
81
+ const isTileBigEnoughToShowStats = calculatedHeight >= 180 && calculatedWidth >= 180;
82
+
73
83
  const avatarSize = useMemo(() => {
74
- if (!width || !height) {
84
+ if (!calculatedWidth || !calculatedHeight) {
75
85
  return undefined;
76
86
  }
77
- if (width <= 150 || height <= 150) {
87
+ if (calculatedWidth <= 150 || calculatedHeight <= 150) {
78
88
  return 'small';
79
- } else if (width <= 300 || height <= 300) {
89
+ } else if (calculatedWidth <= 300 || calculatedHeight <= 300) {
80
90
  return 'medium';
81
91
  }
82
92
  return 'large';
83
- }, [width, height]);
93
+ }, [calculatedWidth, calculatedHeight]);
84
94
 
85
95
  return (
86
96
  <StyledVideoTile.Root
97
+ ref={ref}
87
98
  css={{
88
99
  width,
89
100
  height,
@@ -130,7 +141,7 @@ const Tile = ({
130
141
  isAudioMuted ? (
131
142
  <StyledVideoTile.AudioIndicator
132
143
  data-testid="participant_audio_mute_icon"
133
- size={width && height && (width < 180 || height < 180) ? 'small' : 'medium'}
144
+ size={getAttributeBoxSize(calculatedWidth, calculatedHeight)}
134
145
  >
135
146
  <MicOffIcon />
136
147
  </StyledVideoTile.AudioIndicator>
@@ -138,7 +149,7 @@ const Tile = ({
138
149
  <AudioLevel trackId={audioTrack?.id} />
139
150
  )
140
151
  ) : null}
141
- {isMouseHovered || isDragabble ? (
152
+ {isMouseHovered || (isDragabble && isMobile) ? (
142
153
  <TileMenu
143
154
  peerID={peerId}
144
155
  audioTrackID={audioTrack?.id}
@@ -147,7 +158,7 @@ const Tile = ({
147
158
  enableSpotlightingPeer={enableSpotlightingPeer}
148
159
  />
149
160
  ) : null}
150
- {!hideMetadataOnTile && <PeerMetadata peerId={peerId} />}
161
+ {!hideMetadataOnTile && <PeerMetadata peerId={peerId} height={calculatedHeight} width={calculatedWidth} />}
151
162
 
152
163
  <TileConnection
153
164
  hideLabel={hideParticipantNameOnTile}
@@ -164,8 +175,6 @@ const Tile = ({
164
175
  );
165
176
  };
166
177
 
167
- const metaStyles = { top: '$4', left: '$4', width: '$14', height: '$14' };
168
-
169
178
  const heightAnimation = value =>
170
179
  keyframes({
171
180
  '50%': {
@@ -215,20 +224,20 @@ export const AudioLevel = ({ trackId }) => {
215
224
  );
216
225
  };
217
226
 
218
- const PeerMetadata = ({ peerId }) => {
227
+ const PeerMetadata = ({ peerId, height, width }) => {
219
228
  const metaData = useHMSStore(selectPeerMetadata(peerId));
220
- const isHandRaised = metaData?.isHandRaised || false;
221
229
  const isBRB = metaData?.isBRBOn || false;
230
+ const isHandRaised = useHMSStore(selectHasPeerHandRaised(peerId));
222
231
 
223
232
  return (
224
233
  <Fragment>
225
234
  {isHandRaised ? (
226
- <StyledVideoTile.AttributeBox css={metaStyles} data-testid="raiseHand_icon_onTile">
235
+ <StyledVideoTile.AttributeBox size={getAttributeBoxSize(width, height)} data-testid="raiseHand_icon_onTile">
227
236
  <HandIcon width={24} height={24} />
228
237
  </StyledVideoTile.AttributeBox>
229
238
  ) : null}
230
239
  {isBRB ? (
231
- <StyledVideoTile.AttributeBox css={metaStyles} data-testid="brb_icon_onTile">
240
+ <StyledVideoTile.AttributeBox size={getAttributeBoxSize(width, height)} data-testid="brb_icon_onTile">
232
241
  <BrbTileIcon width={22} height={22} />
233
242
  </StyledVideoTile.AttributeBox>
234
243
  ) : null}
@@ -13,12 +13,12 @@ import { Footer } from './Footer/Footer';
13
13
  import { HLSFailureModal } from './Notifications/HLSFailureModal';
14
14
  import { ActivatedPIP } from './PIP/PIPComponent';
15
15
  import { PictureInPicture } from './PIP/PIPManager';
16
+ import { RoleChangeRequestModal } from './RoleChangeRequest/RoleChangeRequestModal';
16
17
  import { Box, Flex } from '../../Layout';
17
18
  import { useHMSPrebuiltContext } from '../AppContext';
18
19
  import { VideoStreamingSection } from '../layouts/VideoStreamingSection';
19
20
  import FullPageProgress from './FullPageProgress';
20
21
  import { Header } from './Header';
21
- import { RoleChangeRequestModal } from './RoleChangeRequestModal';
22
22
  import {
23
23
  useRoomLayoutConferencingScreen,
24
24
  useRoomLayoutPreviewScreen,