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

Sign up to get free protection for your applications and to get access to all the features.
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,251 @@
1
+ // @ts-check
2
+ import React, { useCallback, useRef, useState } from 'react';
3
+ import { AddCircleIcon, TrashIcon } from '@100mslive/react-icons';
4
+ import { Box, Button, Dropdown, Flex, Input, Switch, Text, Tooltip } from '../../../../';
5
+ import { DialogDropdownTrigger } from '../../../primitives/DropdownTrigger';
6
+ import { DeleteQuestionModal } from './DeleteQuestionModal';
7
+ import { useDropdownSelection } from '../../hooks/useDropdownSelection';
8
+ import { isValidTextInput } from '../../../common/utils';
9
+ import { MultipleChoiceOptionInputs } from '../common/MultipleChoiceOptions';
10
+ import { SingleChoiceOptionInputs } from '../common/SingleChoiceOptions';
11
+ import { QUESTION_TYPE, QUESTION_TYPE_TITLE } from '../../../common/constants';
12
+
13
+ export const QuestionForm = ({ question, index, length, onSave, removeQuestion, isQuiz }) => {
14
+ const ref = useRef(null);
15
+ const selectionBg = useDropdownSelection();
16
+ const [openDelete, setOpenDelete] = useState(false);
17
+ const [open, setOpen] = useState(false);
18
+ const [type, setType] = useState(question.type || QUESTION_TYPE.SINGLE_CHOICE);
19
+ const [text, setText] = useState(question.text);
20
+ const [options, setOptions] = useState(
21
+ question?.options || [
22
+ { text: '', isCorrectAnswer: false },
23
+ { text: '', isCorrectAnswer: false },
24
+ ],
25
+ );
26
+ const [skippable, setSkippable] = useState(false);
27
+ const isValid = isValidQuestion({
28
+ text,
29
+ type,
30
+ options,
31
+ isQuiz,
32
+ });
33
+
34
+ const handleOptionTextChange = useCallback(
35
+ (index, text) => {
36
+ setOptions(options => [...options.slice(0, index), { ...options[index], text }, ...options.slice(index + 1)]);
37
+ },
38
+ [setOptions],
39
+ );
40
+
41
+ const removeOption = useCallback(
42
+ index =>
43
+ setOptions(options => {
44
+ const newOptions = [...options];
45
+ newOptions.splice(index, 1);
46
+ return newOptions;
47
+ }),
48
+ [setOptions],
49
+ );
50
+
51
+ const selectSingleChoiceAnswer = useCallback(
52
+ answerIndex => {
53
+ if (!isQuiz) {
54
+ return;
55
+ }
56
+ setOptions(options =>
57
+ options.map((option, index) => ({
58
+ ...option,
59
+ isCorrectAnswer: index === answerIndex,
60
+ })),
61
+ );
62
+ },
63
+ [setOptions, isQuiz],
64
+ );
65
+
66
+ const selectMultipleChoiceAnswer = useCallback(
67
+ (checked, index) => {
68
+ if (!isQuiz) {
69
+ return;
70
+ }
71
+ setOptions(options => [
72
+ ...options.slice(0, index),
73
+ { ...options[index], isCorrectAnswer: checked },
74
+ ...options.slice(index + 1),
75
+ ]);
76
+ },
77
+ [setOptions, isQuiz],
78
+ );
79
+
80
+ return (
81
+ <>
82
+ <Text variant="overline" css={{ c: '$on_surface_low', textTransform: 'uppercase' }}>
83
+ Question {index + 1} of {length}
84
+ </Text>
85
+ <Text variant="body2" css={{ mt: '$4', mb: '$md' }}>
86
+ Question Type
87
+ </Text>
88
+ <Dropdown.Root open={open} onOpenChange={setOpen}>
89
+ <DialogDropdownTrigger
90
+ ref={ref}
91
+ title={QUESTION_TYPE_TITLE[type]}
92
+ css={{
93
+ backgroundColor: '$surface_bright',
94
+ border: '1px solid $border_bright',
95
+ }}
96
+ open={open}
97
+ />
98
+ <Dropdown.Portal>
99
+ <Dropdown.Content align="start" sideOffset={8} css={{ w: ref.current?.clientWidth, zIndex: 1000 }}>
100
+ {Object.keys(QUESTION_TYPE_TITLE).map(value => {
101
+ return (
102
+ <Dropdown.Item
103
+ key={value}
104
+ onSelect={() => setType(value)}
105
+ css={{
106
+ px: '$9',
107
+ bg: type === value ? selectionBg : undefined,
108
+ }}
109
+ >
110
+ {QUESTION_TYPE_TITLE[value]}
111
+ </Dropdown.Item>
112
+ );
113
+ })}
114
+ </Dropdown.Content>
115
+ </Dropdown.Portal>
116
+ </Dropdown.Root>
117
+ <Input
118
+ placeholder="Ask a question"
119
+ css={{
120
+ mt: '$md',
121
+ backgroundColor: '$surface_bright',
122
+ border: '1px solid $border_bright',
123
+ }}
124
+ type="text"
125
+ value={text}
126
+ onChange={event => setText(event.target.value)}
127
+ />
128
+ {type === QUESTION_TYPE.SINGLE_CHOICE || type === QUESTION_TYPE.MULTIPLE_CHOICE ? (
129
+ <>
130
+ <Text variant="body2" css={{ my: '$6', c: '$on_surface_medium' }}>
131
+ Options
132
+ </Text>
133
+
134
+ {isQuiz && (
135
+ <Text variant="xs" css={{ c: '$on_surface_medium', mb: '$md' }}>
136
+ {type === QUESTION_TYPE.SINGLE_CHOICE
137
+ ? 'Use the radio buttons to indicate the correct answer'
138
+ : 'Use the checkboxes to indicate the correct answer(s)'}
139
+ </Text>
140
+ )}
141
+
142
+ {type === QUESTION_TYPE.SINGLE_CHOICE && (
143
+ <SingleChoiceOptionInputs
144
+ isQuiz={isQuiz}
145
+ options={options}
146
+ selectAnswer={selectSingleChoiceAnswer}
147
+ handleOptionTextChange={handleOptionTextChange}
148
+ removeOption={removeOption}
149
+ />
150
+ )}
151
+
152
+ {type === QUESTION_TYPE.MULTIPLE_CHOICE && (
153
+ <MultipleChoiceOptionInputs
154
+ isQuiz={isQuiz}
155
+ options={options}
156
+ selectAnswer={selectMultipleChoiceAnswer}
157
+ handleOptionTextChange={handleOptionTextChange}
158
+ removeOption={removeOption}
159
+ />
160
+ )}
161
+
162
+ {options?.length < 20 && (
163
+ <Flex
164
+ css={{
165
+ c: '$on_surface_medium',
166
+ cursor: 'pointer',
167
+ '&:hover': { c: '$on_surface_high' },
168
+ }}
169
+ onClick={() => setOptions([...options, { text: '', isCorrectAnswer: false }])}
170
+ >
171
+ <AddCircleIcon style={{ position: 'relative', left: '-2px' }} />
172
+
173
+ <Text
174
+ variant="body1"
175
+ css={{
176
+ ml: '$4',
177
+ c: 'inherit',
178
+ }}
179
+ >
180
+ Add an option
181
+ </Text>
182
+ </Flex>
183
+ )}
184
+ {isQuiz ? (
185
+ <Flex css={{ mt: '$md', gap: '$6' }}>
186
+ <Switch defaultChecked={skippable} onCheckedChange={checked => setSkippable(checked)} />
187
+ <Text variant="sm" css={{ color: '$on_surface_medium' }}>
188
+ Not required to answer
189
+ </Text>
190
+ </Flex>
191
+ ) : null}
192
+ </>
193
+ ) : null}
194
+
195
+ <Flex justify="between" align="center" css={{ mt: '$12' }}>
196
+ <Box
197
+ css={{
198
+ color: '$on_surface_medium',
199
+ cursor: 'pointer',
200
+ '&:hover': { color: '$on_surface_high' },
201
+ }}
202
+ >
203
+ <TrashIcon onClick={() => setOpenDelete(!open)} />
204
+ </Box>
205
+ <Tooltip
206
+ disabled={isValid}
207
+ title={`Please fill all the fields ${isQuiz ? 'and mark the correct answer(s)' : ''} to continue`}
208
+ boxCss={{ maxWidth: '$40' }}
209
+ >
210
+ <Button
211
+ variant="standard"
212
+ disabled={!isValid}
213
+ onClick={() => {
214
+ onSave({
215
+ saved: true,
216
+ text,
217
+ type,
218
+ options,
219
+ skippable,
220
+ draftID: question.draftID,
221
+ });
222
+ }}
223
+ >
224
+ Save
225
+ </Button>
226
+ </Tooltip>
227
+ </Flex>
228
+
229
+ <DeleteQuestionModal open={openDelete} setOpen={setOpenDelete} removeQuestion={removeQuestion} />
230
+ </>
231
+ );
232
+ };
233
+
234
+ export const isValidQuestion = ({ text, type, options, isQuiz = false }) => {
235
+ if (!isValidTextInput(text) || !type) {
236
+ return false;
237
+ }
238
+
239
+ if (![QUESTION_TYPE.SINGLE_CHOICE, QUESTION_TYPE.MULTIPLE_CHOICE].includes(type)) {
240
+ return true;
241
+ }
242
+
243
+ const everyOptionHasText = options.every(option => option && isValidTextInput(option.text, 1));
244
+ const hasCorrectAnswer = options.some(option => option.isCorrectAnswer);
245
+
246
+ if (!isQuiz) {
247
+ return everyOptionHasText;
248
+ }
249
+
250
+ return everyOptionHasText && hasCorrectAnswer;
251
+ };
@@ -0,0 +1,57 @@
1
+ // @ts-check
2
+ import React, { useState } from 'react';
3
+ import { CheckCircleIcon, TrashIcon } from '@100mslive/react-icons';
4
+ import { Box, Button, Flex, Text } from '../../../../';
5
+ import { DeleteQuestionModal } from './DeleteQuestionModal';
6
+ import { QUESTION_TYPE_TITLE } from '../../../common/constants';
7
+
8
+ export const SavedQuestion = ({ question, index, length, convertToDraft, removeQuestion }) => {
9
+ const [openDeleteModal, setOpenDeleteModal] = useState(false);
10
+ return (
11
+ <>
12
+ <Text variant="overline" css={{ c: '$on_surface_low', textTransform: 'uppercase' }}>
13
+ Question {index + 1} of {length}: {QUESTION_TYPE_TITLE[question.type]}
14
+ </Text>
15
+ <Text variant="body2" css={{ mt: '$4', mb: '$md' }}>
16
+ {question.text}
17
+ </Text>
18
+ {question.options.map(option => (
19
+ <Flex css={{ alignItems: 'center', my: '$xs' }}>
20
+ <Text variant="body2" css={{ c: '$on_surface_medium' }}>
21
+ {option.text}
22
+ </Text>
23
+ {option.isCorrectAnswer && (
24
+ <Flex css={{ color: '$alert_success', mx: '$xs' }}>
25
+ <CheckCircleIcon height={24} width={24} />
26
+ </Flex>
27
+ )}
28
+ </Flex>
29
+ ))}
30
+ {question.skippable ? (
31
+ <Text variant="sm" css={{ color: '$on_surface_low', my: '$md' }}>
32
+ Not required to answer
33
+ </Text>
34
+ ) : null}
35
+ <Flex justify="between" css={{ w: '100%', alignItems: 'center' }}>
36
+ <Box
37
+ onClick={() => setOpenDeleteModal(true)}
38
+ css={{ color: '$on_surface_low', '&:hover': { color: '$on_surface_medium', cursor: 'pointer' } }}
39
+ >
40
+ <TrashIcon />
41
+ </Box>
42
+ <Button
43
+ variant="standard"
44
+ css={{ fontWeight: '$semiBold', p: '$4 $8' }}
45
+ onClick={() => convertToDraft(question.draftID)}
46
+ >
47
+ Edit
48
+ </Button>
49
+ </Flex>
50
+ <DeleteQuestionModal
51
+ removeQuestion={() => removeQuestion(question.draftID)}
52
+ open={openDeleteModal}
53
+ setOpen={setOpenDeleteModal}
54
+ />
55
+ </>
56
+ );
57
+ };
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ // @ts-ignore: No implicit Any
3
+ import { PollsQuizMenu } from './CreatePollQuiz/PollsQuizMenu';
4
+ // @ts-ignore: No implicit Any
5
+ import { CreateQuestions } from './CreateQuestions/CreateQuestions';
6
+ // @ts-ignore: No implicit Any
7
+ import { Voting } from './Voting/Voting';
8
+ // @ts-ignore: No implicit Any
9
+ import { usePollViewToggle } from '../AppData/useSidepane';
10
+ // @ts-ignore: No implicit Any
11
+ import { usePollViewState } from '../AppData/useUISettings';
12
+ // @ts-ignore: No implicit Any
13
+ import { POLL_VIEWS } from '../../common/constants';
14
+
15
+ export const Polls = () => {
16
+ const togglePollView = usePollViewToggle();
17
+ const { pollInView: pollID, view } = usePollViewState();
18
+
19
+ if (view === POLL_VIEWS.CREATE_POLL_QUIZ) {
20
+ return <PollsQuizMenu />;
21
+ } else if (view === POLL_VIEWS.CREATE_QUESTIONS) {
22
+ return <CreateQuestions />;
23
+ } else if (view === POLL_VIEWS.VOTE) {
24
+ return <Voting toggleVoting={togglePollView} id={pollID} />;
25
+ } else {
26
+ return null;
27
+ }
28
+ };
@@ -0,0 +1,125 @@
1
+ // @ts-check
2
+ import React, { useMemo } from 'react';
3
+ import { selectLocalPeerID, useHMSStore } from '@100mslive/react-sdk';
4
+ import { Box, Text } from '../../../../';
5
+ import { checkCorrectAnswer } from '../../../common/utils';
6
+
7
+ /**
8
+ * @param {{ isQuiz: boolean;
9
+ * isAdmin: boolean;
10
+ * pollResult: import("@100mslive/react-sdk").HMSPoll['result'];
11
+ * questions: import("@100mslive/react-sdk").HMSPoll['questions'] }} param0
12
+ */
13
+ export const PollResultSummary = ({ isQuiz, isAdmin, pollResult, questions }) => {
14
+ const localPeerID = useHMSStore(selectLocalPeerID);
15
+ const noAnswers = pollResult?.maxUsers || 0 - (pollResult?.totalUsers || 0);
16
+ const participationPercentage =
17
+ pollResult?.maxUsers && pollResult?.maxUsers > 0 ? ((pollResult?.totalUsers || 0) * 100) / pollResult.maxUsers : 0;
18
+
19
+ const totalCorrectAnswers = useMemo(() => {
20
+ let correctAnswers = 0;
21
+ questions?.forEach(question => {
22
+ correctAnswers += question.result?.correctResponses || 0;
23
+ });
24
+ return correctAnswers;
25
+ }, [questions]);
26
+
27
+ const totalIncorrectAnswers = useMemo(() => {
28
+ let incorrectAnswers = 0;
29
+ questions?.forEach(question => {
30
+ incorrectAnswers +=
31
+ (question.result?.totalResponses || 0) -
32
+ (question.result?.correctResponses || 0) -
33
+ (question.result?.skippedCount || 0);
34
+ });
35
+ return incorrectAnswers;
36
+ }, [questions]);
37
+
38
+ const localCorrectAnswers = useMemo(() => {
39
+ let correctAnswers = 0;
40
+ questions?.forEach(question => {
41
+ const localResponse = question.responses?.find(response => response.peer?.peerid === localPeerID);
42
+ if (checkCorrectAnswer(question.answer, localResponse, question.type)) {
43
+ correctAnswers++;
44
+ }
45
+ });
46
+ return correctAnswers;
47
+ }, [localPeerID, questions]);
48
+
49
+ const localIncorrectAnswers = useMemo(() => {
50
+ let incorrectAnswers = 0;
51
+ questions?.forEach(question => {
52
+ const localResponse = question.responses?.find(response => response.peer?.peerid === localPeerID);
53
+ if (!checkCorrectAnswer(question.answer, localResponse, question.type) && localResponse) {
54
+ incorrectAnswers++;
55
+ }
56
+ });
57
+ return incorrectAnswers;
58
+ }, [localPeerID, questions]);
59
+
60
+ if (!pollResult) {
61
+ return null;
62
+ }
63
+
64
+ let StatsComponents;
65
+
66
+ if (isQuiz && isAdmin) {
67
+ StatsComponents = (
68
+ <>
69
+ <PollStat label="No. of correct answers" value={totalCorrectAnswers} />
70
+ <PollStat label="No. of wrong answerss" value={totalIncorrectAnswers} />
71
+ <PollStat label="Peers who didn't answer" value={noAnswers} />
72
+ <PollStat label="Participation Percentage" value={participationPercentage.toFixed(2) + '%'} />
73
+ </>
74
+ );
75
+ } else if (isQuiz && !isAdmin) {
76
+ StatsComponents = (
77
+ <>
78
+ <PollStat label="No. of correct answers" value={localCorrectAnswers} />
79
+ <PollStat label="No. of wrong answers" value={localIncorrectAnswers} />
80
+ </>
81
+ );
82
+ } else if (!isQuiz && isAdmin) {
83
+ StatsComponents = (
84
+ <>
85
+ <PollStat label="Peers who didn't answer" value={noAnswers} />
86
+ <PollStat label="Participation Percentage" value={participationPercentage.toFixed(2) + '%'} />
87
+ </>
88
+ );
89
+ } else {
90
+ return null;
91
+ }
92
+
93
+ return (
94
+ <Box
95
+ css={{
96
+ display: 'grid',
97
+ 'grid-template-columns': 'repeat(2, 2fr)',
98
+ gap: '$4',
99
+ mt: '$3',
100
+ }}
101
+ >
102
+ {StatsComponents}
103
+ </Box>
104
+ );
105
+ };
106
+
107
+ const PollStat = ({ label, value }) => {
108
+ return (
109
+ <Box css={{ bg: '$surface_bright', p: '$8', r: '$1' }}>
110
+ <Text
111
+ variant="overline"
112
+ css={{
113
+ fontWeight: '$semiBold',
114
+ color: '$on_surface_medium',
115
+ textTransform: 'uppercase',
116
+ }}
117
+ >
118
+ {label}
119
+ </Text>
120
+ <Text variant="sub1" css={{ fontWeight: '$semiBold', color: '$on_surface_medium' }}>
121
+ {value}
122
+ </Text>
123
+ </Box>
124
+ );
125
+ };