@100mslive/roomkit-react 0.1.13-alpha.0 → 0.1.13
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/{HLSView-AIPLCDXY.js → HLSView-IENE4HRP.js} +2 -2
- package/dist/Prebuilt/components/Notifications/ChatNotifications.d.ts +2 -0
- package/dist/{chunk-5DCII2TP.js → chunk-U4AB6X6M.js} +945 -911
- package/dist/chunk-U4AB6X6M.js.map +7 -0
- package/dist/index.cjs.js +1450 -1400
- package/dist/index.cjs.js.map +4 -4
- package/dist/index.js +1 -1
- package/dist/meta.cjs.json +227 -148
- package/dist/meta.esbuild.json +232 -153
- package/package.json +6 -6
- package/src/Prebuilt/components/AuthToken.jsx +12 -2
- package/src/Prebuilt/components/Chat/Chat.jsx +5 -7
- package/src/Prebuilt/components/Chat/ChatBody.jsx +53 -34
- package/src/Prebuilt/components/Chat/ChatFooter.tsx +13 -7
- package/src/Prebuilt/components/Chat/ChatStates.jsx +8 -6
- package/src/Prebuilt/components/Chat/Navigation.tsx +1 -1
- package/src/Prebuilt/components/Chat/PinnedMessage.tsx +15 -17
- package/src/Prebuilt/components/Notifications/ChatNotifications.tsx +34 -0
- package/src/Prebuilt/components/Notifications/Notifications.tsx +2 -0
- package/src/Prebuilt/components/Polls/Voting/QuestionCard.jsx +6 -4
- package/src/Prebuilt/components/Polls/Voting/TimedVoting.jsx +3 -2
- package/src/Prebuilt/components/Polls/common/VoteCount.jsx +6 -4
- package/src/Prebuilt/components/Preview/PreviewJoin.tsx +1 -1
- package/src/Prebuilt/components/Toast/ToastConfig.jsx +0 -19
- package/src/Prebuilt/components/VirtualBackground/VBPicker.tsx +46 -35
- package/src/Prebuilt/components/hooks/useSetPinnedMessages.ts +1 -2
- package/src/Prebuilt/components/hooks/useUserPreferences.jsx +1 -0
- package/src/Prebuilt/layouts/VideoStreamingSection.tsx +10 -30
- package/dist/chunk-5DCII2TP.js.map +0 -7
- /package/dist/{HLSView-AIPLCDXY.js.map → HLSView-IENE4HRP.js.map} +0 -0
package/package.json
CHANGED
@@ -10,7 +10,7 @@
|
|
10
10
|
"prebuilt",
|
11
11
|
"roomkit"
|
12
12
|
],
|
13
|
-
"version": "0.1.13
|
13
|
+
"version": "0.1.13",
|
14
14
|
"author": "100ms",
|
15
15
|
"license": "MIT",
|
16
16
|
"files": [
|
@@ -76,10 +76,10 @@
|
|
76
76
|
"react": ">=17.0.2 <19.0.0"
|
77
77
|
},
|
78
78
|
"dependencies": {
|
79
|
-
"@100mslive/hls-player": "0.1.22
|
80
|
-
"@100mslive/hms-virtual-background": "1.11.22
|
81
|
-
"@100mslive/react-icons": "0.8.22
|
82
|
-
"@100mslive/react-sdk": "0.8.22
|
79
|
+
"@100mslive/hls-player": "0.1.22",
|
80
|
+
"@100mslive/hms-virtual-background": "1.11.22",
|
81
|
+
"@100mslive/react-icons": "0.8.22",
|
82
|
+
"@100mslive/react-sdk": "0.8.22",
|
83
83
|
"@100mslive/types-prebuilt": "0.12.4",
|
84
84
|
"@emoji-mart/data": "^1.0.6",
|
85
85
|
"@emoji-mart/react": "^1.0.1",
|
@@ -115,5 +115,5 @@
|
|
115
115
|
"uuid": "^8.3.2",
|
116
116
|
"worker-timers": "^7.0.40"
|
117
117
|
},
|
118
|
-
"gitHead": "
|
118
|
+
"gitHead": "543b9152024ee7e4554701f1387b1af32906b58a"
|
119
119
|
}
|
@@ -1,9 +1,12 @@
|
|
1
1
|
import React, { useEffect, useState } from 'react';
|
2
|
+
import { useSessionStorage } from 'react-use';
|
3
|
+
import { v4 } from 'uuid';
|
2
4
|
import { useHMSActions } from '@100mslive/react-sdk';
|
3
5
|
import { styled } from '../../Theme';
|
4
6
|
import { useHMSPrebuiltContext } from '../AppContext';
|
5
7
|
import { ErrorDialog } from '../primitives/DialogContent';
|
6
8
|
import { useSetAppDataByKey } from './AppData/useUISettings';
|
9
|
+
import { UserPreferencesKeys } from './hooks/useUserPreferences';
|
7
10
|
import { APP_DATA } from '../common/constants';
|
8
11
|
|
9
12
|
/**
|
@@ -21,6 +24,13 @@ const AuthToken = React.memo(({ authTokenByRoomCodeEndpoint, defaultAuthToken })
|
|
21
24
|
const [error, setError] = useState({ title: '', body: '' });
|
22
25
|
let authToken = defaultAuthToken;
|
23
26
|
const [, setAuthTokenInAppData] = useSetAppDataByKey(APP_DATA.authToken);
|
27
|
+
const [savedUserId, setSavedUserId] = useSessionStorage(UserPreferencesKeys.USER_ID);
|
28
|
+
|
29
|
+
useEffect(() => {
|
30
|
+
if (!savedUserId && !userId) {
|
31
|
+
setSavedUserId(v4());
|
32
|
+
}
|
33
|
+
}, [savedUserId, setSavedUserId, userId]);
|
24
34
|
|
25
35
|
useEffect(() => {
|
26
36
|
if (authToken) {
|
@@ -33,10 +43,10 @@ const AuthToken = React.memo(({ authTokenByRoomCodeEndpoint, defaultAuthToken })
|
|
33
43
|
}
|
34
44
|
|
35
45
|
hmsActions
|
36
|
-
.getAuthTokenByRoomCode({ roomCode, userId }, { endpoint: authTokenByRoomCodeEndpoint })
|
46
|
+
.getAuthTokenByRoomCode({ roomCode, userId: userId || savedUserId }, { endpoint: authTokenByRoomCodeEndpoint })
|
37
47
|
.then(token => setAuthTokenInAppData(token))
|
38
48
|
.catch(error => setError(convertError(error)));
|
39
|
-
}, [hmsActions, authToken, authTokenByRoomCodeEndpoint, setAuthTokenInAppData, roomCode, userId]);
|
49
|
+
}, [hmsActions, authToken, authTokenByRoomCodeEndpoint, setAuthTokenInAppData, roomCode, userId, savedUserId]);
|
40
50
|
|
41
51
|
if (error.title) {
|
42
52
|
return <ErrorDialog title={error.title}>{error.body}</ErrorDialog>;
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
2
2
|
import { useMedia } from 'react-use';
|
3
|
-
import {
|
3
|
+
import { selectLocalPeer, selectSessionStore } from '@100mslive/hms-video-store';
|
4
4
|
import {
|
5
5
|
HMSNotificationTypes,
|
6
6
|
selectHMSMessagesCount,
|
@@ -28,7 +28,7 @@ export const Chat = ({ screenType }) => {
|
|
28
28
|
const [peerSelector, setPeerSelector] = useSetSubscribedChatSelector(CHAT_SELECTOR.PEER_ID);
|
29
29
|
const [roleSelector, setRoleSelector] = useSetSubscribedChatSelector(CHAT_SELECTOR.ROLE);
|
30
30
|
const peerName = useHMSStore(selectPeerNameByID(peerSelector));
|
31
|
-
const
|
31
|
+
const localPeer = useHMSStore(selectLocalPeer);
|
32
32
|
const [chatOptions, setChatOptions] = useState({
|
33
33
|
role: roleSelector || '',
|
34
34
|
peerId: peerSelector && peerName ? peerSelector : '',
|
@@ -52,7 +52,7 @@ export const Chat = ({ screenType }) => {
|
|
52
52
|
}, [notification, peerSelector, setPeerSelector]);
|
53
53
|
const blacklistedPeerIDs = useHMSStore(selectSessionStore(SESSION_STORE_KEY.CHAT_PEER_BLACKLIST)) || [];
|
54
54
|
const blacklistedPeerIDSet = new Set(blacklistedPeerIDs);
|
55
|
-
const isLocalPeerBlacklisted = blacklistedPeerIDSet.has(
|
55
|
+
const isLocalPeerBlacklisted = blacklistedPeerIDSet.has(localPeer?.customerUserId);
|
56
56
|
const storeMessageSelector = selectHMSMessagesCount;
|
57
57
|
const { elements } = useRoomLayoutConferencingScreen();
|
58
58
|
const { enabled: isChatEnabled = true } = useHMSStore(selectSessionStore(SESSION_STORE_KEY.CHAT_STATE)) || {};
|
@@ -88,9 +88,7 @@ export const Chat = ({ screenType }) => {
|
|
88
88
|
>
|
89
89
|
{isMobile && elements?.chat?.is_overlay ? null : (
|
90
90
|
<>
|
91
|
-
{
|
92
|
-
<PinnedMessage clearPinnedMessage={index => removePinnedMessage(pinnedMessages, index)} />
|
93
|
-
) : null}
|
91
|
+
<PinnedMessage clearPinnedMessage={index => removePinnedMessage(pinnedMessages, index)} />
|
94
92
|
</>
|
95
93
|
)}
|
96
94
|
|
@@ -107,7 +105,7 @@ export const Chat = ({ screenType }) => {
|
|
107
105
|
|
108
106
|
{isLocalPeerBlacklisted ? <ChatBlocked /> : null}
|
109
107
|
|
110
|
-
{isMobile && elements?.chat?.is_overlay
|
108
|
+
{isMobile && elements?.chat?.is_overlay ? (
|
111
109
|
<PinnedMessage clearPinnedMessage={index => removePinnedMessage(pinnedMessages, index)} />
|
112
110
|
) : null}
|
113
111
|
|
@@ -34,6 +34,13 @@ import { useUnreadCount } from './useUnreadCount';
|
|
34
34
|
import { SESSION_STORE_KEY } from '../../common/constants';
|
35
35
|
|
36
36
|
const iconStyle = { height: '1.125rem', width: '1.125rem' };
|
37
|
+
const tooltipBoxCSS = {
|
38
|
+
fontSize: '$xs',
|
39
|
+
backgroundColor: '$surface_default',
|
40
|
+
p: '$1 $5',
|
41
|
+
fontWeight: '$regular',
|
42
|
+
borderRadius: '$3',
|
43
|
+
};
|
37
44
|
|
38
45
|
const formatTime = date => {
|
39
46
|
if (!(date instanceof Date)) {
|
@@ -136,7 +143,7 @@ const getMessageType = ({ roles, receiver }) => {
|
|
136
143
|
}
|
137
144
|
return receiver ? 'private' : '';
|
138
145
|
};
|
139
|
-
const ChatActions = ({ onPin, showPinAction, message,
|
146
|
+
const ChatActions = ({ onPin, showPinAction, message, sentByLocalPeer, isMobile, openSheet, setOpenSheet }) => {
|
140
147
|
const { elements } = useRoomLayoutConferencingScreen();
|
141
148
|
const { can_hide_message, can_block_user } = elements?.chat?.real_time_controls || {
|
142
149
|
can_hide_message: false,
|
@@ -144,23 +151,23 @@ const ChatActions = ({ onPin, showPinAction, message, peerId, sentByLocalPeer, i
|
|
144
151
|
};
|
145
152
|
const [open, setOpen] = useState(false);
|
146
153
|
const blacklistedPeerIDs = useHMSStore(selectSessionStore(SESSION_STORE_KEY.CHAT_PEER_BLACKLIST)) || [];
|
147
|
-
const { blacklistItem:
|
154
|
+
const { blacklistItem: blacklistPeer } = useChatBlacklist(SESSION_STORE_KEY.CHAT_PEER_BLACKLIST);
|
148
155
|
|
149
156
|
const blacklistedMessageIDs = useHMSStore(selectSessionStore(SESSION_STORE_KEY.CHAT_MESSAGE_BLACKLIST)) || [];
|
150
|
-
const { blacklistItem:
|
157
|
+
const { blacklistItem: blacklistMessage } = useChatBlacklist(SESSION_STORE_KEY.CHAT_MESSAGE_BLACKLIST);
|
158
|
+
|
151
159
|
const { unpinBlacklistedMessages } = useSetPinnedMessages();
|
152
160
|
|
153
161
|
const pinnedMessages = useHMSStore(selectSessionStore(SESSION_STORE_KEY.PINNED_MESSAGES)) || [];
|
154
162
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
}, [blacklistedMessageIDs, blacklistedPeerIDs, pinnedMessages, unpinBlacklistedMessages]);
|
163
|
+
const updatePinnedMessages = useCallback(
|
164
|
+
({ messageID = '', peerID = '' }) => {
|
165
|
+
const blacklistedMessageIDSet = new Set([...blacklistedMessageIDs, messageID]);
|
166
|
+
const blacklistedPeerIDSet = new Set([...blacklistedPeerIDs, peerID]);
|
167
|
+
unpinBlacklistedMessages(pinnedMessages, blacklistedPeerIDSet, blacklistedMessageIDSet);
|
168
|
+
},
|
169
|
+
[pinnedMessages, blacklistedMessageIDs, blacklistedPeerIDs],
|
170
|
+
);
|
164
171
|
|
165
172
|
const copyMessageContent = useCallback(() => {
|
166
173
|
try {
|
@@ -179,12 +186,14 @@ const ChatActions = ({ onPin, showPinAction, message, peerId, sentByLocalPeer, i
|
|
179
186
|
const options = {
|
180
187
|
pin: {
|
181
188
|
text: 'Pin message',
|
189
|
+
tooltipText: 'Pin',
|
182
190
|
icon: <PinIcon style={iconStyle} />,
|
183
191
|
onClick: onPin,
|
184
192
|
show: showPinAction,
|
185
193
|
},
|
186
194
|
copy: {
|
187
195
|
text: 'Copy text',
|
196
|
+
tooltipText: 'Copy',
|
188
197
|
icon: <CopyIcon style={iconStyle} />,
|
189
198
|
onClick: copyMessageContent,
|
190
199
|
show: true,
|
@@ -192,13 +201,19 @@ const ChatActions = ({ onPin, showPinAction, message, peerId, sentByLocalPeer, i
|
|
192
201
|
hide: {
|
193
202
|
text: 'Hide for everyone',
|
194
203
|
icon: <EyeCloseIcon style={iconStyle} />,
|
195
|
-
onClick: async () =>
|
204
|
+
onClick: async () => {
|
205
|
+
blacklistMessage(blacklistedMessageIDs, message.id);
|
206
|
+
updatePinnedMessages({ messageID: message.id });
|
207
|
+
},
|
196
208
|
show: can_hide_message,
|
197
209
|
},
|
198
210
|
block: {
|
199
211
|
text: 'Block from chat',
|
200
212
|
icon: <CrossCircleIcon style={iconStyle} />,
|
201
|
-
onClick: async () =>
|
213
|
+
onClick: async () => {
|
214
|
+
blacklistPeer(blacklistedPeerIDs, message?.senderUserId);
|
215
|
+
updatePinnedMessages({ peerID: message?.senderUserId });
|
216
|
+
},
|
202
217
|
color: '$alert_error_default',
|
203
218
|
show: can_block_user && !sentByLocalPeer,
|
204
219
|
},
|
@@ -258,25 +273,29 @@ const ChatActions = ({ onPin, showPinAction, message, peerId, sentByLocalPeer, i
|
|
258
273
|
}}
|
259
274
|
>
|
260
275
|
{options.pin.show ? (
|
261
|
-
<
|
262
|
-
{options.pin.
|
263
|
-
|
276
|
+
<Tooltip boxCss={tooltipBoxCSS} title={options.pin.tooltipText}>
|
277
|
+
<IconButton data-testid="pin_message_btn" onClick={options.pin.onClick}>
|
278
|
+
{options.pin.icon}
|
279
|
+
</IconButton>
|
280
|
+
</Tooltip>
|
264
281
|
) : null}
|
265
282
|
|
266
283
|
{options.copy.show ? (
|
267
|
-
<
|
268
|
-
<
|
269
|
-
|
284
|
+
<Tooltip boxCss={tooltipBoxCSS} title={options.copy.tooltipText}>
|
285
|
+
<IconButton onClick={options.copy.onClick} data-testid="copy_message_btn">
|
286
|
+
<CopyIcon style={iconStyle} />
|
287
|
+
</IconButton>
|
288
|
+
</Tooltip>
|
270
289
|
) : null}
|
271
290
|
|
272
291
|
{options.block.show || options.hide.show ? (
|
273
|
-
<
|
274
|
-
<
|
275
|
-
<
|
292
|
+
<Tooltip boxCss={tooltipBoxCSS} title="More actions">
|
293
|
+
<Dropdown.Trigger asChild>
|
294
|
+
<IconButton>
|
276
295
|
<VerticalMenuIcon style={iconStyle} />
|
277
|
-
</
|
278
|
-
</
|
279
|
-
</
|
296
|
+
</IconButton>
|
297
|
+
</Dropdown.Trigger>
|
298
|
+
</Tooltip>
|
280
299
|
) : null}
|
281
300
|
</Flex>
|
282
301
|
<Dropdown.Portal>
|
@@ -344,7 +363,6 @@ const ChatMessage = React.memo(
|
|
344
363
|
const [openSheet, setOpenSheet] = useState(false);
|
345
364
|
// show pin action only if peer has remove others permission and the message is of broadcast type
|
346
365
|
const showPinAction = permissions.removeOthers && !messageType && elements?.chat?.allow_pinning_messages;
|
347
|
-
|
348
366
|
useEffect(() => {
|
349
367
|
if (message.id && !message.read && inView) {
|
350
368
|
hmsActions.setMessageRead(true, message.id);
|
@@ -362,9 +380,9 @@ const ChatMessage = React.memo(
|
|
362
380
|
ref={ref}
|
363
381
|
as="div"
|
364
382
|
css={{
|
365
|
-
mb: '$
|
383
|
+
mb: '$5',
|
366
384
|
pr: '$10',
|
367
|
-
mt: '$
|
385
|
+
mt: '$4',
|
368
386
|
'&:hover .chat_actions': { opacity: 1 },
|
369
387
|
}}
|
370
388
|
style={style}
|
@@ -376,13 +394,15 @@ const ChatMessage = React.memo(
|
|
376
394
|
flexWrap: 'wrap',
|
377
395
|
// Theme independent color, token should not be used for transparent chat
|
378
396
|
bg: messageType ? (isOverlay ? 'rgba(0, 0, 0, 0.64)' : '$surface_default') : undefined,
|
379
|
-
r:
|
380
|
-
|
381
|
-
py: messageType ? '$4' : 0,
|
397
|
+
r: '$1',
|
398
|
+
p: '$1 $2',
|
382
399
|
userSelect: 'none',
|
383
400
|
'@md': {
|
384
401
|
cursor: 'pointer',
|
385
402
|
},
|
403
|
+
'&:hover': {
|
404
|
+
background: 'linear-gradient(277deg, $surface_default 0%, $surface_dim 60.87%)',
|
405
|
+
},
|
386
406
|
}}
|
387
407
|
key={message.time}
|
388
408
|
data-testid="chat_msg"
|
@@ -439,7 +459,6 @@ const ChatMessage = React.memo(
|
|
439
459
|
onPin={onPin}
|
440
460
|
showPinAction={showPinAction}
|
441
461
|
message={message}
|
442
|
-
peerId={message.sender}
|
443
462
|
sentByLocalPeer={message.sender === localPeerId}
|
444
463
|
isMobile={isMobile}
|
445
464
|
openSheet={openSheet}
|
@@ -571,7 +590,7 @@ export const ChatBody = React.forwardRef(({ role, peerId, scrollToBottom, blackl
|
|
571
590
|
message =>
|
572
591
|
message.type === 'chat' &&
|
573
592
|
!blacklistedMessageIDSet.has(message.id) &&
|
574
|
-
!blacklistedPeerIDSet.has(message
|
593
|
+
!blacklistedPeerIDSet.has(message?.senderUserId),
|
575
594
|
) || []
|
576
595
|
);
|
577
596
|
};
|
@@ -2,7 +2,7 @@ import React, { ReactNode, useCallback, useEffect, useRef, useState } from 'reac
|
|
2
2
|
import { useMedia } from 'react-use';
|
3
3
|
import data from '@emoji-mart/data';
|
4
4
|
import Picker from '@emoji-mart/react';
|
5
|
-
import {
|
5
|
+
import { selectLocalPeer, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
|
6
6
|
import { EmojiIcon, PauseCircleIcon, SendIcon, VerticalMenuIcon } from '@100mslive/react-icons';
|
7
7
|
import { Box, config as cssConfig, Flex, IconButton as BaseIconButton, Popover, styled, Text } from '../../..';
|
8
8
|
import { IconButton } from '../../../IconButton';
|
@@ -86,9 +86,9 @@ export const ChatFooter = ({
|
|
86
86
|
const isMobile = useMedia(cssConfig.media.md);
|
87
87
|
const { elements } = useRoomLayoutConferencingScreen();
|
88
88
|
const message_placeholder = elements?.chat?.message_placeholder || 'Send a message';
|
89
|
-
const
|
89
|
+
const localPeer = useHMSStore(selectLocalPeer);
|
90
90
|
const isOverlayChat = elements?.chat?.is_overlay;
|
91
|
-
const
|
91
|
+
const canDisableChat = !!elements?.chat?.real_time_controls?.can_disable_chat;
|
92
92
|
|
93
93
|
const sendMessage = useCallback(async () => {
|
94
94
|
const message = inputRef?.current?.value;
|
@@ -132,7 +132,7 @@ export const ChatFooter = ({
|
|
132
132
|
{/* {screenType !== 'hls_live_streaming' ? (
|
133
133
|
<ChatSelectorContainer onSelect={onSelect} role={role} peerId={peerId} selection={selection} />
|
134
134
|
) : null} */}
|
135
|
-
{
|
135
|
+
{canDisableChat ? (
|
136
136
|
<Flex align="center" justify="end" css={{ w: '100%', mb: '$4' }}>
|
137
137
|
<Popover.Root>
|
138
138
|
<Popover.Trigger asChild>
|
@@ -145,10 +145,16 @@ export const ChatFooter = ({
|
|
145
145
|
align="end"
|
146
146
|
side="top"
|
147
147
|
onClick={() => {
|
148
|
-
|
148
|
+
const chatState = {
|
149
149
|
enabled: false,
|
150
|
-
updatedBy:
|
151
|
-
|
150
|
+
updatedBy: {
|
151
|
+
peerId: localPeer?.id,
|
152
|
+
userId: localPeer?.customerUserId,
|
153
|
+
userName: localPeer?.name,
|
154
|
+
},
|
155
|
+
updatedAt: Date.now(),
|
156
|
+
};
|
157
|
+
hmsActions.sessionStore.set(SESSION_STORE_KEY.CHAT_STATE, chatState);
|
152
158
|
}}
|
153
159
|
css={{
|
154
160
|
backgroundColor: '$surface_default',
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import React, { useCallback } from 'react';
|
2
|
-
import {
|
2
|
+
import { selectLocalPeer, selectSessionStore, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
|
3
3
|
import { Button } from '../../../Button';
|
4
4
|
import { Box, Flex } from '../../../Layout';
|
5
5
|
import { Text } from '../../../Text';
|
@@ -10,17 +10,19 @@ export const ChatPaused = () => {
|
|
10
10
|
const hmsActions = useHMSActions();
|
11
11
|
const { elements } = useRoomLayoutConferencingScreen();
|
12
12
|
const { can_disable_chat } = elements?.chat.real_time_controls || false;
|
13
|
-
const { enabled: isChatEnabled = true, updatedBy: chatStateUpdatedBy
|
13
|
+
const { enabled: isChatEnabled = true, updatedBy: chatStateUpdatedBy } =
|
14
14
|
useHMSStore(selectSessionStore(SESSION_STORE_KEY.CHAT_STATE)) || {};
|
15
|
-
|
15
|
+
|
16
|
+
const localPeer = useHMSStore(selectLocalPeer);
|
16
17
|
|
17
18
|
const unPauseChat = useCallback(
|
18
19
|
async () =>
|
19
20
|
await hmsActions.sessionStore.set(SESSION_STORE_KEY.CHAT_STATE, {
|
20
21
|
enabled: true,
|
21
|
-
updatedBy:
|
22
|
+
updatedBy: { userName: localPeer.name, userId: localPeer?.customerUserId, peerId: localPeer.id },
|
23
|
+
updatedAt: Date.now(),
|
22
24
|
}),
|
23
|
-
[hmsActions,
|
25
|
+
[hmsActions, localPeer],
|
24
26
|
);
|
25
27
|
|
26
28
|
return isChatEnabled ? null : (
|
@@ -37,7 +39,7 @@ export const ChatPaused = () => {
|
|
37
39
|
variant="xs"
|
38
40
|
css={{ color: '$on_surface_medium', maxWidth: '100%', overflow: 'hidden', textOverflow: 'ellipsis' }}
|
39
41
|
>
|
40
|
-
Chat has been paused by {chatStateUpdatedBy}
|
42
|
+
Chat has been paused by {chatStateUpdatedBy?.peerId === localPeer.id ? 'you' : chatStateUpdatedBy?.userName}
|
41
43
|
</Text>
|
42
44
|
</Box>
|
43
45
|
{can_disable_chat ? (
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import React, { useEffect, useRef, useState } from 'react';
|
2
2
|
import { useSwipeable } from 'react-swipeable';
|
3
3
|
import { useMedia } from 'react-use';
|
4
|
-
import {
|
4
|
+
import { selectSessionStore, useHMSStore } from '@100mslive/react-sdk';
|
5
5
|
import { CrossIcon, PinIcon } from '@100mslive/react-icons';
|
6
6
|
import { Box, Flex } from '../../../Layout';
|
7
7
|
import { Text } from '../../../Text';
|
@@ -16,13 +16,12 @@ import { SESSION_STORE_KEY } from '../../common/constants';
|
|
16
16
|
const PINNED_MESSAGE_LENGTH = 75;
|
17
17
|
|
18
18
|
export const PinnedMessage = ({ clearPinnedMessage }: { clearPinnedMessage: (index: number) => void }) => {
|
19
|
-
const permissions = useHMSStore(selectPermissions);
|
20
19
|
const pinnedMessages = useHMSStore(selectSessionStore(SESSION_STORE_KEY.PINNED_MESSAGES)) || [];
|
21
20
|
const [pinnedMessageIndex, setPinnedMessageIndex] = useState(0);
|
22
21
|
const isMobile = useMedia(cssConfig.media.md);
|
23
22
|
|
24
23
|
const [hideOverflow, setHideOverflow] = useState(false);
|
25
|
-
|
24
|
+
const canOverflow = pinnedMessages?.[pinnedMessageIndex]?.text?.length > PINNED_MESSAGE_LENGTH || false;
|
26
25
|
const formattedPinnedMessage = hideOverflow
|
27
26
|
? `${pinnedMessages?.[pinnedMessageIndex]?.text.slice(0, PINNED_MESSAGE_LENGTH)}... `
|
28
27
|
: pinnedMessages?.[pinnedMessageIndex]?.text;
|
@@ -94,24 +93,23 @@ export const PinnedMessage = ({ clearPinnedMessage }: { clearPinnedMessage: (ind
|
|
94
93
|
>
|
95
94
|
<Text variant="sm" css={{ color: '$on_surface_medium' }} {...swipeHandlers}>
|
96
95
|
<AnnotisedMessage message={formattedPinnedMessage} />
|
97
|
-
{
|
98
|
-
<span style={{ cursor: 'pointer' }} onClick={() => setHideOverflow(
|
99
|
-
See more
|
96
|
+
{canOverflow ? (
|
97
|
+
<span style={{ cursor: 'pointer' }} onClick={() => setHideOverflow(prev => !prev)}>
|
98
|
+
$nbsp;{hideOverflow ? 'See more' : 'Collapse'}
|
100
99
|
</span>
|
101
100
|
) : null}
|
102
101
|
</Text>
|
103
102
|
</Box>
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
)}
|
103
|
+
|
104
|
+
<Flex
|
105
|
+
onClick={() => {
|
106
|
+
clearPinnedMessage(pinnedMessageIndex);
|
107
|
+
setPinnedMessageIndex(Math.max(0, pinnedMessageIndex - 1));
|
108
|
+
}}
|
109
|
+
css={{ cursor: 'pointer', color: '$on_surface_medium', '&:hover': { color: '$on_surface_high' } }}
|
110
|
+
>
|
111
|
+
<CrossIcon />
|
112
|
+
</Flex>
|
115
113
|
</Flex>
|
116
114
|
</Flex>
|
117
115
|
) : null;
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import React, { useEffect } from 'react';
|
2
|
+
import { v4 as uuid } from 'uuid';
|
3
|
+
import { selectLocalPeerID, selectSessionStore, useHMSStore } from '@100mslive/react-sdk';
|
4
|
+
import { ChatIcon, ChatUnreadIcon } from '@100mslive/react-icons';
|
5
|
+
// @ts-ignore
|
6
|
+
import { ToastManager } from '../Toast/ToastManager';
|
7
|
+
import { SESSION_STORE_KEY } from '../../common/constants';
|
8
|
+
|
9
|
+
const NOTIFICATION_TIME_DIFFERENCE = 5000;
|
10
|
+
|
11
|
+
export const ChatNotifications = () => {
|
12
|
+
const chatState = useHMSStore(selectSessionStore(SESSION_STORE_KEY.CHAT_STATE));
|
13
|
+
const localPeerId = useHMSStore(selectLocalPeerID);
|
14
|
+
|
15
|
+
useEffect(() => {
|
16
|
+
if (!chatState || chatState.updatedBy?.peerId === localPeerId) {
|
17
|
+
return;
|
18
|
+
}
|
19
|
+
|
20
|
+
const showToast = Date.now() - chatState.updatedAt < NOTIFICATION_TIME_DIFFERENCE;
|
21
|
+
|
22
|
+
if (!showToast) {
|
23
|
+
return;
|
24
|
+
}
|
25
|
+
|
26
|
+
const notification = {
|
27
|
+
id: uuid(),
|
28
|
+
icon: chatState.enabled ? <ChatUnreadIcon /> : <ChatIcon />,
|
29
|
+
title: `Chat ${chatState.enabled ? 'resumed' : 'paused'} by ${chatState.updatedBy?.userName}`,
|
30
|
+
};
|
31
|
+
ToastManager.addToast(notification);
|
32
|
+
}, [chatState]);
|
33
|
+
return <></>;
|
34
|
+
};
|
@@ -20,6 +20,7 @@ import { ToastBatcher } from '../Toast/ToastBatcher';
|
|
20
20
|
// @ts-ignore: No implicit Any
|
21
21
|
import { ToastManager } from '../Toast/ToastManager';
|
22
22
|
import { AutoplayBlockedModal } from './AutoplayBlockedModal';
|
23
|
+
import { ChatNotifications } from './ChatNotifications';
|
23
24
|
import { InitErrorModal } from './InitErrorModal';
|
24
25
|
import { PeerNotifications } from './PeerNotifications';
|
25
26
|
import { PermissionErrorModal } from './PermissionErrorModal';
|
@@ -186,6 +187,7 @@ export function Notifications() {
|
|
186
187
|
<AutoplayBlockedModal />
|
187
188
|
<PermissionErrorModal />
|
188
189
|
<InitErrorModal />
|
190
|
+
<ChatNotifications />
|
189
191
|
</>
|
190
192
|
);
|
191
193
|
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
// @ts-check
|
2
2
|
import React, { useCallback, useMemo, useState } from 'react';
|
3
|
-
import {
|
3
|
+
import { selectLocalPeer, selectLocalPeerRoleName, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
|
4
4
|
import { ChevronLeftIcon, ChevronRightIcon } from '@100mslive/react-icons';
|
5
5
|
import { Box, Button, Flex, IconButton, Input, styled, Text } from '../../../../';
|
6
6
|
import { checkCorrectAnswer } from '../../../common/utils';
|
@@ -38,9 +38,11 @@ export const QuestionCard = ({
|
|
38
38
|
rolesThatCanViewResponses,
|
39
39
|
}) => {
|
40
40
|
const actions = useHMSActions();
|
41
|
-
const
|
42
|
-
const localPeerResponse = responses?.find(
|
43
|
-
|
41
|
+
const localPeer = useHMSStore(selectLocalPeer);
|
42
|
+
const localPeerResponse = responses?.find(
|
43
|
+
response => response.peer?.peerid === localPeer?.id || response.peer?.userid === localPeer?.customerUserId,
|
44
|
+
);
|
45
|
+
const isLocalPeerCreator = localPeer?.id === startedBy;
|
44
46
|
const localPeerRoleName = useHMSStore(selectLocalPeerRoleName);
|
45
47
|
const roleCanViewResponse =
|
46
48
|
!rolesThatCanViewResponses ||
|
@@ -8,8 +8,9 @@ import { QuestionCard } from './QuestionCard';
|
|
8
8
|
* @returns
|
9
9
|
*/
|
10
10
|
export const TimedView = ({ poll }) => {
|
11
|
-
|
12
|
-
const
|
11
|
+
// backend question index starts at 1
|
12
|
+
const [currentIndex, setCurrentIndex] = useState(1);
|
13
|
+
const activeQuestion = poll.questions?.find(question => question.index === currentIndex);
|
13
14
|
if (!activeQuestion) {
|
14
15
|
return null;
|
15
16
|
}
|
@@ -19,10 +19,12 @@ export const VoteCount = ({ isQuiz, voteCount, isCorrectAnswer }) => {
|
|
19
19
|
{isCorrectAnswer ? 'Correct' : 'Incorrect'}
|
20
20
|
</Text>
|
21
21
|
)}
|
22
|
-
|
23
|
-
{
|
24
|
-
|
25
|
-
|
22
|
+
{voteCount ? (
|
23
|
+
<Text variant="sm" css={{ color: '$on_surface_medium' }}>
|
24
|
+
{voteCount}
|
25
|
+
{voteCount === 1 ? 'vote' : 'votes'}
|
26
|
+
</Text>
|
27
|
+
) : null}
|
26
28
|
</Flex>
|
27
29
|
);
|
28
30
|
};
|
@@ -186,7 +186,7 @@ const PreviewJoin = ({
|
|
186
186
|
/>
|
187
187
|
</Box>
|
188
188
|
</Container>
|
189
|
-
<Box css={{ position: 'absolute', right: '0', top: 0, height: '100%' }}>
|
189
|
+
<Box css={{ position: 'absolute', right: '0', top: 0, height: '100%', overflow: 'hidden' }}>
|
190
190
|
<SidePane screenType="default" />
|
191
191
|
</Box>
|
192
192
|
</Flex>
|
@@ -1,7 +1,6 @@
|
|
1
1
|
import React, { useCallback } from 'react';
|
2
2
|
import { selectPeerByID, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
|
3
3
|
import {
|
4
|
-
ChatIcon,
|
5
4
|
ChatUnreadIcon,
|
6
5
|
ConnectivityIcon,
|
7
6
|
HandIcon,
|
@@ -146,24 +145,6 @@ export const ToastConfig = {
|
|
146
145
|
};
|
147
146
|
},
|
148
147
|
},
|
149
|
-
CHAT_PAUSED: {
|
150
|
-
single: notification => {
|
151
|
-
return {
|
152
|
-
title: `Chat paused by ${notification.data?.name}`,
|
153
|
-
icon: <ChatIcon />,
|
154
|
-
action: <ChatAction />,
|
155
|
-
};
|
156
|
-
},
|
157
|
-
},
|
158
|
-
CHAT_RESUMED: {
|
159
|
-
single: notification => {
|
160
|
-
return {
|
161
|
-
title: `Chat resumed by ${notification.data?.name}`,
|
162
|
-
icon: <ChatUnreadIcon />,
|
163
|
-
action: <ChatAction />,
|
164
|
-
};
|
165
|
-
},
|
166
|
-
},
|
167
148
|
RECONNECTED: {
|
168
149
|
single: () => {
|
169
150
|
return {
|