@100mslive/roomkit-react 0.1.8 → 0.1.9-alpha.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (139) hide show
  1. package/dist/{HLSView-DDGPZHA2.js → HLSView-U53QN3AC.js} +3 -3
  2. package/dist/Modal/Dialog.d.ts +402 -1706
  3. package/dist/Prebuilt/App.d.ts +5 -0
  4. package/dist/Prebuilt/AppContext.d.ts +1 -0
  5. package/dist/Prebuilt/AppStateContext.d.ts +16 -0
  6. package/dist/Prebuilt/components/ConferenceScreen.d.ts +2 -0
  7. package/dist/Prebuilt/components/Footer/PollsToggle.d.ts +2 -0
  8. package/dist/Prebuilt/components/LeaveScreen.d.ts +2 -0
  9. package/dist/Prebuilt/components/MwebLandscapePrompt.d.ts +2 -0
  10. package/dist/Prebuilt/components/Notifications/AutoplayBlockedModal.d.ts +2 -0
  11. package/dist/Prebuilt/components/Notifications/HLSFailureModal.d.ts +2 -0
  12. package/dist/Prebuilt/components/Notifications/InitErrorModal.d.ts +2 -0
  13. package/dist/Prebuilt/components/Notifications/Notifications.d.ts +2 -0
  14. package/dist/Prebuilt/components/Notifications/PeerNotifications.d.ts +1 -0
  15. package/dist/Prebuilt/components/Notifications/PermissionErrorModal.d.ts +2 -0
  16. package/dist/Prebuilt/components/Notifications/ReconnectNotifications.d.ts +2 -0
  17. package/dist/Prebuilt/components/Notifications/TrackBulkUnmuteModal.d.ts +2 -0
  18. package/dist/Prebuilt/components/Notifications/TrackNotifications.d.ts +1 -0
  19. package/dist/Prebuilt/components/Notifications/TrackUnmuteModal.d.ts +2 -0
  20. package/dist/Prebuilt/components/Polls/Polls.d.ts +2 -0
  21. package/dist/Prebuilt/components/Preview/PreviewJoin.d.ts +1 -2
  22. package/dist/Prebuilt/components/Preview/PreviewScreen.d.ts +2 -0
  23. package/dist/Prebuilt/components/hooks/useRedirectToLeave.d.ts +1 -1
  24. package/dist/{VirtualBackground-UVZJVOA2.js → VirtualBackground-PMLQPJB6.js} +3 -5
  25. package/dist/{VirtualBackground-UVZJVOA2.js.map → VirtualBackground-PMLQPJB6.js.map} +1 -1
  26. package/dist/chunk-ANQRGVIX.js +14441 -0
  27. package/dist/chunk-ANQRGVIX.js.map +7 -0
  28. package/dist/{chunk-6SQTFOK6.js → chunk-XQ2NRKIW.js} +66 -3
  29. package/dist/{chunk-6SQTFOK6.js.map → chunk-XQ2NRKIW.js.map} +4 -4
  30. package/dist/context/DialogContext.d.ts +6 -0
  31. package/dist/hooks/useDialogContainerSelector.d.ts +1 -0
  32. package/dist/index.cjs.js +10944 -9974
  33. package/dist/index.cjs.js.map +4 -4
  34. package/dist/index.d.ts +1 -0
  35. package/dist/index.js +6 -2
  36. package/dist/meta.cjs.json +3871 -3188
  37. package/dist/meta.esbuild.json +4303 -3728
  38. package/dist/utils/animations.d.ts +11 -0
  39. package/package.json +6 -7
  40. package/src/Modal/Dialog.tsx +31 -3
  41. package/src/Prebuilt/App.tsx +46 -99
  42. package/src/Prebuilt/AppContext.tsx +4 -0
  43. package/src/Prebuilt/AppStateContext.tsx +71 -0
  44. package/src/Prebuilt/common/constants.js +35 -0
  45. package/src/Prebuilt/common/utils.js +47 -0
  46. package/src/Prebuilt/components/AppData/AppData.jsx +5 -0
  47. package/src/Prebuilt/components/AppData/useSidepane.js +23 -1
  48. package/src/Prebuilt/components/AppData/useUISettings.js +48 -4
  49. package/src/Prebuilt/components/{conference.jsx → ConferenceScreen.tsx} +30 -43
  50. package/src/Prebuilt/components/Footer/Footer.tsx +5 -0
  51. package/src/Prebuilt/components/Footer/PaginatedParticipants.tsx +63 -32
  52. package/src/Prebuilt/components/Footer/ParticipantList.jsx +2 -1
  53. package/src/Prebuilt/components/Footer/PollsToggle.tsx +22 -0
  54. package/src/Prebuilt/components/Footer/RoleAccordion.tsx +2 -2
  55. package/src/Prebuilt/components/Header/StreamActions.tsx +5 -3
  56. package/src/Prebuilt/components/Leave/DesktopLeaveRoom.tsx +4 -5
  57. package/src/Prebuilt/components/Leave/LeaveRoom.tsx +0 -4
  58. package/src/Prebuilt/components/{PostLeave.jsx → LeaveScreen.tsx} +6 -13
  59. package/src/Prebuilt/components/MoreSettings/ChangeNameModal.jsx +2 -3
  60. package/src/Prebuilt/components/MoreSettings/EmbedUrl.jsx +2 -3
  61. package/src/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.tsx +18 -1
  62. package/src/Prebuilt/components/{MwebLandscapePrompt.jsx → MwebLandscapePrompt.tsx} +10 -11
  63. package/src/Prebuilt/components/Notifications/{AutoplayBlockedModal.jsx → AutoplayBlockedModal.tsx} +2 -1
  64. package/src/Prebuilt/components/Notifications/{HLSFailureModal.jsx → HLSFailureModal.tsx} +10 -8
  65. package/src/Prebuilt/components/Notifications/{InitErrorModal.jsx → InitErrorModal.tsx} +5 -2
  66. package/src/Prebuilt/components/Notifications/{Notifications.jsx → Notifications.tsx} +41 -27
  67. package/src/Prebuilt/components/Notifications/{PeerNotifications.jsx → PeerNotifications.tsx} +3 -0
  68. package/src/Prebuilt/components/Notifications/{PermissionErrorModal.jsx → PermissionErrorModal.tsx} +6 -4
  69. package/src/Prebuilt/components/Notifications/{ReconnectNotifications.jsx → ReconnectNotifications.tsx} +11 -6
  70. package/src/Prebuilt/components/Notifications/{TrackBulkUnmuteModal.jsx → TrackBulkUnmuteModal.tsx} +9 -3
  71. package/src/Prebuilt/components/Notifications/{TrackUnmuteModal.jsx → TrackUnmuteModal.tsx} +9 -3
  72. package/src/Prebuilt/components/Notifications/index.tsx +1 -0
  73. package/src/Prebuilt/components/Polls/CreatePollQuiz/PollsQuizMenu.jsx +229 -0
  74. package/src/Prebuilt/components/Polls/CreatePollQuiz/Timer.jsx +71 -0
  75. package/src/Prebuilt/components/Polls/CreateQuestions/CreateQuestions.jsx +132 -0
  76. package/src/Prebuilt/components/Polls/CreateQuestions/DeleteQuestionModal.jsx +66 -0
  77. package/src/Prebuilt/components/Polls/CreateQuestions/QuestionForm.jsx +251 -0
  78. package/src/Prebuilt/components/Polls/CreateQuestions/SavedQuestion.jsx +57 -0
  79. package/src/Prebuilt/components/Polls/Polls.tsx +28 -0
  80. package/src/Prebuilt/components/Polls/Voting/PollResultSummary.jsx +125 -0
  81. package/src/Prebuilt/components/Polls/Voting/QuestionCard.jsx +249 -0
  82. package/src/Prebuilt/components/Polls/Voting/StandardVoting.jsx +40 -0
  83. package/src/Prebuilt/components/Polls/Voting/TimedVoting.jsx +36 -0
  84. package/src/Prebuilt/components/Polls/Voting/Voting.jsx +99 -0
  85. package/src/Prebuilt/components/Polls/common/MultipleChoiceOptions.jsx +101 -0
  86. package/src/Prebuilt/components/Polls/common/OptionInputWithDelete.jsx +25 -0
  87. package/src/Prebuilt/components/Polls/common/SingleChoiceOptions.jsx +125 -0
  88. package/src/Prebuilt/components/Polls/common/StatusIndicator.jsx +47 -0
  89. package/src/Prebuilt/components/Polls/common/VoteCount.jsx +28 -0
  90. package/src/Prebuilt/components/Polls/common/VoteProgress.jsx +17 -0
  91. package/src/Prebuilt/components/Polls/common/VoterList.jsx +22 -0
  92. package/src/Prebuilt/components/Polls/common/Votes.jsx +72 -0
  93. package/src/Prebuilt/components/Preview/PreviewForm.tsx +3 -2
  94. package/src/Prebuilt/components/Preview/PreviewJoin.tsx +32 -27
  95. package/src/Prebuilt/components/Preview/{PreviewContainer.tsx → PreviewScreen.tsx} +2 -19
  96. package/src/Prebuilt/components/RaiseHand.jsx +1 -1
  97. package/src/Prebuilt/components/RoleChangeModal.jsx +2 -3
  98. package/src/Prebuilt/components/RoleChangeRequest/RequestPrompt.tsx +2 -3
  99. package/src/Prebuilt/components/Settings/SettingsModal.jsx +2 -3
  100. package/src/Prebuilt/components/Settings/StartRecording.jsx +15 -4
  101. package/src/Prebuilt/components/SidePaneTabs.tsx +1 -1
  102. package/src/Prebuilt/components/StatsForNerds.jsx +2 -3
  103. package/src/Prebuilt/components/Streaming/Common.jsx +31 -21
  104. package/src/Prebuilt/components/VideoLayouts/ScreenshareLayout.tsx +8 -9
  105. package/src/Prebuilt/components/VideoTile.jsx +37 -33
  106. package/src/Prebuilt/components/hooks/useAutoStartStreaming.tsx +3 -3
  107. package/src/Prebuilt/components/hooks/useRedirectToLeave.tsx +9 -17
  108. package/src/Prebuilt/components/pdfAnnotator/pdfFileOptions.jsx +2 -3
  109. package/src/Prebuilt/components/pdfAnnotator/submitPdf.jsx +1 -1
  110. package/src/Prebuilt/components/pdfAnnotator/uploadedFile.jsx +2 -3
  111. package/src/Prebuilt/layouts/EmbedView.jsx +47 -60
  112. package/src/Prebuilt/layouts/PDFView.jsx +49 -99
  113. package/src/Prebuilt/layouts/SidePane.tsx +8 -4
  114. package/src/Prebuilt/layouts/VideoStreamingSection.tsx +2 -2
  115. package/src/Prebuilt/primitives/DialogContent.jsx +4 -5
  116. package/src/context/DialogContext.tsx +13 -0
  117. package/src/hooks/useDialogContainerSelector.tsx +7 -0
  118. package/src/index.ts +1 -0
  119. package/src/utils/animations.ts +6 -0
  120. package/dist/Prebuilt/components/Notifications/HeadlessEndRoomListener.d.ts +0 -2
  121. package/dist/Prebuilt/components/PrebuiltDialogPortal.d.ts +0 -4
  122. package/dist/Prebuilt/components/PrebuiltTileElements.d.ts +0 -2198
  123. package/dist/Prebuilt/components/Preview/PreviewContainer.d.ts +0 -3
  124. package/dist/chunk-HUMNPIYI.js +0 -70
  125. package/dist/chunk-HUMNPIYI.js.map +0 -7
  126. package/dist/chunk-PRM33R4R.js +0 -7160
  127. package/dist/chunk-PRM33R4R.js.map +0 -7
  128. package/dist/conference-N7S47TDK.js +0 -6602
  129. package/dist/conference-N7S47TDK.js.map +0 -7
  130. package/src/Prebuilt/components/GoLiveButton.jsx +0 -42
  131. package/src/Prebuilt/components/Notifications/HeadlessEndRoomListener.tsx +0 -23
  132. package/src/Prebuilt/components/PrebuiltDialogPortal.tsx +0 -6
  133. package/src/Prebuilt/components/PrebuiltTileElements.tsx +0 -5
  134. package/src/Prebuilt/components/Streaming/HLSStreaming.jsx +0 -220
  135. package/src/Prebuilt/components/Streaming/RTMPStreaming.jsx +0 -334
  136. package/src/Prebuilt/components/Streaming/StreamingLanding.jsx +0 -76
  137. /package/dist/{HLSView-DDGPZHA2.js.map → HLSView-U53QN3AC.js.map} +0 -0
  138. /package/{src/Prebuilt/components/Notifications/index.jsx → dist/Prebuilt/components/Notifications/index.d.ts} +0 -0
  139. /package/src/Prebuilt/components/Notifications/{TrackNotifications.jsx → TrackNotifications.tsx} +0 -0
@@ -1,8 +1,10 @@
1
- import { useCallback } from 'react';
1
+ import { useCallback, useMemo } from 'react';
2
2
  import {
3
3
  selectAppData,
4
4
  selectAppDataByPath,
5
5
  selectAudioTrackByPeerID,
6
+ selectPermissions,
7
+ selectPolls,
6
8
  selectSessionStore,
7
9
  selectTrackByID,
8
10
  selectVideoTrackByPeerID,
@@ -11,7 +13,7 @@ import {
11
13
  useHMSVanillaStore,
12
14
  } from '@100mslive/react-sdk';
13
15
  import { UserPreferencesKeys, useUserPreferences } from '../hooks/useUserPreferences';
14
- import { APP_DATA, SESSION_STORE_KEY } from '../../common/constants';
16
+ import { APP_DATA, POLL_STATE, SESSION_STORE_KEY } from '../../common/constants';
15
17
 
16
18
  /**
17
19
  * fields saved related to UI settings in store's app data can be
@@ -69,8 +71,18 @@ export const useUrlToEmbed = () => {
69
71
  return useHMSStore(selectAppData(APP_DATA.embedConfig))?.url;
70
72
  };
71
73
 
72
- export const usePDFAnnotator = () => {
73
- return useHMSStore(selectAppData(APP_DATA.pdfConfig))?.state;
74
+ export const usePDFConfig = () => {
75
+ return useHMSStore(selectAppData(APP_DATA.pdfConfig));
76
+ };
77
+
78
+ export const useResetPDFConfig = () => {
79
+ const [, setPDFConfig] = useSetAppDataByKey(APP_DATA.pdfConfig);
80
+ return useCallback(() => setPDFConfig(), [setPDFConfig]);
81
+ };
82
+
83
+ export const useResetEmbedConfig = () => {
84
+ const [, setEmbedConfig] = useSetAppDataByKey(APP_DATA.embedConfig);
85
+ return () => setEmbedConfig();
74
86
  };
75
87
  export const usePinnedTrack = () => {
76
88
  const pinnedTrackId = useHMSStore(selectAppData(APP_DATA.pinnedTrackId));
@@ -153,3 +165,35 @@ const useSetAppData = ({ key1, key2 }) => {
153
165
  );
154
166
  return setValue;
155
167
  };
168
+
169
+ export const useShowPolls = () => {
170
+ const permissions = useHMSStore(selectPermissions);
171
+ const polls = useHMSStore(selectPolls)?.filter(poll => poll.state === 'started' || poll.state === 'stopped');
172
+
173
+ const showPolls = useMemo(() => {
174
+ return permissions?.pollWrite || (permissions?.pollRead && polls?.length > 0);
175
+ }, [permissions?.pollRead, permissions?.pollWrite, polls?.length]);
176
+
177
+ return { showPolls };
178
+ };
179
+
180
+ export const usePollViewState = () => {
181
+ const [pollState, setPollState] = useSetAppDataByKey(APP_DATA.pollState);
182
+
183
+ const setPollView = useCallback(
184
+ view => {
185
+ setPollState({
186
+ [POLL_STATE.pollInView]: pollState?.pollInView,
187
+ [POLL_STATE.view]: view,
188
+ });
189
+ },
190
+ [pollState?.pollInView, setPollState],
191
+ );
192
+
193
+ return {
194
+ setPollState,
195
+ setPollView,
196
+ pollInView: pollState?.pollInView,
197
+ view: pollState?.view,
198
+ };
199
+ };
@@ -1,6 +1,5 @@
1
1
  import React, { useEffect, useRef, useState } from 'react';
2
- import { useNavigate, useParams } from 'react-router-dom';
3
- import { usePrevious } from 'react-use';
2
+ import { DefaultConferencingScreen_Elements } from '@100mslive/types-prebuilt';
4
3
  import {
5
4
  HMSRoomState,
6
5
  selectAppData,
@@ -11,38 +10,40 @@ import {
11
10
  } from '@100mslive/react-sdk';
12
11
  import { Footer } from './Footer/Footer';
13
12
  import { HLSFailureModal } from './Notifications/HLSFailureModal';
13
+ // @ts-ignore: No implicit Any
14
14
  import { ActivatedPIP } from './PIP/PIPComponent';
15
+ // @ts-ignore: No implicit Any
15
16
  import { PictureInPicture } from './PIP/PIPManager';
16
17
  import { RoleChangeRequestModal } from './RoleChangeRequest/RoleChangeRequestModal';
17
18
  import { Box, Flex } from '../../Layout';
18
19
  import { useHMSPrebuiltContext } from '../AppContext';
19
20
  import { VideoStreamingSection } from '../layouts/VideoStreamingSection';
21
+ // @ts-ignore: No implicit Any
20
22
  import FullPageProgress from './FullPageProgress';
21
23
  import { Header } from './Header';
22
24
  import {
23
25
  useRoomLayoutConferencingScreen,
24
26
  useRoomLayoutPreviewScreen,
25
27
  } from '../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
28
+ // @ts-ignore: No implicit Any
26
29
  import { useAuthToken, useSetAppDataByKey } from './AppData/useUISettings';
30
+ // @ts-ignore: No implicit Any
27
31
  import { APP_DATA, isAndroid, isIOS, isIPadOS } from '../common/constants';
28
32
 
29
- const Conference = () => {
30
- const navigate = useNavigate();
31
- const { roomId, role } = useParams();
33
+ export const ConferenceScreen = () => {
32
34
  const { userName, endpoints, onJoin: onJoinFunc } = useHMSPrebuiltContext();
33
35
  const screenProps = useRoomLayoutConferencingScreen();
34
36
  const { isPreviewScreenEnabled } = useRoomLayoutPreviewScreen();
35
37
  const roomState = useHMSStore(selectRoomState);
36
- const prevState = usePrevious(roomState);
37
38
  const isConnectedToRoom = useHMSStore(selectIsConnectedToRoom);
38
39
  const hmsActions = useHMSActions();
39
40
  const [hideControls, setHideControls] = useState(false);
40
41
  const dropdownList = useHMSStore(selectAppData(APP_DATA.dropdownList));
41
42
  const authTokenInAppData = useAuthToken();
42
- const headerRef = useRef();
43
- const footerRef = useRef();
43
+ const headerRef = useRef<HTMLDivElement | null>(null);
44
+ const footerRef = useRef<HTMLDivElement | null>(null);
44
45
  const isMobileDevice = isAndroid || isIOS || isIPadOS;
45
- const dropdownListRef = useRef();
46
+ const dropdownListRef = useRef<string[]>();
46
47
  const [isHLSStarted] = useSetAppDataByKey(APP_DATA.hlsStarted);
47
48
  const toggleControls = () => {
48
49
  if (dropdownListRef.current?.length === 0 && isMobileDevice) {
@@ -52,12 +53,12 @@ const Conference = () => {
52
53
  const autoRoomJoined = useRef(isPreviewScreenEnabled);
53
54
 
54
55
  useEffect(() => {
55
- let timeout = null;
56
+ let timeout: undefined | ReturnType<typeof setTimeout>;
56
57
  dropdownListRef.current = dropdownList || [];
57
- if (dropdownListRef.current.length === 0) {
58
+ if (dropdownListRef.current && dropdownListRef.current.length === 0) {
58
59
  clearTimeout(timeout);
59
60
  timeout = setTimeout(() => {
60
- if (dropdownListRef.current.length === 0) {
61
+ if (dropdownListRef.current && dropdownListRef.current.length === 0) {
61
62
  setHideControls(isMobileDevice);
62
63
  }
63
64
  }, 5000);
@@ -67,23 +68,6 @@ const Conference = () => {
67
68
  };
68
69
  }, [dropdownList, hideControls, isMobileDevice]);
69
70
 
70
- useEffect(() => {
71
- if (!roomId) {
72
- navigate(`/`);
73
- return;
74
- }
75
- if (!isPreviewScreenEnabled) {
76
- return;
77
- }
78
- if (
79
- !prevState &&
80
- !(roomState === HMSRoomState.Connecting || roomState === HMSRoomState.Reconnecting || isConnectedToRoom)
81
- ) {
82
- if (role) navigate(`/preview/${roomId || ''}/${role}`);
83
- else navigate(`/preview/${roomId || ''}`);
84
- }
85
- }, [isConnectedToRoom, prevState, roomState, navigate, role, roomId, isPreviewScreenEnabled]);
86
-
87
71
  useEffect(() => {
88
72
  if (
89
73
  authTokenInAppData &&
@@ -94,10 +78,10 @@ const Conference = () => {
94
78
  ) {
95
79
  hmsActions
96
80
  .join({
97
- userName,
81
+ userName: userName || '',
98
82
  authToken: authTokenInAppData,
99
83
  initEndpoint: endpoints?.init,
100
- initialSettings: {
84
+ settings: {
101
85
  isAudioMuted: !isPreviewScreenEnabled,
102
86
  isVideoMuted: !isPreviewScreenEnabled,
103
87
  speakerAutoSelectionBlacklist: ['Yeti Stereo Microphone'],
@@ -111,9 +95,9 @@ const Conference = () => {
111
95
  useEffect(() => {
112
96
  onJoinFunc?.();
113
97
  return () => {
114
- PictureInPicture.stop().catch(error => console.error('stopping pip', error));
98
+ PictureInPicture.stop().catch((error: unknown) => console.error('stopping pip', (error as Error).message));
115
99
  };
116
- }, []);
100
+ }, [onJoinFunc]);
117
101
 
118
102
  if (!isConnectedToRoom && ![HMSRoomState.Reconnecting, HMSRoomState.Disconnected].includes(roomState)) {
119
103
  return <FullPageProgress text={roomState === HMSRoomState.Connecting ? 'Joining...' : ''} />;
@@ -140,7 +124,7 @@ const Conference = () => {
140
124
  }}
141
125
  data-testid="header"
142
126
  >
143
- <Header elements={screenProps.elements} screenType={screenProps.screenType} />
127
+ <Header />
144
128
  </Box>
145
129
  )}
146
130
  <Box
@@ -148,7 +132,10 @@ const Conference = () => {
148
132
  w: '100%',
149
133
  flex: '1 1 0',
150
134
  minHeight: 0,
151
- px: screenProps?.elements?.video_tile_layout?.grid?.edge_to_edge ? 0 : '$10', // TODO: padding to be controlled by section/element
135
+ // @ts-ignore
136
+ px: (screenProps?.elements as DefaultConferencingScreen_Elements)?.video_tile_layout?.grid?.edge_to_edge
137
+ ? 0
138
+ : '$10', // TODO: padding to be controlled by section/element
152
139
  paddingBottom: 'env(safe-area-inset-bottom)',
153
140
  '@lg': {
154
141
  px: 0,
@@ -158,13 +145,15 @@ const Conference = () => {
158
145
  data-testid="conferencing"
159
146
  onClick={toggleControls}
160
147
  >
161
- <VideoStreamingSection
162
- screenType={screenProps.screenType}
163
- elements={screenProps.elements}
164
- hideControls={hideControls}
165
- />
148
+ {screenProps.elements ? (
149
+ <VideoStreamingSection
150
+ screenType={screenProps.screenType}
151
+ elements={screenProps.elements}
152
+ hideControls={hideControls}
153
+ />
154
+ ) : null}
166
155
  </Box>
167
- {!screenProps.hideSections.includes('footer') && (
156
+ {!screenProps.hideSections.includes('footer') && screenProps.elements && (
168
157
  <Box
169
158
  ref={footerRef}
170
159
  css={{
@@ -190,5 +179,3 @@ const Conference = () => {
190
179
  </>
191
180
  );
192
181
  };
193
-
194
- export default Conference;
@@ -24,9 +24,12 @@ import { ScreenshareToggle } from '../ScreenShareToggle';
24
24
  import { ChatToggle } from './ChatToggle';
25
25
  // @ts-ignore: No implicit Any
26
26
  import { ParticipantCount } from './ParticipantList';
27
+ import { PollsToggle } from './PollsToggle';
27
28
  // @ts-ignore: No implicit Any
28
29
  import { useIsSidepaneTypeOpen, useSidepaneToggle } from '../AppData/useSidepane';
29
30
  // @ts-ignore: No implicit Any
31
+ import { useShowPolls } from '../AppData/useUISettings';
32
+ // @ts-ignore: No implicit Any
30
33
  import { SIDE_PANE_OPTIONS } from '../../common/constants';
31
34
  // @ts-ignore: No implicit Any
32
35
  const VirtualBackground = React.lazy(() => import('../../plugins/VirtualBackground/VirtualBackground'));
@@ -46,6 +49,7 @@ export const Footer = ({
46
49
  const noAVPermissions = !(toggleAudio || toggleVideo);
47
50
  const isChatOpen = useIsSidepaneTypeOpen(SIDE_PANE_OPTIONS.CHAT);
48
51
  const toggleChat = useSidepaneToggle(SIDE_PANE_OPTIONS.CHAT);
52
+ const { showPolls } = useShowPolls();
49
53
 
50
54
  useEffect(() => {
51
55
  if (!isChatOpen && openByDefault) {
@@ -108,6 +112,7 @@ export const Footer = ({
108
112
  )}
109
113
  </AppFooter.Center>
110
114
  <AppFooter.Right>
115
+ {showPolls && <PollsToggle />}
111
116
  {!isMobile && elements?.chat && <ChatToggle />}
112
117
  {elements?.participant_list && <ParticipantCount />}
113
118
  <MoreSettings elements={elements} screenType={screenType} />
@@ -1,32 +1,80 @@
1
- import React, { useEffect, useRef, useState } from 'react';
1
+ import React, { useEffect, useState } from 'react';
2
+ import { useInView } from 'react-intersection-observer';
2
3
  import { useMeasure } from 'react-use';
3
- import { FixedSizeList } from 'react-window';
4
+ import { VariableSizeList } from 'react-window';
4
5
  import { selectIsConnectedToRoom, useHMSStore, usePaginatedParticipants } from '@100mslive/react-sdk';
5
6
  import { ChevronLeftIcon, CrossIcon } from '@100mslive/react-icons';
6
- import { Button } from '../../../Button';
7
7
  import { IconButton } from '../../../IconButton';
8
8
  import { Box, Flex } from '../../../Layout';
9
9
  import { Loading } from '../../../Loading';
10
10
  import { Text } from '../../../Text';
11
11
  // @ts-ignore: No implicit Any
12
- import { ParticipantSearch } from './ParticipantList';
13
- import { itemKey, ROW_HEIGHT, VirtualizedParticipantItem } from './RoleAccordion';
12
+ import { Participant, ParticipantSearch } from './ParticipantList';
13
+ import { ItemData, itemKey, ROW_HEIGHT } from './RoleAccordion';
14
14
  // @ts-ignore: No implicit Any
15
15
  import { useSidepaneReset } from '../AppData/useSidepane';
16
16
  // @ts-ignore: No implicit Any
17
17
  import { getFormattedCount } from '../../common/utils';
18
18
 
19
+ const LoadMoreParticipants = ({
20
+ hasNext,
21
+ loadMore,
22
+ style,
23
+ }: {
24
+ hasNext: boolean;
25
+ loadMore: () => Promise<void>;
26
+ style: React.CSSProperties;
27
+ }) => {
28
+ const { ref, inView } = useInView();
29
+ const [inProgress, setInProgress] = useState(false);
30
+
31
+ useEffect(() => {
32
+ if (hasNext && inView && !inProgress) {
33
+ setInProgress(true);
34
+ loadMore()
35
+ .catch(console.error)
36
+ .finally(() => setInProgress(false));
37
+ }
38
+ }, [hasNext, loadMore, inView, inProgress]);
39
+ return (
40
+ <Flex ref={ref} style={style} align="center" justify="center">
41
+ {inProgress ? <Loading size={16} /> : null}
42
+ </Flex>
43
+ );
44
+ };
45
+
46
+ const VirtualizedParticipantItem = React.memo(
47
+ ({
48
+ index,
49
+ data,
50
+ style,
51
+ }: {
52
+ index: number;
53
+ data: ItemData & { hasNext: boolean; loadMorePeers: () => Promise<void> };
54
+ style: React.CSSProperties;
55
+ }) => {
56
+ if (!data.peerList[index]) {
57
+ return <LoadMoreParticipants hasNext={data.hasNext} loadMore={data.loadMorePeers} style={style} />;
58
+ }
59
+ return (
60
+ <Participant
61
+ key={data.peerList[index].id}
62
+ peer={data.peerList[index]}
63
+ isConnected={data.isConnected}
64
+ style={style}
65
+ />
66
+ );
67
+ },
68
+ );
69
+
19
70
  export const PaginatedParticipants = ({ roleName, onBack }: { roleName: string; onBack: () => void }) => {
20
- const { peers, total, loadPeers, loadMorePeers } = usePaginatedParticipants({ role: roleName, limit: 20 });
71
+ const { peers, total, hasNext, loadPeers, loadMorePeers } = usePaginatedParticipants({ role: roleName, limit: 20 });
21
72
  const [search, setSearch] = useState<string>('');
22
- const [isLoading, setIsLoading] = useState(false);
23
73
  const filteredPeers = peers.filter(p => p.name?.toLowerCase().includes(search));
24
74
  const isConnected = useHMSStore(selectIsConnectedToRoom);
25
75
  const [ref, { width }] = useMeasure<HTMLDivElement>();
26
- const containerRef = useRef<HTMLDivElement | null>(null);
27
- const height = ROW_HEIGHT * peers.length;
76
+ const height = ROW_HEIGHT * (filteredPeers.length + 1);
28
77
  const resetSidePane = useSidepaneReset();
29
- const hasNext = total > peers.length;
30
78
 
31
79
  useEffect(() => {
32
80
  loadPeers();
@@ -60,33 +108,16 @@ export const PaginatedParticipants = ({ roleName, onBack }: { roleName: string;
60
108
  </Text>
61
109
  </Flex>
62
110
  <Box css={{ flex: '1 1 0', overflowY: 'auto', overflowX: 'hidden', mr: '-$10' }}>
63
- <FixedSizeList
64
- itemSize={ROW_HEIGHT}
65
- itemData={{ peerList: filteredPeers, isConnected: isConnected === true }}
111
+ <VariableSizeList
112
+ itemSize={index => (index === filteredPeers.length + 1 ? 16 : ROW_HEIGHT)}
113
+ itemData={{ peerList: filteredPeers, hasNext: hasNext(), loadMorePeers, isConnected: isConnected === true }}
66
114
  itemKey={itemKey}
67
- itemCount={filteredPeers.length}
115
+ itemCount={filteredPeers.length + 1}
68
116
  width={width}
69
117
  height={height}
70
- outerRef={containerRef}
71
118
  >
72
119
  {VirtualizedParticipantItem}
73
- </FixedSizeList>
74
- {hasNext ? (
75
- <Flex justify="center" css={{ w: '100%' }}>
76
- <Button
77
- css={{ w: 'max-content', p: '$4' }}
78
- onClick={() => {
79
- setIsLoading(true);
80
- loadMorePeers()
81
- .catch(console.error)
82
- .finally(() => setIsLoading(false));
83
- }}
84
- disabled={isLoading}
85
- >
86
- {isLoading ? <Loading size={16} /> : 'Load More'}
87
- </Button>
88
- </Flex>
89
- ) : null}
120
+ </VariableSizeList>
90
121
  </Box>
91
122
  </Flex>
92
123
  </Flex>
@@ -176,7 +176,7 @@ const VirtualizedParticipants = ({
176
176
  );
177
177
  };
178
178
 
179
- export const Participant = ({ peer, isConnected }) => {
179
+ export const Participant = ({ peer, isConnected, style }) => {
180
180
  const localPeerId = useHMSStore(selectLocalPeerID);
181
181
  return (
182
182
  <Flex
@@ -191,6 +191,7 @@ export const Participant = ({ peer, isConnected }) => {
191
191
  align="center"
192
192
  justify="between"
193
193
  data-testid={'participant_' + peer.name}
194
+ style={style}
194
195
  >
195
196
  <Text
196
197
  variant="sm"
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ import { QuizIcon } from '@100mslive/react-icons';
3
+ import { Tooltip } from '../../..';
4
+ // @ts-ignore: No implicit Any
5
+ import IconButton from '../../IconButton';
6
+ // @ts-ignore: No implicit Any
7
+ import { useIsSidepaneTypeOpen, usePollViewToggle } from '../AppData/useSidepane';
8
+ // @ts-ignore: No implicit Any
9
+ import { SIDE_PANE_OPTIONS } from '../../common/constants';
10
+
11
+ export const PollsToggle = () => {
12
+ const isPollsOpen = useIsSidepaneTypeOpen(SIDE_PANE_OPTIONS.POLLS);
13
+ const togglePollView = usePollViewToggle();
14
+
15
+ return (
16
+ <Tooltip key="polls" title={`${isPollsOpen ? 'Close' : 'Open'} polls and quizzes`}>
17
+ <IconButton onClick={togglePollView} active={!isPollsOpen} data-testid="polls_btn">
18
+ <QuizIcon />
19
+ </IconButton>
20
+ </Tooltip>
21
+ );
22
+ };
@@ -21,7 +21,7 @@ export interface ItemData {
21
21
  }
22
22
 
23
23
  export function itemKey(index: number, data: ItemData) {
24
- return data.peerList[index].id;
24
+ return data.peerList[index]?.id;
25
25
  }
26
26
 
27
27
  export const VirtualizedParticipantItem = React.memo(({ index, data }: { index: number; data: ItemData }) => {
@@ -64,8 +64,8 @@ export const RoleAccordion = ({
64
64
  return null;
65
65
  }
66
66
 
67
- const height = ROW_HEIGHT * (peers.length || peerList.length);
68
67
  const peersInAccordion = isOffStageRole && isLargeRoom ? peers : peerList;
68
+ const height = ROW_HEIGHT * peersInAccordion.length;
69
69
  const hasNext = total > peersInAccordion.length;
70
70
 
71
71
  if (peersInAccordion.length === 0) {
@@ -17,6 +17,7 @@ import { Sheet } from '../../../Sheet';
17
17
  import { ToastManager } from '../Toast/ToastManager';
18
18
  // @ts-ignore
19
19
  import { AdditionalRoomState, getRecordingText } from './AdditionalRoomState';
20
+ import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
20
21
  // @ts-ignore
21
22
  import { useSetAppDataByKey } from '../AppData/useUISettings';
22
23
  // @ts-ignore
@@ -29,13 +30,14 @@ export const LiveStatus = () => {
29
30
  const hlsState = useHMSStore(selectHLSState);
30
31
  const isMobile = useMedia(cssConfig.media.md);
31
32
  const intervalRef = useRef<NodeJS.Timeout | null>(null);
32
-
33
+ const { screenType } = useRoomLayoutConferencingScreen();
33
34
  const [liveTime, setLiveTime] = useState(0);
34
35
 
35
36
  const startTimer = useCallback(() => {
36
37
  intervalRef.current = setInterval(() => {
37
- if (hlsState?.running && hlsState?.variants[0]?.startedAt) {
38
- setLiveTime(Date.now() - hlsState.variants[0].startedAt.getTime());
38
+ const timeStamp = hlsState?.variants[0]?.[screenType === 'hls_live_streaming' ? 'startedAt' : 'initialisedAt'];
39
+ if (hlsState?.running && timeStamp) {
40
+ setLiveTime(Date.now() - timeStamp.getTime());
39
41
  }
40
42
  }, 1000);
41
43
  }, [hlsState?.running, hlsState?.variants]);
@@ -8,7 +8,6 @@ import { Dropdown } from '../../../Dropdown';
8
8
  import { Box, Flex } from '../../../Layout';
9
9
  import { Dialog } from '../../../Modal';
10
10
  import { Tooltip } from '../../../Tooltip';
11
- import { PrebuiltDialogPortal } from '../PrebuiltDialogPortal';
12
11
  import { EndSessionContent } from './EndSessionContent';
13
12
  import { LeaveIconButton, MenuTriggerButton } from './LeaveAtoms';
14
13
  import { LeaveCard } from './LeaveCard';
@@ -138,7 +137,7 @@ export const DesktopLeaveRoom = ({
138
137
  )}
139
138
 
140
139
  <Dialog.Root open={showEndStreamAlert} modal={false}>
141
- <PrebuiltDialogPortal>
140
+ <Dialog.Portal>
142
141
  <Dialog.Overlay />
143
142
  <Dialog.Content css={{ w: 'min(420px, 90%)', p: '$8', bg: '$surface_dim' }}>
144
143
  <EndSessionContent
@@ -148,16 +147,16 @@ export const DesktopLeaveRoom = ({
148
147
  isModal
149
148
  />
150
149
  </Dialog.Content>
151
- </PrebuiltDialogPortal>
150
+ </Dialog.Portal>
152
151
  </Dialog.Root>
153
152
 
154
153
  <Dialog.Root open={showLeaveRoomAlert} modal={false}>
155
- <PrebuiltDialogPortal>
154
+ <Dialog.Portal>
156
155
  <Dialog.Overlay />
157
156
  <Dialog.Content css={{ w: 'min(420px, 90%)', p: '$8', bg: '$surface_dim' }}>
158
157
  <LeaveSessionContent setShowLeaveRoomAlert={setShowLeaveRoomAlert} leaveRoom={leaveRoom} isModal />
159
158
  </Dialog.Content>
160
- </PrebuiltDialogPortal>
159
+ </Dialog.Portal>
161
160
  </Dialog.Root>
162
161
  </Fragment>
163
162
  );
@@ -18,7 +18,6 @@ import { config as cssConfig } from '../../../Theme';
18
18
  import { ToastManager } from '../Toast/ToastManager';
19
19
  import { DesktopLeaveRoom } from './DesktopLeaveRoom';
20
20
  import { MwebLeaveRoom } from './MwebLeaveRoom';
21
- import { useRedirectToLeave } from '../hooks/useRedirectToLeave';
22
21
 
23
22
  export const LeaveRoom = ({ screenType }: { screenType: keyof ConferencingScreen }) => {
24
23
  const isConnected = useHMSStore(selectIsConnectedToRoom);
@@ -34,7 +33,6 @@ export const LeaveRoom = ({ screenType }: { screenType: keyof ConferencingScreen
34
33
  );
35
34
  const hlsState = useHMSStore(selectHLSState);
36
35
  const hmsActions = useHMSActions();
37
- const { redirectToLeave } = useRedirectToLeave();
38
36
 
39
37
  const stopStream = async () => {
40
38
  try {
@@ -48,7 +46,6 @@ export const LeaveRoom = ({ screenType }: { screenType: keyof ConferencingScreen
48
46
  };
49
47
  const endRoom = () => {
50
48
  hmsActions.endRoom(false, 'End Room');
51
- redirectToLeave();
52
49
  };
53
50
 
54
51
  const leaveRoom = async ({ endstream = false }) => {
@@ -56,7 +53,6 @@ export const LeaveRoom = ({ screenType }: { screenType: keyof ConferencingScreen
56
53
  await stopStream();
57
54
  }
58
55
  hmsActions.leave();
59
- redirectToLeave();
60
56
  };
61
57
 
62
58
  if (!permissions || !isConnected) {
@@ -1,21 +1,18 @@
1
1
  import React from 'react';
2
- import { useNavigate, useParams } from 'react-router-dom';
3
2
  import { ExitIcon } from '@100mslive/react-icons';
3
+ // @ts-ignore: No implicit Any
4
4
  import { ToastManager } from './Toast/ToastManager';
5
5
  import { Button } from '../../Button';
6
6
  import { Box, Flex } from '../../Layout';
7
7
  import { Text } from '../../Text';
8
- import { useHMSPrebuiltContext } from '../AppContext';
8
+ import { useHMSAppStateContext } from '../AppStateContext';
9
9
  import { Header } from './Header';
10
- import { useRoomLayoutPreviewScreen } from '../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
10
+ // @ts-ignore: No implicit Any
11
11
  import { defaultPreviewPreference, UserPreferencesKeys, useUserPreferences } from './hooks/useUserPreferences';
12
12
  import { textEllipsis } from '../../utils';
13
13
 
14
- const PostLeave = () => {
15
- const navigate = useNavigate();
16
- const { isPreviewScreenEnabled } = useRoomLayoutPreviewScreen();
17
- const { roomCode } = useHMSPrebuiltContext();
18
- const { roomId, role } = useParams();
14
+ export const LeaveScreen = () => {
15
+ const { rejoin } = useHMSAppStateContext();
19
16
  const [previewPreference] = useUserPreferences(UserPreferencesKeys.PREVIEW, defaultPreviewPreference);
20
17
  return (
21
18
  <Flex direction="column" css={{ size: '100%' }}>
@@ -57,9 +54,7 @@ const PostLeave = () => {
57
54
  </Text>
58
55
  <Button
59
56
  onClick={() => {
60
- let redirectUrl = `${isPreviewScreenEnabled ? '/preview/' : '/meeting/'}${roomCode || roomId}`;
61
- if (role && roomId) redirectUrl += '/' + role;
62
- navigate(redirectUrl);
57
+ rejoin();
63
58
  ToastManager.clearAllToast();
64
59
  }}
65
60
  data-testid="join_again_btn"
@@ -72,5 +67,3 @@ const PostLeave = () => {
72
67
  </Flex>
73
68
  );
74
69
  };
75
-
76
- export default PostLeave;
@@ -3,7 +3,6 @@ import { useMedia } from 'react-use';
3
3
  import { selectLocalPeerName, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
4
4
  import { config as cssConfig, Dialog } from '../../../';
5
5
  import { Sheet } from '../../../Sheet';
6
- import { PrebuiltDialogPortal } from '../PrebuiltDialogPortal';
7
6
  import { ToastManager } from '../Toast/ToastManager';
8
7
  import { ChangeNameContent } from './ChangeNameContent';
9
8
  import { UserPreferencesKeys, useUserPreferences } from '../hooks/useUserPreferences';
@@ -59,12 +58,12 @@ export const ChangeNameModal = ({ onOpenChange, openParentSheet = null }) => {
59
58
 
60
59
  return (
61
60
  <Dialog.Root defaultOpen onOpenChange={onOpenChange}>
62
- <PrebuiltDialogPortal>
61
+ <Dialog.Portal>
63
62
  <Dialog.Overlay />
64
63
  <Dialog.Content css={{ bg: '$surface_dim', width: 'min(400px,80%)', p: '$10' }}>
65
64
  <ChangeNameContent {...props} />
66
65
  </Dialog.Content>
67
- </PrebuiltDialogPortal>
66
+ </Dialog.Portal>
68
67
  </Dialog.Root>
69
68
  );
70
69
  };
@@ -1,7 +1,6 @@
1
1
  import React, { useState } from 'react';
2
2
  import { LinkIcon } from '@100mslive/react-icons';
3
3
  import { Button, Dialog, Dropdown, Flex, Input, Text } from '../../../';
4
- import { PrebuiltDialogPortal } from '../PrebuiltDialogPortal';
5
4
  import { useSetAppDataByKey } from '../AppData/useUISettings';
6
5
  import { APP_DATA } from '../../common/constants';
7
6
 
@@ -31,7 +30,7 @@ export function EmbedUrlModal({ onOpenChange }) {
31
30
 
32
31
  return (
33
32
  <Dialog.Root defaultOpen onOpenChange={onOpenChange}>
34
- <PrebuiltDialogPortal>
33
+ <Dialog.Portal>
35
34
  <Dialog.Overlay />
36
35
  <Dialog.Content css={{ w: 'min(420px, 90%)', p: '$8', bg: '$surface_dim' }}>
37
36
  <Dialog.Title
@@ -76,7 +75,7 @@ export function EmbedUrlModal({ onOpenChange }) {
76
75
  </Button>
77
76
  </Flex>
78
77
  </Dialog.Content>
79
- </PrebuiltDialogPortal>
78
+ </Dialog.Portal>
80
79
  </Dialog.Root>
81
80
  );
82
81
  }