@100mslive/roomkit-react 0.1.13-alpha.0 → 0.1.13
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-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 {
|