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

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. package/dist/{HLSView-UXA322ED.css → HLSView-IQOQUTLY.css} +3 -3
  2. package/dist/{HLSView-UXA322ED.css.map → HLSView-IQOQUTLY.css.map} +1 -1
  3. package/dist/{HLSView-BRZ2FW7O.js → HLSView-LMQPPX5V.js} +2 -2
  4. package/dist/Prebuilt/components/EndCallFeedback/Feedback.d.ts +2 -0
  5. package/dist/Prebuilt/components/EndCallFeedback/FeedbackForm.d.ts +28 -0
  6. package/dist/Prebuilt/components/EndCallFeedback/ThankyouView.d.ts +2 -0
  7. package/dist/Prebuilt/provider/roomLayoutProvider/hooks/useRoomLayoutScreen.d.ts +1 -0
  8. package/dist/{chunk-KR2DZJO5.js → chunk-FZNVIKYB.js} +1063 -559
  9. package/dist/chunk-FZNVIKYB.js.map +7 -0
  10. package/dist/index.cjs.css +2 -2
  11. package/dist/index.cjs.css.map +1 -1
  12. package/dist/index.cjs.js +1302 -764
  13. package/dist/index.cjs.js.map +4 -4
  14. package/dist/index.css +2 -2
  15. package/dist/index.css.map +1 -1
  16. package/dist/index.js +1 -1
  17. package/dist/meta.cjs.json +269 -27
  18. package/dist/meta.esbuild.json +279 -37
  19. package/package.json +8 -8
  20. package/src/Prebuilt/App.tsx +3 -0
  21. package/src/Prebuilt/AppStateContext.tsx +1 -2
  22. package/src/Prebuilt/Prebuilt.stories.tsx +1 -0
  23. package/src/Prebuilt/components/EndCallFeedback/Feedback.tsx +70 -0
  24. package/src/Prebuilt/components/EndCallFeedback/FeedbackForm.tsx +371 -0
  25. package/src/Prebuilt/components/EndCallFeedback/ThankyouView.tsx +44 -0
  26. package/src/Prebuilt/components/LeaveScreen.tsx +2 -0
  27. package/src/Prebuilt/provider/roomLayoutProvider/hooks/useRoomLayoutScreen.ts +1 -0
  28. package/dist/chunk-KR2DZJO5.js.map +0 -7
  29. /package/dist/{HLSView-BRZ2FW7O.js.map → HLSView-LMQPPX5V.js.map} +0 -0
@@ -0,0 +1,70 @@
1
+ import React, { useState } from 'react';
2
+ import { useMedia } from 'react-use';
3
+ import { Flex } from '../../../Layout';
4
+ import { config as cssConfig } from '../../../Theme';
5
+ import { FEEBACK_INDEX, FeedbackHeader, FeedbackModal } from './FeedbackForm';
6
+ import { ThankyouView } from './ThankyouView';
7
+ import { useRoomLayoutLeaveScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
8
+
9
+ export const Feedback = () => {
10
+ const { feedback } = useRoomLayoutLeaveScreen();
11
+ const [index, setIndex] = useState(FEEBACK_INDEX.INIT);
12
+ const isMobile = useMedia(cssConfig.media.md);
13
+
14
+ if (!feedback) {
15
+ return null;
16
+ }
17
+ const { ratings } = feedback;
18
+ if (!ratings) {
19
+ return null;
20
+ }
21
+ ratings.sort((a, b) => {
22
+ if (!a.value || !b.value) {
23
+ return 0;
24
+ }
25
+ return a.value - b.value;
26
+ });
27
+ // TO show thank ypu page
28
+ if (index === FEEBACK_INDEX.THANK_YOU) {
29
+ return (
30
+ <Flex
31
+ justify="center"
32
+ css={{
33
+ pt: '$16',
34
+ }}
35
+ >
36
+ <ThankyouView />
37
+ </Flex>
38
+ );
39
+ }
40
+ return (
41
+ <Flex
42
+ justify="center"
43
+ css={{
44
+ pt: '$16',
45
+ w: '528px',
46
+ }}
47
+ >
48
+ {index === FEEBACK_INDEX.INIT ? (
49
+ <Flex
50
+ css={{
51
+ p: '$12',
52
+ border: '1px solid $border_default',
53
+ bg: '$surface_dim',
54
+ borderRadius: !isMobile ? '$3' : '$3 $3 0 0',
55
+ gap: '$10',
56
+ '@md': {
57
+ position: 'absolute',
58
+ bottom: '0',
59
+ },
60
+ }}
61
+ direction="column"
62
+ >
63
+ <FeedbackHeader ratings={ratings} onEmojiClicked={setIndex} />
64
+ </Flex>
65
+ ) : (
66
+ <FeedbackModal ratings={ratings} index={index} setIndex={setIndex} />
67
+ )}
68
+ </Flex>
69
+ );
70
+ };
@@ -0,0 +1,371 @@
1
+ import React, { useState } from 'react';
2
+ import { useMedia } from 'react-use';
3
+ import { Rating } from '@100mslive/types-prebuilt/elements/feedback';
4
+ import { useHMSActions } from '@100mslive/react-sdk';
5
+ import { CheckIcon, CrossIcon } from '@100mslive/react-icons';
6
+ import { Button } from '../../../Button';
7
+ import { Checkbox } from '../../../Checkbox';
8
+ import { Label } from '../../../Label';
9
+ import { Flex } from '../../../Layout';
10
+ import { Dialog } from '../../../Modal';
11
+ import { Sheet } from '../../../Sheet';
12
+ import { Text } from '../../../Text';
13
+ import { TextArea } from '../../../TextArea';
14
+ import { config as cssConfig } from '../../../Theme';
15
+ import { useHMSPrebuiltContext } from '../../AppContext';
16
+ import { useRoomLayoutLeaveScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
17
+
18
+ export const FEEBACK_INDEX = {
19
+ THANK_YOU: -10,
20
+ INIT: -1,
21
+ };
22
+ export const FeedbackModal = ({
23
+ ratings,
24
+ index,
25
+ setIndex,
26
+ }: {
27
+ ratings: Rating[];
28
+ index: number;
29
+ setIndex: (index: number) => void;
30
+ }) => {
31
+ const isMobile = useMedia(cssConfig.media.md);
32
+ const onOpenChange = () => {
33
+ setIndex(FEEBACK_INDEX.INIT);
34
+ };
35
+ const avoidDefaultDomBehavior = (e: Event) => {
36
+ e.preventDefault();
37
+ };
38
+ if (isMobile) {
39
+ return (
40
+ <Sheet.Root open={index !== FEEBACK_INDEX.INIT} onOpenChange={onOpenChange}>
41
+ <Sheet.Content
42
+ css={{ bg: '$surface_dim', p: '$12' }}
43
+ onPointerDownOutside={avoidDefaultDomBehavior}
44
+ onInteractOutside={avoidDefaultDomBehavior}
45
+ >
46
+ <FeedbackContent ratings={ratings} indexSelected={index} setIndex={setIndex} />
47
+ </Sheet.Content>
48
+ </Sheet.Root>
49
+ );
50
+ }
51
+ return (
52
+ <Dialog.Root open={index !== FEEBACK_INDEX.INIT} onOpenChange={onOpenChange}>
53
+ <Dialog.Portal>
54
+ <Dialog.Overlay />
55
+ <Dialog.Content
56
+ css={{ bg: '$surface_dim', width: '528px', p: '$12' }}
57
+ onPointerDownOutside={avoidDefaultDomBehavior}
58
+ onInteractOutside={avoidDefaultDomBehavior}
59
+ >
60
+ <FeedbackContent ratings={ratings} indexSelected={index} setIndex={setIndex} />
61
+ </Dialog.Content>
62
+ </Dialog.Portal>
63
+ </Dialog.Root>
64
+ );
65
+ };
66
+
67
+ export const FeedbackContent = ({
68
+ ratings,
69
+ indexSelected,
70
+ setIndex,
71
+ }: {
72
+ ratings: Rating[];
73
+ indexSelected: number;
74
+ setIndex: (index: number) => void;
75
+ }) => {
76
+ const { feedback } = useRoomLayoutLeaveScreen();
77
+ const { endpoints } = useHMSPrebuiltContext();
78
+ const hmsActions = useHMSActions();
79
+ const [comment, setComment] = useState('');
80
+ const [selectedReasons, setSelectedReasons] = useState(new Set<number>());
81
+ const handleCheckedChange = (checked: boolean | string, index: number) => {
82
+ const newSelected = new Set(selectedReasons);
83
+ if (checked) {
84
+ newSelected.add(index);
85
+ } else {
86
+ newSelected.delete(index);
87
+ }
88
+ setSelectedReasons(newSelected);
89
+ };
90
+ const submitFeedback = async () => {
91
+ if (indexSelected < 0 || ratings.length <= indexSelected) {
92
+ return;
93
+ }
94
+ try {
95
+ const reasons = [...selectedReasons].map((value: number) => ratings[indexSelected]?.reasons?.[value] || '');
96
+ await hmsActions.submitSessionFeedback(
97
+ {
98
+ question: ratings[indexSelected].question,
99
+ rating: ratings[indexSelected].value || 1,
100
+ min_rating: 1,
101
+ max_rating: ratings.length,
102
+ reasons: selectedReasons.size === 0 ? [] : reasons,
103
+ comment: comment,
104
+ },
105
+ endpoints?.event,
106
+ );
107
+ } catch (e) {
108
+ console.error(e);
109
+ }
110
+ // always submit and take it to thankyou page
111
+ setIndex(FEEBACK_INDEX.THANK_YOU);
112
+ };
113
+ return (
114
+ <Flex
115
+ css={{
116
+ p: indexSelected === FEEBACK_INDEX.INIT ? '$12 !important' : '0',
117
+ bg: '$surface_dim',
118
+ r: '$3',
119
+ gap: '$10',
120
+ }}
121
+ direction="column"
122
+ >
123
+ <FeedbackHeader
124
+ ratings={ratings}
125
+ indexSelected={indexSelected}
126
+ onEmojiClicked={(value: number) => {
127
+ setSelectedReasons(new Set<number>());
128
+ setIndex(value);
129
+ }}
130
+ />
131
+ <FeedbackForm
132
+ rating={ratings[indexSelected]}
133
+ comment={comment}
134
+ setComment={setComment}
135
+ selectedReasons={selectedReasons}
136
+ handleCheckedChange={handleCheckedChange}
137
+ />
138
+ <Button
139
+ type="submit"
140
+ icon
141
+ css={{
142
+ alignSelf: 'end',
143
+ }}
144
+ onClick={submitFeedback}
145
+ >
146
+ {feedback?.submit_btn_label || 'Submit Feedback'}
147
+ </Button>
148
+ </Flex>
149
+ );
150
+ };
151
+ export const FeedbackHeader = ({
152
+ onEmojiClicked,
153
+ ratings,
154
+ indexSelected = FEEBACK_INDEX.INIT,
155
+ }: {
156
+ onEmojiClicked: (index: number) => void;
157
+ ratings: Rating[];
158
+ indexSelected?: number;
159
+ }) => {
160
+ const { feedback } = useRoomLayoutLeaveScreen();
161
+ return (
162
+ <>
163
+ <Flex align="center">
164
+ <Flex
165
+ direction="column"
166
+ css={{
167
+ flex: '1 1 0',
168
+ }}
169
+ >
170
+ <Text
171
+ variant="h5"
172
+ css={{
173
+ c: '$on_surface_high',
174
+ fontStyle: 'normal',
175
+ }}
176
+ >
177
+ {feedback?.title || 'How was your experience?'}
178
+ </Text>
179
+ <Text
180
+ variant="body1"
181
+ css={{
182
+ c: '$on_surface_medium',
183
+ opacity: 0.9,
184
+ fontWeight: '$regular',
185
+ }}
186
+ >
187
+ {feedback?.sub_title || 'Your answers help us improve the quality.'}
188
+ </Text>
189
+ </Flex>
190
+ {indexSelected !== FEEBACK_INDEX.INIT ? (
191
+ <CrossIcon width="24px" height="24px" color="white" onClick={() => onEmojiClicked(FEEBACK_INDEX.INIT)} />
192
+ ) : null}
193
+ </Flex>
194
+ <Flex
195
+ css={{
196
+ gap: '$17',
197
+ c: '$on_surface_high',
198
+ }}
199
+ >
200
+ {ratings.map((element, index) => {
201
+ return (
202
+ <Flex
203
+ align="center"
204
+ direction="column"
205
+ css={{
206
+ c:
207
+ indexSelected === index || indexSelected === FEEBACK_INDEX.INIT
208
+ ? '$on_surface_high'
209
+ : '$on_surface_default',
210
+ gap: '$4',
211
+ }}
212
+ onClick={() => onEmojiClicked(index)}
213
+ key={`${index}`}
214
+ >
215
+ <Text
216
+ css={{
217
+ fontWeight: '$semiBold',
218
+ fontSize: '$h4',
219
+ pb: '$1',
220
+ cursor: 'pointer',
221
+ opacity: indexSelected === index || indexSelected === FEEBACK_INDEX.INIT ? 1 : 0.2,
222
+ }}
223
+ >
224
+ {element.emoji}
225
+ </Text>
226
+ <Text
227
+ variant="body1"
228
+ css={{
229
+ c:
230
+ indexSelected === index || indexSelected === FEEBACK_INDEX.INIT
231
+ ? '$on_surface_medium'
232
+ : '$on_surface_low',
233
+ fontWeight: '$regular',
234
+ }}
235
+ >
236
+ {element.label}
237
+ </Text>
238
+ </Flex>
239
+ );
240
+ })}
241
+ </Flex>
242
+ </>
243
+ );
244
+ };
245
+ export const FeedbackForm = ({
246
+ rating,
247
+ comment,
248
+ setComment,
249
+ selectedReasons,
250
+ handleCheckedChange,
251
+ }: {
252
+ rating: Rating;
253
+ comment: string;
254
+ setComment: (value: string) => void;
255
+ selectedReasons: Set<number>;
256
+ handleCheckedChange: (checked: string | boolean, index: number) => void;
257
+ }) => {
258
+ const { feedback } = useRoomLayoutLeaveScreen();
259
+ return (
260
+ <>
261
+ {rating.reasons && rating.reasons.length > 0 && (
262
+ <Flex
263
+ direction="column"
264
+ css={{
265
+ gap: '$4',
266
+ }}
267
+ >
268
+ <Text
269
+ variant="sub2"
270
+ css={{
271
+ c: '$on_surface_high',
272
+ fontWeight: '$semiBold',
273
+ fontSize: '$sm',
274
+ px: '$2',
275
+ }}
276
+ >
277
+ {rating.question || 'What do you like/dislike here?'}
278
+ </Text>
279
+ <Flex
280
+ css={{
281
+ alignItems: 'flex-start',
282
+ alignSelf: 'stretch',
283
+ flexWrap: 'wrap',
284
+ gap: '$6',
285
+ flex: '1 1 calc(25% - 12px)',
286
+ '@md': {
287
+ flex: '1 1 calc(50% - 12px)',
288
+ },
289
+ '@sm': {
290
+ flex: '1 1 100%',
291
+ },
292
+ }}
293
+ >
294
+ {rating.reasons.map((option: string, index: number) => {
295
+ return (
296
+ <Flex
297
+ align="center"
298
+ gap="2"
299
+ key={index}
300
+ css={{
301
+ border: '1px solid $border_bright',
302
+ r: '$1',
303
+ p: '$6',
304
+ }}
305
+ >
306
+ <Checkbox.Root
307
+ id={`${option}-${index}`}
308
+ checked={selectedReasons.has(index)}
309
+ onCheckedChange={checked => handleCheckedChange(checked, index)}
310
+ css={{
311
+ cursor: 'pointer',
312
+ flexShrink: 0,
313
+ bg: '$on_secondary_low',
314
+ border: '1px solid $border_bright',
315
+ }}
316
+ >
317
+ <Checkbox.Indicator>
318
+ <CheckIcon width={12} height={12} />
319
+ </Checkbox.Indicator>
320
+ </Checkbox.Root>
321
+ <Label
322
+ css={{
323
+ color: '$on_surface_high',
324
+ fontSize: '$sm',
325
+ fontWeight: '$regular',
326
+ lineHeight: '20px' /* 142.857% */,
327
+ }}
328
+ >
329
+ {option}
330
+ </Label>
331
+ </Flex>
332
+ );
333
+ })}
334
+ </Flex>
335
+ </Flex>
336
+ )}
337
+ {feedback?.comment && (
338
+ <Flex
339
+ direction="column"
340
+ css={{
341
+ gap: '$4',
342
+ }}
343
+ >
344
+ <Text
345
+ variant="body2"
346
+ css={{
347
+ c: '$on_surface_high',
348
+ fontWeight: '$regular',
349
+ fontSize: '$sm',
350
+ }}
351
+ >
352
+ {feedback?.comment.label || 'Additional comments (optional)'}
353
+ </Text>
354
+ <TextArea
355
+ maxLength={1024}
356
+ placeholder={feedback?.comment.placeholder || 'Tell us more...'}
357
+ css={{
358
+ backgroundColor: '$surface_bright',
359
+ border: '1px solid $border_bright',
360
+ resize: 'none',
361
+ height: '$36',
362
+ display: 'flex',
363
+ }}
364
+ value={comment}
365
+ onChange={event => setComment(event.target.value.trimStart())}
366
+ />
367
+ </Flex>
368
+ )}
369
+ </>
370
+ );
371
+ };
@@ -0,0 +1,44 @@
1
+ import React from 'react';
2
+ import { useMedia } from 'react-use';
3
+ import { UserMusicIcon } from '@100mslive/react-icons';
4
+ import { Flex } from '../../../Layout';
5
+ import { Text } from '../../../Text';
6
+ import { config as cssConfig } from '../../../Theme';
7
+
8
+ export const ThankyouView = () => {
9
+ const isMobile = useMedia(cssConfig.media.md);
10
+ return (
11
+ <Flex
12
+ direction={isMobile ? 'column' : 'row'}
13
+ align="center"
14
+ css={{
15
+ gap: '$10',
16
+ border: '1px solid $border_default',
17
+ borderRadius: !isMobile ? '$3' : '$3 $3 0 0',
18
+ bg: '$surface_dim',
19
+ w: !isMobile ? '528px' : '410px',
20
+ p: '$12',
21
+ pb: isMobile ? '$16' : '$12',
22
+ '@md': {
23
+ position: 'absolute',
24
+ bottom: '0',
25
+ },
26
+ }}
27
+ >
28
+ <UserMusicIcon width="64px" height="64px" />
29
+ <Flex direction="column" align={isMobile ? 'center' : 'start'}>
30
+ <Text variant="h5">Thank you for your feedback!</Text>
31
+ <Text
32
+ variant="body1"
33
+ css={{
34
+ fontWeight: '$regular',
35
+ fontSize: '$md',
36
+ opacity: '0.9',
37
+ }}
38
+ >
39
+ Your answers help us improve.
40
+ </Text>
41
+ </Flex>
42
+ </Flex>
43
+ );
44
+ };
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import { ExitIcon } from '@100mslive/react-icons';
3
+ import { Feedback } from './EndCallFeedback/Feedback';
3
4
  // @ts-ignore: No implicit Any
4
5
  import { ToastManager } from './Toast/ToastManager';
5
6
  import { Button } from '../../Button';
@@ -63,6 +64,7 @@ export const LeaveScreen = () => {
63
64
  <Text css={{ ml: '$3', fontWeight: '$semiBold', color: 'inherit' }}>Rejoin</Text>
64
65
  </Button>
65
66
  </Flex>
67
+ <Feedback />
66
68
  </Flex>
67
69
  </Flex>
68
70
  );
@@ -77,6 +77,7 @@ export function useRoomLayoutLeaveScreen() {
77
77
  const isLeaveScreenEnabled = !!screenProps;
78
78
  return {
79
79
  isLeaveScreenEnabled,
80
+ feedback: screenProps?.default?.elements?.feedback,
80
81
  };
81
82
  }
82
83