@100mslive/roomkit-react 0.3.10-alpha.0 → 0.3.10-alpha.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. package/dist/{HLSView-5GXP76IN.js → HLSView-KRJMDNAF.js} +2 -2
  2. package/dist/Prebuilt/common/constants.d.ts +1 -0
  3. package/dist/Prebuilt/components/AppData/useSidepaneResetOnLayoutUpdate.d.ts +3 -0
  4. package/dist/Prebuilt/components/Chat/Chat.d.ts +1 -1
  5. package/dist/Prebuilt/components/RoleChangeModal.d.ts +5 -0
  6. package/dist/Prebuilt/components/TileMenu/TileMenuContent.d.ts +2 -1
  7. package/dist/Prebuilt/components/VideoLayouts/WhiteboardLayout.d.ts +0 -1
  8. package/dist/{chunk-WSDBUVSZ.js → chunk-AFSI3LBT.js} +618 -564
  9. package/dist/chunk-AFSI3LBT.js.map +7 -0
  10. package/dist/index.cjs.js +1953 -1896
  11. package/dist/index.cjs.js.map +4 -4
  12. package/dist/index.js +1 -1
  13. package/dist/meta.cjs.json +125 -204
  14. package/dist/meta.esbuild.json +131 -280
  15. package/package.json +7 -9
  16. package/src/Modal/DialogContent.tsx +1 -1
  17. package/src/Prebuilt/common/constants.ts +2 -0
  18. package/src/Prebuilt/components/AppData/useSidepaneResetOnLayoutUpdate.tsx +22 -0
  19. package/src/Prebuilt/components/AudioVideoToggle.tsx +1 -1
  20. package/src/Prebuilt/components/Chat/Chat.tsx +3 -4
  21. package/src/Prebuilt/components/Footer/ParticipantList.tsx +56 -37
  22. package/src/Prebuilt/components/RoleChangeModal.tsx +187 -0
  23. package/src/Prebuilt/components/TileMenu/TileMenu.tsx +5 -0
  24. package/src/Prebuilt/components/TileMenu/TileMenuContent.tsx +23 -1
  25. package/src/Prebuilt/components/VideoLayouts/WhiteboardLayout.tsx +13 -7
  26. package/src/Prebuilt/components/VirtualBackground/VBPicker.tsx +3 -0
  27. package/src/Prebuilt/layouts/SidePane.tsx +9 -9
  28. package/dist/HLSView-FBGVUTA5.css +0 -2767
  29. package/dist/HLSView-FBGVUTA5.css.map +0 -7
  30. package/dist/chunk-WSDBUVSZ.js.map +0 -7
  31. package/dist/index.cjs.css +0 -2767
  32. package/dist/index.cjs.css.map +0 -7
  33. package/dist/index.css +0 -2767
  34. package/dist/index.css.map +0 -7
  35. package/src/Prebuilt/components/RoleChangeModal.jsx +0 -185
  36. /package/dist/{HLSView-5GXP76IN.js.map → HLSView-KRJMDNAF.js.map} +0 -0
package/package.json CHANGED
@@ -10,7 +10,7 @@
10
10
  "prebuilt",
11
11
  "roomkit"
12
12
  ],
13
- "version": "0.3.10-alpha.0",
13
+ "version": "0.3.10-alpha.2",
14
14
  "author": "100ms",
15
15
  "license": "MIT",
16
16
  "repository": {
@@ -27,8 +27,7 @@
27
27
  "require": "./dist/index.cjs.js",
28
28
  "import": "./dist/index.js",
29
29
  "default": "./dist/index.js"
30
- },
31
- "./index.css": "./dist/index.css"
30
+ }
32
31
  },
33
32
  "sideEffects": false,
34
33
  "scripts": {
@@ -74,12 +73,11 @@
74
73
  "react": ">=17.0.2 <19.0.0"
75
74
  },
76
75
  "dependencies": {
77
- "@100mslive/hls-player": "0.3.10-alpha.0",
76
+ "@100mslive/hls-player": "0.3.10-alpha.2",
78
77
  "@100mslive/hms-noise-cancellation": "0.0.1",
79
- "@100mslive/hms-virtual-background": "1.13.10-alpha.0",
80
- "@100mslive/hms-whiteboard": "0.0.0-alpha.1",
81
- "@100mslive/react-icons": "0.10.10-alpha.0",
82
- "@100mslive/react-sdk": "0.10.10-alpha.0",
78
+ "@100mslive/hms-virtual-background": "1.13.10-alpha.2",
79
+ "@100mslive/react-icons": "0.10.10-alpha.2",
80
+ "@100mslive/react-sdk": "0.10.10-alpha.2",
83
81
  "@100mslive/types-prebuilt": "0.12.8",
84
82
  "@emoji-mart/data": "^1.0.6",
85
83
  "@emoji-mart/react": "^1.0.1",
@@ -115,5 +113,5 @@
115
113
  "uuid": "^8.3.2",
116
114
  "worker-timers": "^7.0.40"
117
115
  },
118
- "gitHead": "c705b5b8ce729747f28c7aff242057ac8178d338"
116
+ "gitHead": "303a4fc9e47b81f2171e8dfb89ceaa98f52e2c25"
119
117
  }
@@ -27,7 +27,7 @@ export const StyledDialogPortal = styled(DialogPrimitive.Portal, {});
27
27
 
28
28
  export const CustomDialogContent = styled(DialogPrimitive.Content, {
29
29
  color: '$on_surface_medium',
30
- backgroundColor: '$surface_default',
30
+ backgroundColor: '$surface_dim',
31
31
  borderRadius: '8px',
32
32
  position: 'absolute',
33
33
  top: '50%',
@@ -70,6 +70,8 @@ export const SIDE_PANE_OPTIONS = {
70
70
  ROOM_DETAILS: 'ROOM_DETAILS',
71
71
  };
72
72
 
73
+ export type SidePaneOption = (typeof SIDE_PANE_OPTIONS)[keyof typeof SIDE_PANE_OPTIONS];
74
+
73
75
  export const SHEET_OPTIONS = {
74
76
  ROOM_DETAILS: 'ROOM_DETAILS',
75
77
  };
@@ -0,0 +1,22 @@
1
+ import { useEffect } from 'react';
2
+ import { DefaultConferencingScreen_Elements } from '@100mslive/types-prebuilt';
3
+ import { selectAppData, useHMSStore } from '@100mslive/react-sdk';
4
+ import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
5
+ // @ts-ignore
6
+ import { useSidepaneReset } from './useSidepane';
7
+ import { APP_DATA, SidePaneOption } from '../../common/constants';
8
+
9
+ // Closes the sidepane if an element is removed from the layout via the customiser
10
+ export const useSidepaneResetOnLayoutUpdate = (
11
+ layoutKey: keyof DefaultConferencingScreen_Elements,
12
+ sidepaneOption: SidePaneOption,
13
+ ) => {
14
+ const { elements } = useRoomLayoutConferencingScreen();
15
+ const sidepane = useHMSStore(selectAppData(APP_DATA.sidePane));
16
+ const resetSidePane = useSidepaneReset();
17
+ useEffect(() => {
18
+ if (sidepane === sidepaneOption && !elements?.[layoutKey]) {
19
+ resetSidePane();
20
+ }
21
+ }, [elements, elements?.[layoutKey], resetSidePane, sidepane, layoutKey, sidepaneOption]);
22
+ };
@@ -122,6 +122,7 @@ const NoiseCancellation = () => {
122
122
 
123
123
  return (
124
124
  <>
125
+ <Dropdown.ItemSeparator css={{ mx: 0 }} />
125
126
  <Dropdown.Item
126
127
  css={{
127
128
  p: '$4 $8',
@@ -256,7 +257,6 @@ export const AudioVideoToggle = ({ hideOptions = false }) => {
256
257
  </Dropdown.Group>
257
258
  </>
258
259
  )}
259
- <Dropdown.ItemSeparator css={{ mx: 0 }} />
260
260
  <NoiseCancellation />
261
261
  <AudioSettings onClick={() => setShowSettings(true)} />
262
262
  </IconButtonWithOptions>
@@ -15,8 +15,9 @@ import { ChatFooter } from './ChatFooter';
15
15
  import { ChatBlocked, ChatPaused } from './ChatStates';
16
16
  import { PinnedMessage } from './PinnedMessage';
17
17
  import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
18
+ import { useSidepaneResetOnLayoutUpdate } from '../AppData/useSidepaneResetOnLayoutUpdate';
18
19
  import { useLandscapeHLSStream, useMobileHLSStream } from '../../common/hooks';
19
- import { SESSION_STORE_KEY } from '../../common/constants';
20
+ import { SESSION_STORE_KEY, SIDE_PANE_OPTIONS } from '../../common/constants';
20
21
 
21
22
  export const Chat = () => {
22
23
  const { elements } = useRoomLayoutConferencingScreen();
@@ -27,6 +28,7 @@ export const Chat = () => {
27
28
  const isMobile = useMedia(cssConfig.media.md);
28
29
  const isMobileHLSStream = useMobileHLSStream();
29
30
  const isLandscapeStream = useLandscapeHLSStream();
31
+ useSidepaneResetOnLayoutUpdate('chat', SIDE_PANE_OPTIONS.CHAT);
30
32
 
31
33
  const scrollToBottom = useCallback(
32
34
  (unreadCount = 0) => {
@@ -42,9 +44,6 @@ export const Chat = () => {
42
44
  [hmsActions, vanillaStore],
43
45
  );
44
46
 
45
- if (!elements?.chat) {
46
- return null;
47
- }
48
47
  const streaming = isMobileHLSStream || isLandscapeStream;
49
48
 
50
49
  return (
@@ -21,6 +21,7 @@ import {
21
21
  HandIcon,
22
22
  MicOffIcon,
23
23
  PeopleIcon,
24
+ PersonSettingsIcon,
24
25
  SearchIcon,
25
26
  VerticalMenuIcon,
26
27
  } from '@100mslive/react-icons';
@@ -29,10 +30,12 @@ import { Accordion, Box, Button, config as cssConfig, Dropdown, Flex, Input, Tex
29
30
  import IconButton from '../../IconButton';
30
31
  import { ConnectionIndicator } from '../Connection/ConnectionIndicator';
31
32
  import { RemoveParticipant } from '../RemoveParticipant';
33
+ import { RoleChangeModal } from '../RoleChangeModal';
32
34
  import { RoleAccordion } from './RoleAccordion';
33
35
  import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
34
36
  // @ts-ignore: No implicit Any
35
37
  import { useIsSidepaneTypeOpen, useSidepaneToggle } from '../AppData/useSidepane';
38
+ import { useSidepaneResetOnLayoutUpdate } from '../AppData/useSidepaneResetOnLayoutUpdate';
36
39
  import { usePeerOnStageActions } from '../hooks/usePeerOnStageActions';
37
40
  import { useParticipants } from '../../common/hooks';
38
41
  // @ts-ignore: No implicit Any
@@ -71,6 +74,8 @@ export const ParticipantList = ({
71
74
  });
72
75
  }
73
76
 
77
+ useSidepaneResetOnLayoutUpdate('participant_list', SIDE_PANE_OPTIONS.PARTICIPANTS);
78
+
74
79
  const onSearch = useCallback((value: string) => {
75
80
  setFilter(filterValue => {
76
81
  if (!filterValue) {
@@ -365,45 +370,59 @@ const ParticipantMoreActions = ({ peerId, role }: { peerId: string; role: string
365
370
  isInStage,
366
371
  shouldShowStageRoleChange,
367
372
  } = usePeerOnStageActions({ peerId, role });
373
+ const canChangeRole = !!useHMSStore(selectPermissions)?.changeRole;
374
+ const [openRoleChangeModal, setOpenRoleChangeModal] = useState(false);
375
+
368
376
  return (
369
- <Dropdown.Root open={open} onOpenChange={value => setOpen(value)} modal={false}>
370
- <Dropdown.Trigger
371
- asChild
372
- data-testid="participant_more_actions"
373
- className="participant_item"
374
- css={{
375
- p: '$1',
376
- r: '$0',
377
- c: '$on_surface_high',
378
- display: open ? 'flex' : 'none',
379
- '&:hover': {
380
- bg: '$surface_bright',
381
- },
382
- '@md': {
383
- display: 'flex',
384
- },
385
- }}
386
- tabIndex={0}
387
- >
388
- <Box css={{ my: 'auto' }}>
389
- <VerticalMenuIcon />
390
- </Box>
391
- </Dropdown.Trigger>
392
- <Dropdown.Portal>
393
- <Dropdown.Content align="end" sideOffset={8} css={{ w: '$64', bg: '$surface_default' }}>
394
- {shouldShowStageRoleChange ? (
395
- <Dropdown.Item css={{ bg: '$surface_default' }} onClick={() => handleStageAction()}>
396
- <ChangeRoleIcon />
397
- <Text variant="sm" css={{ ml: '$4', fontWeight: '$semiBold', c: '$on_surface_high' }}>
398
- {isInStage ? remove_from_stage_label : bring_to_stage_label}
399
- </Text>
400
- </Dropdown.Item>
401
- ) : null}
377
+ <>
378
+ <Dropdown.Root open={open} onOpenChange={value => setOpen(value)} modal={false}>
379
+ <Dropdown.Trigger
380
+ asChild
381
+ data-testid="participant_more_actions"
382
+ className="participant_item"
383
+ css={{
384
+ p: '$1',
385
+ r: '$0',
386
+ c: '$on_surface_high',
387
+ display: open ? 'flex' : 'none',
388
+ '&:hover': {
389
+ bg: '$surface_bright',
390
+ },
391
+ '@md': {
392
+ display: 'flex',
393
+ },
394
+ }}
395
+ tabIndex={0}
396
+ >
397
+ <Box css={{ my: 'auto' }}>
398
+ <VerticalMenuIcon />
399
+ </Box>
400
+ </Dropdown.Trigger>
401
+ <Dropdown.Portal>
402
+ <Dropdown.Content align="end" sideOffset={8} css={{ w: '$64', bg: '$surface_default' }}>
403
+ {shouldShowStageRoleChange ? (
404
+ <Dropdown.Item css={{ bg: '$surface_default' }} onClick={() => handleStageAction()}>
405
+ <ChangeRoleIcon />
406
+ <Text variant="sm" css={{ ml: '$4', fontWeight: '$semiBold', c: '$on_surface_high' }}>
407
+ {isInStage ? remove_from_stage_label : bring_to_stage_label}
408
+ </Text>
409
+ </Dropdown.Item>
410
+ ) : null}
402
411
 
403
- <RemoveParticipant peerId={peerId} />
404
- </Dropdown.Content>
405
- </Dropdown.Portal>
406
- </Dropdown.Root>
412
+ {canChangeRole ? (
413
+ <Dropdown.Item css={{ bg: '$surface_default' }} onClick={() => setOpenRoleChangeModal(true)}>
414
+ <PersonSettingsIcon />
415
+ <Text variant="sm" css={{ ml: '$4', fontWeight: '$semiBold', c: '$on_surface_high' }}>
416
+ Switch Role
417
+ </Text>
418
+ </Dropdown.Item>
419
+ ) : null}
420
+ <RemoveParticipant peerId={peerId} />
421
+ </Dropdown.Content>
422
+ </Dropdown.Portal>
423
+ </Dropdown.Root>
424
+ {openRoleChangeModal && <RoleChangeModal peerId={peerId} onOpenChange={setOpenRoleChangeModal} />}
425
+ </>
407
426
  );
408
427
  };
409
428
 
@@ -0,0 +1,187 @@
1
+ import React, { useRef, useState } from 'react';
2
+ import { useMedia } from 'react-use';
3
+ import { HMSPeer, selectAvailableRoleNames, selectPeerByID, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
4
+ import { ChevronDownIcon, ChevronUpIcon, CrossIcon } from '@100mslive/react-icons';
5
+ import { Button } from '../../Button';
6
+ import { Dropdown } from '../../Dropdown';
7
+ import { Box, Flex } from '../../Layout';
8
+ import { Dialog } from '../../Modal';
9
+ import { Sheet } from '../../Sheet';
10
+ import { Text } from '../../Text';
11
+ import { config as cssConfig } from '../../Theme';
12
+ import { Tooltip } from '../../Tooltip';
13
+
14
+ const HighlightTerm = ({ value }: { value: string | undefined }) => {
15
+ return value ? (
16
+ <Tooltip side="top" title={value}>
17
+ <Text
18
+ variant="body2"
19
+ css={{
20
+ color: '$on_surface_medium',
21
+ fontWeight: '$semiBold',
22
+ }}
23
+ >
24
+ '{value.slice(0, 100)}
25
+ {value.length > 100 ? '...' : ''}'
26
+ </Text>
27
+ </Tooltip>
28
+ ) : (
29
+ <></>
30
+ );
31
+ };
32
+
33
+ const RoleChangeContent = ({
34
+ peer,
35
+ onOpenChange,
36
+ isMobile = false,
37
+ }: {
38
+ peer: HMSPeer;
39
+ onOpenChange: (open: boolean) => void;
40
+ isMobile?: boolean;
41
+ }) => {
42
+ const roles = useHMSStore(selectAvailableRoleNames).filter(role => role !== peer?.roleName);
43
+ const [selectedRole, setRole] = useState(roles.filter(role => role !== peer?.roleName)?.[0] || peer?.roleName);
44
+ const hmsActions = useHMSActions();
45
+ const [open, setOpen] = useState(false);
46
+ const triggerRef = useRef<HTMLButtonElement | undefined>();
47
+
48
+ return (
49
+ <>
50
+ <Flex align="center" justify="between" css={{ w: '100%' }}>
51
+ <Text as="h6" variant="h6">
52
+ Switch Role
53
+ </Text>
54
+ {isMobile && <CrossIcon onClick={() => onOpenChange(false)} />}
55
+ </Flex>
56
+
57
+ <Box>
58
+ <Text
59
+ variant="body2"
60
+ css={{
61
+ mt: '$4',
62
+ mb: '$8',
63
+ c: '$on_surface_medium',
64
+ display: 'flex',
65
+ flexWrap: 'wrap',
66
+ columnGap: '4px',
67
+ }}
68
+ >
69
+ Switch the role of
70
+ <HighlightTerm value={peer.name} />
71
+ from <HighlightTerm value={peer.roleName} />
72
+ </Text>
73
+ </Box>
74
+ <Flex
75
+ align="center"
76
+ css={{
77
+ w: '100%',
78
+ mb: '$10',
79
+ }}
80
+ >
81
+ <Box
82
+ css={{
83
+ position: 'relative',
84
+ flex: '1 1 0',
85
+ minWidth: 0,
86
+ }}
87
+ >
88
+ <Dropdown.Root open={open} onOpenChange={setOpen} css={{ width: '100%' }}>
89
+ <Dropdown.Trigger
90
+ // @ts-ignore
91
+ ref={triggerRef}
92
+ data-testid="open_role_selection_dropdown"
93
+ asChild
94
+ css={{
95
+ border: '1px solid $border_bright',
96
+ bg: '$surface_default',
97
+ r: '$1',
98
+ p: '$6 $9',
99
+ }}
100
+ >
101
+ <Flex align="center" justify="between" css={{ width: '100%' }}>
102
+ <Text>{selectedRole}</Text>
103
+ {open ? <ChevronUpIcon /> : <ChevronDownIcon />}
104
+ </Flex>
105
+ </Dropdown.Trigger>
106
+
107
+ <Dropdown.Content align="start" sideOffset={8} css={{ zIndex: 1000, w: '100%' }}>
108
+ {roles.map(role => (
109
+ <Dropdown.Item
110
+ data-testid={role}
111
+ key={role}
112
+ onSelect={() => setRole(role)}
113
+ css={{ w: `${triggerRef.current?.clientWidth}px` }}
114
+ >
115
+ {role}
116
+ </Dropdown.Item>
117
+ ))}
118
+ </Dropdown.Content>
119
+ </Dropdown.Root>
120
+ </Box>
121
+ </Flex>
122
+ <Flex justify="center" align="center" css={{ width: '100%', gap: '$md' }}>
123
+ {!isMobile && (
124
+ <Button
125
+ variant="standard"
126
+ outlined
127
+ css={{ width: '100%' }}
128
+ onClick={() => onOpenChange(false)}
129
+ data-testid="cancel_button"
130
+ >
131
+ Cancel
132
+ </Button>
133
+ )}
134
+
135
+ <Button
136
+ data-testid="change_button"
137
+ variant="primary"
138
+ css={{ width: '100%' }}
139
+ onClick={async () => {
140
+ if (selectedRole) {
141
+ await hmsActions.changeRoleOfPeer(peer.id, selectedRole, true);
142
+ onOpenChange(false);
143
+ }
144
+ }}
145
+ >
146
+ Switch Role
147
+ </Button>
148
+ </Flex>
149
+ </>
150
+ );
151
+ };
152
+
153
+ export const RoleChangeModal = ({
154
+ peerId,
155
+ onOpenChange,
156
+ }: {
157
+ peerId: string;
158
+ onOpenChange: (open: boolean) => void;
159
+ }) => {
160
+ const peer = useHMSStore(selectPeerByID(peerId));
161
+ const isMobile = useMedia(cssConfig.media.md);
162
+
163
+ if (!peer) {
164
+ return null;
165
+ }
166
+
167
+ if (isMobile) {
168
+ return (
169
+ <Sheet.Root open={true} onOpenChange={onOpenChange}>
170
+ <Sheet.Content css={{ p: '$12 $8', background: '$surface_dim' }}>
171
+ <RoleChangeContent peer={peer} onOpenChange={onOpenChange} isMobile />
172
+ </Sheet.Content>
173
+ </Sheet.Root>
174
+ );
175
+ }
176
+
177
+ return (
178
+ <Dialog.Root defaultOpen onOpenChange={onOpenChange}>
179
+ <Dialog.Portal>
180
+ <Dialog.Overlay />
181
+ <Dialog.Content css={{ width: 'min(400px,80%)', p: '$10' }}>
182
+ <RoleChangeContent peer={peer} onOpenChange={onOpenChange} />
183
+ </Dialog.Content>
184
+ </Dialog.Portal>
185
+ </Dialog.Root>
186
+ );
187
+ };
@@ -17,6 +17,7 @@ import { Text } from '../../../Text';
17
17
  import { config as cssConfig, useTheme } from '../../../Theme';
18
18
  import { StyledMenuTile } from '../../../TileMenu';
19
19
  import { ChangeNameModal } from '../MoreSettings/ChangeNameModal';
20
+ import { RoleChangeModal } from '../RoleChangeModal';
20
21
  import { TileMenuContent } from './TileMenuContent';
21
22
  import { useDropdownList } from '../hooks/useDropdownList';
22
23
  import { getDragClassName } from './utils';
@@ -56,6 +57,7 @@ const TileMenu = ({
56
57
  const isMobile = useMedia(cssConfig.media.md);
57
58
  const peer = useHMSStore(selectPeerByID(peerID));
58
59
  const [showNameChangeModal, setShowNameChangeModal] = useState(false);
60
+ const [showRoleChangeModal, setShowRoleChangeModal] = useState(false);
59
61
  useDropdownList({ open, name: 'TileMenu' });
60
62
  const dragClassName = getDragClassName();
61
63
 
@@ -64,6 +66,7 @@ const TileMenu = ({
64
66
  }
65
67
 
66
68
  const openNameChangeModal = () => setShowNameChangeModal(true);
69
+ const openRoleChangeModal = () => setShowRoleChangeModal(true);
67
70
 
68
71
  const props = {
69
72
  isLocal,
@@ -76,6 +79,7 @@ const TileMenu = ({
76
79
  showPinAction,
77
80
  canMinimise,
78
81
  openNameChangeModal,
82
+ openRoleChangeModal,
79
83
  };
80
84
 
81
85
  return (
@@ -133,6 +137,7 @@ const TileMenu = ({
133
137
  )}
134
138
  </StyledMenuTile.Root>
135
139
  {showNameChangeModal && <ChangeNameModal onOpenChange={setShowNameChangeModal} />}
140
+ {showRoleChangeModal && <RoleChangeModal peerId={peerID} onOpenChange={setShowRoleChangeModal} />}
136
141
  </>
137
142
  );
138
143
  };
@@ -17,6 +17,7 @@ import {
17
17
  MicOffIcon,
18
18
  MicOnIcon,
19
19
  PencilIcon,
20
+ PersonSettingsIcon,
20
21
  PinIcon,
21
22
  RemoveUserIcon,
22
23
  ShareScreenIcon,
@@ -224,6 +225,9 @@ export const TileMenuContent = ({
224
225
  openNameChangeModal = () => {
225
226
  return;
226
227
  },
228
+ openRoleChangeModal = () => {
229
+ return;
230
+ },
227
231
  }: {
228
232
  videoTrackID: string;
229
233
  audioTrackID: string;
@@ -235,10 +239,13 @@ export const TileMenuContent = ({
235
239
  canMinimise?: boolean;
236
240
  closeSheetOnClick?: () => void;
237
241
  openNameChangeModal?: () => void;
242
+ openRoleChangeModal?: () => void;
238
243
  }) => {
239
244
  const actions = useHMSActions();
240
245
  const dragClassName = getDragClassName();
241
- const removeOthers: boolean | undefined = useHMSStore(selectPermissions)?.removeOthers;
246
+ const permissions = useHMSStore(selectPermissions);
247
+ const canChangeRole = !!permissions?.changeRole;
248
+ const removeOthers = !!permissions?.removeOthers;
242
249
  const { userName } = useHMSPrebuiltContext();
243
250
 
244
251
  const { isAudioEnabled, isVideoEnabled, setVolume, toggleAudio, toggleVideo, volume } = useRemoteAVToggle(
@@ -308,6 +315,21 @@ export const TileMenuContent = ({
308
315
  </StyledMenuTile.ItemButton>
309
316
  ) : null}
310
317
 
318
+ {canChangeRole ? (
319
+ <StyledMenuTile.ItemButton
320
+ className={dragClassName}
321
+ css={spacingCSS}
322
+ onClick={() => {
323
+ openRoleChangeModal();
324
+ closeSheetOnClick();
325
+ }}
326
+ data-testid="change_role_btn"
327
+ >
328
+ <PersonSettingsIcon height={20} width={20} />
329
+ <span>Switch Role</span>
330
+ </StyledMenuTile.ItemButton>
331
+ ) : null}
332
+
311
333
  {audioTrackID ? (
312
334
  <StyledMenuTile.VolumeItem data-testid="participant_volume_slider" css={{ ...spacingCSS, mb: '$0' }}>
313
335
  <Flex align="center" gap={1}>
@@ -1,6 +1,5 @@
1
1
  import React, { useEffect, useMemo } from 'react';
2
2
  import { useMedia } from 'react-use';
3
- import { Whiteboard } from '@100mslive/hms-whiteboard';
4
3
  import { selectPeerByCondition, selectWhiteboard, useHMSStore, useWhiteboard } from '@100mslive/react-sdk';
5
4
  import { Box } from '../../../Layout';
6
5
  import { config as cssConfig } from '../../../Theme';
@@ -12,12 +11,10 @@ import { ProminenceLayout } from './ProminenceLayout';
12
11
  // @ts-ignore: No implicit Any
13
12
  import { useSetUiSettings } from '../AppData/useUISettings';
14
13
  import { UI_SETTINGS } from '../../common/constants';
15
- // eslint-disable-next-line import/no-unresolved
16
- import '@100mslive/hms-whiteboard/index.css';
17
14
 
18
15
  const WhiteboardEmbed = () => {
19
16
  const isMobile = useMedia(cssConfig.media.md);
20
- const { token, endpoint, zoomToContent } = useWhiteboard(isMobile);
17
+ const { iframeRef } = useWhiteboard(isMobile);
21
18
 
22
19
  return (
23
20
  <Box
@@ -31,9 +28,18 @@ const WhiteboardEmbed = () => {
31
28
  },
32
29
  }}
33
30
  >
34
- <Box css={{ size: '100%' }}>
35
- <Whiteboard token={token} endpoint={`https://${endpoint}`} zoomToContent={zoomToContent} />
36
- </Box>
31
+ <iframe
32
+ title="Whiteboard View"
33
+ ref={iframeRef}
34
+ style={{
35
+ width: '100%',
36
+ height: '100%',
37
+ border: 0,
38
+ borderRadius: '0.75rem',
39
+ }}
40
+ allow="autoplay; clipboard-write;"
41
+ referrerPolicy="no-referrer"
42
+ />
37
43
  </Box>
38
44
  );
39
45
  };
@@ -26,6 +26,7 @@ import { VBCollection } from './VBCollection';
26
26
  import { VBHandler } from './VBHandler';
27
27
  // @ts-ignore
28
28
  import { useSidepaneToggle } from '../AppData/useSidepane';
29
+ import { useSidepaneResetOnLayoutUpdate } from '../AppData/useSidepaneResetOnLayoutUpdate';
29
30
  // @ts-ignore
30
31
  import { useSetAppDataByKey, useUISettings } from '../AppData/useUISettings';
31
32
  import { APP_DATA, SIDE_PANE_OPTIONS, UI_SETTINGS } from '../../common/constants';
@@ -113,6 +114,8 @@ export const VBPicker = ({ backgroundMedia = [] }: { backgroundMedia: VirtualBac
113
114
  return () => setLoadingEffects(false);
114
115
  }, [isVideoOn, setLoadingEffects, toggleVB]);
115
116
 
117
+ useSidepaneResetOnLayoutUpdate('virtual_background', SIDE_PANE_OPTIONS.VB);
118
+
116
119
  return (
117
120
  <Flex css={{ pr: '$6', size: '100%' }} direction="column">
118
121
  <Flex align="center" justify="between" css={{ w: '100%', background: '$surface_dim', pb: '$4' }}>
@@ -141,14 +141,6 @@ const SidePane = ({
141
141
  ? preview_elements?.virtual_background?.background_media
142
142
  : elements?.virtual_background?.background_media || [];
143
143
 
144
- const resetSidePane = useSidepaneReset();
145
-
146
- useEffect(() => {
147
- return () => {
148
- resetSidePane();
149
- };
150
- }, [resetSidePane]);
151
-
152
144
  const tileLayout = {
153
145
  hideParticipantNameOnTile: tileProps?.hide_participant_name_on_tile,
154
146
  roundedVideoTile: tileProps?.rounded_video_tile,
@@ -199,7 +191,15 @@ const SidePane = ({
199
191
  return null;
200
192
  });
201
193
 
202
- if (!trackId && !SidepaneComponent) {
194
+ const resetSidePane = useSidepaneReset();
195
+
196
+ useEffect(() => {
197
+ return () => {
198
+ resetSidePane();
199
+ };
200
+ }, [resetSidePane]);
201
+
202
+ if (!SidepaneComponent && !trackId) {
203
203
  return null;
204
204
  }
205
205