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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/{HLSView-5GXP76IN.js → HLSView-73GDHCD4.js} +2 -2
  2. package/dist/{HLSView-FBGVUTA5.css → HLSView-NUX3NEDM.css} +16 -3
  3. package/dist/{HLSView-FBGVUTA5.css.map → HLSView-NUX3NEDM.css.map} +3 -3
  4. package/dist/Prebuilt/common/constants.d.ts +1 -0
  5. package/dist/Prebuilt/components/AppData/useSidepaneResetOnLayoutUpdate.d.ts +3 -0
  6. package/dist/Prebuilt/components/Chat/Chat.d.ts +1 -1
  7. package/dist/Prebuilt/components/RoleChangeModal.d.ts +5 -0
  8. package/dist/Prebuilt/components/TileMenu/TileMenuContent.d.ts +2 -1
  9. package/dist/{chunk-WSDBUVSZ.js → chunk-K7LIJG5P.js} +610 -563
  10. package/dist/chunk-K7LIJG5P.js.map +7 -0
  11. package/dist/index.cjs.css +15 -2
  12. package/dist/index.cjs.css.map +3 -3
  13. package/dist/index.cjs.js +1949 -1894
  14. package/dist/index.cjs.js.map +4 -4
  15. package/dist/index.css +15 -2
  16. package/dist/index.css.map +3 -3
  17. package/dist/index.js +1 -1
  18. package/dist/meta.cjs.json +136 -62
  19. package/dist/meta.esbuild.json +150 -76
  20. package/package.json +7 -7
  21. package/src/Modal/DialogContent.tsx +1 -1
  22. package/src/Prebuilt/common/constants.ts +2 -0
  23. package/src/Prebuilt/components/AppData/useSidepaneResetOnLayoutUpdate.tsx +22 -0
  24. package/src/Prebuilt/components/AudioVideoToggle.tsx +1 -1
  25. package/src/Prebuilt/components/Chat/Chat.tsx +3 -4
  26. package/src/Prebuilt/components/Footer/ParticipantList.tsx +58 -37
  27. package/src/Prebuilt/components/RoleChangeModal.tsx +188 -0
  28. package/src/Prebuilt/components/TileMenu/TileMenu.tsx +5 -0
  29. package/src/Prebuilt/components/TileMenu/TileMenuContent.tsx +25 -1
  30. package/src/Prebuilt/components/VirtualBackground/VBPicker.tsx +3 -0
  31. package/src/Prebuilt/layouts/SidePane.tsx +9 -9
  32. package/dist/chunk-WSDBUVSZ.js.map +0 -7
  33. package/src/Prebuilt/components/RoleChangeModal.jsx +0 -185
  34. /package/dist/{HLSView-5GXP76IN.js.map → HLSView-73GDHCD4.js.map} +0 -0
@@ -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 (
@@ -4,6 +4,7 @@ import {
4
4
  HMSPeer,
5
5
  HMSPeerType,
6
6
  HMSRoleName,
7
+ selectAvailableRoleNames,
7
8
  selectHandRaisedPeers,
8
9
  selectHasPeerHandRaised,
9
10
  selectIsLargeRoom,
@@ -21,6 +22,7 @@ import {
21
22
  HandIcon,
22
23
  MicOffIcon,
23
24
  PeopleIcon,
25
+ PersonSettingsIcon,
24
26
  SearchIcon,
25
27
  VerticalMenuIcon,
26
28
  } from '@100mslive/react-icons';
@@ -29,10 +31,12 @@ import { Accordion, Box, Button, config as cssConfig, Dropdown, Flex, Input, Tex
29
31
  import IconButton from '../../IconButton';
30
32
  import { ConnectionIndicator } from '../Connection/ConnectionIndicator';
31
33
  import { RemoveParticipant } from '../RemoveParticipant';
34
+ import { RoleChangeModal } from '../RoleChangeModal';
32
35
  import { RoleAccordion } from './RoleAccordion';
33
36
  import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
34
37
  // @ts-ignore: No implicit Any
35
38
  import { useIsSidepaneTypeOpen, useSidepaneToggle } from '../AppData/useSidepane';
39
+ import { useSidepaneResetOnLayoutUpdate } from '../AppData/useSidepaneResetOnLayoutUpdate';
36
40
  import { usePeerOnStageActions } from '../hooks/usePeerOnStageActions';
37
41
  import { useParticipants } from '../../common/hooks';
38
42
  // @ts-ignore: No implicit Any
@@ -71,6 +75,8 @@ export const ParticipantList = ({
71
75
  });
72
76
  }
73
77
 
78
+ useSidepaneResetOnLayoutUpdate('participant_list', SIDE_PANE_OPTIONS.PARTICIPANTS);
79
+
74
80
  const onSearch = useCallback((value: string) => {
75
81
  setFilter(filterValue => {
76
82
  if (!filterValue) {
@@ -365,45 +371,60 @@ const ParticipantMoreActions = ({ peerId, role }: { peerId: string; role: string
365
371
  isInStage,
366
372
  shouldShowStageRoleChange,
367
373
  } = usePeerOnStageActions({ peerId, role });
374
+ const canChangeRole = !!useHMSStore(selectPermissions)?.changeRole;
375
+ const [openRoleChangeModal, setOpenRoleChangeModal] = useState(false);
376
+ const roles = useHMSStore(selectAvailableRoleNames);
377
+
368
378
  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}
379
+ <>
380
+ <Dropdown.Root open={open} onOpenChange={value => setOpen(value)} modal={false}>
381
+ <Dropdown.Trigger
382
+ asChild
383
+ data-testid="participant_more_actions"
384
+ className="participant_item"
385
+ css={{
386
+ p: '$1',
387
+ r: '$0',
388
+ c: '$on_surface_high',
389
+ display: open ? 'flex' : 'none',
390
+ '&:hover': {
391
+ bg: '$surface_bright',
392
+ },
393
+ '@md': {
394
+ display: 'flex',
395
+ },
396
+ }}
397
+ tabIndex={0}
398
+ >
399
+ <Box css={{ my: 'auto' }}>
400
+ <VerticalMenuIcon />
401
+ </Box>
402
+ </Dropdown.Trigger>
403
+ <Dropdown.Portal>
404
+ <Dropdown.Content align="end" sideOffset={8} css={{ w: '$64', bg: '$surface_default' }}>
405
+ {shouldShowStageRoleChange ? (
406
+ <Dropdown.Item css={{ bg: '$surface_default' }} onClick={() => handleStageAction()}>
407
+ <ChangeRoleIcon />
408
+ <Text variant="sm" css={{ ml: '$4', fontWeight: '$semiBold', c: '$on_surface_high' }}>
409
+ {isInStage ? remove_from_stage_label : bring_to_stage_label}
410
+ </Text>
411
+ </Dropdown.Item>
412
+ ) : null}
402
413
 
403
- <RemoveParticipant peerId={peerId} />
404
- </Dropdown.Content>
405
- </Dropdown.Portal>
406
- </Dropdown.Root>
414
+ {canChangeRole && roles.length > 1 ? (
415
+ <Dropdown.Item css={{ bg: '$surface_default' }} onClick={() => setOpenRoleChangeModal(true)}>
416
+ <PersonSettingsIcon />
417
+ <Text variant="sm" css={{ ml: '$4', fontWeight: '$semiBold', c: '$on_surface_high' }}>
418
+ Switch Role
419
+ </Text>
420
+ </Dropdown.Item>
421
+ ) : null}
422
+ <RemoveParticipant peerId={peerId} />
423
+ </Dropdown.Content>
424
+ </Dropdown.Portal>
425
+ </Dropdown.Root>
426
+ {openRoleChangeModal && <RoleChangeModal peerId={peerId} onOpenChange={setOpenRoleChangeModal} />}
427
+ </>
407
428
  );
408
429
  };
409
430
 
@@ -0,0 +1,188 @@
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(
43
+ role => role !== peer?.roleName && role !== '__internal_recorder',
44
+ );
45
+ const [selectedRole, setRole] = useState(roles.filter(role => role !== peer?.roleName)?.[0] || peer?.roleName);
46
+ const hmsActions = useHMSActions();
47
+ const [open, setOpen] = useState(false);
48
+ const triggerRef = useRef<HTMLButtonElement | undefined>();
49
+
50
+ return (
51
+ <>
52
+ <Flex align="center" justify="between" css={{ w: '100%' }}>
53
+ <Text as="h6" variant="h6">
54
+ Switch Role
55
+ </Text>
56
+ {isMobile && <CrossIcon onClick={() => onOpenChange(false)} />}
57
+ </Flex>
58
+
59
+ <Box>
60
+ <Text
61
+ variant="sm"
62
+ css={{
63
+ mt: '$4',
64
+ mb: '$8',
65
+ c: '$on_surface_medium',
66
+ display: 'flex',
67
+ flexWrap: 'wrap',
68
+ columnGap: '4px',
69
+ }}
70
+ >
71
+ Switch the role of
72
+ <HighlightTerm value={peer.name} />
73
+ from <HighlightTerm value={peer.roleName} /> to
74
+ </Text>
75
+ </Box>
76
+ <Flex
77
+ align="center"
78
+ css={{
79
+ w: '100%',
80
+ mb: '$10',
81
+ }}
82
+ >
83
+ <Box
84
+ css={{
85
+ position: 'relative',
86
+ flex: '1 1 0',
87
+ minWidth: 0,
88
+ }}
89
+ >
90
+ <Dropdown.Root open={open} onOpenChange={setOpen} css={{ width: '100%' }}>
91
+ <Dropdown.Trigger
92
+ // @ts-ignore
93
+ ref={triggerRef}
94
+ data-testid="open_role_selection_dropdown"
95
+ asChild
96
+ css={{
97
+ bg: '$surface_default',
98
+ r: '$1',
99
+ p: '$6 $9',
100
+ }}
101
+ >
102
+ <Flex align="center" justify="between" css={{ width: '100%' }}>
103
+ <Text>{selectedRole}</Text>
104
+ {open ? <ChevronUpIcon /> : <ChevronDownIcon />}
105
+ </Flex>
106
+ </Dropdown.Trigger>
107
+
108
+ <Dropdown.Content align="start" sideOffset={8} css={{ zIndex: 1000, w: '100%' }}>
109
+ {roles.map(role => (
110
+ <Dropdown.Item
111
+ data-testid={role}
112
+ key={role}
113
+ onSelect={() => setRole(role)}
114
+ css={{ w: `${triggerRef.current?.clientWidth}px` }}
115
+ >
116
+ {role}
117
+ </Dropdown.Item>
118
+ ))}
119
+ </Dropdown.Content>
120
+ </Dropdown.Root>
121
+ </Box>
122
+ </Flex>
123
+ <Flex justify="center" align="center" css={{ width: '100%', gap: '$md' }}>
124
+ {!isMobile && (
125
+ <Button
126
+ variant="standard"
127
+ outlined
128
+ css={{ width: '100%' }}
129
+ onClick={() => onOpenChange(false)}
130
+ data-testid="cancel_button"
131
+ >
132
+ Cancel
133
+ </Button>
134
+ )}
135
+
136
+ <Button
137
+ data-testid="change_button"
138
+ variant="primary"
139
+ css={{ width: '100%' }}
140
+ onClick={async () => {
141
+ if (selectedRole) {
142
+ await hmsActions.changeRoleOfPeer(peer.id, selectedRole, true);
143
+ onOpenChange(false);
144
+ }
145
+ }}
146
+ >
147
+ Switch Role
148
+ </Button>
149
+ </Flex>
150
+ </>
151
+ );
152
+ };
153
+
154
+ export const RoleChangeModal = ({
155
+ peerId,
156
+ onOpenChange,
157
+ }: {
158
+ peerId: string;
159
+ onOpenChange: (open: boolean) => void;
160
+ }) => {
161
+ const peer = useHMSStore(selectPeerByID(peerId));
162
+ const isMobile = useMedia(cssConfig.media.md);
163
+
164
+ if (!peer) {
165
+ return null;
166
+ }
167
+
168
+ if (isMobile) {
169
+ return (
170
+ <Sheet.Root open={true} onOpenChange={onOpenChange} css={{ borderRadius: '$0 $0 0 0' }}>
171
+ <Sheet.Content css={{ p: '$10 $8', background: '$surface_dim', border: '1px solid $border_default' }}>
172
+ <RoleChangeContent peer={peer} onOpenChange={onOpenChange} isMobile />
173
+ </Sheet.Content>
174
+ </Sheet.Root>
175
+ );
176
+ }
177
+
178
+ return (
179
+ <Dialog.Root defaultOpen onOpenChange={onOpenChange}>
180
+ <Dialog.Portal>
181
+ <Dialog.Overlay />
182
+ <Dialog.Content css={{ width: 'min(400px,80%)', p: '$10', overflow: 'visible' }}>
183
+ <RoleChangeContent peer={peer} onOpenChange={onOpenChange} />
184
+ </Dialog.Content>
185
+ </Dialog.Portal>
186
+ </Dialog.Root>
187
+ );
188
+ };
@@ -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
  };
@@ -5,6 +5,7 @@ import {
5
5
  HMSSimulcastLayerDefinition,
6
6
  HMSTrackID,
7
7
  HMSVideoTrack,
8
+ selectAvailableRoleNames,
8
9
  selectPermissions,
9
10
  selectSessionStore,
10
11
  selectTrackByID,
@@ -17,6 +18,7 @@ import {
17
18
  MicOffIcon,
18
19
  MicOnIcon,
19
20
  PencilIcon,
21
+ PersonSettingsIcon,
20
22
  PinIcon,
21
23
  RemoveUserIcon,
22
24
  ShareScreenIcon,
@@ -224,6 +226,9 @@ export const TileMenuContent = ({
224
226
  openNameChangeModal = () => {
225
227
  return;
226
228
  },
229
+ openRoleChangeModal = () => {
230
+ return;
231
+ },
227
232
  }: {
228
233
  videoTrackID: string;
229
234
  audioTrackID: string;
@@ -235,11 +240,15 @@ export const TileMenuContent = ({
235
240
  canMinimise?: boolean;
236
241
  closeSheetOnClick?: () => void;
237
242
  openNameChangeModal?: () => void;
243
+ openRoleChangeModal?: () => void;
238
244
  }) => {
239
245
  const actions = useHMSActions();
240
246
  const dragClassName = getDragClassName();
241
- const removeOthers: boolean | undefined = useHMSStore(selectPermissions)?.removeOthers;
247
+ const permissions = useHMSStore(selectPermissions);
248
+ const canChangeRole = !!permissions?.changeRole;
249
+ const removeOthers = !!permissions?.removeOthers;
242
250
  const { userName } = useHMSPrebuiltContext();
251
+ const roles = useHMSStore(selectAvailableRoleNames);
243
252
 
244
253
  const { isAudioEnabled, isVideoEnabled, setVolume, toggleAudio, toggleVideo, volume } = useRemoteAVToggle(
245
254
  audioTrackID,
@@ -308,6 +317,21 @@ export const TileMenuContent = ({
308
317
  </StyledMenuTile.ItemButton>
309
318
  ) : null}
310
319
 
320
+ {canChangeRole && roles.length > 1 ? (
321
+ <StyledMenuTile.ItemButton
322
+ className={dragClassName}
323
+ css={spacingCSS}
324
+ onClick={() => {
325
+ openRoleChangeModal();
326
+ closeSheetOnClick();
327
+ }}
328
+ data-testid="change_role_btn"
329
+ >
330
+ <PersonSettingsIcon height={20} width={20} />
331
+ <span>Switch Role</span>
332
+ </StyledMenuTile.ItemButton>
333
+ ) : null}
334
+
311
335
  {audioTrackID ? (
312
336
  <StyledMenuTile.VolumeItem data-testid="participant_volume_slider" css={{ ...spacingCSS, mb: '$0' }}>
313
337
  <Flex align="center" gap={1}>
@@ -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