@100mslive/roomkit-react 0.3.10-alpha.9 → 0.3.11-alpha.0
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/{HLSView-UIAB54GS.js → HLSView-HJ44JWJK.js} +18 -3
- package/dist/HLSView-HJ44JWJK.js.map +7 -0
- package/dist/{HLSView-5TZVXD62.css → HLSView-IBWU4R7W.css} +16 -3
- package/dist/{HLSView-5TZVXD62.css.map → HLSView-IBWU4R7W.css.map} +3 -3
- package/dist/Prebuilt/common/constants.d.ts +0 -2
- package/dist/Prebuilt/common/hooks.d.ts +8 -1
- package/dist/Prebuilt/components/MoreSettings/CaptionContent.d.ts +5 -0
- package/dist/Prebuilt/components/MoreSettings/CaptionModal.d.ts +4 -0
- package/dist/Prebuilt/components/Polls/Voting/StandardVoting.d.ts +4 -2
- package/dist/Prebuilt/components/Polls/Voting/TimedVoting.d.ts +4 -2
- package/dist/Prebuilt/layouts/WaitingView.d.ts +6 -0
- package/dist/{chunk-GQGXO6NF.js → chunk-WDZ4KRYM.js} +2148 -1858
- package/dist/chunk-WDZ4KRYM.js.map +7 -0
- package/dist/index.cjs.css +15 -2
- package/dist/index.cjs.css.map +3 -3
- package/dist/index.cjs.js +2790 -2484
- package/dist/index.cjs.js.map +4 -4
- package/dist/index.css +15 -2
- package/dist/index.css.map +3 -3
- package/dist/index.js +1 -1
- package/dist/meta.cjs.json +296 -118
- package/dist/meta.esbuild.json +318 -139
- package/package.json +7 -7
- package/src/Prebuilt/common/constants.ts +0 -2
- package/src/Prebuilt/common/hooks.ts +34 -1
- package/src/Prebuilt/common/utils.js +11 -11
- package/src/Prebuilt/components/AppData/AppData.tsx +2 -4
- package/src/Prebuilt/components/AppData/useUISettings.js +0 -3
- package/src/Prebuilt/components/Chat/Chat.tsx +26 -6
- package/src/Prebuilt/components/Chat/ChatFooter.tsx +18 -2
- package/src/Prebuilt/components/Chat/ChatStates.tsx +1 -1
- package/src/Prebuilt/components/Footer/ChatToggle.tsx +5 -1
- package/src/Prebuilt/components/Footer/ParticipantList.tsx +4 -2
- package/src/Prebuilt/components/Footer/PollsToggle.tsx +1 -1
- package/src/Prebuilt/components/MoreSettings/CaptionContent.tsx +132 -0
- package/src/Prebuilt/components/MoreSettings/CaptionModal.tsx +37 -0
- package/src/Prebuilt/components/MoreSettings/SplitComponents/DesktopOptions.tsx +40 -3
- package/src/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.tsx +19 -19
- package/src/Prebuilt/components/Polls/CreatePollQuiz/PollsQuizMenu.tsx +2 -15
- package/src/Prebuilt/components/Polls/Voting/LeaderboardSummary.tsx +71 -66
- package/src/Prebuilt/components/Polls/Voting/QuestionCard.jsx +39 -40
- package/src/Prebuilt/components/Polls/Voting/StandardVoting.tsx +12 -6
- package/src/Prebuilt/components/Polls/Voting/TimedVoting.tsx +21 -10
- package/src/Prebuilt/components/Polls/Voting/Voting.tsx +44 -2
- package/src/Prebuilt/components/VideoLayouts/EqualProminence.tsx +13 -17
- package/src/Prebuilt/components/VideoLayouts/GridLayout.tsx +17 -0
- package/src/Prebuilt/layouts/HLSView.jsx +14 -11
- package/src/Prebuilt/layouts/VideoStreamingSection.tsx +43 -9
- package/src/Prebuilt/layouts/WaitingView.tsx +52 -0
- package/dist/HLSView-UIAB54GS.js.map +0 -7
- package/dist/chunk-GQGXO6NF.js.map +0 -7
- package/src/Prebuilt/layouts/NonPublisherView.jsx +0 -51
- package/src/Prebuilt/layouts/WaitingView.jsx +0 -51
@@ -29,7 +29,7 @@ import {
|
|
29
29
|
SettingsIcon,
|
30
30
|
VirtualBackgroundIcon,
|
31
31
|
} from '@100mslive/react-icons';
|
32
|
-
import { Box, Loading, Tooltip } from '../../../..';
|
32
|
+
import { Box, Loading, Text, Tooltip } from '../../../..';
|
33
33
|
import { Sheet } from '../../../../Sheet';
|
34
34
|
// @ts-ignore: No implicit any
|
35
35
|
import IconButton from '../../../IconButton';
|
@@ -43,6 +43,7 @@ import SettingsModal from '../../Settings/SettingsModal';
|
|
43
43
|
import { ToastManager } from '../../Toast/ToastManager';
|
44
44
|
// @ts-ignore: No implicit any
|
45
45
|
import { ActionTile } from '../ActionTile';
|
46
|
+
import { CaptionModal } from '../CaptionModal';
|
46
47
|
// @ts-ignore: No implicit any
|
47
48
|
import { ChangeNameModal } from '../ChangeNameModal';
|
48
49
|
// @ts-ignore: No implicit any
|
@@ -73,6 +74,7 @@ const MODALS = {
|
|
73
74
|
BULK_ROLE_CHANGE: 'bulkRoleChange',
|
74
75
|
MUTE_ALL: 'muteAll',
|
75
76
|
EMBED_URL: 'embedUrl',
|
77
|
+
CAPTION: 'caption',
|
76
78
|
};
|
77
79
|
|
78
80
|
export const MwebOptions = ({
|
@@ -106,9 +108,9 @@ export const MwebOptions = ({
|
|
106
108
|
const isLocalVideoEnabled = useHMSStore(selectIsLocalVideoEnabled);
|
107
109
|
const { startRecording, isRecordingLoading } = useRecordingHandler();
|
108
110
|
|
109
|
-
const
|
111
|
+
const isTranscriptionEnabled = useHMSStore(selectIsTranscriptionEnabled);
|
110
112
|
|
111
|
-
const [isCaptionEnabled
|
113
|
+
const [isCaptionEnabled] = useSetIsCaptionEnabled();
|
112
114
|
useDropdownList({ open: openModals.size > 0 || openOptionsSheet || openSettingsSheet, name: 'MoreSettings' });
|
113
115
|
|
114
116
|
const updateState = (modalName: string, value: boolean) => {
|
@@ -193,21 +195,17 @@ export const MwebOptions = ({
|
|
193
195
|
<ActionTile.Title>{isHandRaised ? 'Lower' : 'Raise'} Hand</ActionTile.Title>
|
194
196
|
</ActionTile.Root>
|
195
197
|
) : null}
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
<ActionTile.Title>{isCaptionEnabled ? 'Hide Captions' : 'Captions Disabled'}</ActionTile.Title>
|
208
|
-
</ActionTile.Root>
|
209
|
-
) : null}
|
210
|
-
|
198
|
+
<ActionTile.Root
|
199
|
+
onClick={() => {
|
200
|
+
setOpenOptionsSheet(false);
|
201
|
+
updateState(MODALS.CAPTION, true);
|
202
|
+
}}
|
203
|
+
>
|
204
|
+
{isTranscriptionEnabled && isCaptionEnabled ? <ClosedCaptionIcon /> : <OpenCaptionIcon />}
|
205
|
+
<Text variant="sm" css={{ ml: '$4', color: '$on_surface_high', flexGrow: '1' }}>
|
206
|
+
Closed Caption
|
207
|
+
</Text>
|
208
|
+
</ActionTile.Root>
|
211
209
|
{isLocalVideoEnabled && !!elements?.virtual_background ? (
|
212
210
|
<ActionTile.Root
|
213
211
|
onClick={() => {
|
@@ -323,7 +321,9 @@ export const MwebOptions = ({
|
|
323
321
|
openParentSheet={() => setOpenOptionsSheet(true)}
|
324
322
|
/>
|
325
323
|
)}
|
326
|
-
|
324
|
+
{openModals.has(MODALS.CAPTION) && (
|
325
|
+
<CaptionModal onOpenChange={(value: boolean) => updateState(MODALS.CAPTION, value)} />
|
326
|
+
)}
|
327
327
|
{showEmojiCard && (
|
328
328
|
<Box
|
329
329
|
ref={emojiCardRef}
|
@@ -152,18 +152,6 @@ const AddMenu = () => {
|
|
152
152
|
Hide Vote Count
|
153
153
|
</Text>
|
154
154
|
</Flex>
|
155
|
-
{/* <Flex align="center" css={{ mt: '$10' }}>
|
156
|
-
<Switch onCheckedChange={value => setAnonymous(value)} css={{ mr: '$6' }} />
|
157
|
-
<Text variant="body2" css={{ c: '$on_surface_medium' }}>
|
158
|
-
Make Results Anonymous
|
159
|
-
</Text>
|
160
|
-
</Flex> */}
|
161
|
-
{/* <Timer
|
162
|
-
timer={timer}
|
163
|
-
setTimer={setTimer}
|
164
|
-
showTimerDropDown={showTimerDropDown}
|
165
|
-
setShowTimerDropDown={setShowTimerDropDown}
|
166
|
-
/> */}
|
167
155
|
|
168
156
|
<Button
|
169
157
|
variant="primary"
|
@@ -198,8 +186,8 @@ const PrevMenu = () => {
|
|
198
186
|
const sortedPolls = useMemo(
|
199
187
|
() =>
|
200
188
|
polls
|
201
|
-
?.sort((a, b) => (b
|
202
|
-
?.sort((a, b) => (b
|
189
|
+
?.sort((a, b) => (b?.createdAt?.getTime?.() || 0) - (a?.createdAt?.getTime?.() || 0))
|
190
|
+
?.sort((a, b) => (b?.state === 'started' ? 1 : 0) - (a?.state === 'started' ? 1 : 0)),
|
203
191
|
[polls],
|
204
192
|
);
|
205
193
|
const permissions = useHMSStore(selectPermissions);
|
@@ -208,7 +196,6 @@ const PrevMenu = () => {
|
|
208
196
|
const updatePolls = async () => {
|
209
197
|
await hmsActions.interactivityCenter.getPolls();
|
210
198
|
};
|
211
|
-
|
212
199
|
updatePolls();
|
213
200
|
}, [hmsActions.interactivityCenter]);
|
214
201
|
|
@@ -4,6 +4,8 @@ import { ChevronLeftIcon, ChevronRightIcon, CrossIcon } from '@100mslive/react-i
|
|
4
4
|
import { Box, Flex } from '../../../../Layout';
|
5
5
|
import { Loading } from '../../../../Loading';
|
6
6
|
import { Text } from '../../../../Text';
|
7
|
+
// @ts-ignore
|
8
|
+
import { Container } from '../../Streaming/Common';
|
7
9
|
import { LeaderboardEntry } from './LeaderboardEntry';
|
8
10
|
import { PeerParticipationSummary } from './PeerParticipationSummary';
|
9
11
|
// @ts-ignore
|
@@ -32,80 +34,83 @@ export const LeaderboardSummary = ({ pollID }: { pollID: string }) => {
|
|
32
34
|
const questionCount = quiz.questions?.length || 0;
|
33
35
|
|
34
36
|
return (
|
35
|
-
<
|
36
|
-
<Flex
|
37
|
-
<Flex align="center" css={{
|
37
|
+
<Container rounded>
|
38
|
+
<Flex direction="column" css={{ size: '100%', p: '$8' }}>
|
39
|
+
<Flex justify="between" align="center" css={{ pb: '$6', borderBottom: '1px solid $border_bright', mb: '$8' }}>
|
40
|
+
<Flex align="center" css={{ gap: '$4' }}>
|
41
|
+
<Flex
|
42
|
+
css={{ color: '$on_surface_medium', '&:hover': { color: '$on_surface_high', cursor: 'pointer' } }}
|
43
|
+
onClick={() => setPollView(POLL_VIEWS.VOTE)}
|
44
|
+
>
|
45
|
+
<ChevronLeftIcon />
|
46
|
+
</Flex>
|
47
|
+
<Text variant="lg" css={{ fontWeight: '$semiBold' }}>
|
48
|
+
{quiz.title}
|
49
|
+
</Text>
|
50
|
+
<StatusIndicator status={quiz.state} />
|
51
|
+
</Flex>
|
38
52
|
<Flex
|
39
53
|
css={{ color: '$on_surface_medium', '&:hover': { color: '$on_surface_high', cursor: 'pointer' } }}
|
40
|
-
onClick={
|
54
|
+
onClick={toggleSidepane}
|
41
55
|
>
|
42
|
-
<
|
56
|
+
<CrossIcon />
|
43
57
|
</Flex>
|
44
|
-
<Text variant="lg" css={{ fontWeight: '$semiBold' }}>
|
45
|
-
{quiz.title}
|
46
|
-
</Text>
|
47
|
-
<StatusIndicator status={quiz.state} />
|
48
58
|
</Flex>
|
49
|
-
<
|
50
|
-
|
51
|
-
onClick={toggleSidepane}
|
52
|
-
>
|
53
|
-
<CrossIcon />
|
54
|
-
</Flex>
|
55
|
-
</Flex>
|
56
|
-
|
57
|
-
{!viewAllEntries ? <PeerParticipationSummary quiz={quiz} /> : null}
|
59
|
+
<Box css={{ overflowY: 'auto', mr: '-$4', pr: '$4' }}>
|
60
|
+
{!viewAllEntries ? <PeerParticipationSummary quiz={quiz} /> : null}
|
58
61
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
css={{
|
67
|
-
mt: '$8',
|
68
|
-
overflowY: 'auto',
|
69
|
-
flex: viewAllEntries ? '1 1 0' : 'unset',
|
70
|
-
mr: viewAllEntries ? '-$6' : 'unset',
|
71
|
-
px: viewAllEntries ? '0' : '$4',
|
72
|
-
pr: viewAllEntries ? '$6' : '$4',
|
73
|
-
backgroundColor: viewAllEntries ? '' : '$surface_default',
|
74
|
-
borderRadius: '$1',
|
75
|
-
}}
|
76
|
-
>
|
77
|
-
{quizLeaderboard?.entries &&
|
78
|
-
quizLeaderboard.entries
|
79
|
-
.slice(0, viewAllEntries ? undefined : 5)
|
80
|
-
.map(question => (
|
81
|
-
<LeaderboardEntry
|
82
|
-
key={question.position}
|
83
|
-
position={question.position}
|
84
|
-
score={question.score}
|
85
|
-
questionCount={questionCount}
|
86
|
-
correctResponses={question.correctResponses}
|
87
|
-
userName={question.peer.username || ''}
|
88
|
-
maxPossibleScore={maxPossibleScore}
|
89
|
-
duration={question.duration}
|
90
|
-
/>
|
91
|
-
))}
|
92
|
-
{quizLeaderboard?.entries?.length > 5 && !viewAllEntries ? (
|
93
|
-
<Flex
|
94
|
-
align="center"
|
95
|
-
justify="end"
|
62
|
+
<Text variant="sm" css={{ fontWeight: '$semiBold', mt: '$4' }}>
|
63
|
+
Leaderboard
|
64
|
+
</Text>
|
65
|
+
<Text variant="xs" css={{ color: '$on_surface_medium' }}>
|
66
|
+
Based on score and time taken to cast the correct answer
|
67
|
+
</Text>
|
68
|
+
<Box
|
96
69
|
css={{
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
70
|
+
mt: '$8',
|
71
|
+
overflowY: 'auto',
|
72
|
+
flex: viewAllEntries ? '1 1 0' : 'unset',
|
73
|
+
mr: viewAllEntries ? '-$6' : 'unset',
|
74
|
+
px: viewAllEntries ? '0' : '$4',
|
75
|
+
pr: viewAllEntries ? '$6' : '$4',
|
76
|
+
backgroundColor: viewAllEntries ? '' : '$surface_default',
|
77
|
+
borderRadius: '$1',
|
102
78
|
}}
|
103
|
-
onClick={() => setViewAllEntries(true)}
|
104
79
|
>
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
80
|
+
{quizLeaderboard?.entries &&
|
81
|
+
quizLeaderboard.entries
|
82
|
+
.slice(0, viewAllEntries ? undefined : 5)
|
83
|
+
.map(question => (
|
84
|
+
<LeaderboardEntry
|
85
|
+
key={question.position}
|
86
|
+
position={question.position}
|
87
|
+
score={question.score}
|
88
|
+
questionCount={questionCount}
|
89
|
+
correctResponses={question.correctResponses}
|
90
|
+
userName={question.peer.username || ''}
|
91
|
+
maxPossibleScore={maxPossibleScore}
|
92
|
+
duration={question.duration}
|
93
|
+
/>
|
94
|
+
))}
|
95
|
+
{quizLeaderboard?.entries?.length > 5 && !viewAllEntries ? (
|
96
|
+
<Flex
|
97
|
+
align="center"
|
98
|
+
justify="end"
|
99
|
+
css={{
|
100
|
+
w: '100%',
|
101
|
+
borderTop: '1px solid $border_bright',
|
102
|
+
cursor: 'pointer',
|
103
|
+
color: '$on_surface_high',
|
104
|
+
p: '$6 $2',
|
105
|
+
}}
|
106
|
+
onClick={() => setViewAllEntries(true)}
|
107
|
+
>
|
108
|
+
<Text variant="sm">View All</Text> <ChevronRightIcon />
|
109
|
+
</Flex>
|
110
|
+
) : null}
|
111
|
+
</Box>
|
112
|
+
</Box>
|
113
|
+
</Flex>
|
114
|
+
</Container>
|
110
115
|
);
|
111
116
|
};
|
@@ -1,5 +1,5 @@
|
|
1
1
|
// @ts-check
|
2
|
-
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
2
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
3
3
|
import { match } from 'ts-pattern';
|
4
4
|
import { selectLocalPeer, selectLocalPeerRoleName, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
|
5
5
|
import { CheckCircleIcon, ChevronDownIcon, CrossCircleIcon } from '@100mslive/react-icons';
|
@@ -21,15 +21,12 @@ export const QuestionCard = ({
|
|
21
21
|
text,
|
22
22
|
options = [],
|
23
23
|
answer,
|
24
|
-
|
25
|
-
|
24
|
+
localPeerResponse,
|
25
|
+
updateSavedResponses,
|
26
26
|
rolesThatCanViewResponses,
|
27
27
|
}) => {
|
28
28
|
const actions = useHMSActions();
|
29
29
|
const localPeer = useHMSStore(selectLocalPeer);
|
30
|
-
const localPeerResponse = responses?.find(
|
31
|
-
response => response.peer?.peerid === localPeer?.id || response.peer?.userid === localPeer?.customerUserId,
|
32
|
-
);
|
33
30
|
|
34
31
|
const isLocalPeerCreator = localPeer?.id === startedBy;
|
35
32
|
const localPeerRoleName = useHMSStore(selectLocalPeerRoleName);
|
@@ -37,20 +34,26 @@ export const QuestionCard = ({
|
|
37
34
|
!rolesThatCanViewResponses ||
|
38
35
|
rolesThatCanViewResponses.length === 0 ||
|
39
36
|
rolesThatCanViewResponses.includes(localPeerRoleName || '');
|
37
|
+
const [localPeerChoice, setLocalPeerChoice] = useState(localPeerResponse);
|
38
|
+
|
39
|
+
useEffect(() => {
|
40
|
+
setLocalPeerChoice(localPeerResponse);
|
41
|
+
}, [localPeerResponse]);
|
42
|
+
|
40
43
|
const showVoteCount =
|
41
|
-
roleCanViewResponse && (
|
44
|
+
roleCanViewResponse && (localPeerChoice || (isLocalPeerCreator && pollState === 'stopped')) && !isQuiz;
|
42
45
|
|
43
46
|
const isLive = pollState === 'started';
|
44
47
|
const pollEnded = pollState === 'stopped';
|
45
|
-
const canRespond = isLive && !
|
48
|
+
const canRespond = isLive && !localPeerChoice;
|
46
49
|
const startTime = useRef(Date.now());
|
47
|
-
const isCorrectAnswer = checkCorrectAnswer(answer,
|
50
|
+
const isCorrectAnswer = checkCorrectAnswer(answer, localPeerChoice, type);
|
48
51
|
|
49
52
|
const [singleOptionAnswer, setSingleOptionAnswer] = useState();
|
50
53
|
const [multipleOptionAnswer, setMultipleOptionAnswer] = useState(new Set());
|
51
54
|
const [showOptions, setShowOptions] = useState(true);
|
52
55
|
|
53
|
-
const respondedToQuiz = isQuiz &&
|
56
|
+
const respondedToQuiz = isQuiz && localPeerChoice && !localPeerChoice.skipped;
|
54
57
|
|
55
58
|
const isValidVote = useMemo(() => {
|
56
59
|
if (type === QUESTION_TYPE.SINGLE_CHOICE) {
|
@@ -64,17 +67,28 @@ export const QuestionCard = ({
|
|
64
67
|
if (!isValidVote) {
|
65
68
|
return;
|
66
69
|
}
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
70
|
+
const submittedResponse = {
|
71
|
+
questionIndex: index,
|
72
|
+
option: singleOptionAnswer,
|
73
|
+
options: Array.from(multipleOptionAnswer),
|
74
|
+
duration: Date.now() - startTime.current,
|
75
|
+
};
|
76
|
+
await actions.interactivityCenter.addResponsesToPoll(pollID, [submittedResponse]);
|
77
|
+
updateSavedResponses(prev => {
|
78
|
+
const prevCopy = { ...prev };
|
79
|
+
prevCopy[index] = { option: singleOptionAnswer, options: Array.from(multipleOptionAnswer) };
|
80
|
+
return prevCopy;
|
81
|
+
});
|
76
82
|
startTime.current = Date.now();
|
77
|
-
}, [
|
83
|
+
}, [
|
84
|
+
isValidVote,
|
85
|
+
index,
|
86
|
+
singleOptionAnswer,
|
87
|
+
multipleOptionAnswer,
|
88
|
+
actions.interactivityCenter,
|
89
|
+
pollID,
|
90
|
+
updateSavedResponses,
|
91
|
+
]);
|
78
92
|
|
79
93
|
return (
|
80
94
|
<Box
|
@@ -147,7 +161,7 @@ export const QuestionCard = ({
|
|
147
161
|
setAnswer={setSingleOptionAnswer}
|
148
162
|
totalResponses={result?.totalResponses}
|
149
163
|
showVoteCount={showVoteCount}
|
150
|
-
localPeerResponse={
|
164
|
+
localPeerResponse={localPeerChoice}
|
151
165
|
isStopped={pollState === 'stopped'}
|
152
166
|
/>
|
153
167
|
) : null}
|
@@ -163,27 +177,19 @@ export const QuestionCard = ({
|
|
163
177
|
setSelectedOptions={setMultipleOptionAnswer}
|
164
178
|
totalResponses={result?.totalResponses}
|
165
179
|
showVoteCount={showVoteCount}
|
166
|
-
localPeerResponse={
|
180
|
+
localPeerResponse={localPeerChoice}
|
167
181
|
isStopped={pollState === 'stopped'}
|
168
182
|
/>
|
169
183
|
) : null}
|
170
184
|
</Box>
|
171
185
|
{isLive && (
|
172
|
-
<QuestionActions
|
173
|
-
isValidVote={isValidVote}
|
174
|
-
onVote={handleVote}
|
175
|
-
response={localPeerResponse}
|
176
|
-
isQuiz={isQuiz}
|
177
|
-
incrementIndex={() => {
|
178
|
-
setCurrentIndex(curr => Math.min(totalQuestions, curr + 1));
|
179
|
-
}}
|
180
|
-
/>
|
186
|
+
<QuestionActions isValidVote={isValidVote} onVote={handleVote} response={localPeerChoice} isQuiz={isQuiz} />
|
181
187
|
)}
|
182
188
|
</Box>
|
183
189
|
);
|
184
190
|
};
|
185
191
|
|
186
|
-
const QuestionActions = ({ isValidVote, response, isQuiz, onVote
|
192
|
+
const QuestionActions = ({ isValidVote, response, isQuiz, onVote }) => {
|
187
193
|
return (
|
188
194
|
<Flex align="center" justify="end" css={{ gap: '$4', w: '100%' }}>
|
189
195
|
{response ? (
|
@@ -193,14 +199,7 @@ const QuestionActions = ({ isValidVote, response, isQuiz, onVote, incrementIndex
|
|
193
199
|
{!isQuiz && !response.skipped ? 'Voted' : null}
|
194
200
|
</Text>
|
195
201
|
) : (
|
196
|
-
<Button
|
197
|
-
css={{ p: '$xs $10', fontWeight: '$semiBold' }}
|
198
|
-
disabled={!isValidVote}
|
199
|
-
onClick={() => {
|
200
|
-
onVote();
|
201
|
-
incrementIndex();
|
202
|
-
}}
|
203
|
-
>
|
202
|
+
<Button css={{ p: '$xs $10', fontWeight: '$semiBold' }} disabled={!isValidVote} onClick={onVote}>
|
204
203
|
{isQuiz ? 'Answer' : 'Vote'}
|
205
204
|
</Button>
|
206
205
|
)}
|
@@ -1,10 +1,18 @@
|
|
1
|
-
import React from 'react';
|
1
|
+
import React, { Dispatch, SetStateAction } from 'react';
|
2
2
|
import { HMSPoll } from '@100mslive/react-sdk';
|
3
3
|
import { PeerParticipationSummary } from './PeerParticipationSummary';
|
4
4
|
// @ts-ignore
|
5
5
|
import { QuestionCard } from './QuestionCard';
|
6
6
|
|
7
|
-
export const StandardView = ({
|
7
|
+
export const StandardView = ({
|
8
|
+
poll,
|
9
|
+
localPeerResponses,
|
10
|
+
updateSavedResponses,
|
11
|
+
}: {
|
12
|
+
poll: HMSPoll;
|
13
|
+
localPeerResponses: Record<number, number | number[] | undefined>;
|
14
|
+
updateSavedResponses: Dispatch<SetStateAction<Record<any, any>>>;
|
15
|
+
}) => {
|
8
16
|
if (!poll?.questions) {
|
9
17
|
return null;
|
10
18
|
}
|
@@ -28,11 +36,9 @@ export const StandardView = ({ poll }: { poll: HMSPoll }) => {
|
|
28
36
|
result={question.result}
|
29
37
|
totalQuestions={poll.questions?.length || 0}
|
30
38
|
options={question.options}
|
31
|
-
|
39
|
+
localPeerResponse={localPeerResponses?.[question.index]}
|
32
40
|
answer={question.answer}
|
33
|
-
|
34
|
-
return;
|
35
|
-
}}
|
41
|
+
updateSavedResponses={updateSavedResponses}
|
36
42
|
rolesThatCanViewResponses={poll.rolesThatCanViewResponses}
|
37
43
|
/>
|
38
44
|
))}
|
@@ -1,16 +1,27 @@
|
|
1
|
-
import React, { useState } from 'react';
|
2
|
-
import { HMSPoll
|
1
|
+
import React, { Dispatch, SetStateAction, useEffect, useState } from 'react';
|
2
|
+
import { HMSPoll } from '@100mslive/react-sdk';
|
3
3
|
// @ts-ignore
|
4
4
|
import { QuestionCard } from './QuestionCard';
|
5
5
|
// @ts-ignore
|
6
|
-
import {
|
6
|
+
import { getIndexToShow } from '../../../common/utils';
|
7
7
|
|
8
|
-
export const TimedView = ({
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
export const TimedView = ({
|
9
|
+
poll,
|
10
|
+
localPeerResponses,
|
11
|
+
updateSavedResponses,
|
12
|
+
}: {
|
13
|
+
poll: HMSPoll;
|
14
|
+
localPeerResponses?: Record<number, number | number[] | undefined>;
|
15
|
+
updateSavedResponses: Dispatch<SetStateAction<Record<any, any>>>;
|
16
|
+
}) => {
|
17
|
+
const [currentIndex, setCurrentIndex] = useState(getIndexToShow(localPeerResponses));
|
12
18
|
const activeQuestion = poll.questions?.find(question => question.index === currentIndex);
|
13
|
-
const attemptedAll = poll.questions?.length
|
19
|
+
const attemptedAll = (poll.questions?.length || 0) < currentIndex;
|
20
|
+
|
21
|
+
// Handles increments so only one question is shown at a time in quiz
|
22
|
+
useEffect(() => {
|
23
|
+
setCurrentIndex(getIndexToShow(localPeerResponses));
|
24
|
+
}, [localPeerResponses]);
|
14
25
|
|
15
26
|
if ((!activeQuestion && !attemptedAll) || !poll.questions?.length) {
|
16
27
|
return null;
|
@@ -32,10 +43,10 @@ export const TimedView = ({ poll }: { poll: HMSPoll }) => {
|
|
32
43
|
result={question?.result}
|
33
44
|
totalQuestions={poll.questions?.length || 0}
|
34
45
|
options={question.options}
|
35
|
-
|
46
|
+
localPeerResponse={localPeerResponses?.[question.index]}
|
36
47
|
answer={question.answer}
|
37
|
-
setCurrentIndex={setCurrentIndex}
|
38
48
|
rolesThatCanViewResponses={poll.rolesThatCanViewResponses}
|
49
|
+
updateSavedResponses={updateSavedResponses}
|
39
50
|
/>
|
40
51
|
) : null;
|
41
52
|
})}
|
@@ -1,5 +1,6 @@
|
|
1
|
-
import React from 'react';
|
1
|
+
import React, { useEffect, useRef, useState } from 'react';
|
2
2
|
import {
|
3
|
+
selectLocalPeerID,
|
3
4
|
selectPeerNameByID,
|
4
5
|
selectPermissions,
|
5
6
|
selectPollByID,
|
@@ -14,6 +15,8 @@ import { StandardView } from './StandardVoting';
|
|
14
15
|
import { TimedView } from './TimedVoting';
|
15
16
|
// @ts-ignore
|
16
17
|
import { usePollViewState } from '../../AppData/useUISettings';
|
18
|
+
// @ts-ignore
|
19
|
+
import { getPeerResponses } from '../../../common/utils';
|
17
20
|
import { StatusIndicator } from '../common/StatusIndicator';
|
18
21
|
import { POLL_VIEWS } from '../../../common/constants';
|
19
22
|
|
@@ -26,6 +29,41 @@ export const Voting = ({ id, toggleVoting }: { id: string; toggleVoting: () => v
|
|
26
29
|
const { setPollView } = usePollViewState();
|
27
30
|
// Sets view - linear or vertical, toggles timer indicator
|
28
31
|
const showSingleView = poll?.type === 'quiz' && poll.state === 'started';
|
32
|
+
const fetchedInitialResponses = useRef(false);
|
33
|
+
const [savedResponses, setSavedResponses] = useState<Record<any, any>>({});
|
34
|
+
const localPeerId = useHMSStore(selectLocalPeerID);
|
35
|
+
|
36
|
+
// To reset whenever a different poll is opened
|
37
|
+
useEffect(() => {
|
38
|
+
fetchedInitialResponses.current = false;
|
39
|
+
setSavedResponses({});
|
40
|
+
}, [id, setSavedResponses]);
|
41
|
+
|
42
|
+
useEffect(() => {
|
43
|
+
const getResponses = async () => {
|
44
|
+
if (poll && actions.interactivityCenter && !fetchedInitialResponses.current) {
|
45
|
+
await actions.interactivityCenter.getPollResponses(poll, true);
|
46
|
+
fetchedInitialResponses.current = true;
|
47
|
+
}
|
48
|
+
};
|
49
|
+
getResponses();
|
50
|
+
}, [poll, actions.interactivityCenter]);
|
51
|
+
|
52
|
+
useEffect(() => {
|
53
|
+
if (poll?.questions) {
|
54
|
+
const localPeerResponses = getPeerResponses(poll.questions, localPeerId);
|
55
|
+
// @ts-ignore
|
56
|
+
localPeerResponses?.forEach(response => {
|
57
|
+
if (response) {
|
58
|
+
setSavedResponses(prev => {
|
59
|
+
const prevCopy = { ...prev };
|
60
|
+
prevCopy[response[0]?.questionIndex] = { option: response[0]?.option, options: response[0]?.options };
|
61
|
+
return prevCopy;
|
62
|
+
});
|
63
|
+
}
|
64
|
+
});
|
65
|
+
}
|
66
|
+
}, [localPeerId, poll?.questions, id]);
|
29
67
|
|
30
68
|
if (!poll) {
|
31
69
|
return null;
|
@@ -74,7 +112,11 @@ export const Voting = ({ id, toggleVoting }: { id: string; toggleVoting: () => v
|
|
74
112
|
</Text>
|
75
113
|
) : null}
|
76
114
|
|
77
|
-
{showSingleView ?
|
115
|
+
{showSingleView ? (
|
116
|
+
<TimedView poll={poll} localPeerResponses={savedResponses} updateSavedResponses={setSavedResponses} />
|
117
|
+
) : (
|
118
|
+
<StandardView poll={poll} localPeerResponses={savedResponses} updateSavedResponses={setSavedResponses} />
|
119
|
+
)}
|
78
120
|
</Flex>
|
79
121
|
<Flex
|
80
122
|
css={{ w: '100%', justifyContent: 'end', alignItems: 'center', p: '$8', borderTop: '1px solid $border_bright' }}
|
@@ -1,8 +1,9 @@
|
|
1
|
-
import React, { useEffect,
|
1
|
+
import React, { useEffect, useState } from 'react';
|
2
2
|
import { useMedia } from 'react-use';
|
3
|
-
import {
|
3
|
+
import { PeopleAddIcon } from '@100mslive/react-icons';
|
4
4
|
import { Flex } from '../../../Layout';
|
5
5
|
import { config as cssConfig } from '../../../Theme';
|
6
|
+
import { WaitingView } from '../../layouts/WaitingView';
|
6
7
|
import { InsetTile } from '../InsetTile';
|
7
8
|
import { Pagination } from '../Pagination';
|
8
9
|
import { Grid } from './Grid';
|
@@ -13,26 +14,14 @@ import { usePagesWithTiles, useTileLayout } from '../hooks/useTileLayout';
|
|
13
14
|
import { UI_SETTINGS } from '../../common/constants';
|
14
15
|
|
15
16
|
export function EqualProminence({ isInsetEnabled = false, peers, onPageChange, onPageSize, edgeToEdge }: LayoutProps) {
|
16
|
-
const localPeer = useHMSStore(selectLocalPeer);
|
17
17
|
const isMobile = useMedia(cssConfig.media.md);
|
18
18
|
let maxTileCount = useUISettings(UI_SETTINGS.maxTileCount);
|
19
19
|
maxTileCount = isMobile ? Math.min(maxTileCount, 6) : maxTileCount;
|
20
|
-
|
20
|
+
const pageList = usePagesWithTiles({
|
21
21
|
peers,
|
22
22
|
maxTileCount,
|
23
23
|
});
|
24
|
-
|
25
|
-
const inputPeers = useMemo(() => {
|
26
|
-
if (pageList.length === 0) {
|
27
|
-
return localPeer ? [localPeer] : [];
|
28
|
-
}
|
29
|
-
return peers;
|
30
|
-
}, [pageList.length, peers, localPeer]);
|
31
|
-
// Pass local peer to main grid if no other peer has tiles
|
32
|
-
pageList = usePagesWithTiles({
|
33
|
-
peers: inputPeers,
|
34
|
-
maxTileCount,
|
35
|
-
});
|
24
|
+
|
36
25
|
const { ref, pagesWithTiles } = useTileLayout({
|
37
26
|
pageList,
|
38
27
|
maxTileCount,
|
@@ -60,7 +49,14 @@ export function EqualProminence({ isInsetEnabled = false, peers, onPageChange, o
|
|
60
49
|
numPages={pagesWithTiles.length}
|
61
50
|
/>
|
62
51
|
)}
|
63
|
-
{
|
52
|
+
{pageList.length === 0 ? (
|
53
|
+
<WaitingView
|
54
|
+
title="Waiting for Host to join"
|
55
|
+
subtitle="Sit back and relax till others join"
|
56
|
+
icon={<PeopleAddIcon width="56px" height="56px" style={{ color: 'white' }} />}
|
57
|
+
/>
|
58
|
+
) : null}
|
59
|
+
{isInsetEnabled && <InsetTile />}
|
64
60
|
</Flex>
|
65
61
|
);
|
66
62
|
}
|