@100mslive/roomkit-react 0.2.2-alpha.4 → 0.2.2-alpha.6
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-DPM6YJWZ.js → HLSView-U346BIZQ.js} +2 -2
- package/dist/Prebuilt/components/Chat/ChatActions.d.ts +1 -1
- package/dist/Prebuilt/components/Polls/common/utils.d.ts +1 -0
- package/dist/{chunk-S5NNUR2M.js → chunk-DY3FWEXJ.js} +317 -263
- package/dist/{chunk-S5NNUR2M.js.map → chunk-DY3FWEXJ.js.map} +4 -4
- package/dist/index.cjs.js +554 -493
- package/dist/index.cjs.js.map +4 -4
- package/dist/index.js +1 -1
- package/dist/meta.cjs.json +60 -26
- package/dist/meta.esbuild.json +66 -32
- package/package.json +6 -6
- package/src/Prebuilt/common/utils.js +13 -0
- package/src/Prebuilt/components/Chat/ChatActions.tsx +3 -3
- package/src/Prebuilt/components/Chat/ChatBody.tsx +9 -5
- package/src/Prebuilt/components/Polls/Voting/LeaderboardEntry.tsx +3 -2
- package/src/Prebuilt/components/Polls/Voting/PeerParticipationSummary.tsx +4 -3
- package/src/Prebuilt/components/Polls/Voting/QuestionCard.jsx +16 -21
- package/src/Prebuilt/components/Polls/Voting/StatisticBox.tsx +1 -1
- package/src/Prebuilt/components/Polls/Voting/TimedVoting.tsx +31 -20
- package/src/Prebuilt/components/Polls/Voting/Voting.tsx +7 -8
- package/src/Prebuilt/components/Polls/common/MultipleChoiceOptions.jsx +2 -2
- package/src/Prebuilt/components/Polls/common/SingleChoiceOptions.jsx +4 -5
- package/src/Prebuilt/components/Polls/common/utils.ts +16 -0
- /package/dist/{HLSView-DPM6YJWZ.js.map → HLSView-U346BIZQ.js.map} +0 -0
@@ -189,7 +189,7 @@ const ChatMessage = React.memo(
|
|
189
189
|
roles: message.recipientRoles,
|
190
190
|
receiver: message.recipientPeer,
|
191
191
|
});
|
192
|
-
const [openSheet,
|
192
|
+
const [openSheet, setOpenSheetBare] = useState(false);
|
193
193
|
const showPinAction = !!elements?.chat?.allow_pinning_messages;
|
194
194
|
const showReply = message.sender !== selectedPeer.id && message.sender !== localPeerId && isPrivateChatEnabled;
|
195
195
|
useLayoutEffect(() => {
|
@@ -198,6 +198,11 @@ const ChatMessage = React.memo(
|
|
198
198
|
}
|
199
199
|
}, [index, message.id]);
|
200
200
|
|
201
|
+
const setOpenSheet = (value: boolean, e?: React.MouseEvent<HTMLElement, MouseEvent>) => {
|
202
|
+
e?.stopPropagation();
|
203
|
+
setOpenSheetBare(value);
|
204
|
+
};
|
205
|
+
|
201
206
|
return (
|
202
207
|
<Box
|
203
208
|
css={{
|
@@ -228,9 +233,9 @@ const ChatMessage = React.memo(
|
|
228
233
|
},
|
229
234
|
}}
|
230
235
|
data-testid="chat_msg"
|
231
|
-
onClick={
|
236
|
+
onClick={e => {
|
232
237
|
if (isMobile) {
|
233
|
-
setOpenSheet(true);
|
238
|
+
setOpenSheet(true, e);
|
234
239
|
}
|
235
240
|
}}
|
236
241
|
>
|
@@ -321,8 +326,7 @@ const ChatMessage = React.memo(
|
|
321
326
|
color: isOverlay ? '#FFF' : '$on_surface_high',
|
322
327
|
}}
|
323
328
|
onClick={e => {
|
324
|
-
e
|
325
|
-
setOpenSheet(true);
|
329
|
+
setOpenSheet(true, e);
|
326
330
|
}}
|
327
331
|
>
|
328
332
|
<AnnotisedMessage message={message.message} />
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|
2
2
|
import { CheckCircleIcon, ClockIcon, TrophyFilledIcon } from '@100mslive/react-icons';
|
3
3
|
import { Box, Flex } from '../../../../Layout';
|
4
4
|
import { Text } from '../../../../Text';
|
5
|
+
import { getFormattedTime } from '../common/utils';
|
5
6
|
|
6
7
|
const positionColorMap: Record<number, string> = { 1: '#D69516', 2: '#3E3E3E', 3: '#583B0F' };
|
7
8
|
|
@@ -23,7 +24,7 @@ export const LeaderboardEntry = ({
|
|
23
24
|
duration: number;
|
24
25
|
}) => {
|
25
26
|
return (
|
26
|
-
<Flex align="center" justify="between" css={{ my: '$
|
27
|
+
<Flex align="center" justify="between" css={{ my: '$8' }}>
|
27
28
|
<Flex align="center" css={{ gap: '$6' }}>
|
28
29
|
<Flex
|
29
30
|
align="center"
|
@@ -66,7 +67,7 @@ export const LeaderboardEntry = ({
|
|
66
67
|
{duration ? (
|
67
68
|
<Flex align="center" css={{ gap: '$2', color: '$on_surface_medium' }}>
|
68
69
|
<ClockIcon height={16} width={16} />
|
69
|
-
<Text variant="xs">{(duration
|
70
|
+
<Text variant="xs">{getFormattedTime(duration)}</Text>
|
70
71
|
</Flex>
|
71
72
|
) : null}
|
72
73
|
</Flex>
|
@@ -4,6 +4,7 @@ import { Box } from '../../../../Layout';
|
|
4
4
|
import { Text } from '../../../../Text';
|
5
5
|
import { StatisticBox } from './StatisticBox';
|
6
6
|
import { useQuizSummary } from './useQuizSummary';
|
7
|
+
import { getFormattedTime } from '../common/utils';
|
7
8
|
|
8
9
|
export const PeerParticipationSummary = ({ quiz }: { quiz: HMSPoll }) => {
|
9
10
|
const localPeerId = useHMSStore(selectLocalPeerID);
|
@@ -29,7 +30,7 @@ export const PeerParticipationSummary = ({ quiz }: { quiz: HMSPoll }) => {
|
|
29
30
|
}/${summary.totalUsers})`,
|
30
31
|
},
|
31
32
|
// Time in ms
|
32
|
-
{ title: 'Avg. Time Taken', value:
|
33
|
+
{ title: 'Avg. Time Taken', value: getFormattedTime(summary.avgTime) },
|
33
34
|
{
|
34
35
|
title: 'Avg. Score',
|
35
36
|
value: Number.isInteger(summary.avgScore) ? summary.avgScore : summary.avgScore.toFixed(2),
|
@@ -37,9 +38,9 @@ export const PeerParticipationSummary = ({ quiz }: { quiz: HMSPoll }) => {
|
|
37
38
|
]
|
38
39
|
: [
|
39
40
|
{ title: 'Your rank', value: peerEntry?.position || '-' },
|
40
|
-
{ title: 'Points', value: peerEntry?.score },
|
41
|
+
{ title: 'Points', value: peerEntry?.score || 0 },
|
41
42
|
// Time in ms
|
42
|
-
{ title: 'Time Taken', value:
|
43
|
+
{ title: 'Time Taken', value: getFormattedTime(peerEntry?.duration) },
|
43
44
|
{
|
44
45
|
title: 'Correct Answers',
|
45
46
|
value: peerEntry?.totalResponses ? `${peerEntry?.correctResponses}/${peerEntry.totalResponses}` : '-',
|
@@ -73,11 +73,6 @@ export const QuestionCard = ({
|
|
73
73
|
},
|
74
74
|
]);
|
75
75
|
startTime.current = Date.now();
|
76
|
-
|
77
|
-
if (isQuiz && index !== totalQuestions) {
|
78
|
-
setSingleOptionAnswer(undefined);
|
79
|
-
setMultipleOptionAnswer(new Set());
|
80
|
-
}
|
81
76
|
}, [
|
82
77
|
isValidVote,
|
83
78
|
actions.interactivityCenter,
|
@@ -118,8 +113,8 @@ export const QuestionCard = ({
|
|
118
113
|
gap: '$4',
|
119
114
|
}}
|
120
115
|
>
|
121
|
-
{respondedToQuiz && isCorrectAnswer && pollEnded ? <CheckCircleIcon height={
|
122
|
-
{respondedToQuiz && !isCorrectAnswer && pollEnded ? <CrossCircleIcon height={
|
116
|
+
{respondedToQuiz && isCorrectAnswer && pollEnded ? <CheckCircleIcon height={16} width={16} /> : null}
|
117
|
+
{respondedToQuiz && !isCorrectAnswer && pollEnded ? <CrossCircleIcon height={16} width={16} /> : null}
|
123
118
|
QUESTION {index} OF {totalQuestions}: {type.toUpperCase()}
|
124
119
|
</Text>
|
125
120
|
</Flex>
|
@@ -136,7 +131,9 @@ export const QuestionCard = ({
|
|
136
131
|
</Box>
|
137
132
|
</Flex>
|
138
133
|
|
139
|
-
<Box
|
134
|
+
<Box
|
135
|
+
css={{ maxHeight: showOptions ? '$80' : '0', transition: 'max-height 0.3s ease', overflowY: 'auto', mb: '$4' }}
|
136
|
+
>
|
140
137
|
{type === QUESTION_TYPE.SINGLE_CHOICE ? (
|
141
138
|
<SingleChoiceOptions
|
142
139
|
key={index}
|
@@ -150,7 +147,6 @@ export const QuestionCard = ({
|
|
150
147
|
showVoteCount={showVoteCount}
|
151
148
|
localPeerResponse={localPeerResponse}
|
152
149
|
isStopped={pollState === 'stopped'}
|
153
|
-
answer={singleOptionAnswer}
|
154
150
|
/>
|
155
151
|
) : null}
|
156
152
|
|
@@ -169,19 +165,18 @@ export const QuestionCard = ({
|
|
169
165
|
isStopped={pollState === 'stopped'}
|
170
166
|
/>
|
171
167
|
) : null}
|
172
|
-
|
173
|
-
{isLive && (
|
174
|
-
<QuestionActions
|
175
|
-
isValidVote={isValidVote}
|
176
|
-
onVote={handleVote}
|
177
|
-
response={localPeerResponse}
|
178
|
-
isQuiz={isQuiz}
|
179
|
-
incrementIndex={() => {
|
180
|
-
setCurrentIndex(curr => Math.min(totalQuestions, curr + 1));
|
181
|
-
}}
|
182
|
-
/>
|
183
|
-
)}
|
184
168
|
</Box>
|
169
|
+
{isLive && (
|
170
|
+
<QuestionActions
|
171
|
+
isValidVote={isValidVote}
|
172
|
+
onVote={handleVote}
|
173
|
+
response={localPeerResponse}
|
174
|
+
isQuiz={isQuiz}
|
175
|
+
incrementIndex={() => {
|
176
|
+
setCurrentIndex(curr => Math.min(totalQuestions, curr + 1));
|
177
|
+
}}
|
178
|
+
/>
|
179
|
+
)}
|
185
180
|
</Box>
|
186
181
|
);
|
187
182
|
};
|
@@ -3,7 +3,7 @@ import { Box } from '../../../../Layout';
|
|
3
3
|
import { Text } from '../../../../Text';
|
4
4
|
|
5
5
|
export const StatisticBox = ({ title, value = 0 }: { title: string; value: string | number | undefined }) => {
|
6
|
-
if (!value) {
|
6
|
+
if (!value && !(typeof value === 'number')) {
|
7
7
|
return <></>;
|
8
8
|
}
|
9
9
|
return (
|
@@ -1,33 +1,44 @@
|
|
1
1
|
import React, { useState } from 'react';
|
2
|
-
import { HMSPoll } from '@100mslive/react-sdk';
|
2
|
+
import { HMSPoll, selectLocalPeerID, useHMSStore } from '@100mslive/react-sdk';
|
3
3
|
// @ts-ignore
|
4
4
|
import { QuestionCard } from './QuestionCard';
|
5
|
+
// @ts-ignore
|
6
|
+
import { getLastAttemptedIndex } from '../../../common/utils';
|
5
7
|
|
6
8
|
export const TimedView = ({ poll }: { poll: HMSPoll }) => {
|
7
|
-
|
8
|
-
const
|
9
|
+
const localPeerId = useHMSStore(selectLocalPeerID);
|
10
|
+
const lastAttemptedIndex = getLastAttemptedIndex(poll.questions, localPeerId, '');
|
11
|
+
const [currentIndex, setCurrentIndex] = useState(lastAttemptedIndex);
|
9
12
|
const activeQuestion = poll.questions?.find(question => question.index === currentIndex);
|
13
|
+
const attemptedAll = poll.questions?.length === lastAttemptedIndex - 1;
|
10
14
|
|
11
|
-
if (!activeQuestion) {
|
15
|
+
if (!activeQuestion || !poll.questions?.length) {
|
12
16
|
return null;
|
13
17
|
}
|
14
18
|
|
15
19
|
return (
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
20
|
+
<>
|
21
|
+
{poll.questions.map(question => {
|
22
|
+
return attemptedAll || activeQuestion.index === question.index ? (
|
23
|
+
<QuestionCard
|
24
|
+
key={question.index}
|
25
|
+
pollID={poll.id}
|
26
|
+
isQuiz={poll.type === 'quiz'}
|
27
|
+
startedBy={poll.startedBy}
|
28
|
+
pollState={poll.state}
|
29
|
+
index={question.index}
|
30
|
+
text={question.text}
|
31
|
+
type={question.type}
|
32
|
+
result={question?.result}
|
33
|
+
totalQuestions={poll.questions?.length || 0}
|
34
|
+
options={question.options}
|
35
|
+
responses={question.responses}
|
36
|
+
answer={question.answer}
|
37
|
+
setCurrentIndex={setCurrentIndex}
|
38
|
+
rolesThatCanViewResponses={poll.rolesThatCanViewResponses}
|
39
|
+
/>
|
40
|
+
) : null;
|
41
|
+
})}
|
42
|
+
</>
|
32
43
|
);
|
33
44
|
};
|
@@ -68,7 +68,7 @@ export const Voting = ({ id, toggleVoting }: { id: string; toggleVoting: () => v
|
|
68
68
|
</Box>
|
69
69
|
</Flex>
|
70
70
|
|
71
|
-
<Flex direction="column" css={{ p: '$8 $10', overflowY: 'auto' }}>
|
71
|
+
<Flex direction="column" css={{ p: '$8 $10', flex: '1 1 0', overflowY: 'auto' }}>
|
72
72
|
{poll.state === 'started' ? (
|
73
73
|
<Text css={{ color: '$on_surface_medium', fontWeight: '$semiBold' }}>
|
74
74
|
{pollCreatorName || 'Participant'} started a {poll.type}
|
@@ -76,22 +76,21 @@ export const Voting = ({ id, toggleVoting }: { id: string; toggleVoting: () => v
|
|
76
76
|
) : null}
|
77
77
|
|
78
78
|
{showSingleView ? <TimedView poll={poll} /> : <StandardView poll={poll} />}
|
79
|
-
|
79
|
+
</Flex>
|
80
|
+
<Flex
|
81
|
+
css={{ w: '100%', justifyContent: 'end', alignItems: 'center', p: '$8', borderTop: '1px solid $border_bright' }}
|
82
|
+
>
|
80
83
|
{poll.state === 'started' && canEndActivity && (
|
81
84
|
<Button
|
82
85
|
variant="danger"
|
83
|
-
css={{ fontWeight: '$semiBold', w: 'max-content'
|
86
|
+
css={{ fontWeight: '$semiBold', w: 'max-content' }}
|
84
87
|
onClick={() => actions.interactivityCenter.stopPoll(id)}
|
85
88
|
>
|
86
89
|
End {poll.type}
|
87
90
|
</Button>
|
88
91
|
)}
|
89
|
-
|
90
92
|
{canViewLeaderboard ? (
|
91
|
-
<Button
|
92
|
-
css={{ fontWeight: '$semiBold', w: 'max-content', ml: 'auto', mt: '$8' }}
|
93
|
-
onClick={() => setPollView(POLL_VIEWS.RESULTS)}
|
94
|
-
>
|
93
|
+
<Button css={{ fontWeight: '$semiBold', w: 'max-content' }} onClick={() => setPollView(POLL_VIEWS.RESULTS)}>
|
95
94
|
View Leaderboard
|
96
95
|
</Button>
|
97
96
|
) : null}
|
@@ -52,7 +52,7 @@ export const MultipleChoiceOptions = ({
|
|
52
52
|
|
53
53
|
{isStopped && correctOptionIndexes?.includes(option.index) ? (
|
54
54
|
<Flex css={{ color: '$on_surface_high' }}>
|
55
|
-
<CheckCircleIcon />
|
55
|
+
<CheckCircleIcon height={20} width={20} />
|
56
56
|
</Flex>
|
57
57
|
) : null}
|
58
58
|
|
@@ -83,7 +83,7 @@ export const MultipleChoiceOptionInputs = ({ isQuiz, options, selectAnswer, hand
|
|
83
83
|
<Flex direction="column" css={{ gap: '$md', w: '100%', mb: '$md' }}>
|
84
84
|
{options.map((option, index) => {
|
85
85
|
return (
|
86
|
-
<Flex align="center" key={index} css={{ w: '100%', gap: '$
|
86
|
+
<Flex align="center" key={index} css={{ w: '100%', gap: '$4' }}>
|
87
87
|
{isQuiz && (
|
88
88
|
<Checkbox.Root
|
89
89
|
onCheckedChange={checked => selectAnswer(checked, index)}
|
@@ -17,14 +17,13 @@ export const SingleChoiceOptions = ({
|
|
17
17
|
isStopped,
|
18
18
|
isQuiz,
|
19
19
|
localPeerResponse,
|
20
|
-
answer,
|
21
20
|
}) => {
|
22
21
|
return (
|
23
|
-
<RadioGroup.Root value={
|
22
|
+
<RadioGroup.Root value={localPeerResponse?.option} onValueChange={value => setAnswer(value)}>
|
24
23
|
<Flex direction="column" css={{ gap: '$md', w: '100%', mb: '$md' }}>
|
25
24
|
{options.map(option => {
|
26
25
|
return (
|
27
|
-
<Flex align="start" key={`${questionIndex}-${option.index}`} css={{ w: '100%', gap: '$
|
26
|
+
<Flex align="start" key={`${questionIndex}-${option.index}`} css={{ w: '100%', gap: '$4' }}>
|
28
27
|
{!isStopped || !isQuiz ? (
|
29
28
|
<RadioGroup.Item
|
30
29
|
css={{
|
@@ -59,7 +58,7 @@ export const SingleChoiceOptions = ({
|
|
59
58
|
|
60
59
|
{isStopped && correctOptionIndex === option.index && isQuiz ? (
|
61
60
|
<Flex css={{ color: '$on_surface_high' }}>
|
62
|
-
<CheckCircleIcon />
|
61
|
+
<CheckCircleIcon height={20} width={20} />
|
63
62
|
</Flex>
|
64
63
|
) : null}
|
65
64
|
|
@@ -95,7 +94,7 @@ export const SingleChoiceOptionInputs = ({ isQuiz, options, selectAnswer, handle
|
|
95
94
|
<Flex direction="column" css={{ gap: '$md', w: '100%', mb: '$md' }}>
|
96
95
|
{options.map((option, index) => {
|
97
96
|
return (
|
98
|
-
<Flex align="center" key={`option-${index}`} css={{ w: '100%', gap: '$
|
97
|
+
<Flex align="center" key={`option-${index}`} css={{ w: '100%', gap: '$4' }}>
|
99
98
|
{isQuiz && (
|
100
99
|
<RadioGroup.Item
|
101
100
|
css={{
|
@@ -0,0 +1,16 @@
|
|
1
|
+
export const getFormattedTime = (milliseconds: number | undefined) => {
|
2
|
+
if (!milliseconds) return '-';
|
3
|
+
|
4
|
+
const totalSeconds = milliseconds / 1000;
|
5
|
+
const minutes = Math.floor(totalSeconds / 60);
|
6
|
+
const seconds = totalSeconds % 60;
|
7
|
+
|
8
|
+
let formattedSeconds = '';
|
9
|
+
if (Number.isInteger(seconds) || minutes) {
|
10
|
+
formattedSeconds = seconds.toFixed(0);
|
11
|
+
} else {
|
12
|
+
formattedSeconds = seconds.toFixed(1);
|
13
|
+
}
|
14
|
+
|
15
|
+
return `${minutes ? `${minutes}m ` : ''}${formattedSeconds}s`;
|
16
|
+
};
|
File without changes
|