@100mslive/roomkit-react 0.2.1-alpha.0 → 0.2.1-alpha.2
Sign up to get free protection for your applications and to get access to all the features.
- package/LICENSE +21 -0
- package/dist/{HLSView-GKCGIZ5F.js → HLSView-S5JHEMWJ.js} +2 -2
- package/dist/Prebuilt/components/Polls/Voting/PeerParticipationSummary.d.ts +2 -2
- package/dist/Prebuilt/components/Polls/Voting/StatisticBox.d.ts +1 -1
- package/dist/Prebuilt/components/Polls/Voting/useQuizSummary.d.ts +7 -0
- package/dist/{chunk-FTOP3RHP.js → chunk-AWWYBQSE.js} +468 -452
- package/dist/chunk-AWWYBQSE.js.map +7 -0
- package/dist/index.cjs.js +1511 -1489
- package/dist/index.cjs.js.map +4 -4
- package/dist/index.js +1 -1
- package/dist/meta.cjs.json +124 -70
- package/dist/meta.esbuild.json +137 -83
- package/package.json +12 -6
- package/src/Introduction/Integrating.stories.mdx +1 -1
- package/src/Prebuilt/components/IconButtonWithOptions/IconButtonWithOptions.jsx +3 -3
- package/src/Prebuilt/components/Notifications/Notifications.tsx +14 -1
- package/src/Prebuilt/components/Polls/CreatePollQuiz/PollsQuizMenu.jsx +3 -4
- package/src/Prebuilt/components/Polls/CreateQuestions/QuestionForm.tsx +6 -5
- package/src/Prebuilt/components/Polls/Voting/LeaderboardSummary.tsx +7 -59
- package/src/Prebuilt/components/Polls/Voting/PeerParticipationSummary.tsx +40 -14
- package/src/Prebuilt/components/Polls/Voting/StandardVoting.tsx +1 -1
- package/src/Prebuilt/components/Polls/Voting/StatisticBox.tsx +16 -11
- package/src/Prebuilt/components/Polls/Voting/Voting.tsx +5 -7
- package/src/Prebuilt/components/Polls/Voting/useQuizSummary.tsx +50 -0
- package/src/Prebuilt/layouts/WhiteboardView.tsx +4 -1
- package/src/Toast/Toast.tsx +1 -0
- package/dist/chunk-FTOP3RHP.js.map +0 -7
- /package/dist/{HLSView-GKCGIZ5F.js.map → HLSView-S5JHEMWJ.js.map} +0 -0
@@ -67,7 +67,6 @@ const AddMenu = () => {
|
|
67
67
|
const actions = useHMSActions();
|
68
68
|
const [title, setTitle] = useState('');
|
69
69
|
const localPeerRoleName = useHMSStore(selectLocalPeerRoleName);
|
70
|
-
const [anonymous, setAnonymous] = useState(false);
|
71
70
|
const [hideVoteCount, setHideVoteCount] = useState(false);
|
72
71
|
const [error, setError] = useState();
|
73
72
|
const [titleError, setTitleError] = useState('');
|
@@ -141,12 +140,12 @@ const AddMenu = () => {
|
|
141
140
|
Hide Vote Count
|
142
141
|
</Text>
|
143
142
|
</Flex>
|
144
|
-
<Flex align="center" css={{ mt: '$10' }}>
|
143
|
+
{/* <Flex align="center" css={{ mt: '$10' }}>
|
145
144
|
<Switch onCheckedChange={value => setAnonymous(value)} css={{ mr: '$6' }} />
|
146
145
|
<Text variant="body2" css={{ c: '$on_surface_medium' }}>
|
147
146
|
Make Results Anonymous
|
148
147
|
</Text>
|
149
|
-
</Flex>
|
148
|
+
</Flex> */}
|
150
149
|
{/* <Timer
|
151
150
|
timer={timer}
|
152
151
|
setTimer={setTimer}
|
@@ -164,7 +163,7 @@ const AddMenu = () => {
|
|
164
163
|
.createPoll({
|
165
164
|
id,
|
166
165
|
title,
|
167
|
-
anonymous,
|
166
|
+
anonymous: false,
|
168
167
|
rolesThatCanViewResponses: hideVoteCount && localPeerRoleName ? [localPeerRoleName] : undefined,
|
169
168
|
type: interactionType.toLowerCase(),
|
170
169
|
// duration: showTimerDropDown ? timer : undefined,
|
@@ -6,7 +6,8 @@ import {
|
|
6
6
|
HMSPollQuestionType,
|
7
7
|
} from '@100mslive/react-sdk';
|
8
8
|
import { AddCircleIcon, TrashIcon } from '@100mslive/react-icons';
|
9
|
-
import { Button, Dropdown, Flex, IconButton, Input, Switch, Text, TextArea, Tooltip } from '../../../..';
|
9
|
+
// import { Button, Dropdown, Flex, IconButton, Input, Switch, Text, TextArea, Tooltip } from '../../../..';
|
10
|
+
import { Button, Dropdown, Flex, IconButton, Input, Text, TextArea, Tooltip } from '../../../..';
|
10
11
|
// @ts-ignore
|
11
12
|
import { DialogDropdownTrigger } from '../../../primitives/DropdownTrigger';
|
12
13
|
// @ts-ignore
|
@@ -50,7 +51,7 @@ export const QuestionForm = ({
|
|
50
51
|
{ text: '', isCorrectAnswer: false },
|
51
52
|
],
|
52
53
|
);
|
53
|
-
const [skippable, setSkippable] = useState(false);
|
54
|
+
// const [skippable, setSkippable] = useState(false);
|
54
55
|
const isValid = isValidQuestion({
|
55
56
|
text,
|
56
57
|
type,
|
@@ -241,12 +242,12 @@ export const QuestionForm = ({
|
|
241
242
|
}}
|
242
243
|
/>
|
243
244
|
</Flex>
|
244
|
-
<Flex justify="between" css={{ mt: '$md', gap: '$6', w: '100%' }}>
|
245
|
+
{/* <Flex justify="between" css={{ mt: '$md', gap: '$6', w: '100%' }}>
|
245
246
|
<Text variant="sm" css={{ color: '$on_surface_medium' }}>
|
246
247
|
Allow to skip
|
247
248
|
</Text>
|
248
249
|
<Switch defaultChecked={skippable} onCheckedChange={checked => setSkippable(checked)} />
|
249
|
-
</Flex>
|
250
|
+
</Flex> */}
|
250
251
|
</>
|
251
252
|
) : null}
|
252
253
|
</>
|
@@ -274,7 +275,7 @@ export const QuestionForm = ({
|
|
274
275
|
text,
|
275
276
|
type,
|
276
277
|
options,
|
277
|
-
skippable,
|
278
|
+
skippable: false,
|
278
279
|
draftID: question.draftID,
|
279
280
|
weight,
|
280
281
|
});
|
@@ -1,51 +1,27 @@
|
|
1
|
-
import React, {
|
2
|
-
import {
|
3
|
-
HMSQuizLeaderboardResponse,
|
4
|
-
HMSQuizLeaderboardSummary,
|
5
|
-
selectPollByID,
|
6
|
-
useHMSActions,
|
7
|
-
useHMSStore,
|
8
|
-
} from '@100mslive/react-sdk';
|
1
|
+
import React, { useState } from 'react';
|
2
|
+
import { selectPollByID, useHMSStore } from '@100mslive/react-sdk';
|
9
3
|
import { ChevronLeftIcon, ChevronRightIcon, CrossIcon } from '@100mslive/react-icons';
|
10
4
|
import { Box, Flex } from '../../../../Layout';
|
11
5
|
import { Loading } from '../../../../Loading';
|
12
6
|
import { Text } from '../../../../Text';
|
13
7
|
import { LeaderboardEntry } from './LeaderboardEntry';
|
14
|
-
import {
|
8
|
+
import { PeerParticipationSummary } from './PeerParticipationSummary';
|
15
9
|
// @ts-ignore
|
16
10
|
import { useSidepaneToggle } from '../../AppData/useSidepane';
|
17
11
|
// @ts-ignore
|
18
12
|
import { usePollViewState } from '../../AppData/useUISettings';
|
13
|
+
import { useQuizSummary } from './useQuizSummary';
|
19
14
|
// @ts-ignore
|
20
15
|
import { StatusIndicator } from '../common/StatusIndicator';
|
21
16
|
import { POLL_VIEWS } from '../../../common/constants';
|
22
17
|
|
23
18
|
export const LeaderboardSummary = ({ pollID }: { pollID: string }) => {
|
24
|
-
const hmsActions = useHMSActions();
|
25
19
|
const quiz = useHMSStore(selectPollByID(pollID));
|
26
|
-
const
|
20
|
+
const { quizLeaderboard, maxPossibleScore } = useQuizSummary(pollID);
|
27
21
|
const [viewAllEntries, setViewAllEntries] = useState(false);
|
28
|
-
const summary: HMSQuizLeaderboardSummary = quizLeaderboard?.summary || {
|
29
|
-
totalUsers: 0,
|
30
|
-
votedUsers: 0,
|
31
|
-
avgScore: 0,
|
32
|
-
avgTime: 0,
|
33
|
-
correctAnswers: 0,
|
34
|
-
};
|
35
|
-
|
36
22
|
const { setPollView } = usePollViewState();
|
37
23
|
const toggleSidepane = useSidepaneToggle();
|
38
24
|
|
39
|
-
useEffect(() => {
|
40
|
-
const fetchLeaderboardData = async () => {
|
41
|
-
if (!quizLeaderboard && quiz) {
|
42
|
-
const leaderboardData = await hmsActions.interactivityCenter.fetchLeaderboard(quiz.id, 0, 50);
|
43
|
-
setQuizLeaderboard(leaderboardData);
|
44
|
-
}
|
45
|
-
};
|
46
|
-
fetchLeaderboardData();
|
47
|
-
}, [quiz, hmsActions.interactivityCenter, quizLeaderboard]);
|
48
|
-
|
49
25
|
if (!quiz || !quizLeaderboard)
|
50
26
|
return (
|
51
27
|
<Flex align="center" justify="center" css={{ size: '100%' }}>
|
@@ -53,14 +29,6 @@ export const LeaderboardSummary = ({ pollID }: { pollID: string }) => {
|
|
53
29
|
</Flex>
|
54
30
|
);
|
55
31
|
|
56
|
-
const defaultCalculations = { maxPossibleScore: 0, totalResponses: 0 };
|
57
|
-
const { maxPossibleScore, totalResponses } =
|
58
|
-
quiz.questions?.reduce((accumulator, question) => {
|
59
|
-
accumulator.maxPossibleScore += question.weight || 0;
|
60
|
-
accumulator.totalResponses += question?.responses?.length || 0;
|
61
|
-
return accumulator;
|
62
|
-
}, defaultCalculations) || defaultCalculations;
|
63
|
-
|
64
32
|
const questionCount = quiz.questions?.length || 0;
|
65
33
|
|
66
34
|
return (
|
@@ -86,29 +54,9 @@ export const LeaderboardSummary = ({ pollID }: { pollID: string }) => {
|
|
86
54
|
</Flex>
|
87
55
|
</Flex>
|
88
56
|
|
89
|
-
{!viewAllEntries ?
|
90
|
-
<Box css={{ py: '$4' }}>
|
91
|
-
<Text variant="sm" css={{ fontWeight: '$semiBold' }}>
|
92
|
-
Participation Summary
|
93
|
-
</Text>
|
94
|
-
|
95
|
-
<Box css={{ my: '$4' }}>
|
96
|
-
<Flex css={{ w: '100%', gap: '$4' }}>
|
97
|
-
<StatisticBox
|
98
|
-
title="Voted"
|
99
|
-
value={`${summary?.totalUsers ? (100 * summary?.votedUsers) / summary?.totalUsers : 0}%`}
|
100
|
-
/>
|
101
|
-
<StatisticBox title="Correct Answers" value={`${summary?.correctAnswers}/${totalResponses}`} />
|
102
|
-
</Flex>
|
103
|
-
<Flex css={{ w: '100%', gap: '$4', mt: '$4' }}>
|
104
|
-
{summary?.avgTime > 0 ? <StatisticBox title="Avg. Time" value={summary?.avgTime} /> : null}
|
105
|
-
<StatisticBox title="Avg. Score" value={summary?.avgScore} />
|
106
|
-
</Flex>
|
107
|
-
</Box>
|
108
|
-
</Box>
|
109
|
-
) : null}
|
57
|
+
{!viewAllEntries ? <PeerParticipationSummary quiz={quiz} /> : null}
|
110
58
|
|
111
|
-
<Text variant="sm" css={{ fontWeight: '$semiBold' }}>
|
59
|
+
<Text variant="sm" css={{ fontWeight: '$semiBold', mt: '$4' }}>
|
112
60
|
Leaderboard
|
113
61
|
</Text>
|
114
62
|
<Text variant="xs" css={{ color: '$on_surface_medium' }}>
|
@@ -1,23 +1,49 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import { HMSPoll,
|
2
|
+
import { HMSPoll, selectLocalPeerID, useHMSStore } from '@100mslive/react-sdk';
|
3
3
|
import { Box } from '../../../../Layout';
|
4
4
|
import { Text } from '../../../../Text';
|
5
5
|
import { StatisticBox } from './StatisticBox';
|
6
|
-
|
7
|
-
import { getPeerParticipationSummary } from '../../../common/utils';
|
6
|
+
import { useQuizSummary } from './useQuizSummary';
|
8
7
|
|
9
|
-
export const PeerParticipationSummary = ({
|
10
|
-
const
|
11
|
-
const {
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
8
|
+
export const PeerParticipationSummary = ({ quiz }: { quiz: HMSPoll }) => {
|
9
|
+
const localPeerId = useHMSStore(selectLocalPeerID);
|
10
|
+
const { quizLeaderboard, summary } = useQuizSummary(quiz.id);
|
11
|
+
if (quiz.state !== 'stopped') {
|
12
|
+
return <></>;
|
13
|
+
}
|
14
|
+
const isLocalPeerQuizCreator = localPeerId === quiz.startedBy;
|
15
|
+
const peerEntry = quizLeaderboard?.entries.find(entry => entry.peer?.peerid === localPeerId);
|
16
|
+
|
17
|
+
const boxes = isLocalPeerQuizCreator
|
18
|
+
? [
|
19
|
+
{
|
20
|
+
title: 'Voted',
|
21
|
+
value: `${summary.totalUsers ? ((100 * summary.votedUsers) / summary.totalUsers).toFixed(0) : 0}% (${
|
22
|
+
summary.votedUsers
|
23
|
+
}/${summary.totalUsers})`,
|
24
|
+
},
|
25
|
+
{
|
26
|
+
title: 'Correct Answers',
|
27
|
+
value: `${summary.totalUsers ? ((100 * summary.correctUsers) / summary.totalUsers).toFixed(0) : 0}% (${
|
28
|
+
summary.correctUsers
|
29
|
+
}/${summary.totalUsers})`,
|
30
|
+
},
|
31
|
+
{ title: 'Avg. Time Taken', value: summary.avgTime },
|
32
|
+
{
|
33
|
+
title: 'Avg. Score',
|
34
|
+
value: Number.isInteger(summary.avgScore) ? summary.avgScore : summary.avgScore.toFixed(2),
|
35
|
+
},
|
36
|
+
]
|
37
|
+
: [
|
38
|
+
{ title: 'Your rank', value: peerEntry?.position ? `${peerEntry.position}/${summary.totalUsers}` : '-' },
|
39
|
+
{ title: 'Points', value: peerEntry?.score },
|
40
|
+
{ title: 'Time Taken', value: peerEntry?.duration },
|
41
|
+
{
|
42
|
+
title: 'Correct Answers',
|
43
|
+
value: peerEntry?.totalResponses ? `${peerEntry?.correctResponses}/${peerEntry.totalResponses}` : '-',
|
44
|
+
},
|
45
|
+
];
|
16
46
|
|
17
|
-
const boxes = [
|
18
|
-
{ title: 'Points', value: score },
|
19
|
-
{ title: 'Correct Answers', value: `${correctResponses}/${totalResponses}` },
|
20
|
-
];
|
21
47
|
return (
|
22
48
|
<Box>
|
23
49
|
<Text css={{ fontWeight: '$semiBold', my: '$8' }}>Participation Summary</Text>
|
@@ -14,7 +14,7 @@ export const StandardView = ({ poll }: { poll: HMSPoll }) => {
|
|
14
14
|
|
15
15
|
return (
|
16
16
|
<>
|
17
|
-
{isQuiz && isStopped ? <PeerParticipationSummary
|
17
|
+
{isQuiz && isStopped ? <PeerParticipationSummary quiz={poll} /> : null}
|
18
18
|
{poll.questions?.map((question, index) => (
|
19
19
|
<QuestionCard
|
20
20
|
pollID={poll.id}
|
@@ -2,14 +2,19 @@ import React from 'react';
|
|
2
2
|
import { Box } from '../../../../Layout';
|
3
3
|
import { Text } from '../../../../Text';
|
4
4
|
|
5
|
-
export const StatisticBox = ({ title, value = 0 }: { title: string; value: string | number }) =>
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
>
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
5
|
+
export const StatisticBox = ({ title, value = 0 }: { title: string; value: string | number | undefined }) => {
|
6
|
+
if (!value) {
|
7
|
+
return <></>;
|
8
|
+
}
|
9
|
+
return (
|
10
|
+
<Box css={{ p: '$8', background: '$surface_default', borderRadius: '$1', w: '100%' }}>
|
11
|
+
<Text
|
12
|
+
variant="tiny"
|
13
|
+
css={{ textTransform: 'uppercase', color: '$on_surface_medium', fontWeight: '$semiBold', my: '$4' }}
|
14
|
+
>
|
15
|
+
{title}
|
16
|
+
</Text>
|
17
|
+
<Text css={{ fontWeight: '$semiBold' }}>{value}</Text>
|
18
|
+
</Box>
|
19
|
+
);
|
20
|
+
};
|
@@ -68,13 +68,11 @@ export const Voting = ({ id, toggleVoting }: { id: string; toggleVoting: () => v
|
|
68
68
|
</Flex>
|
69
69
|
|
70
70
|
<Flex direction="column" css={{ p: '$8 $10', overflowY: 'auto' }}>
|
71
|
-
|
72
|
-
<
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
</Box>
|
77
|
-
</Flex>
|
71
|
+
{poll.state === 'started' ? (
|
72
|
+
<Text css={{ color: '$on_surface_medium', fontWeight: '$semiBold' }}>
|
73
|
+
{pollCreatorName || 'Participant'} started a {poll.type}
|
74
|
+
</Text>
|
75
|
+
) : null}
|
78
76
|
|
79
77
|
{isTimed ? <TimedView poll={poll} /> : <StandardView poll={poll} />}
|
80
78
|
|
@@ -0,0 +1,50 @@
|
|
1
|
+
import { useEffect, useState } from 'react';
|
2
|
+
import {
|
3
|
+
HMSQuizLeaderboardResponse,
|
4
|
+
HMSQuizLeaderboardSummary,
|
5
|
+
selectPollByID,
|
6
|
+
useHMSActions,
|
7
|
+
useHMSStore,
|
8
|
+
} from '@100mslive/react-sdk';
|
9
|
+
|
10
|
+
export const useQuizSummary = (quizID: string) => {
|
11
|
+
const hmsActions = useHMSActions();
|
12
|
+
const quiz = useHMSStore(selectPollByID(quizID));
|
13
|
+
const [quizLeaderboard, setQuizLeaderboard] = useState<HMSQuizLeaderboardResponse | undefined>();
|
14
|
+
|
15
|
+
const summary: HMSQuizLeaderboardSummary = quizLeaderboard?.summary || {
|
16
|
+
totalUsers: 0,
|
17
|
+
votedUsers: 0,
|
18
|
+
avgScore: 0,
|
19
|
+
avgTime: 0,
|
20
|
+
correctUsers: 0,
|
21
|
+
};
|
22
|
+
const [calculations, setCalculations] = useState({ maxPossibleScore: 0, totalResponses: 0 });
|
23
|
+
|
24
|
+
useEffect(() => {
|
25
|
+
const fetchLeaderboardData = async () => {
|
26
|
+
if (!quizLeaderboard && quiz && !quiz?.anonymous && quiz.state === 'stopped') {
|
27
|
+
const leaderboardData = await hmsActions.interactivityCenter.fetchLeaderboard(quiz.id, 0, 50);
|
28
|
+
|
29
|
+
const { maxPossibleScore, totalResponses } =
|
30
|
+
quiz?.questions?.reduce((accumulator, question) => {
|
31
|
+
accumulator.maxPossibleScore += question.weight || 0;
|
32
|
+
accumulator.totalResponses += question?.responses?.length || 0;
|
33
|
+
return accumulator;
|
34
|
+
}, calculations) || calculations;
|
35
|
+
|
36
|
+
setQuizLeaderboard(leaderboardData);
|
37
|
+
setCalculations({ maxPossibleScore, totalResponses });
|
38
|
+
}
|
39
|
+
};
|
40
|
+
|
41
|
+
fetchLeaderboardData();
|
42
|
+
}, [quiz, hmsActions.interactivityCenter, quizLeaderboard, calculations]);
|
43
|
+
|
44
|
+
return {
|
45
|
+
quizLeaderboard,
|
46
|
+
summary,
|
47
|
+
maxPossibleScore: calculations.maxPossibleScore,
|
48
|
+
totalResponses: calculations.totalResponses,
|
49
|
+
};
|
50
|
+
};
|
@@ -1,14 +1,17 @@
|
|
1
1
|
import React, { useEffect, useMemo } from 'react';
|
2
|
+
import { useMedia } from 'react-use';
|
2
3
|
import { selectPeers, selectWhiteboard, useHMSStore, useWhiteboard } from '@100mslive/react-sdk';
|
3
4
|
import { SecondaryTiles } from '../components/SecondaryTiles';
|
4
5
|
import { ProminenceLayout } from '../components/VideoLayouts/ProminenceLayout';
|
6
|
+
import { config as cssConfig } from '../../';
|
5
7
|
import { Box } from '../../Layout';
|
6
8
|
// @ts-ignore: No implicit Any
|
7
9
|
import { useSetAppDataByKey } from '../components/AppData/useUISettings';
|
8
10
|
import { APP_DATA } from '../common/constants';
|
9
11
|
|
10
12
|
const EmbedComponent = () => {
|
11
|
-
const
|
13
|
+
const isMobile = useMedia(cssConfig.media.md);
|
14
|
+
const { iframeRef } = useWhiteboard(isMobile);
|
12
15
|
|
13
16
|
return (
|
14
17
|
<Box
|
package/src/Toast/Toast.tsx
CHANGED
@@ -78,6 +78,7 @@ const ToastClose = styled(ToastPrimitives.Close, {});
|
|
78
78
|
const ToastAction = styled(ToastPrimitives.Action, {
|
79
79
|
cursor: 'pointer',
|
80
80
|
background: 'none',
|
81
|
+
border: 'none',
|
81
82
|
});
|
82
83
|
const ToastViewport = styled(ToastPrimitives.Viewport, {
|
83
84
|
position: 'fixed',
|