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

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 (140) hide show
  1. package/dist/{HLSView-DDGPZHA2.js → HLSView-4JC65BAY.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-MIRXD2HZ.js} +3 -5
  25. package/dist/{VirtualBackground-UVZJVOA2.js.map → VirtualBackground-MIRXD2HZ.js.map} +1 -1
  26. package/dist/chunk-322YFA55.js +14441 -0
  27. package/dist/chunk-322YFA55.js.map +7 -0
  28. package/dist/{chunk-6SQTFOK6.js → chunk-6UGU3UJL.js} +66 -3
  29. package/dist/chunk-6UGU3UJL.js.map +7 -0
  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-6SQTFOK6.js.map +0 -7
  125. package/dist/chunk-HUMNPIYI.js +0 -70
  126. package/dist/chunk-HUMNPIYI.js.map +0 -7
  127. package/dist/chunk-PRM33R4R.js +0 -7160
  128. package/dist/chunk-PRM33R4R.js.map +0 -7
  129. package/dist/conference-N7S47TDK.js +0 -6602
  130. package/dist/conference-N7S47TDK.js.map +0 -7
  131. package/src/Prebuilt/components/GoLiveButton.jsx +0 -42
  132. package/src/Prebuilt/components/Notifications/HeadlessEndRoomListener.tsx +0 -23
  133. package/src/Prebuilt/components/PrebuiltDialogPortal.tsx +0 -6
  134. package/src/Prebuilt/components/PrebuiltTileElements.tsx +0 -5
  135. package/src/Prebuilt/components/Streaming/HLSStreaming.jsx +0 -220
  136. package/src/Prebuilt/components/Streaming/RTMPStreaming.jsx +0 -334
  137. package/src/Prebuilt/components/Streaming/StreamingLanding.jsx +0 -76
  138. /package/dist/{HLSView-DDGPZHA2.js.map → HLSView-4JC65BAY.js.map} +0 -0
  139. /package/{src/Prebuilt/components/Notifications/index.jsx → dist/Prebuilt/components/Notifications/index.d.ts} +0 -0
  140. /package/src/Prebuilt/components/Notifications/{TrackNotifications.jsx → TrackNotifications.tsx} +0 -0
@@ -0,0 +1,229 @@
1
+ // @ts-check
2
+ import React, { useMemo, useState } from 'react';
3
+ import {
4
+ selectLocalPeerRoleName,
5
+ selectPermissions,
6
+ selectPolls,
7
+ useHMSActions,
8
+ useHMSStore,
9
+ } from '@100mslive/react-sdk';
10
+ import { QuestionIcon, StatsIcon } from '@100mslive/react-icons';
11
+ import { Button, Flex, Input, Switch, Text } from '../../../../';
12
+ import { Container, ContentHeader, ErrorText } from '../../Streaming/Common';
13
+ import { usePollViewToggle } from '../../AppData/useSidepane';
14
+ import { usePollViewState } from '../../AppData/useUISettings';
15
+ import { isValidTextInput } from '../../../common/utils';
16
+ import { StatusIndicator } from '../common/StatusIndicator';
17
+ import { INTERACTION_TYPE, POLL_STATE, POLL_VIEWS } from '../../../common/constants';
18
+
19
+ export const PollsQuizMenu = () => {
20
+ const togglePollView = usePollViewToggle();
21
+ const permissions = useHMSStore(selectPermissions);
22
+
23
+ return (
24
+ <Container rounded>
25
+ <ContentHeader content="Polls and Quizzes" onClose={togglePollView} />
26
+ <Flex direction="column" css={{ px: '$10', pb: '$10', overflowY: 'auto' }}>
27
+ {permissions?.pollWrite && <AddMenu />}
28
+ <PrevMenu />
29
+ </Flex>
30
+ </Container>
31
+ );
32
+ };
33
+
34
+ function InteractionSelectionCard({ title, icon, active, onClick }) {
35
+ const activeBorderStyle = active ? '$space$px solid $primary_default' : '$space$px solid $border_bright';
36
+ return (
37
+ <Flex
38
+ onClick={onClick}
39
+ css={{
40
+ border: activeBorderStyle,
41
+ p: '$4',
42
+ r: '$2',
43
+ w: '100%',
44
+ cursor: 'pointer',
45
+ }}
46
+ align="center"
47
+ >
48
+ <Flex
49
+ css={{
50
+ border: activeBorderStyle,
51
+ p: '$4',
52
+ bg: '$surface_bright',
53
+ c: '$on_surface_high',
54
+ r: '$0',
55
+ }}
56
+ >
57
+ {icon}
58
+ </Flex>
59
+ <Text variant="sub1" css={{ ml: '$md' }}>
60
+ {title}
61
+ </Text>
62
+ </Flex>
63
+ );
64
+ }
65
+
66
+ const AddMenu = () => {
67
+ const actions = useHMSActions();
68
+ const [title, setTitle] = useState('');
69
+ const localPeerRoleName = useHMSStore(selectLocalPeerRoleName);
70
+ const [anonymous, setAnonymous] = useState(false);
71
+ const [hideVoteCount, setHideVoteCount] = useState(false);
72
+ const [error, setError] = useState();
73
+ const [titleError, setTitleError] = useState('');
74
+ const { setPollState } = usePollViewState();
75
+ const [interactionType, setInteractionType] = useState(INTERACTION_TYPE.POLL);
76
+
77
+ const handleCreate = id => {
78
+ setPollState({
79
+ [POLL_STATE.pollInView]: id,
80
+ [POLL_STATE.view]: POLL_VIEWS.CREATE_QUESTIONS,
81
+ });
82
+ };
83
+
84
+ const validateTitle = useMemo(() => {
85
+ if (!isValidTextInput(title)) {
86
+ if (title) {
87
+ setTitleError('The title should have between 2-100 characters');
88
+ }
89
+ return true;
90
+ } else {
91
+ setTitleError('');
92
+ return false;
93
+ }
94
+ }, [title]);
95
+ // const [timer, setTimer] = useState(10);
96
+ // const [showTimerDropDown, setShowTimerDropDown] = useState(false);
97
+
98
+ return (
99
+ <>
100
+ <Text variant="caption" css={{ c: '$on_surface_medium', mb: '$md' }}>
101
+ Select the type you want to continue with
102
+ </Text>
103
+ <Flex css={{ w: '100%', gap: '$10', mb: '$md' }}>
104
+ <InteractionSelectionCard
105
+ title={INTERACTION_TYPE.POLL}
106
+ icon={<StatsIcon width={32} height={32} />}
107
+ onClick={() => setInteractionType(INTERACTION_TYPE.POLL)}
108
+ active={interactionType === INTERACTION_TYPE.POLL}
109
+ />
110
+ <InteractionSelectionCard
111
+ title={INTERACTION_TYPE.QUIZ}
112
+ icon={<QuestionIcon width={32} height={32} />}
113
+ onClick={() => setInteractionType(INTERACTION_TYPE.QUIZ)}
114
+ active={interactionType === INTERACTION_TYPE.QUIZ}
115
+ />
116
+ </Flex>
117
+ <Flex direction="column">
118
+ <Text variant="body2" css={{ mb: '$4' }}>{`Name this ${interactionType.toLowerCase()}`}</Text>
119
+ <Input
120
+ type="text"
121
+ value={title}
122
+ onChange={event => setTitle(event.target.value)}
123
+ css={{
124
+ backgroundColor: '$surface_bright',
125
+ border: '1px solid $border_default',
126
+ }}
127
+ />
128
+ <Flex align="center" css={{ mt: '$10' }}>
129
+ <Switch onCheckedChange={value => setHideVoteCount(value)} css={{ mr: '$6' }} />
130
+ <Text variant="body2" css={{ c: '$on_surface_medium' }}>
131
+ Hide Vote Count
132
+ </Text>
133
+ </Flex>
134
+ <Flex align="center" css={{ mt: '$10' }}>
135
+ <Switch onCheckedChange={value => setAnonymous(value)} css={{ mr: '$6' }} />
136
+ <Text variant="body2" css={{ c: '$on_surface_medium' }}>
137
+ Make Results Anonymous
138
+ </Text>
139
+ </Flex>
140
+ {/* <Timer
141
+ timer={timer}
142
+ setTimer={setTimer}
143
+ showTimerDropDown={showTimerDropDown}
144
+ setShowTimerDropDown={setShowTimerDropDown}
145
+ /> */}
146
+
147
+ <Button
148
+ variant="primary"
149
+ disabled={validateTitle}
150
+ css={{ mt: '$10' }}
151
+ onClick={async () => {
152
+ const id = Date.now().toString();
153
+ await actions.interactivityCenter
154
+ .createPoll({
155
+ id,
156
+ title,
157
+ anonymous,
158
+ rolesThatCanViewResponses: hideVoteCount && localPeerRoleName ? [localPeerRoleName] : undefined,
159
+ type: interactionType.toLowerCase(),
160
+ // duration: showTimerDropDown ? timer : undefined,
161
+ })
162
+ .then(() => handleCreate(id))
163
+ .catch(err => setError(err.message));
164
+ }}
165
+ >
166
+ Create {interactionType}
167
+ </Button>
168
+ <ErrorText error={error || titleError} />
169
+ </Flex>
170
+ </>
171
+ );
172
+ };
173
+
174
+ const PrevMenu = () => {
175
+ const polls = useHMSStore(selectPolls)?.filter(poll => poll.state === 'started' || poll.state === 'stopped');
176
+ return polls?.length ? (
177
+ <Flex
178
+ css={{
179
+ borderTop: '$space$px solid $border_bright',
180
+ mt: '$10',
181
+ pt: '$10',
182
+ }}
183
+ >
184
+ <Flex direction="column" css={{ w: '100%' }}>
185
+ <Text variant="h6" css={{ c: '$on_surface_high' }}>
186
+ Previous Polls and Quizzes
187
+ </Text>
188
+ <Flex direction="column" css={{ gap: '$10', mt: '$8' }}>
189
+ {polls.map(poll => (
190
+ <InteractionCard
191
+ key={poll.id}
192
+ id={poll.id}
193
+ title={poll.title}
194
+ isLive={poll.state === 'started'}
195
+ isTimed={(poll.duration || 0) > 0}
196
+ />
197
+ ))}
198
+ </Flex>
199
+ </Flex>
200
+ </Flex>
201
+ ) : null;
202
+ };
203
+
204
+ const InteractionCard = ({ id, title, isLive, isTimed }) => {
205
+ const { setPollState } = usePollViewState();
206
+
207
+ const goToVote = id => {
208
+ setPollState({
209
+ [POLL_STATE.pollInView]: id,
210
+ [POLL_STATE.view]: POLL_VIEWS.VOTE,
211
+ });
212
+ };
213
+
214
+ return (
215
+ <Flex direction="column" css={{ backgroundColor: '$surface_bright', borderRadius: '$1', p: '$8' }}>
216
+ <Flex css={{ w: '100%', justifyContent: 'space-between', mb: '$sm' }}>
217
+ <Text variant="sub1" css={{ c: '$on_surface_high', fontWeight: '$semiBold' }}>
218
+ {title}
219
+ </Text>
220
+ <StatusIndicator isLive={isLive} shouldShowTimer={isLive && isTimed} />
221
+ </Flex>
222
+ <Flex css={{ w: '100%', gap: '$4' }} justify="end">
223
+ <Button variant="primary" onClick={() => goToVote(id)}>
224
+ View
225
+ </Button>
226
+ </Flex>
227
+ </Flex>
228
+ );
229
+ };
@@ -0,0 +1,71 @@
1
+ // @ts-check
2
+ import React, { useRef, useState } from 'react';
3
+ import { Dropdown, Flex, Switch, Text } from '../../../../';
4
+ import { DialogDropdownTrigger } from '../../../primitives/DropdownTrigger';
5
+ import { useDropdownSelection } from '../../hooks/useDropdownSelection';
6
+
7
+ const timerSettings = {
8
+ 10: '10 secs',
9
+ 15: '15 secs',
10
+ 20: '20 secs',
11
+ 25: '25 secs',
12
+ 30: '30 secs',
13
+ 60: '1 min',
14
+ 120: '2 mins',
15
+ 300: '5 mins',
16
+ };
17
+
18
+ export const Timer = ({ timer, setTimer, showTimerDropDown, setShowTimerDropDown }) => {
19
+ const selectionBg = useDropdownSelection();
20
+ const [timerDropdownToggle, setTimerDropdownToggle] = useState(false);
21
+ const timerDropdownRef = useRef();
22
+
23
+ return (
24
+ <Flex justify="between" align="center" css={{ mt: '$10' }}>
25
+ <Flex align="center">
26
+ <Switch checked={showTimerDropDown} onCheckedChange={setShowTimerDropDown} css={{ mr: '$6' }} />
27
+ <Text variant="body2" css={{ c: '$on_surface_medium' }}>
28
+ Timer
29
+ </Text>
30
+ </Flex>
31
+ <Flex align="center">
32
+ {showTimerDropDown ? (
33
+ <Dropdown.Root open={timerDropdownToggle} onOpenChange={setTimerDropdownToggle}>
34
+ <DialogDropdownTrigger
35
+ ref={timerDropdownRef}
36
+ title={timerSettings[timer]}
37
+ open={timerDropdownToggle}
38
+ titleCss={{ c: '$on_surface_high', ml: '$md' }}
39
+ />
40
+ <Dropdown.Portal>
41
+ <Dropdown.Content
42
+ align="start"
43
+ sideOffset={8}
44
+ css={{
45
+ w: timerDropdownRef.current?.clientWidth,
46
+ zIndex: 1000,
47
+ }}
48
+ >
49
+ {Object.keys(timerSettings).map(value => {
50
+ const val = parseInt(value);
51
+ return (
52
+ <Dropdown.Item
53
+ key={value}
54
+ onSelect={() => setTimer(val)}
55
+ css={{
56
+ px: '$9',
57
+ bg: timer === val ? selectionBg : undefined,
58
+ }}
59
+ >
60
+ {timerSettings[val]}
61
+ </Dropdown.Item>
62
+ );
63
+ })}
64
+ </Dropdown.Content>
65
+ </Dropdown.Portal>
66
+ </Dropdown.Root>
67
+ ) : null}
68
+ </Flex>
69
+ </Flex>
70
+ );
71
+ };
@@ -0,0 +1,132 @@
1
+ // @ts-check
2
+ import React, { useMemo, useState } from 'react';
3
+ import { v4 as uuid } from 'uuid';
4
+ import { selectPollByID, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
5
+ import { AddCircleIcon } from '@100mslive/react-icons';
6
+ import { Button, Flex, Text } from '../../../../';
7
+ import { Container, ContentHeader } from '../../Streaming/Common';
8
+ import { isValidQuestion, QuestionForm } from './QuestionForm';
9
+ import { SavedQuestion } from './SavedQuestion';
10
+ import { usePollViewToggle } from '../../AppData/useSidepane';
11
+ import { usePollViewState } from '../../AppData/useUISettings';
12
+ import { POLL_VIEWS } from '../../../common/constants';
13
+
14
+ export function CreateQuestions() {
15
+ const [questions, setQuestions] = useState([{ draftID: uuid() }]);
16
+ const actions = useHMSActions();
17
+ const togglePollView = usePollViewToggle();
18
+ const { pollInView: id, setPollView } = usePollViewState();
19
+ const interaction = useHMSStore(selectPollByID(id));
20
+
21
+ const isValidPoll = useMemo(
22
+ () => questions.length > 0 && questions.every(question => isValidQuestion(question)),
23
+ [questions],
24
+ );
25
+
26
+ const launchPoll = async () => {
27
+ const validQuestions = questions
28
+ .filter(question => isValidQuestion(question))
29
+ .map(question => ({
30
+ text: question.text,
31
+ type: question.type,
32
+ options: question.options,
33
+ skippable: question.skippable,
34
+ }));
35
+ await actions.interactivityCenter.addQuestionsToPoll(id, validQuestions);
36
+ await actions.interactivityCenter.startPoll(id);
37
+ setPollView(POLL_VIEWS.VOTE);
38
+ };
39
+ const headingTitle = interaction?.type
40
+ ? interaction?.type?.[0]?.toUpperCase() + interaction?.type?.slice(1)
41
+ : 'Polls and Quizzes';
42
+ const isQuiz = interaction?.type === 'quiz';
43
+ return (
44
+ <Container rounded>
45
+ <ContentHeader
46
+ content={headingTitle}
47
+ onClose={togglePollView}
48
+ onBack={() => setPollView(POLL_VIEWS.CREATE_POLL_QUIZ)}
49
+ />
50
+ <Flex direction="column" css={{ p: '$10', overflowY: 'auto' }}>
51
+ <Flex direction="column">
52
+ {questions.map((question, index) => (
53
+ <QuestionCard
54
+ key={question.draftID}
55
+ question={question}
56
+ index={index}
57
+ length={questions.length}
58
+ onSave={questionParams => {
59
+ setQuestions(questions => [
60
+ ...questions.slice(0, index),
61
+ questionParams,
62
+ ...questions.slice(index + 1),
63
+ ]);
64
+ }}
65
+ isQuiz={isQuiz}
66
+ removeQuestion={questionID =>
67
+ setQuestions(prev => {
68
+ return prev.filter(questionFromSet => questionID !== questionFromSet.draftID);
69
+ })
70
+ }
71
+ convertToDraft={questionID =>
72
+ setQuestions(prev => {
73
+ const copyOfQuestions = [...prev];
74
+ copyOfQuestions.forEach(question => {
75
+ if (questionID && question.draftID === questionID) {
76
+ question.saved = false;
77
+ }
78
+ });
79
+ return copyOfQuestions;
80
+ })
81
+ }
82
+ />
83
+ ))}
84
+ </Flex>
85
+ <Flex
86
+ css={{
87
+ c: '$on_surface_low',
88
+ my: '$sm',
89
+ cursor: 'pointer',
90
+ '&:hover': { c: '$on_surface_medium' },
91
+ }}
92
+ onClick={() => setQuestions([...questions, { draftID: uuid() }])}
93
+ >
94
+ <AddCircleIcon />
95
+ <Text variant="body1" css={{ ml: '$md', c: '$inherit' }}>
96
+ Add another question
97
+ </Text>
98
+ </Flex>
99
+ <Flex css={{ w: '100%' }} justify="end">
100
+ <Button disabled={!isValidPoll} onClick={launchPoll}>
101
+ Launch {interaction.type}
102
+ </Button>
103
+ </Flex>
104
+ </Flex>
105
+ </Container>
106
+ );
107
+ }
108
+
109
+ const QuestionCard = ({ question, onSave, index, length, removeQuestion, isQuiz, convertToDraft }) => {
110
+ return (
111
+ <Flex direction="column" css={{ p: '$md', bg: '$surface_default', r: '$1', mb: '$sm' }}>
112
+ {question.saved ? (
113
+ <SavedQuestion
114
+ question={question}
115
+ index={index}
116
+ length={length}
117
+ convertToDraft={convertToDraft}
118
+ removeQuestion={removeQuestion}
119
+ />
120
+ ) : (
121
+ <QuestionForm
122
+ question={question}
123
+ removeQuestion={() => removeQuestion(question.draftID)}
124
+ onSave={params => onSave(params)}
125
+ index={index}
126
+ length={length}
127
+ isQuiz={isQuiz}
128
+ />
129
+ )}
130
+ </Flex>
131
+ );
132
+ };
@@ -0,0 +1,66 @@
1
+ import React from 'react';
2
+ import { AlertTriangleIcon, CrossIcon } from '@100mslive/react-icons';
3
+ import { Button } from '../../../../Button';
4
+ import { Box, Flex } from '../../../../Layout';
5
+ import { Dialog } from '../../../../Modal';
6
+ import { Text } from '../../../../Text';
7
+
8
+ export const DeleteQuestionModal = ({ open, setOpen, removeQuestion }) => {
9
+ return (
10
+ <Dialog.Root open={open}>
11
+ <Dialog.Overlay />
12
+ <Dialog.Portal>
13
+ <Dialog.Content css={{ p: '$10' }}>
14
+ <Box>
15
+ <Flex
16
+ css={{
17
+ color: '$alert_error_default',
18
+ display: 'flex',
19
+ alignItems: 'center',
20
+ }}
21
+ >
22
+ <AlertTriangleIcon style={{ marginRight: '0.5rem' }} />
23
+ <Text variant="lg" css={{ color: 'inherit', fontWeight: '$semiBold' }}>
24
+ Delete Question?
25
+ </Text>
26
+
27
+ <Box
28
+ css={{
29
+ ml: 'auto',
30
+ color: '$on_surface_medium',
31
+ '&:hover': { color: '$on_surface_high', cursor: 'pointer' },
32
+ }}
33
+ onClick={() => setOpen(false)}
34
+ >
35
+ <CrossIcon />
36
+ </Box>
37
+ </Flex>
38
+ <Text variant="sm" css={{ color: '$on_surface_medium', mb: '$8', mt: '$4' }}>
39
+ The question will be deleted. You can't undo this action.
40
+ </Text>
41
+ <Flex css={{ w: '100%', mt: '$12', gap: '$md' }}>
42
+ <Button
43
+ variant="standard"
44
+ outlined
45
+ onClick={() => setOpen(false)}
46
+ css={{ w: '100%', fontSize: '$md', fontWeight: '$semiBold' }}
47
+ >
48
+ Cancel
49
+ </Button>
50
+ <Button
51
+ css={{ w: '100%', fontSize: '$md', fontWeight: '$semiBold' }}
52
+ variant="danger"
53
+ onClick={() => {
54
+ removeQuestion();
55
+ setOpen(false);
56
+ }}
57
+ >
58
+ Delete
59
+ </Button>
60
+ </Flex>
61
+ </Box>
62
+ </Dialog.Content>
63
+ </Dialog.Portal>
64
+ </Dialog.Root>
65
+ );
66
+ };