@100mslive/roomkit-react 0.2.2-alpha.2 → 0.2.2-alpha.4

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.
Files changed (37) hide show
  1. package/dist/{HLSView-DJGDJPXM.js → HLSView-DPM6YJWZ.js} +19 -4
  2. package/dist/HLSView-DPM6YJWZ.js.map +7 -0
  3. package/dist/Prebuilt/components/Polls/Voting/LeaderboardEntry.d.ts +2 -1
  4. package/dist/Prebuilt/components/RoleChangeRequest/RequestPrompt.d.ts +2 -1
  5. package/dist/Prebuilt/components/VirtualBackground/VBHandler.d.ts +1 -0
  6. package/dist/{chunk-ERKB3GGI.js → chunk-S5NNUR2M.js} +230 -194
  7. package/dist/{chunk-ERKB3GGI.js.map → chunk-S5NNUR2M.js.map} +3 -3
  8. package/dist/index.cjs.js +189 -135
  9. package/dist/index.cjs.js.map +3 -3
  10. package/dist/index.js +1 -1
  11. package/dist/meta.cjs.json +46 -46
  12. package/dist/meta.esbuild.json +56 -56
  13. package/package.json +6 -6
  14. package/src/Button/Button.tsx +2 -2
  15. package/src/Prebuilt/components/Notifications/Notifications.tsx +14 -1
  16. package/src/Prebuilt/components/Notifications/PermissionErrorModal.tsx +8 -1
  17. package/src/Prebuilt/components/Polls/CreatePollQuiz/PollsQuizMenu.jsx +3 -4
  18. package/src/Prebuilt/components/Polls/Voting/LeaderboardEntry.tsx +17 -5
  19. package/src/Prebuilt/components/Polls/Voting/LeaderboardSummary.tsx +1 -0
  20. package/src/Prebuilt/components/Polls/Voting/PeerParticipationSummary.tsx +5 -3
  21. package/src/Prebuilt/components/Polls/Voting/QuestionCard.jsx +41 -83
  22. package/src/Prebuilt/components/Polls/Voting/StandardVoting.tsx +0 -1
  23. package/src/Prebuilt/components/Polls/Voting/TimedVoting.tsx +2 -3
  24. package/src/Prebuilt/components/Polls/Voting/Voting.tsx +7 -6
  25. package/src/Prebuilt/components/Polls/common/MultipleChoiceOptions.jsx +1 -2
  26. package/src/Prebuilt/components/Polls/common/SingleChoiceOptions.jsx +6 -4
  27. package/src/Prebuilt/components/Polls/common/StatusIndicator.tsx +1 -1
  28. package/src/Prebuilt/components/Preview/PreviewJoin.tsx +4 -14
  29. package/src/Prebuilt/components/RoleChangeRequest/RequestPrompt.tsx +15 -5
  30. package/src/Prebuilt/components/RoleChangeRequest/RoleChangeRequestModal.tsx +3 -0
  31. package/src/Prebuilt/components/TileMenu/TileMenuContent.tsx +6 -1
  32. package/src/Prebuilt/components/VirtualBackground/VBHandler.tsx +11 -1
  33. package/src/Prebuilt/components/VirtualBackground/VBPicker.tsx +16 -2
  34. package/src/Prebuilt/layouts/HLSView.jsx +16 -1
  35. package/src/Sheet/Sheet.tsx +1 -1
  36. package/dist/HLSView-DJGDJPXM.js.map +0 -7
  37. package/src/Prebuilt/images/first_person.png +0 -0
@@ -1,14 +1,8 @@
1
1
  // @ts-check
2
- import React, { useCallback, useMemo, useState } from 'react';
2
+ import React, { useCallback, useMemo, useRef, useState } from 'react';
3
3
  import { selectLocalPeer, selectLocalPeerRoleName, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
4
- import {
5
- CheckCircleIcon,
6
- ChevronDownIcon,
7
- ChevronLeftIcon,
8
- ChevronRightIcon,
9
- CrossCircleIcon,
10
- } from '@100mslive/react-icons';
11
- import { Box, Button, Flex, IconButton, Text } from '../../../../';
4
+ import { CheckCircleIcon, ChevronDownIcon, CrossCircleIcon } from '@100mslive/react-icons';
5
+ import { Box, Button, Flex, Text } from '../../../../';
12
6
  import { checkCorrectAnswer } from '../../../common/utils';
13
7
  import { MultipleChoiceOptions } from '../common/MultipleChoiceOptions';
14
8
  import { SingleChoiceOptions } from '../common/SingleChoiceOptions';
@@ -27,9 +21,7 @@ export const QuestionCard = ({
27
21
  options = [],
28
22
  answer,
29
23
  setCurrentIndex,
30
- skippable = false,
31
24
  responses = [],
32
- isTimed = false,
33
25
  rolesThatCanViewResponses,
34
26
  }) => {
35
27
  const actions = useHMSActions();
@@ -37,6 +29,7 @@ export const QuestionCard = ({
37
29
  const localPeerResponse = responses?.find(
38
30
  response => response.peer?.peerid === localPeer?.id || response.peer?.userid === localPeer?.customerUserId,
39
31
  );
32
+
40
33
  const isLocalPeerCreator = localPeer?.id === startedBy;
41
34
  const localPeerRoleName = useHMSStore(selectLocalPeerRoleName);
42
35
  const roleCanViewResponse =
@@ -47,28 +40,15 @@ export const QuestionCard = ({
47
40
  roleCanViewResponse && (localPeerResponse || (isLocalPeerCreator && pollState === 'stopped')) && !isQuiz;
48
41
 
49
42
  const isLive = pollState === 'started';
43
+ const pollEnded = pollState === 'stopped';
50
44
  const canRespond = isLive && !localPeerResponse;
51
-
45
+ const startTime = useRef(Date.now());
52
46
  const isCorrectAnswer = checkCorrectAnswer(answer, localPeerResponse, type);
53
47
 
54
- const prev = index !== 1;
55
- const next = index !== totalQuestions && (skippable || localPeerResponse);
56
-
57
- const moveNext = useCallback(() => {
58
- setCurrentIndex(curr => Math.min(totalQuestions, curr + 1));
59
- }, [setCurrentIndex, totalQuestions]);
60
-
61
- const movePrev = () => {
62
- setCurrentIndex(curr => Math.max(1, curr - 1));
63
- };
64
-
65
- // const [textAnswer, setTextAnswer] = useState('');
66
48
  const [singleOptionAnswer, setSingleOptionAnswer] = useState();
67
49
  const [multipleOptionAnswer, setMultipleOptionAnswer] = useState(new Set());
68
50
  const [showOptions, setShowOptions] = useState(true);
69
51
 
70
- // const stringAnswerExpected = [QUESTION_TYPE.LONG_ANSWER, QUESTION_TYPE.SHORT_ANSWER].includes(type);
71
-
72
52
  const respondedToQuiz = isQuiz && localPeerResponse && !localPeerResponse.skipped;
73
53
 
74
54
  const isValidVote = useMemo(() => {
@@ -83,24 +63,31 @@ export const QuestionCard = ({
83
63
  if (!isValidVote) {
84
64
  return;
85
65
  }
66
+
86
67
  await actions.interactivityCenter.addResponsesToPoll(pollID, [
87
68
  {
88
69
  questionIndex: index,
89
70
  option: singleOptionAnswer,
90
71
  options: Array.from(multipleOptionAnswer),
72
+ duration: Date.now() - startTime.current,
91
73
  },
92
74
  ]);
93
- }, [actions, index, pollID, isValidVote, singleOptionAnswer, multipleOptionAnswer]);
75
+ startTime.current = Date.now();
94
76
 
95
- const handleSkip = useCallback(async () => {
96
- await actions.interactivityCenter.addResponsesToPoll(pollID, [
97
- {
98
- questionIndex: index,
99
- skipped: true,
100
- },
101
- ]);
102
- moveNext();
103
- }, [actions, index, pollID, moveNext]);
77
+ if (isQuiz && index !== totalQuestions) {
78
+ setSingleOptionAnswer(undefined);
79
+ setMultipleOptionAnswer(new Set());
80
+ }
81
+ }, [
82
+ isValidVote,
83
+ actions.interactivityCenter,
84
+ pollID,
85
+ index,
86
+ singleOptionAnswer,
87
+ multipleOptionAnswer,
88
+ totalQuestions,
89
+ isQuiz,
90
+ ]);
104
91
 
105
92
  return (
106
93
  <Box
@@ -131,43 +118,10 @@ export const QuestionCard = ({
131
118
  gap: '$4',
132
119
  }}
133
120
  >
134
- {respondedToQuiz && isCorrectAnswer ? <CheckCircleIcon height={20} width={20} /> : null}
135
- {respondedToQuiz && !isCorrectAnswer ? <CrossCircleIcon height={20} width={20} /> : null}
121
+ {respondedToQuiz && isCorrectAnswer && pollEnded ? <CheckCircleIcon height={20} width={20} /> : null}
122
+ {respondedToQuiz && !isCorrectAnswer && pollEnded ? <CrossCircleIcon height={20} width={20} /> : null}
136
123
  QUESTION {index} OF {totalQuestions}: {type.toUpperCase()}
137
124
  </Text>
138
-
139
- {isTimed ? (
140
- <Flex align="center" css={{ gap: '$4' }}>
141
- <IconButton
142
- disabled={!prev}
143
- onClick={movePrev}
144
- css={
145
- prev
146
- ? { color: '$on_surface_high', cursor: 'pointer' }
147
- : {
148
- color: '$on_surface_low',
149
- cursor: 'not-allowed',
150
- }
151
- }
152
- >
153
- <ChevronLeftIcon height={16} width={16} />
154
- </IconButton>
155
- <IconButton
156
- disabled={!next}
157
- onClick={moveNext}
158
- css={
159
- next
160
- ? { color: '$on_surface_high', cursor: 'pointer' }
161
- : {
162
- color: '$on_surface_low',
163
- cursor: 'not-allowed',
164
- }
165
- }
166
- >
167
- <ChevronRightIcon height={16} width={16} />
168
- </IconButton>
169
- </Flex>
170
- ) : null}
171
125
  </Flex>
172
126
 
173
127
  <Flex justify="between" css={{ my: '$md' }}>
@@ -185,10 +139,10 @@ export const QuestionCard = ({
185
139
  <Box css={{ maxHeight: showOptions ? '$80' : '0', transition: 'max-height 0.3s ease', overflowY: 'hidden' }}>
186
140
  {type === QUESTION_TYPE.SINGLE_CHOICE ? (
187
141
  <SingleChoiceOptions
142
+ key={index}
188
143
  questionIndex={index}
189
144
  isQuiz={isQuiz}
190
145
  canRespond={canRespond}
191
- response={localPeerResponse}
192
146
  correctOptionIndex={answer?.option}
193
147
  options={options}
194
148
  setAnswer={setSingleOptionAnswer}
@@ -196,14 +150,15 @@ export const QuestionCard = ({
196
150
  showVoteCount={showVoteCount}
197
151
  localPeerResponse={localPeerResponse}
198
152
  isStopped={pollState === 'stopped'}
153
+ answer={singleOptionAnswer}
199
154
  />
200
155
  ) : null}
156
+
201
157
  {type === QUESTION_TYPE.MULTIPLE_CHOICE ? (
202
158
  <MultipleChoiceOptions
203
159
  questionIndex={index}
204
160
  isQuiz={isQuiz}
205
161
  canRespond={canRespond}
206
- response={localPeerResponse}
207
162
  correctOptionIndexes={answer?.options}
208
163
  options={options}
209
164
  selectedOptions={multipleOptionAnswer}
@@ -214,14 +169,16 @@ export const QuestionCard = ({
214
169
  isStopped={pollState === 'stopped'}
215
170
  />
216
171
  ) : null}
172
+
217
173
  {isLive && (
218
174
  <QuestionActions
219
175
  isValidVote={isValidVote}
220
- skippable={skippable}
221
- onSkip={handleSkip}
222
176
  onVote={handleVote}
223
177
  response={localPeerResponse}
224
178
  isQuiz={isQuiz}
179
+ incrementIndex={() => {
180
+ setCurrentIndex(curr => Math.min(totalQuestions, curr + 1));
181
+ }}
225
182
  />
226
183
  )}
227
184
  </Box>
@@ -229,15 +186,9 @@ export const QuestionCard = ({
229
186
  );
230
187
  };
231
188
 
232
- const QuestionActions = ({ isValidVote, skippable, response, isQuiz, onVote, onSkip }) => {
189
+ const QuestionActions = ({ isValidVote, response, isQuiz, onVote, incrementIndex }) => {
233
190
  return (
234
191
  <Flex align="center" justify="end" css={{ gap: '$4', w: '100%' }}>
235
- {skippable && !response ? (
236
- <Button variant="standard" onClick={onSkip} css={{ p: '$xs $10', fontWeight: '$semiBold' }}>
237
- Skip
238
- </Button>
239
- ) : null}
240
-
241
192
  {response ? (
242
193
  <Text css={{ fontWeight: '$semiBold', color: '$on_surface_medium' }}>
243
194
  {response.skipped ? 'Skipped' : null}
@@ -245,7 +196,14 @@ const QuestionActions = ({ isValidVote, skippable, response, isQuiz, onVote, onS
245
196
  {!isQuiz && !response.skipped ? 'Voted' : null}
246
197
  </Text>
247
198
  ) : (
248
- <Button css={{ p: '$xs $10', fontWeight: '$semiBold' }} disabled={!isValidVote} onClick={onVote}>
199
+ <Button
200
+ css={{ p: '$xs $10', fontWeight: '$semiBold' }}
201
+ disabled={!isValidVote}
202
+ onClick={() => {
203
+ onVote();
204
+ incrementIndex();
205
+ }}
206
+ >
249
207
  {isQuiz ? 'Answer' : 'Vote'}
250
208
  </Button>
251
209
  )}
@@ -28,7 +28,6 @@ export const StandardView = ({ poll }: { poll: HMSPoll }) => {
28
28
  result={question.result}
29
29
  totalQuestions={poll.questions?.length || 0}
30
30
  options={question.options}
31
- skippable={question.skippable}
32
31
  responses={question.responses}
33
32
  answer={question.answer}
34
33
  setCurrentIndex={() => {
@@ -4,9 +4,10 @@ import { HMSPoll } from '@100mslive/react-sdk';
4
4
  import { QuestionCard } from './QuestionCard';
5
5
 
6
6
  export const TimedView = ({ poll }: { poll: HMSPoll }) => {
7
- // backend question index starts at 1
7
+ // Backend question index starts at 1
8
8
  const [currentIndex, setCurrentIndex] = useState(1);
9
9
  const activeQuestion = poll.questions?.find(question => question.index === currentIndex);
10
+
10
11
  if (!activeQuestion) {
11
12
  return null;
12
13
  }
@@ -23,12 +24,10 @@ export const TimedView = ({ poll }: { poll: HMSPoll }) => {
23
24
  result={activeQuestion?.result}
24
25
  totalQuestions={poll.questions?.length || 0}
25
26
  options={activeQuestion.options}
26
- skippable={activeQuestion.skippable || false}
27
27
  responses={activeQuestion.responses}
28
28
  answer={activeQuestion.answer}
29
29
  setCurrentIndex={setCurrentIndex}
30
30
  rolesThatCanViewResponses={poll.rolesThatCanViewResponses}
31
- isTimed
32
31
  />
33
32
  );
34
33
  };
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import {
3
- selectLocalPeerID,
4
3
  selectPeerNameByID,
4
+ selectPermissions,
5
5
  selectPollByID,
6
6
  useHMSActions,
7
7
  useHMSStore,
@@ -21,8 +21,11 @@ export const Voting = ({ id, toggleVoting }: { id: string; toggleVoting: () => v
21
21
  const actions = useHMSActions();
22
22
  const poll = useHMSStore(selectPollByID(id));
23
23
  const pollCreatorName = useHMSStore(selectPeerNameByID(poll?.createdBy));
24
- const isLocalPeerCreator = useHMSStore(selectLocalPeerID) === poll?.createdBy;
24
+ const permissions = useHMSStore(selectPermissions);
25
+ const canEndActivity = !!permissions?.pollWrite;
25
26
  const { setPollView } = usePollViewState();
27
+ // Sets view - linear or vertical, toggles timer indicator
28
+ const showSingleView = poll?.type === 'quiz' && poll.state === 'started';
26
29
 
27
30
  if (!poll) {
28
31
  return null;
@@ -30,8 +33,6 @@ export const Voting = ({ id, toggleVoting }: { id: string; toggleVoting: () => v
30
33
 
31
34
  const canViewLeaderboard = poll.type === 'quiz' && poll.state === 'stopped' && !poll.anonymous;
32
35
 
33
- // Sets view - linear or vertical, toggles timer indicator
34
- const isTimed = (poll.duration || 0) > 0;
35
36
  const isLive = poll.state === 'started';
36
37
 
37
38
  return (
@@ -74,9 +75,9 @@ export const Voting = ({ id, toggleVoting }: { id: string; toggleVoting: () => v
74
75
  </Text>
75
76
  ) : null}
76
77
 
77
- {isTimed ? <TimedView poll={poll} /> : <StandardView poll={poll} />}
78
+ {showSingleView ? <TimedView poll={poll} /> : <StandardView poll={poll} />}
78
79
 
79
- {poll.state === 'started' && isLocalPeerCreator && (
80
+ {poll.state === 'started' && canEndActivity && (
80
81
  <Button
81
82
  variant="danger"
82
83
  css={{ fontWeight: '$semiBold', w: 'max-content', ml: 'auto', mt: '$8' }}
@@ -10,7 +10,6 @@ export const MultipleChoiceOptions = ({
10
10
  questionIndex,
11
11
  options,
12
12
  canRespond,
13
- response,
14
13
  totalResponses,
15
14
  selectedOptions,
16
15
  setSelectedOptions,
@@ -39,7 +38,7 @@ export const MultipleChoiceOptions = ({
39
38
  <Checkbox.Root
40
39
  id={`${questionIndex}-${option.index}`}
41
40
  disabled={!canRespond}
42
- checked={response?.options?.includes(option.index)}
41
+ checked={localPeerResponse?.options?.includes(option.index)}
43
42
  onCheckedChange={checked => handleCheckedChange(checked, option.index)}
44
43
  css={{
45
44
  cursor: canRespond ? 'pointer' : 'not-allowed',
@@ -9,7 +9,6 @@ import { VoteProgress } from './VoteProgress';
9
9
  export const SingleChoiceOptions = ({
10
10
  questionIndex,
11
11
  options,
12
- response,
13
12
  canRespond,
14
13
  setAnswer,
15
14
  totalResponses,
@@ -18,9 +17,10 @@ export const SingleChoiceOptions = ({
18
17
  isStopped,
19
18
  isQuiz,
20
19
  localPeerResponse,
20
+ answer,
21
21
  }) => {
22
22
  return (
23
- <RadioGroup.Root value={response?.option} onValueChange={value => setAnswer(value)}>
23
+ <RadioGroup.Root value={answer || null} onValueChange={value => setAnswer(value)}>
24
24
  <Flex direction="column" css={{ gap: '$md', w: '100%', mb: '$md' }}>
25
25
  {options.map(option => {
26
26
  return (
@@ -65,8 +65,10 @@ export const SingleChoiceOptions = ({
65
65
 
66
66
  <Flex direction="column" css={{ flexGrow: '1' }}>
67
67
  <Flex css={{ w: '100%' }}>
68
- <Text css={{ display: 'flex', flexGrow: '1' }}>
69
- <Label htmlFor={`${questionIndex}-${option.index}`}>{option.text}</Label>
68
+ <Text css={{ display: 'flex', flexGrow: '1', color: '$on_surface_high' }}>
69
+ <Label style={{ color: 'inherit' }} htmlFor={`${questionIndex}-${option.index}`}>
70
+ {option.text}
71
+ </Label>
70
72
  </Text>
71
73
  {showVoteCount && <VoteCount voteCount={option.voteCount} />}
72
74
  </Flex>
@@ -15,7 +15,7 @@ export const StatusIndicator = ({ isLive }: { isLive: boolean }) => {
15
15
  variant="caption"
16
16
  css={{
17
17
  fontWeight: '$semiBold',
18
- color: '$on_surface_high',
18
+ color: '$on_primary_high',
19
19
  }}
20
20
  >
21
21
  {isLive ? 'LIVE' : 'ENDED'}
@@ -160,20 +160,7 @@ const PreviewJoin = ({
160
160
  <Chip content={getParticipantChipContent(peerCount)} hideIfNoContent />
161
161
  </Flex>
162
162
  </Flex>
163
- {toggleVideo ? (
164
- <Flex
165
- align="center"
166
- justify="center"
167
- css={{
168
- mt: '$14',
169
- '@md': { mt: 0 },
170
- '@sm': { width: '100%' },
171
- flexDirection: 'column',
172
- }}
173
- >
174
- <PreviewTile name={name} error={previewError} />
175
- </Flex>
176
- ) : null}
163
+ {toggleVideo ? <PreviewTile name={name} error={previewError} /> : null}
177
164
  <Box css={{ w: '100%', maxWidth: `${Math.max(aspectRatio, 1) * 360}px` }}>
178
165
  <PreviewControls hideSettings={!toggleVideo && !toggleAudio} vbEnabled={!!virtual_background} />
179
166
  <PreviewForm
@@ -225,9 +212,12 @@ export const PreviewTile = ({ name, error }: { name: string; error?: boolean })
225
212
  bg: '$surface_default',
226
213
  aspectRatio,
227
214
  height: 'min(360px, 70vh)',
215
+ width: 'auto',
228
216
  maxWidth: '640px',
229
217
  overflow: 'clip',
218
+ mt: '$14',
230
219
  '@md': {
220
+ mt: 0,
231
221
  width: 'min(220px, 70vw)',
232
222
  maxWidth: '100%',
233
223
  my: '$4',
@@ -10,6 +10,7 @@ export const RequestPrompt = ({
10
10
  body,
11
11
  actionText = 'Accept',
12
12
  onAction,
13
+ disableActions = false,
13
14
  }: {
14
15
  open?: boolean;
15
16
  onOpenChange: (value: boolean) => void;
@@ -17,6 +18,7 @@ export const RequestPrompt = ({
17
18
  body: React.ReactNode;
18
19
  actionText?: string;
19
20
  onAction: () => void;
21
+ disableActions?: boolean;
20
22
  }) => {
21
23
  const isMobile = useMedia(cssConfig.media.md);
22
24
 
@@ -26,7 +28,7 @@ export const RequestPrompt = ({
26
28
  <Sheet.Content css={{ py: '$8' }}>
27
29
  <Text css={{ fontWeight: '$semiBold', c: '$on_surface_high', '@md': { px: '$8' } }}>{title}</Text>
28
30
  {body}
29
- <RequestActions actionText={actionText} onAction={onAction} />
31
+ <RequestActions actionText={actionText} onAction={onAction} disabled={disableActions} />
30
32
  </Sheet.Content>
31
33
  </Sheet.Root>
32
34
  );
@@ -40,24 +42,32 @@ export const RequestPrompt = ({
40
42
  <Text variant="h6">{title}</Text>
41
43
  </Dialog.Title>
42
44
  <Box css={{ mt: '$4', mb: '$10' }}>{body}</Box>
43
- <RequestActions actionText={actionText} onAction={onAction} />
45
+ <RequestActions actionText={actionText} onAction={onAction} disabled={disableActions} />
44
46
  </Dialog.Content>
45
47
  </Dialog.Portal>
46
48
  </Dialog.Root>
47
49
  );
48
50
  };
49
51
 
50
- const RequestActions = ({ onAction, actionText }: { actionText?: string; onAction: () => void }) => (
52
+ const RequestActions = ({
53
+ onAction,
54
+ actionText,
55
+ disabled = false,
56
+ }: {
57
+ actionText?: string;
58
+ onAction: () => void;
59
+ disabled?: boolean;
60
+ }) => (
51
61
  <Flex justify="center" align="center" css={{ width: '100%', gap: '$md', '@md': { mt: '$8', px: '$8' } }}>
52
62
  <Box css={{ width: '50%' }}>
53
63
  <Dialog.Close css={{ width: '100%' }}>
54
- <Button variant="standard" outlined css={{ width: '100%' }}>
64
+ <Button variant="standard" outlined css={{ width: '100%' }} disabled={disabled}>
55
65
  Decline
56
66
  </Button>
57
67
  </Dialog.Close>
58
68
  </Box>
59
69
  <Box css={{ width: '50%' }}>
60
- <Button variant="primary" css={{ width: '100%' }} onClick={onAction}>
70
+ <Button variant="primary" css={{ width: '100%' }} onClick={onAction} disabled={disabled}>
61
71
  {actionText}
62
72
  </Button>
63
73
  </Box>
@@ -1,5 +1,6 @@
1
1
  import React, { useEffect } from 'react';
2
2
  import {
3
+ selectIsInPreview,
3
4
  selectLocalPeerName,
4
5
  selectLocalPeerRoleName,
5
6
  selectRoleChangeRequest,
@@ -20,6 +21,7 @@ import { ROLE_CHANGE_DECLINED } from '../../common/constants';
20
21
  export const RoleChangeRequestModal = () => {
21
22
  const hmsActions = useHMSActions();
22
23
  const { updateMetaData } = useMyMetadata();
24
+ const isPreview = useHMSStore(selectIsInPreview);
23
25
  const currentRole = useHMSStore(selectLocalPeerRoleName);
24
26
  const roleChangeRequest = useHMSStore(selectRoleChangeRequest);
25
27
  const name = useHMSStore(selectLocalPeerName);
@@ -87,6 +89,7 @@ export const RoleChangeRequestModal = () => {
87
89
  await hmsActions.lowerLocalPeerHand();
88
90
  }}
89
91
  actionText="Accept"
92
+ disableActions={!isPreview}
90
93
  />
91
94
  );
92
95
  };
@@ -314,7 +314,12 @@ export const TileMenuContent = ({
314
314
  Volume ({volume})
315
315
  </Box>
316
316
  </Flex>
317
- <Slider css={{ my: '0.5rem' }} step={5} value={[volume || 100]} onValueChange={e => setVolume?.(e[0])} />
317
+ <Slider
318
+ css={{ my: '0.5rem' }}
319
+ step={5}
320
+ value={[typeof volume === 'number' ? volume : 100]}
321
+ onValueChange={e => setVolume?.(e[0])}
322
+ />
318
323
  </StyledMenuTile.VolumeItem>
319
324
  ) : null}
320
325
 
@@ -19,8 +19,18 @@ export class VBPlugin {
19
19
  if (this.effectsPlugin) {
20
20
  return this.effectsPlugin?.getBackground();
21
21
  } else {
22
+ const background = this.hmsPlugin?.getBackground();
22
23
  // @ts-ignore
23
- return this.hmsPlugin?.background?.src || this.hmsPlugin?.background;
24
+ return background?.src || background;
25
+ }
26
+ };
27
+
28
+ getBlurAmount = () => {
29
+ if (this.effectsPlugin) {
30
+ return this.effectsPlugin.getBlurAmount();
31
+ } else {
32
+ // Treating HMS VB intensity as a fixed value
33
+ return this.hmsPlugin?.getBackground() === HMSVirtualBackgroundTypes.BLUR ? 1 : 0;
24
34
  }
25
35
  };
26
36
 
@@ -14,7 +14,7 @@ import {
14
14
  useHMSStore,
15
15
  } from '@100mslive/react-sdk';
16
16
  import { BlurPersonHighIcon, CloseIcon, CrossCircleIcon } from '@100mslive/react-icons';
17
- import { Box, Flex, Video } from '../../../index';
17
+ import { Box, Flex, Slider, Video } from '../../../index';
18
18
  import { Text } from '../../../Text';
19
19
  import { VBCollection } from './VBCollection';
20
20
  import { VBHandler } from './VBHandler';
@@ -36,6 +36,7 @@ export const VBPicker = ({ backgroundMedia = [] }: { backgroundMedia: VirtualBac
36
36
  const mirrorLocalVideo = useUISettings(UI_SETTINGS.mirrorLocalVideo);
37
37
  const trackSelector = selectVideoTrackByID(localPeer?.videoTrack);
38
38
  const track = useHMSStore(trackSelector);
39
+ const [blurAmount, setBlurAmount] = useState(VBHandler.getBlurAmount() || 0.5);
39
40
  const roomState = useHMSStore(selectRoomState);
40
41
  const isLargeRoom = useHMSStore(selectIsLargeRoom);
41
42
  const isEffectsEnabled = useHMSStore(selectIsEffectsEnabled);
@@ -127,7 +128,7 @@ export const VBPicker = ({ backgroundMedia = [] }: { backgroundMedia: VirtualBac
127
128
  icon: <BlurPersonHighIcon style={iconDims} />,
128
129
  value: HMSVirtualBackgroundTypes.BLUR,
129
130
  onClick: async () => {
130
- await VBHandler?.setBlur(0.5);
131
+ await VBHandler?.setBlur(blurAmount);
131
132
  setActiveBackground(HMSVirtualBackgroundTypes.BLUR);
132
133
  },
133
134
  },
@@ -135,6 +136,19 @@ export const VBPicker = ({ backgroundMedia = [] }: { backgroundMedia: VirtualBac
135
136
  activeBackground={activeBackground}
136
137
  />
137
138
 
139
+ {activeBackground === HMSVirtualBackgroundTypes.BLUR && isEffectsEnabled && effectsKey ? (
140
+ <Slider
141
+ value={[blurAmount]}
142
+ onValueChange={async e => {
143
+ setBlurAmount(e[0]);
144
+ await VBHandler.setBlur(e[0]);
145
+ }}
146
+ step={0.1}
147
+ min={0.1}
148
+ max={1}
149
+ />
150
+ ) : null}
151
+
138
152
  <VBCollection
139
153
  title="Backgrounds"
140
154
  options={mediaList.map(mediaURL => ({
@@ -3,11 +3,13 @@ import { useFullscreen, useMedia, usePrevious, useToggle } from 'react-use';
3
3
  import { HLSPlaybackState, HMSHLSPlayer, HMSHLSPlayerEvents } from '@100mslive/hls-player';
4
4
  import screenfull from 'screenfull';
5
5
  import {
6
+ HMSNotificationTypes,
6
7
  selectAppData,
7
8
  selectHLSState,
8
9
  selectPeerNameByID,
9
10
  selectPollByID,
10
11
  useHMSActions,
12
+ useHMSNotifications,
11
13
  useHMSStore,
12
14
  useHMSVanillaStore,
13
15
  } from '@100mslive/react-sdk';
@@ -30,12 +32,14 @@ import { usePollViewToggle } from '../components/AppData/useSidepane';
30
32
  import { APP_DATA, EMOJI_REACTION_TYPE } from '../common/constants';
31
33
 
32
34
  let hlsPlayer;
35
+ const toastMap = {};
33
36
 
34
37
  const HLSView = () => {
35
38
  const videoRef = useRef(null);
36
39
  const hlsViewRef = useRef(null);
37
40
  const hlsState = useHMSStore(selectHLSState);
38
41
  const enablHlsStats = useHMSStore(selectAppData(APP_DATA.hlsStats));
42
+ const notification = useHMSNotifications(HMSNotificationTypes.POLL_STOPPED);
39
43
  const hmsActions = useHMSActions();
40
44
  const { themeType, theme } = useTheme();
41
45
  const [streamEnded, setStreamEnded] = useState(false);
@@ -85,6 +89,15 @@ const HLSView = () => {
85
89
  }
86
90
  }, [hlsUrl, streamEnded, lastHlsUrl]);
87
91
 
92
+ useEffect(() => {
93
+ if (!notification) return;
94
+ const toastID = toastMap?.[notification.data.id];
95
+ if (toastID) {
96
+ ToastManager.removeToast(toastMap[notification.data.id]);
97
+ delete toastMap[notification.data.id];
98
+ }
99
+ }, [notification]);
100
+
88
101
  useEffect(() => {
89
102
  const videoElem = videoRef.current;
90
103
  const setStreamEndedCallback = () => {
@@ -126,7 +139,7 @@ const HLSView = () => {
126
139
  const poll = vanillaStore.getState(selectPollByID(pollId));
127
140
  const pollStartedBy = vanillaStore.getState(selectPeerNameByID(poll.startedBy)) || 'Participant';
128
141
  // launch poll
129
- ToastManager.addToast({
142
+ const toastID = ToastManager.addToast({
130
143
  title: `${pollStartedBy} started a ${poll.type}: ${poll.title}`,
131
144
  action: (
132
145
  <Button
@@ -142,7 +155,9 @@ const HLSView = () => {
142
155
  {poll.type === 'quiz' ? 'Answer' : 'Vote'}
143
156
  </Button>
144
157
  ),
158
+ duration: Infinity,
145
159
  });
160
+ toastMap[pollId] = toastID;
146
161
  return;
147
162
  }
148
163
  switch (parsedPayload.type) {
@@ -35,7 +35,7 @@ const StyledContent = styled(DialogPrimitive.Content, {
35
35
  borderTopRightRadius: '$3',
36
36
  boxShadow: '0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23)',
37
37
  position: 'fixed',
38
- zIndex: 1001,
38
+ zIndex: 22,
39
39
  top: 0,
40
40
  right: 0,
41
41
  left: 0,