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

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 (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
  }