@100mslive/roomkit-react 0.1.14 → 0.1.16
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.
- package/dist/{HLSView-662T7R7H.js → HLSView-EMUOLCTM.js} +128 -39
- package/dist/HLSView-EMUOLCTM.js.map +7 -0
- package/dist/Prebuilt/common/PeersSorter.d.ts +1 -0
- package/dist/Prebuilt/common/constants.d.ts +9 -5
- package/dist/Prebuilt/common/hooks.d.ts +1 -0
- package/dist/Prebuilt/components/Footer/ParticipantList.d.ts +17 -0
- package/dist/Prebuilt/components/Footer/RoleAccordion.d.ts +3 -2
- package/dist/Prebuilt/components/Footer/WhiteboardToggle.d.ts +2 -0
- package/dist/Prebuilt/components/HMSVideo/HLSCaptionSelector.d.ts +5 -0
- package/dist/Prebuilt/components/Notifications/HandRaisedNotifications.d.ts +1 -0
- package/dist/Prebuilt/components/Polls/Voting/Leaderboard.d.ts +4 -0
- package/dist/Prebuilt/components/Polls/Voting/LeaderboardEntry.d.ts +9 -0
- package/dist/Prebuilt/components/Polls/Voting/PeerParticipationSummary.d.ts +5 -0
- package/dist/Prebuilt/components/PreviousRoleInMetadata.d.ts +1 -0
- package/dist/Prebuilt/components/RemoveParticipant.d.ts +5 -0
- package/dist/Prebuilt/components/hooks/useCloseScreenshareWhiteboard.d.ts +4 -0
- package/dist/Prebuilt/layouts/WhiteboardView.d.ts +2 -0
- package/dist/{chunk-2B7YYNHQ.js → chunk-ZYR4B4KQ.js} +2240 -1767
- package/dist/chunk-ZYR4B4KQ.js.map +7 -0
- package/dist/index.cjs.js +2805 -2172
- package/dist/index.cjs.js.map +4 -4
- package/dist/index.js +1 -1
- package/dist/meta.cjs.json +739 -177
- package/dist/meta.esbuild.json +749 -186
- package/package.json +7 -7
- package/src/Prebuilt/AppStateContext.tsx +1 -1
- package/src/Prebuilt/common/PeersSorter.ts +24 -8
- package/src/Prebuilt/common/constants.ts +6 -6
- package/src/Prebuilt/common/hooks.ts +16 -0
- package/src/Prebuilt/common/utils.js +33 -0
- package/src/Prebuilt/components/AppData/AppData.tsx +1 -16
- package/src/Prebuilt/components/Chat/Chat.jsx +10 -34
- package/src/Prebuilt/components/Chat/ChatBody.jsx +107 -66
- package/src/Prebuilt/components/Chat/ChatFooter.tsx +21 -12
- package/src/Prebuilt/components/Chat/ChatSelector.tsx +25 -25
- package/src/Prebuilt/components/Chat/ChatSelectorContainer.tsx +15 -16
- package/src/Prebuilt/components/Chat/PinnedMessage.tsx +7 -2
- package/src/Prebuilt/components/ConferenceScreen.tsx +2 -0
- package/src/Prebuilt/components/Footer/ChatToggle.tsx +30 -7
- package/src/Prebuilt/components/Footer/Footer.tsx +2 -1
- package/src/Prebuilt/components/Footer/PaginatedParticipants.tsx +0 -1
- package/src/Prebuilt/components/Footer/{ParticipantList.jsx → ParticipantList.tsx} +169 -127
- package/src/Prebuilt/components/Footer/RoleAccordion.tsx +23 -13
- package/src/Prebuilt/components/Footer/WhiteboardToggle.tsx +34 -0
- package/src/Prebuilt/components/HMSVideo/HLSCaptionSelector.tsx +13 -0
- package/src/Prebuilt/components/HMSVideo/HMSVideo.jsx +34 -2
- package/src/Prebuilt/components/Notifications/HandRaisedNotifications.tsx +35 -0
- package/src/Prebuilt/components/Notifications/Notifications.tsx +47 -14
- package/src/Prebuilt/components/Notifications/PeerNotifications.tsx +7 -2
- package/src/Prebuilt/components/Polls/CreatePollQuiz/PollsQuizMenu.jsx +3 -9
- package/src/Prebuilt/components/Polls/CreateQuestions/CreateQuestions.jsx +21 -1
- package/src/Prebuilt/components/Polls/CreateQuestions/QuestionForm.jsx +34 -7
- package/src/Prebuilt/components/Polls/CreateQuestions/SavedQuestion.jsx +2 -2
- package/src/Prebuilt/components/Polls/Polls.tsx +3 -0
- package/src/Prebuilt/components/Polls/Voting/Leaderboard.tsx +115 -0
- package/src/Prebuilt/components/Polls/Voting/LeaderboardEntry.tsx +63 -0
- package/src/Prebuilt/components/Polls/Voting/PeerParticipationSummary.tsx +38 -0
- package/src/Prebuilt/components/Polls/Voting/QuestionCard.jsx +33 -8
- package/src/Prebuilt/components/Polls/Voting/StandardVoting.jsx +7 -1
- package/src/Prebuilt/components/Polls/Voting/Voting.jsx +31 -13
- package/src/Prebuilt/components/Polls/common/MultipleChoiceOptions.jsx +33 -21
- package/src/Prebuilt/components/Polls/common/SingleChoiceOptions.jsx +47 -35
- package/src/Prebuilt/components/Polls/common/StatusIndicator.jsx +2 -22
- package/src/Prebuilt/components/Polls/common/VoteCount.jsx +1 -15
- package/src/Prebuilt/components/PreviousRoleInMetadata.tsx +21 -0
- package/src/Prebuilt/components/RemoveParticipant.tsx +35 -0
- package/src/Prebuilt/components/RoleChangeModal.jsx +1 -1
- package/src/Prebuilt/components/SidePaneTabs.tsx +0 -1
- package/src/Prebuilt/components/TileMenu/TileMenuContent.tsx +1 -1
- package/src/Prebuilt/components/Toast/ToastConfig.jsx +15 -3
- package/src/Prebuilt/components/VideoLayouts/EqualProminence.tsx +6 -5
- package/src/Prebuilt/components/VideoLayouts/GridLayout.tsx +27 -5
- package/src/Prebuilt/components/VideoLayouts/ScreenshareLayout.tsx +0 -1
- package/src/Prebuilt/components/hooks/useCloseScreenshareWhiteboard.tsx +24 -0
- package/src/Prebuilt/layouts/HLSView.jsx +51 -3
- package/src/Prebuilt/layouts/VideoStreamingSection.tsx +20 -3
- package/src/Prebuilt/layouts/WhiteboardView.tsx +66 -0
- package/dist/HLSView-662T7R7H.js.map +0 -7
- package/dist/chunk-2B7YYNHQ.js.map +0 -7
- package/src/Prebuilt/components/AppData/useAppLayout.js +0 -6
- package/src/Prebuilt/components/init/initUtils.js +0 -67
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
import React, { useCallback, useMemo, useState } from 'react';
|
|
3
3
|
import { selectLocalPeer, selectLocalPeerRoleName, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
|
|
4
|
-
import { ChevronLeftIcon, ChevronRightIcon } from '@100mslive/react-icons';
|
|
4
|
+
import { CheckCircleIcon, ChevronLeftIcon, ChevronRightIcon, CrossCircleIcon } from '@100mslive/react-icons';
|
|
5
5
|
import { Box, Button, Flex, IconButton, Input, styled, Text } from '../../../../';
|
|
6
6
|
import { checkCorrectAnswer } from '../../../common/utils';
|
|
7
7
|
import { MultipleChoiceOptions } from '../common/MultipleChoiceOptions';
|
|
@@ -48,7 +48,8 @@ export const QuestionCard = ({
|
|
|
48
48
|
!rolesThatCanViewResponses ||
|
|
49
49
|
rolesThatCanViewResponses.length === 0 ||
|
|
50
50
|
rolesThatCanViewResponses.includes(localPeerRoleName || '');
|
|
51
|
-
const showVoteCount =
|
|
51
|
+
const showVoteCount =
|
|
52
|
+
roleCanViewResponse && (localPeerResponse || (isLocalPeerCreator && pollState === 'stopped')) && !isQuiz;
|
|
52
53
|
|
|
53
54
|
const isLive = pollState === 'started';
|
|
54
55
|
const canRespond = isLive && !localPeerResponse;
|
|
@@ -72,6 +73,8 @@ export const QuestionCard = ({
|
|
|
72
73
|
|
|
73
74
|
const stringAnswerExpected = [QUESTION_TYPE.LONG_ANSWER, QUESTION_TYPE.SHORT_ANSWER].includes(type);
|
|
74
75
|
|
|
76
|
+
const respondedToQuiz = isQuiz && localPeerResponse && !localPeerResponse.skipped;
|
|
77
|
+
|
|
75
78
|
const isValidVote = useMemo(() => {
|
|
76
79
|
if (stringAnswerExpected) {
|
|
77
80
|
return textAnswer.length > 0;
|
|
@@ -114,13 +117,29 @@ export const QuestionCard = ({
|
|
|
114
117
|
p: '$md',
|
|
115
118
|
mt: '$md',
|
|
116
119
|
border:
|
|
117
|
-
|
|
120
|
+
respondedToQuiz && !isLive
|
|
118
121
|
? `1px solid ${isCorrectAnswer ? '$alert_success' : '$alert_error_default'}`
|
|
119
122
|
: 'none',
|
|
120
123
|
}}
|
|
121
124
|
>
|
|
122
125
|
<Flex align="center" justify="between">
|
|
123
|
-
<Text
|
|
126
|
+
<Text
|
|
127
|
+
variant="caption"
|
|
128
|
+
css={{
|
|
129
|
+
color:
|
|
130
|
+
respondedToQuiz && !isLive
|
|
131
|
+
? isCorrectAnswer
|
|
132
|
+
? '$alert_success'
|
|
133
|
+
: '$alert_error_default'
|
|
134
|
+
: '$on_surface_low',
|
|
135
|
+
fontWeight: '$semiBold',
|
|
136
|
+
display: 'flex',
|
|
137
|
+
alignItems: 'center',
|
|
138
|
+
gap: '$4',
|
|
139
|
+
}}
|
|
140
|
+
>
|
|
141
|
+
{respondedToQuiz && isCorrectAnswer ? <CheckCircleIcon height={20} width={20} /> : null}
|
|
142
|
+
{respondedToQuiz && !isCorrectAnswer ? <CrossCircleIcon height={20} width={20} /> : null}
|
|
124
143
|
QUESTION {index} OF {totalQuestions}: {type.toUpperCase()}
|
|
125
144
|
</Text>
|
|
126
145
|
|
|
@@ -196,6 +215,8 @@ export const QuestionCard = ({
|
|
|
196
215
|
setAnswer={setSingleOptionAnswer}
|
|
197
216
|
totalResponses={result?.totalResponses}
|
|
198
217
|
showVoteCount={showVoteCount}
|
|
218
|
+
localPeerResponse={localPeerResponse}
|
|
219
|
+
isStopped={pollState === 'stopped'}
|
|
199
220
|
/>
|
|
200
221
|
) : null}
|
|
201
222
|
|
|
@@ -211,6 +232,8 @@ export const QuestionCard = ({
|
|
|
211
232
|
setSelectedOptions={setMultipleOptionAnswer}
|
|
212
233
|
totalResponses={result?.totalResponses}
|
|
213
234
|
showVoteCount={showVoteCount}
|
|
235
|
+
localPeerResponse={localPeerResponse}
|
|
236
|
+
isStopped={pollState === 'stopped'}
|
|
214
237
|
/>
|
|
215
238
|
) : null}
|
|
216
239
|
|
|
@@ -221,14 +244,14 @@ export const QuestionCard = ({
|
|
|
221
244
|
onSkip={handleSkip}
|
|
222
245
|
onVote={handleVote}
|
|
223
246
|
response={localPeerResponse}
|
|
224
|
-
|
|
247
|
+
isQuiz={isQuiz}
|
|
225
248
|
/>
|
|
226
249
|
)}
|
|
227
250
|
</Box>
|
|
228
251
|
);
|
|
229
252
|
};
|
|
230
253
|
|
|
231
|
-
const QuestionActions = ({ isValidVote, skippable, response,
|
|
254
|
+
const QuestionActions = ({ isValidVote, skippable, response, isQuiz, onVote, onSkip }) => {
|
|
232
255
|
return (
|
|
233
256
|
<Flex align="center" justify="end" css={{ gap: '$4', w: '100%' }}>
|
|
234
257
|
{skippable && !response ? (
|
|
@@ -239,11 +262,13 @@ const QuestionActions = ({ isValidVote, skippable, response, stringAnswerExpecte
|
|
|
239
262
|
|
|
240
263
|
{response ? (
|
|
241
264
|
<Text css={{ fontWeight: '$semiBold', color: '$on_surface_medium' }}>
|
|
242
|
-
{response.skipped ? 'Skipped' :
|
|
265
|
+
{response.skipped ? 'Skipped' : null}
|
|
266
|
+
{isQuiz && !response.skipped ? 'Answered' : null}
|
|
267
|
+
{!isQuiz && !response.skipped ? 'Voted' : null}
|
|
243
268
|
</Text>
|
|
244
269
|
) : (
|
|
245
270
|
<Button css={{ p: '$xs $10', fontWeight: '$semiBold' }} disabled={!isValidVote} onClick={onVote}>
|
|
246
|
-
{
|
|
271
|
+
{isQuiz ? 'Answer' : 'Vote'}
|
|
247
272
|
</Button>
|
|
248
273
|
)}
|
|
249
274
|
</Flex>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
import React from 'react';
|
|
3
|
+
import { PeerParticipationSummary } from './PeerParticipationSummary';
|
|
3
4
|
import { QuestionCard } from './QuestionCard';
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -11,12 +12,17 @@ export const StandardView = ({ poll }) => {
|
|
|
11
12
|
if (!poll?.questions) {
|
|
12
13
|
return null;
|
|
13
14
|
}
|
|
15
|
+
|
|
16
|
+
const isQuiz = poll.type === 'quiz';
|
|
17
|
+
const isStopped = poll.state === 'stopped';
|
|
18
|
+
|
|
14
19
|
return (
|
|
15
20
|
<>
|
|
21
|
+
{isQuiz && isStopped ? <PeerParticipationSummary poll={poll} /> : null}
|
|
16
22
|
{poll.questions?.map((question, index) => (
|
|
17
23
|
<QuestionCard
|
|
18
24
|
pollID={poll.id}
|
|
19
|
-
isQuiz={
|
|
25
|
+
isQuiz={isQuiz}
|
|
20
26
|
startedBy={poll.startedBy}
|
|
21
27
|
pollState={poll.state}
|
|
22
28
|
key={`${question.text}-${index}`}
|
|
@@ -3,6 +3,7 @@ import React from 'react';
|
|
|
3
3
|
import {
|
|
4
4
|
selectLocalPeerID,
|
|
5
5
|
selectPeerNameByID,
|
|
6
|
+
selectPermissions,
|
|
6
7
|
selectPollByID,
|
|
7
8
|
useHMSActions,
|
|
8
9
|
useHMSStore,
|
|
@@ -23,11 +24,18 @@ export const Voting = ({ id, toggleVoting }) => {
|
|
|
23
24
|
const pollCreatorName = useHMSStore(selectPeerNameByID(poll?.createdBy));
|
|
24
25
|
const isLocalPeerCreator = useHMSStore(selectLocalPeerID) === poll?.createdBy;
|
|
25
26
|
const { setPollView } = usePollViewState();
|
|
27
|
+
const permissions = useHMSStore(selectPermissions);
|
|
28
|
+
|
|
29
|
+
// const sharedLeaderboards = useHMSStore(selectSessionStore(SESSION_STORE_KEY.SHARED_LEADERBOARDS));
|
|
26
30
|
|
|
27
31
|
if (!poll) {
|
|
28
32
|
return null;
|
|
29
33
|
}
|
|
30
34
|
|
|
35
|
+
// const isLeaderboardShared = (sharedLeaderboards || []).includes(id);
|
|
36
|
+
const canViewLeaderboard =
|
|
37
|
+
poll.type === 'quiz' && poll.state === 'stopped' && !poll.anonymous && permissions?.pollWrite;
|
|
38
|
+
|
|
31
39
|
// Sets view - linear or vertical, toggles timer indicator
|
|
32
40
|
const isTimed = (poll.duration || 0) > 0;
|
|
33
41
|
const isLive = poll.state === 'started';
|
|
@@ -52,8 +60,8 @@ export const Voting = ({ id, toggleVoting }) => {
|
|
|
52
60
|
>
|
|
53
61
|
<ChevronLeftIcon />
|
|
54
62
|
</Flex>
|
|
55
|
-
<Text variant="h6">{poll
|
|
56
|
-
<StatusIndicator isLive={isLive}
|
|
63
|
+
<Text variant="h6">{poll.title}</Text>
|
|
64
|
+
<StatusIndicator isLive={isLive} />
|
|
57
65
|
<Box
|
|
58
66
|
css={{
|
|
59
67
|
marginLeft: 'auto',
|
|
@@ -72,18 +80,8 @@ export const Voting = ({ id, toggleVoting }) => {
|
|
|
72
80
|
{pollCreatorName || 'Participant'} started a {poll.type}
|
|
73
81
|
</Text>
|
|
74
82
|
</Box>
|
|
75
|
-
{poll.state === 'started' && isLocalPeerCreator && (
|
|
76
|
-
<Box css={{ flex: 'initial' }}>
|
|
77
|
-
<Button
|
|
78
|
-
variant="danger"
|
|
79
|
-
css={{ fontSize: '$sm', fontWeight: '$semiBold', p: '$3 $6' }}
|
|
80
|
-
onClick={() => actions.interactivityCenter.stopPoll(id)}
|
|
81
|
-
>
|
|
82
|
-
End {poll.type}
|
|
83
|
-
</Button>
|
|
84
|
-
</Box>
|
|
85
|
-
)}
|
|
86
83
|
</Flex>
|
|
84
|
+
|
|
87
85
|
{/* {poll.state === "stopped" && (
|
|
88
86
|
<PollResultSummary
|
|
89
87
|
pollResult={poll.result}
|
|
@@ -92,7 +90,27 @@ export const Voting = ({ id, toggleVoting }) => {
|
|
|
92
90
|
isAdmin={isLocalPeerCreator}
|
|
93
91
|
/>
|
|
94
92
|
)} */}
|
|
93
|
+
|
|
95
94
|
{isTimed ? <TimedView poll={poll} /> : <StandardView poll={poll} />}
|
|
95
|
+
|
|
96
|
+
{poll.state === 'started' && isLocalPeerCreator && (
|
|
97
|
+
<Button
|
|
98
|
+
variant="danger"
|
|
99
|
+
css={{ fontWeight: '$semiBold', w: 'max-content', ml: 'auto', mt: '$8' }}
|
|
100
|
+
onClick={() => actions.interactivityCenter.stopPoll(id)}
|
|
101
|
+
>
|
|
102
|
+
End {poll.type}
|
|
103
|
+
</Button>
|
|
104
|
+
)}
|
|
105
|
+
|
|
106
|
+
{canViewLeaderboard ? (
|
|
107
|
+
<Button
|
|
108
|
+
css={{ fontWeight: '$semiBold', w: 'max-content', ml: 'auto', mt: '$8' }}
|
|
109
|
+
onClick={() => setPollView(POLL_VIEWS.RESULTS)}
|
|
110
|
+
>
|
|
111
|
+
View Leaderboard
|
|
112
|
+
</Button>
|
|
113
|
+
) : null}
|
|
96
114
|
</Flex>
|
|
97
115
|
</Container>
|
|
98
116
|
);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import { CheckIcon } from '@100mslive/react-icons';
|
|
3
|
+
import { CheckCircleIcon, CheckIcon } from '@100mslive/react-icons';
|
|
4
4
|
import { Checkbox, Flex, Label, Text } from '../../../../';
|
|
5
5
|
import { OptionInputWithDelete } from './OptionInputWithDelete';
|
|
6
6
|
import { VoteCount } from './VoteCount';
|
|
@@ -8,15 +8,17 @@ import { VoteProgress } from './VoteProgress';
|
|
|
8
8
|
|
|
9
9
|
export const MultipleChoiceOptions = ({
|
|
10
10
|
questionIndex,
|
|
11
|
-
isQuiz,
|
|
12
11
|
options,
|
|
13
|
-
correctOptionIndexes,
|
|
14
12
|
canRespond,
|
|
15
13
|
response,
|
|
16
14
|
totalResponses,
|
|
17
15
|
selectedOptions,
|
|
18
16
|
setSelectedOptions,
|
|
19
17
|
showVoteCount,
|
|
18
|
+
isQuiz,
|
|
19
|
+
correctOptionIndexes,
|
|
20
|
+
localPeerResponse,
|
|
21
|
+
isStopped,
|
|
20
22
|
}) => {
|
|
21
23
|
const handleCheckedChange = (checked, index) => {
|
|
22
24
|
const newSelected = new Set(selectedOptions);
|
|
@@ -31,35 +33,45 @@ export const MultipleChoiceOptions = ({
|
|
|
31
33
|
return (
|
|
32
34
|
<Flex direction="column" css={{ gap: '$md', w: '100%', mb: '$md' }}>
|
|
33
35
|
{options.map(option => {
|
|
34
|
-
const isCorrectAnswer = isQuiz && correctOptionIndexes?.includes(option.index);
|
|
35
|
-
|
|
36
36
|
return (
|
|
37
37
|
<Flex align="center" key={`${questionIndex}-${option.index}`} css={{ w: '100%', gap: '$9' }}>
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
<
|
|
49
|
-
|
|
50
|
-
|
|
38
|
+
{!isStopped || !isQuiz ? (
|
|
39
|
+
<Checkbox.Root
|
|
40
|
+
id={`${questionIndex}-${option.index}`}
|
|
41
|
+
disabled={!canRespond}
|
|
42
|
+
checked={response?.options?.includes(option.index)}
|
|
43
|
+
onCheckedChange={checked => handleCheckedChange(checked, option.index)}
|
|
44
|
+
css={{
|
|
45
|
+
cursor: canRespond ? 'pointer' : 'not-allowed',
|
|
46
|
+
}}
|
|
47
|
+
>
|
|
48
|
+
<Checkbox.Indicator>
|
|
49
|
+
<CheckIcon width={16} height={16} />
|
|
50
|
+
</Checkbox.Indicator>
|
|
51
|
+
</Checkbox.Root>
|
|
52
|
+
) : null}
|
|
53
|
+
|
|
54
|
+
{isStopped && correctOptionIndexes.includes(option.index) ? (
|
|
55
|
+
<Flex css={{ color: '$on_surface_high' }}>
|
|
56
|
+
<CheckCircleIcon />
|
|
57
|
+
</Flex>
|
|
58
|
+
) : null}
|
|
51
59
|
|
|
52
60
|
<Flex direction="column" css={{ flexGrow: '1' }}>
|
|
53
61
|
<Flex css={{ w: '100%' }}>
|
|
54
62
|
<Text css={{ display: 'flex', flexGrow: '1' }}>
|
|
55
63
|
<Label htmlFor={`${questionIndex}-${option.index}`}>{option.text}</Label>
|
|
56
64
|
</Text>
|
|
57
|
-
{showVoteCount &&
|
|
58
|
-
<VoteCount isQuiz={isQuiz} isCorrectAnswer={isCorrectAnswer} voteCount={option.voteCount} />
|
|
59
|
-
)}
|
|
65
|
+
{showVoteCount && <VoteCount voteCount={option.voteCount} />}
|
|
60
66
|
</Flex>
|
|
61
67
|
{showVoteCount && <VoteProgress option={option} totalResponses={totalResponses} />}
|
|
62
68
|
</Flex>
|
|
69
|
+
|
|
70
|
+
{isStopped && isQuiz && localPeerResponse?.options.includes(option.index) ? (
|
|
71
|
+
<Text variant="sm" css={{ color: '$on_surface_medium', maxWidth: 'max-content' }}>
|
|
72
|
+
Your Answer
|
|
73
|
+
</Text>
|
|
74
|
+
) : null}
|
|
63
75
|
</Flex>
|
|
64
76
|
);
|
|
65
77
|
})}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
import React from 'react';
|
|
3
|
+
import { CheckCircleIcon } from '@100mslive/react-icons';
|
|
3
4
|
import { Flex, Label, RadioGroup, Text } from '../../../../';
|
|
4
5
|
import { OptionInputWithDelete } from './OptionInputWithDelete';
|
|
5
6
|
import { VoteCount } from './VoteCount';
|
|
@@ -7,64 +8,75 @@ import { VoteProgress } from './VoteProgress';
|
|
|
7
8
|
|
|
8
9
|
export const SingleChoiceOptions = ({
|
|
9
10
|
questionIndex,
|
|
10
|
-
isQuiz,
|
|
11
11
|
options,
|
|
12
12
|
response,
|
|
13
13
|
canRespond,
|
|
14
|
-
correctOptionIndex,
|
|
15
14
|
setAnswer,
|
|
16
15
|
totalResponses,
|
|
17
16
|
showVoteCount,
|
|
17
|
+
correctOptionIndex,
|
|
18
|
+
isStopped,
|
|
19
|
+
isQuiz,
|
|
20
|
+
localPeerResponse,
|
|
18
21
|
}) => {
|
|
19
22
|
return (
|
|
20
23
|
<RadioGroup.Root value={response?.option} onValueChange={value => setAnswer(value)}>
|
|
21
24
|
<Flex direction="column" css={{ gap: '$md', w: '100%', mb: '$md' }}>
|
|
22
25
|
{options.map(option => {
|
|
23
|
-
const isCorrectAnswer = isQuiz && option.index === correctOptionIndex;
|
|
24
|
-
|
|
25
26
|
return (
|
|
26
|
-
<Flex align="
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
background: 'none',
|
|
30
|
-
h: '$9',
|
|
31
|
-
w: '$9',
|
|
32
|
-
border: '2px solid',
|
|
33
|
-
borderColor: '$on_surface_high',
|
|
34
|
-
display: 'flex',
|
|
35
|
-
justifyContent: 'center',
|
|
36
|
-
alignItems: 'center',
|
|
37
|
-
cursor: canRespond ? 'pointer' : 'not-allowed',
|
|
38
|
-
'&[data-state="checked"]': {
|
|
39
|
-
borderColor: '$primary_bright',
|
|
40
|
-
borderWidth: '2px',
|
|
41
|
-
},
|
|
42
|
-
}}
|
|
43
|
-
disabled={!canRespond}
|
|
44
|
-
value={option.index}
|
|
45
|
-
id={`${questionIndex}-${option.index}`}
|
|
46
|
-
>
|
|
47
|
-
<RadioGroup.Indicator
|
|
27
|
+
<Flex align="start" key={`${questionIndex}-${option.index}`} css={{ w: '100%', gap: '$5' }}>
|
|
28
|
+
{!isStopped || !isQuiz ? (
|
|
29
|
+
<RadioGroup.Item
|
|
48
30
|
css={{
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
31
|
+
background: 'none',
|
|
32
|
+
h: '$9',
|
|
33
|
+
w: '$9',
|
|
34
|
+
border: '2px solid',
|
|
35
|
+
borderColor: '$on_surface_high',
|
|
36
|
+
display: 'flex',
|
|
37
|
+
justifyContent: 'center',
|
|
38
|
+
alignItems: 'center',
|
|
39
|
+
cursor: canRespond ? 'pointer' : 'not-allowed',
|
|
40
|
+
'&[data-state="checked"]': {
|
|
41
|
+
borderColor: '$primary_bright',
|
|
42
|
+
borderWidth: '2px',
|
|
43
|
+
},
|
|
53
44
|
}}
|
|
54
|
-
|
|
55
|
-
|
|
45
|
+
disabled={!canRespond}
|
|
46
|
+
value={option.index}
|
|
47
|
+
id={`${questionIndex}-${option.index}`}
|
|
48
|
+
>
|
|
49
|
+
<RadioGroup.Indicator
|
|
50
|
+
css={{
|
|
51
|
+
h: '80%',
|
|
52
|
+
w: '80%',
|
|
53
|
+
background: '$primary_bright',
|
|
54
|
+
borderRadius: '$round',
|
|
55
|
+
}}
|
|
56
|
+
/>
|
|
57
|
+
</RadioGroup.Item>
|
|
58
|
+
) : null}
|
|
59
|
+
|
|
60
|
+
{isStopped && correctOptionIndex === option.index && isQuiz ? (
|
|
61
|
+
<Flex css={{ color: '$on_surface_high' }}>
|
|
62
|
+
<CheckCircleIcon />
|
|
63
|
+
</Flex>
|
|
64
|
+
) : null}
|
|
56
65
|
|
|
57
66
|
<Flex direction="column" css={{ flexGrow: '1' }}>
|
|
58
67
|
<Flex css={{ w: '100%' }}>
|
|
59
68
|
<Text css={{ display: 'flex', flexGrow: '1' }}>
|
|
60
69
|
<Label htmlFor={`${questionIndex}-${option.index}`}>{option.text}</Label>
|
|
61
70
|
</Text>
|
|
62
|
-
{showVoteCount &&
|
|
63
|
-
<VoteCount isQuiz={isQuiz} isCorrectAnswer={isCorrectAnswer} voteCount={option.voteCount} />
|
|
64
|
-
)}
|
|
71
|
+
{showVoteCount && <VoteCount voteCount={option.voteCount} />}
|
|
65
72
|
</Flex>
|
|
66
73
|
{showVoteCount && <VoteProgress option={option} totalResponses={totalResponses} />}
|
|
67
74
|
</Flex>
|
|
75
|
+
{isStopped && isQuiz && localPeerResponse?.option === option.index ? (
|
|
76
|
+
<Text variant="sm" css={{ color: '$on_surface_medium', maxWidth: 'max-content' }}>
|
|
77
|
+
Your Answer
|
|
78
|
+
</Text>
|
|
79
|
+
) : null}
|
|
68
80
|
</Flex>
|
|
69
81
|
);
|
|
70
82
|
})}
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { Flex, Text } from '../../../../';
|
|
4
4
|
|
|
5
|
-
export const StatusIndicator = ({ isLive
|
|
5
|
+
export const StatusIndicator = ({ isLive }) => {
|
|
6
6
|
return (
|
|
7
7
|
<Flex align="center">
|
|
8
8
|
<Flex
|
|
9
9
|
css={{
|
|
10
10
|
backgroundColor: isLive ? '$alert_error_default' : '$secondary_default',
|
|
11
11
|
p: '$2 $4',
|
|
12
|
-
borderRadius:
|
|
12
|
+
borderRadius: '$0',
|
|
13
13
|
}}
|
|
14
14
|
>
|
|
15
15
|
<Text
|
|
@@ -22,26 +22,6 @@ export const StatusIndicator = ({ isLive, shouldShowTimer }) => {
|
|
|
22
22
|
{isLive ? 'LIVE' : 'ENDED'}
|
|
23
23
|
</Text>
|
|
24
24
|
</Flex>
|
|
25
|
-
|
|
26
|
-
{shouldShowTimer ? (
|
|
27
|
-
<Flex
|
|
28
|
-
css={{
|
|
29
|
-
borderRadius: '0 $0 $0 0',
|
|
30
|
-
p: '$2 $4',
|
|
31
|
-
backgroundColor: '$background_default',
|
|
32
|
-
}}
|
|
33
|
-
>
|
|
34
|
-
<Text
|
|
35
|
-
variant="caption"
|
|
36
|
-
css={{
|
|
37
|
-
fontWeight: '$semiBold',
|
|
38
|
-
color: '$on_surface_high',
|
|
39
|
-
}}
|
|
40
|
-
>
|
|
41
|
-
0:32
|
|
42
|
-
</Text>
|
|
43
|
-
</Flex>
|
|
44
|
-
) : null}
|
|
45
25
|
</Flex>
|
|
46
26
|
);
|
|
47
27
|
};
|
|
@@ -2,23 +2,9 @@
|
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { Flex, Text } from '../../../../';
|
|
4
4
|
|
|
5
|
-
export const VoteCount = ({
|
|
5
|
+
export const VoteCount = ({ voteCount }) => {
|
|
6
6
|
return (
|
|
7
7
|
<Flex css={{ alignItems: 'center' }}>
|
|
8
|
-
{isQuiz && (
|
|
9
|
-
<Text
|
|
10
|
-
variant="xs"
|
|
11
|
-
css={{
|
|
12
|
-
p: '$2',
|
|
13
|
-
mr: '$2',
|
|
14
|
-
color: isCorrectAnswer ? '$alert_success' : '$alert_error_default',
|
|
15
|
-
borderRadius: '$1',
|
|
16
|
-
border: `1px solid ${isCorrectAnswer ? '$alert_success' : '$alert_error_default'}`,
|
|
17
|
-
}}
|
|
18
|
-
>
|
|
19
|
-
{isCorrectAnswer ? 'Correct' : 'Incorrect'}
|
|
20
|
-
</Text>
|
|
21
|
-
)}
|
|
22
8
|
{voteCount ? (
|
|
23
9
|
<Text variant="sm" css={{ color: '$on_surface_medium' }}>
|
|
24
10
|
{voteCount}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { selectLocalPeerRoleName, useHMSVanillaStore } from '@100mslive/react-sdk';
|
|
3
|
+
// @ts-ignore: No implicit Any
|
|
4
|
+
import { useMyMetadata } from './hooks/useMetadata';
|
|
5
|
+
|
|
6
|
+
export const PreviousRoleInMetadata = () => {
|
|
7
|
+
const vanillaStore = useHMSVanillaStore();
|
|
8
|
+
const { updateMetaData } = useMyMetadata();
|
|
9
|
+
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
let previousRole = vanillaStore.getState(selectLocalPeerRoleName);
|
|
12
|
+
const unsubscribe = vanillaStore.subscribe(currentRole => {
|
|
13
|
+
if (previousRole !== currentRole) {
|
|
14
|
+
updateMetaData({ prevRole: previousRole });
|
|
15
|
+
previousRole = currentRole;
|
|
16
|
+
}
|
|
17
|
+
}, selectLocalPeerRoleName);
|
|
18
|
+
return unsubscribe;
|
|
19
|
+
}, [vanillaStore]); //eslint-disable-line
|
|
20
|
+
return null;
|
|
21
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { HMSPeerID, selectLocalPeerID, selectPermissions, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
|
|
3
|
+
import { PeopleRemoveIcon } from '@100mslive/react-icons';
|
|
4
|
+
// @ts-ignore: No implicit Any
|
|
5
|
+
import { ToastManager } from './Toast/ToastManager';
|
|
6
|
+
import { Dropdown } from '../../Dropdown';
|
|
7
|
+
import { Text } from '../../Text';
|
|
8
|
+
|
|
9
|
+
export const RemoveParticipant = ({ peerId }: { peerId: HMSPeerID }) => {
|
|
10
|
+
const canRemoveOthers = useHMSStore(selectPermissions)?.removeOthers;
|
|
11
|
+
const localPeerId = useHMSStore(selectLocalPeerID);
|
|
12
|
+
const actions = useHMSActions();
|
|
13
|
+
|
|
14
|
+
if (peerId === localPeerId || !canRemoveOthers) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
return (
|
|
18
|
+
<Dropdown.Item
|
|
19
|
+
css={{ color: '$alert_error_default', bg: '$surface_default' }}
|
|
20
|
+
onClick={async () => {
|
|
21
|
+
try {
|
|
22
|
+
await actions.removePeer(peerId, '');
|
|
23
|
+
} catch (error) {
|
|
24
|
+
const ex = error as Error;
|
|
25
|
+
ToastManager.addToast({ title: ex.message, variant: 'error' });
|
|
26
|
+
}
|
|
27
|
+
}}
|
|
28
|
+
>
|
|
29
|
+
<PeopleRemoveIcon />
|
|
30
|
+
<Text variant="sm" css={{ ml: '$4', color: 'inherit', fontWeight: '$semiBold' }}>
|
|
31
|
+
Remove Participant
|
|
32
|
+
</Text>
|
|
33
|
+
</Dropdown.Item>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
@@ -170,7 +170,7 @@ export const RoleChangeModal = ({ peerId, onOpenChange }) => {
|
|
|
170
170
|
variant="primary"
|
|
171
171
|
css={{ width: '100%' }}
|
|
172
172
|
onClick={async () => {
|
|
173
|
-
await hmsActions.
|
|
173
|
+
await hmsActions.changeRoleOfPeer(peerId, selectedRole, peer.isLocal ? true : !requestPermission);
|
|
174
174
|
onOpenChange(false);
|
|
175
175
|
}}
|
|
176
176
|
>
|
|
@@ -6,7 +6,6 @@ import { CrossIcon } from '@100mslive/react-icons';
|
|
|
6
6
|
// @ts-ignore: No implicit Any
|
|
7
7
|
import { Chat } from './Chat/Chat';
|
|
8
8
|
import { PaginatedParticipants } from './Footer/PaginatedParticipants';
|
|
9
|
-
// @ts-ignore: No implicit Any
|
|
10
9
|
import { ParticipantList } from './Footer/ParticipantList';
|
|
11
10
|
import { Box, config as cssConfig, Flex, IconButton, Tabs, Text } from '../..';
|
|
12
11
|
import { Tooltip } from '../../Tooltip';
|
|
@@ -287,7 +287,7 @@ export const TileMenuContent = ({
|
|
|
287
287
|
toggleAudio();
|
|
288
288
|
closeSheetOnClick();
|
|
289
289
|
}}
|
|
290
|
-
data-testid={
|
|
290
|
+
data-testid={isAudioEnabled ? 'mute_audio_participant_btn' : 'unmute_audio_participant_btn'}
|
|
291
291
|
>
|
|
292
292
|
{isAudioEnabled ? <MicOnIcon height={20} width={20} /> : <MicOffIcon height={20} width={20} />}
|
|
293
293
|
<span>{isAudioEnabled ? 'Mute' : 'Request Unmute'}</span>
|
|
@@ -38,15 +38,27 @@ const HandRaiseAction = React.forwardRef(({ id = '', isSingleHandRaise = true },
|
|
|
38
38
|
bring_to_stage_label,
|
|
39
39
|
on_stage_role,
|
|
40
40
|
off_stage_roles = [],
|
|
41
|
+
skip_preview_for_role_change = false,
|
|
41
42
|
} = layout?.screens?.conferencing?.default?.elements.on_stage_exp || {};
|
|
42
43
|
|
|
43
|
-
const onClickHandler = useCallback(() => {
|
|
44
|
+
const onClickHandler = useCallback(async () => {
|
|
44
45
|
if (isSingleHandRaise) {
|
|
45
|
-
hmsActions.changeRoleOfPeer(id, on_stage_role);
|
|
46
|
+
hmsActions.changeRoleOfPeer(id, on_stage_role, skip_preview_for_role_change);
|
|
47
|
+
if (skip_preview_for_role_change) {
|
|
48
|
+
await hmsActions.lowerRemotePeerHand(id);
|
|
49
|
+
}
|
|
46
50
|
} else {
|
|
47
51
|
!isParticipantsOpen && toggleSidepane();
|
|
48
52
|
}
|
|
49
|
-
}, [
|
|
53
|
+
}, [
|
|
54
|
+
hmsActions,
|
|
55
|
+
id,
|
|
56
|
+
isParticipantsOpen,
|
|
57
|
+
isSingleHandRaise,
|
|
58
|
+
on_stage_role,
|
|
59
|
+
toggleSidepane,
|
|
60
|
+
skip_preview_for_role_change,
|
|
61
|
+
]);
|
|
50
62
|
|
|
51
63
|
// show nothing if handRaise is single and peer role is not hls
|
|
52
64
|
if (isSingleHandRaise && (!peer || !off_stage_roles.includes(peer.roleName))) {
|
|
@@ -10,7 +10,6 @@ import { LayoutProps } from './interface';
|
|
|
10
10
|
// @ts-ignore: No implicit Any
|
|
11
11
|
import { useUISettings } from '../AppData/useUISettings';
|
|
12
12
|
import { usePagesWithTiles, useTileLayout } from '../hooks/useTileLayout';
|
|
13
|
-
// @ts-ignore: No implicit Any
|
|
14
13
|
import { UI_SETTINGS } from '../../common/constants';
|
|
15
14
|
|
|
16
15
|
export function EqualProminence({ isInsetEnabled = false, peers, onPageChange, onPageSize, edgeToEdge }: LayoutProps) {
|
|
@@ -23,10 +22,12 @@ export function EqualProminence({ isInsetEnabled = false, peers, onPageChange, o
|
|
|
23
22
|
maxTileCount,
|
|
24
23
|
});
|
|
25
24
|
// useMemo is needed to prevent recursion as new array is created for localPeer
|
|
26
|
-
const inputPeers = useMemo(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
const inputPeers = useMemo(() => {
|
|
26
|
+
if (pageList.length === 0) {
|
|
27
|
+
return localPeer ? [localPeer] : [];
|
|
28
|
+
}
|
|
29
|
+
return peers;
|
|
30
|
+
}, [pageList.length, peers, localPeer]);
|
|
30
31
|
// Pass local peer to main grid if no other peer has tiles
|
|
31
32
|
pageList = usePagesWithTiles({
|
|
32
33
|
peers: inputPeers,
|