@100mslive/roomkit-react 0.1.12 → 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-PWVM4OIP.js → HLSView-IENE4HRP.js} +2 -2
- package/dist/Prebuilt/App.d.ts +0 -2
- package/dist/Prebuilt/AppContext.d.ts +0 -2
- package/dist/Prebuilt/common/constants.d.ts +110 -0
- package/dist/Prebuilt/components/AppData/AppData.d.ts +2 -0
- package/dist/Prebuilt/components/Chat/MwebChatOption.d.ts +7 -0
- package/dist/Prebuilt/components/Chat/Navigation.d.ts +8 -0
- package/dist/Prebuilt/components/Chat/PinnedMessage.d.ts +4 -0
- package/dist/Prebuilt/components/Footer/Footer.d.ts +3 -2
- package/dist/Prebuilt/components/Notifications/ChatNotifications.d.ts +2 -0
- package/dist/Prebuilt/components/Preview/PreviewJoin.d.ts +2 -1
- package/dist/Prebuilt/components/VirtualBackground/VBCollection.d.ts +2 -1
- package/dist/Prebuilt/components/VirtualBackground/VBPicker.d.ts +3 -0
- package/dist/Prebuilt/components/VirtualBackground/constants.d.ts +0 -6
- package/dist/Prebuilt/components/hooks/useChatBlacklist.d.ts +4 -0
- package/dist/Prebuilt/components/hooks/useSetPinnedMessages.d.ts +16 -0
- package/dist/Prebuilt/provider/roomLayoutProvider/hooks/useRoomLayoutScreen.d.ts +3 -2
- package/dist/{chunk-WREKGNP6.js → chunk-U4AB6X6M.js} +2178 -1148
- package/dist/chunk-U4AB6X6M.js.map +7 -0
- package/dist/index.cjs.js +2746 -1638
- package/dist/index.cjs.js.map +4 -4
- package/dist/index.js +1 -1
- package/dist/meta.cjs.json +803 -208
- package/dist/meta.esbuild.json +812 -217
- package/package.json +8 -7
- package/src/Prebuilt/App.tsx +3 -14
- package/src/Prebuilt/AppContext.tsx +0 -2
- package/src/Prebuilt/common/{constants.js → constants.ts} +22 -20
- package/src/Prebuilt/components/AppData/{AppData.jsx → AppData.tsx} +8 -22
- package/src/Prebuilt/components/AppData/useUISettings.js +0 -4
- package/src/Prebuilt/components/AuthToken.jsx +15 -5
- package/src/Prebuilt/components/Chat/Chat.jsx +49 -73
- package/src/Prebuilt/components/Chat/ChatBody.jsx +241 -51
- package/src/Prebuilt/components/Chat/ChatFooter.tsx +56 -6
- package/src/Prebuilt/components/Chat/ChatStates.jsx +68 -0
- package/src/Prebuilt/components/Chat/MwebChatOption.tsx +24 -0
- package/src/Prebuilt/components/Chat/Navigation.tsx +60 -0
- package/src/Prebuilt/components/Chat/PinnedMessage.tsx +116 -0
- package/src/Prebuilt/components/Footer/Footer.tsx +4 -7
- package/src/Prebuilt/components/Header/common.jsx +1 -1
- 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 +7 -9
- package/src/Prebuilt/components/RoleChangeRequest/RoleChangeRequestModal.tsx +4 -1
- package/src/Prebuilt/components/Settings/DeviceSettings.jsx +1 -1
- package/src/Prebuilt/components/SidePaneTabs.tsx +3 -2
- package/src/Prebuilt/components/Toast/ToastConfig.jsx +1 -0
- package/src/Prebuilt/components/VirtualBackground/VBCollection.tsx +4 -4
- package/src/Prebuilt/components/VirtualBackground/{VBPicker.jsx → VBPicker.tsx} +64 -44
- package/src/Prebuilt/components/VirtualBackground/constants.ts +0 -8
- package/src/Prebuilt/components/hooks/useAutoStartStreaming.tsx +10 -1
- package/src/Prebuilt/components/hooks/useChatBlacklist.ts +21 -0
- package/src/Prebuilt/components/hooks/useSetPinnedMessages.ts +75 -0
- package/src/Prebuilt/components/hooks/useUserPreferences.jsx +1 -0
- package/src/Prebuilt/layouts/SidePane.tsx +1 -1
- package/src/Prebuilt/layouts/VideoStreamingSection.tsx +16 -8
- package/src/Prebuilt/plugins/whiteboard/PusherCommunicationProvider.js +1 -1
- package/src/Prebuilt/plugins/whiteboard/README.md +1 -1
- package/src/Prebuilt/primitives/DialogContent.jsx +1 -1
- package/src/Prebuilt/provider/roomLayoutProvider/constants/index.ts +12 -1
- package/src/Prebuilt/provider/roomLayoutProvider/hooks/useRoomLayoutScreen.ts +5 -1
- package/dist/chunk-WREKGNP6.js.map +0 -7
- package/src/Prebuilt/components/hooks/useSetPinnedMessage.js +0 -38
- package/src/Prebuilt/services/tokenService.js +0 -49
- /package/dist/{HLSView-PWVM4OIP.js.map → HLSView-IENE4HRP.js.map} +0 -0
@@ -1,4 +1,4 @@
|
|
1
|
-
import React, { Fragment, useCallback, useEffect, useLayoutEffect,
|
1
|
+
import React, { Fragment, useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
2
2
|
import { useInView } from 'react-intersection-observer';
|
3
3
|
import { useMedia } from 'react-use';
|
4
4
|
import AutoSizer from 'react-virtualized-auto-sizer';
|
@@ -6,25 +6,41 @@ import { VariableSizeList } from 'react-window';
|
|
6
6
|
import {
|
7
7
|
selectHMSMessages,
|
8
8
|
selectLocalPeerID,
|
9
|
+
selectLocalPeerName,
|
9
10
|
selectLocalPeerRoleName,
|
10
11
|
selectMessagesByPeerID,
|
11
12
|
selectMessagesByRole,
|
12
13
|
selectPeerNameByID,
|
13
14
|
selectPermissions,
|
15
|
+
selectSessionStore,
|
14
16
|
useHMSActions,
|
15
17
|
useHMSStore,
|
16
18
|
} from '@100mslive/react-sdk';
|
17
|
-
import { PinIcon, VerticalMenuIcon } from '@100mslive/react-icons';
|
19
|
+
import { CopyIcon, CrossCircleIcon, CrossIcon, EyeCloseIcon, PinIcon, VerticalMenuIcon } from '@100mslive/react-icons';
|
18
20
|
import { Dropdown } from '../../../Dropdown';
|
19
21
|
import { IconButton } from '../../../IconButton';
|
20
22
|
import { Box, Flex } from '../../../Layout';
|
23
|
+
import { Sheet } from '../../../Sheet';
|
21
24
|
import { Text } from '../../../Text';
|
22
25
|
import { config as cssConfig, styled } from '../../../Theme';
|
23
26
|
import { Tooltip } from '../../../Tooltip';
|
24
27
|
import emptyChat from '../../images/empty-chat.svg';
|
28
|
+
import { ToastManager } from '../Toast/ToastManager';
|
29
|
+
import { MwebChatOption } from './MwebChatOption';
|
25
30
|
import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
|
26
|
-
import {
|
31
|
+
import { useChatBlacklist } from '../hooks/useChatBlacklist';
|
32
|
+
import { useSetPinnedMessages } from '../hooks/useSetPinnedMessages';
|
27
33
|
import { useUnreadCount } from './useUnreadCount';
|
34
|
+
import { SESSION_STORE_KEY } from '../../common/constants';
|
35
|
+
|
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
|
+
};
|
28
44
|
|
29
45
|
const formatTime = date => {
|
30
46
|
if (!(date instanceof Date)) {
|
@@ -127,56 +143,188 @@ const getMessageType = ({ roles, receiver }) => {
|
|
127
143
|
}
|
128
144
|
return receiver ? 'private' : '';
|
129
145
|
};
|
130
|
-
const ChatActions = ({ onPin, showPinAction }) => {
|
146
|
+
const ChatActions = ({ onPin, showPinAction, message, sentByLocalPeer, isMobile, openSheet, setOpenSheet }) => {
|
147
|
+
const { elements } = useRoomLayoutConferencingScreen();
|
148
|
+
const { can_hide_message, can_block_user } = elements?.chat?.real_time_controls || {
|
149
|
+
can_hide_message: false,
|
150
|
+
can_block_user: false,
|
151
|
+
};
|
131
152
|
const [open, setOpen] = useState(false);
|
132
|
-
|
133
|
-
|
153
|
+
const blacklistedPeerIDs = useHMSStore(selectSessionStore(SESSION_STORE_KEY.CHAT_PEER_BLACKLIST)) || [];
|
154
|
+
const { blacklistItem: blacklistPeer } = useChatBlacklist(SESSION_STORE_KEY.CHAT_PEER_BLACKLIST);
|
155
|
+
|
156
|
+
const blacklistedMessageIDs = useHMSStore(selectSessionStore(SESSION_STORE_KEY.CHAT_MESSAGE_BLACKLIST)) || [];
|
157
|
+
const { blacklistItem: blacklistMessage } = useChatBlacklist(SESSION_STORE_KEY.CHAT_MESSAGE_BLACKLIST);
|
158
|
+
|
159
|
+
const { unpinBlacklistedMessages } = useSetPinnedMessages();
|
160
|
+
|
161
|
+
const pinnedMessages = useHMSStore(selectSessionStore(SESSION_STORE_KEY.PINNED_MESSAGES)) || [];
|
162
|
+
|
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
|
+
);
|
171
|
+
|
172
|
+
const copyMessageContent = useCallback(() => {
|
173
|
+
try {
|
174
|
+
navigator?.clipboard.writeText(message.message);
|
175
|
+
ToastManager.addToast({
|
176
|
+
title: 'Message copied successfully',
|
177
|
+
});
|
178
|
+
} catch (e) {
|
179
|
+
console.log(e);
|
180
|
+
ToastManager.addToast({
|
181
|
+
title: 'Could not copy message',
|
182
|
+
});
|
183
|
+
}
|
184
|
+
}, [message]);
|
185
|
+
|
186
|
+
const options = {
|
187
|
+
pin: {
|
188
|
+
text: 'Pin message',
|
189
|
+
tooltipText: 'Pin',
|
190
|
+
icon: <PinIcon style={iconStyle} />,
|
191
|
+
onClick: onPin,
|
192
|
+
show: showPinAction,
|
193
|
+
},
|
194
|
+
copy: {
|
195
|
+
text: 'Copy text',
|
196
|
+
tooltipText: 'Copy',
|
197
|
+
icon: <CopyIcon style={iconStyle} />,
|
198
|
+
onClick: copyMessageContent,
|
199
|
+
show: true,
|
200
|
+
},
|
201
|
+
hide: {
|
202
|
+
text: 'Hide for everyone',
|
203
|
+
icon: <EyeCloseIcon style={iconStyle} />,
|
204
|
+
onClick: async () => {
|
205
|
+
blacklistMessage(blacklistedMessageIDs, message.id);
|
206
|
+
updatePinnedMessages({ messageID: message.id });
|
207
|
+
},
|
208
|
+
show: can_hide_message,
|
209
|
+
},
|
210
|
+
block: {
|
211
|
+
text: 'Block from chat',
|
212
|
+
icon: <CrossCircleIcon style={iconStyle} />,
|
213
|
+
onClick: async () => {
|
214
|
+
blacklistPeer(blacklistedPeerIDs, message?.senderUserId);
|
215
|
+
updatePinnedMessages({ peerID: message?.senderUserId });
|
216
|
+
},
|
217
|
+
color: '$alert_error_default',
|
218
|
+
show: can_block_user && !sentByLocalPeer,
|
219
|
+
},
|
220
|
+
};
|
221
|
+
|
222
|
+
if (isMobile) {
|
223
|
+
return (
|
224
|
+
<Sheet.Root open={openSheet} onOpenChange={setOpenSheet}>
|
225
|
+
<Sheet.Content css={{ bg: '$surface_default', pb: '$14' }} onClick={() => setOpenSheet(false)}>
|
226
|
+
<Sheet.Title
|
227
|
+
css={{
|
228
|
+
display: 'flex',
|
229
|
+
color: '$on_surface_high',
|
230
|
+
w: '100%',
|
231
|
+
justifyContent: 'space-between',
|
232
|
+
mt: '$8',
|
233
|
+
fontSize: '$md',
|
234
|
+
px: '$10',
|
235
|
+
pb: '$8',
|
236
|
+
borderBottom: '1px solid $border_bright',
|
237
|
+
alignItems: 'center',
|
238
|
+
}}
|
239
|
+
>
|
240
|
+
Message options
|
241
|
+
<Sheet.Close css={{ color: '$on_surface_high' }} onClick={() => setOpenSheet(false)}>
|
242
|
+
<CrossIcon />
|
243
|
+
</Sheet.Close>
|
244
|
+
</Sheet.Title>
|
245
|
+
|
246
|
+
{Object.keys(options).map(optionKey => {
|
247
|
+
const option = options[optionKey];
|
248
|
+
return option.show ? (
|
249
|
+
<MwebChatOption
|
250
|
+
key={optionKey}
|
251
|
+
text={option.text}
|
252
|
+
icon={option.icon}
|
253
|
+
onClick={option.onClick}
|
254
|
+
color={option?.color}
|
255
|
+
/>
|
256
|
+
) : null;
|
257
|
+
})}
|
258
|
+
</Sheet.Content>
|
259
|
+
</Sheet.Root>
|
260
|
+
);
|
134
261
|
}
|
135
262
|
|
136
263
|
return (
|
137
|
-
<Dropdown.Root open={open} onOpenChange={setOpen}>
|
138
|
-
<
|
139
|
-
|
140
|
-
|
141
|
-
|
264
|
+
<Dropdown.Root open={open} onOpenChange={setOpen} css={{ '@md': { display: 'none' } }}>
|
265
|
+
<Flex
|
266
|
+
className="chat_actions"
|
267
|
+
css={{
|
268
|
+
background: '$surface_bright',
|
269
|
+
borderRadius: '$1',
|
270
|
+
p: '$2',
|
271
|
+
opacity: open ? 1 : 0,
|
272
|
+
'@md': { opacity: 1 },
|
273
|
+
}}
|
274
|
+
>
|
275
|
+
{options.pin.show ? (
|
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>
|
281
|
+
) : null}
|
282
|
+
|
283
|
+
{options.copy.show ? (
|
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>
|
289
|
+
) : null}
|
290
|
+
|
291
|
+
{options.block.show || options.hide.show ? (
|
292
|
+
<Tooltip boxCss={tooltipBoxCSS} title="More actions">
|
293
|
+
<Dropdown.Trigger asChild>
|
294
|
+
<IconButton>
|
295
|
+
<VerticalMenuIcon style={iconStyle} />
|
296
|
+
</IconButton>
|
297
|
+
</Dropdown.Trigger>
|
142
298
|
</Tooltip>
|
143
|
-
|
144
|
-
</
|
299
|
+
) : null}
|
300
|
+
</Flex>
|
145
301
|
<Dropdown.Portal>
|
146
302
|
<Dropdown.Content
|
147
303
|
sideOffset={5}
|
148
304
|
align="end"
|
149
305
|
css={{ width: '$48', backgroundColor: '$surface_bright', py: '$0', border: '1px solid $border_bright' }}
|
150
306
|
>
|
151
|
-
|
152
|
-
<
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
307
|
+
{options.hide.show ? (
|
308
|
+
<Dropdown.Item data-testid="hide_message_btn" onClick={options.hide.onClick}>
|
309
|
+
{options.hide.icon}
|
310
|
+
<Text variant="sm" css={{ ml: '$4', fontWeight: '$semiBold' }}>
|
311
|
+
{options.hide.text}
|
312
|
+
</Text>
|
313
|
+
</Dropdown.Item>
|
314
|
+
) : null}
|
315
|
+
|
316
|
+
{options.block.show ? (
|
158
317
|
<Dropdown.Item
|
159
|
-
data-testid="
|
160
|
-
onClick={
|
161
|
-
|
162
|
-
navigator?.clipboard.writeText(messageContent);
|
163
|
-
ToastManager.addToast({
|
164
|
-
title: 'Message copied successfully',
|
165
|
-
});
|
166
|
-
} catch (e) {
|
167
|
-
console.log(e);
|
168
|
-
ToastManager.addToast({
|
169
|
-
title: 'Could not copy message',
|
170
|
-
});
|
171
|
-
}
|
172
|
-
}}
|
318
|
+
data-testid="block_peer_btn"
|
319
|
+
onClick={options.block.onClick}
|
320
|
+
css={{ color: options.block.color }}
|
173
321
|
>
|
174
|
-
|
175
|
-
<Text variant="sm" css={{ ml: '$4' }}>
|
176
|
-
|
322
|
+
{options.block.icon}
|
323
|
+
<Text variant="sm" css={{ ml: '$4', color: 'inherit', fontWeight: '$semiBold' }}>
|
324
|
+
{options.block.text}
|
177
325
|
</Text>
|
178
326
|
</Dropdown.Item>
|
179
|
-
) : null}
|
327
|
+
) : null}
|
180
328
|
</Dropdown.Content>
|
181
329
|
</Dropdown.Portal>
|
182
330
|
</Dropdown.Root>
|
@@ -212,9 +360,9 @@ const ChatMessage = React.memo(
|
|
212
360
|
roles: message.recipientRoles,
|
213
361
|
receiver: message.recipientPeer,
|
214
362
|
});
|
363
|
+
const [openSheet, setOpenSheet] = useState(false);
|
215
364
|
// show pin action only if peer has remove others permission and the message is of broadcast type
|
216
365
|
const showPinAction = permissions.removeOthers && !messageType && elements?.chat?.allow_pinning_messages;
|
217
|
-
|
218
366
|
useEffect(() => {
|
219
367
|
if (message.id && !message.read && inView) {
|
220
368
|
hmsActions.setMessageRead(true, message.id);
|
@@ -231,7 +379,12 @@ const ChatMessage = React.memo(
|
|
231
379
|
<Box
|
232
380
|
ref={ref}
|
233
381
|
as="div"
|
234
|
-
css={{
|
382
|
+
css={{
|
383
|
+
mb: '$5',
|
384
|
+
pr: '$10',
|
385
|
+
mt: '$4',
|
386
|
+
'&:hover .chat_actions': { opacity: 1 },
|
387
|
+
}}
|
235
388
|
style={style}
|
236
389
|
>
|
237
390
|
<Flex
|
@@ -241,13 +394,23 @@ const ChatMessage = React.memo(
|
|
241
394
|
flexWrap: 'wrap',
|
242
395
|
// Theme independent color, token should not be used for transparent chat
|
243
396
|
bg: messageType ? (isOverlay ? 'rgba(0, 0, 0, 0.64)' : '$surface_default') : undefined,
|
244
|
-
r:
|
245
|
-
|
246
|
-
py: messageType ? '$4' : 0,
|
397
|
+
r: '$1',
|
398
|
+
p: '$1 $2',
|
247
399
|
userSelect: 'none',
|
400
|
+
'@md': {
|
401
|
+
cursor: 'pointer',
|
402
|
+
},
|
403
|
+
'&:hover': {
|
404
|
+
background: 'linear-gradient(277deg, $surface_default 0%, $surface_dim 60.87%)',
|
405
|
+
},
|
248
406
|
}}
|
249
407
|
key={message.time}
|
250
408
|
data-testid="chat_msg"
|
409
|
+
onClick={() => {
|
410
|
+
if (isMobile) {
|
411
|
+
setOpenSheet(true);
|
412
|
+
}
|
413
|
+
}}
|
251
414
|
>
|
252
415
|
<Text
|
253
416
|
css={{
|
@@ -291,7 +454,16 @@ const ChatMessage = React.memo(
|
|
291
454
|
receiver={message.recipientPeer}
|
292
455
|
roles={message.recipientRoles}
|
293
456
|
/>
|
294
|
-
|
457
|
+
|
458
|
+
<ChatActions
|
459
|
+
onPin={onPin}
|
460
|
+
showPinAction={showPinAction}
|
461
|
+
message={message}
|
462
|
+
sentByLocalPeer={message.sender === localPeerId}
|
463
|
+
isMobile={isMobile}
|
464
|
+
openSheet={openSheet}
|
465
|
+
setOpenSheet={setOpenSheet}
|
466
|
+
/>
|
295
467
|
</Text>
|
296
468
|
<Text
|
297
469
|
variant="sm"
|
@@ -303,7 +475,10 @@ const ChatMessage = React.memo(
|
|
303
475
|
userSelect: 'all',
|
304
476
|
color: isOverlay ? '#FFF' : '$on_surface_high',
|
305
477
|
}}
|
306
|
-
onClick={e =>
|
478
|
+
onClick={e => {
|
479
|
+
e.stopPropagation();
|
480
|
+
setOpenSheet(true);
|
481
|
+
}}
|
307
482
|
>
|
308
483
|
<AnnotisedMessage message={message.message} />
|
309
484
|
</Text>
|
@@ -314,7 +489,9 @@ const ChatMessage = React.memo(
|
|
314
489
|
);
|
315
490
|
const ChatList = React.forwardRef(
|
316
491
|
({ width, height, setRowHeight, getRowHeight, messages, unreadCount = 0, scrollToBottom }, listRef) => {
|
317
|
-
const {
|
492
|
+
const { setPinnedMessages } = useSetPinnedMessages();
|
493
|
+
const pinnedMessages = useHMSStore(selectSessionStore(SESSION_STORE_KEY.PINNED_MESSAGES)) || [];
|
494
|
+
const localPeerName = useHMSStore(selectLocalPeerName);
|
318
495
|
useLayoutEffect(() => {
|
319
496
|
if (listRef.current && listRef.current.scrollToItem) {
|
320
497
|
scrollToBottom(1);
|
@@ -343,7 +520,7 @@ const ChatList = React.forwardRef(
|
|
343
520
|
unreadCount={unreadCount}
|
344
521
|
isLast={index >= messages.length - 2}
|
345
522
|
scrollToBottom={scrollToBottom}
|
346
|
-
onPin={() =>
|
523
|
+
onPin={() => setPinnedMessages(pinnedMessages, messages[index], localPeerName)}
|
347
524
|
/>
|
348
525
|
)}
|
349
526
|
</VariableSizeList>
|
@@ -397,14 +574,27 @@ const VirtualizedChatMessages = React.forwardRef(({ messages, unreadCount = 0, s
|
|
397
574
|
);
|
398
575
|
});
|
399
576
|
|
400
|
-
export const ChatBody = React.forwardRef(({ role, peerId, scrollToBottom }, listRef) => {
|
577
|
+
export const ChatBody = React.forwardRef(({ role, peerId, scrollToBottom, blacklistedPeerIDs }, listRef) => {
|
401
578
|
const storeMessageSelector = role
|
402
579
|
? selectMessagesByRole(role)
|
403
580
|
: peerId
|
404
581
|
? selectMessagesByPeerID(peerId)
|
405
582
|
: selectHMSMessages;
|
406
|
-
let messages = useHMSStore(storeMessageSelector);
|
407
|
-
|
583
|
+
let messages = useHMSStore(storeMessageSelector) || [];
|
584
|
+
const blacklistedMessageIDs = useHMSStore(selectSessionStore(SESSION_STORE_KEY.CHAT_MESSAGE_BLACKLIST)) || [];
|
585
|
+
const getFilteredMessages = () => {
|
586
|
+
const blacklistedMessageIDSet = new Set(blacklistedMessageIDs);
|
587
|
+
const blacklistedPeerIDSet = new Set(blacklistedPeerIDs);
|
588
|
+
return (
|
589
|
+
messages?.filter(
|
590
|
+
message =>
|
591
|
+
message.type === 'chat' &&
|
592
|
+
!blacklistedMessageIDSet.has(message.id) &&
|
593
|
+
!blacklistedPeerIDSet.has(message?.senderUserId),
|
594
|
+
) || []
|
595
|
+
);
|
596
|
+
};
|
597
|
+
|
408
598
|
const isMobile = useMedia(cssConfig.media.md);
|
409
599
|
const { elements } = useRoomLayoutConferencingScreen();
|
410
600
|
const unreadCount = useUnreadCount({ role, peerId });
|
@@ -440,7 +630,7 @@ export const ChatBody = React.forwardRef(({ role, peerId, scrollToBottom }, list
|
|
440
630
|
return (
|
441
631
|
<Fragment>
|
442
632
|
<VirtualizedChatMessages
|
443
|
-
messages={
|
633
|
+
messages={getFilteredMessages()}
|
444
634
|
scrollToBottom={scrollToBottom}
|
445
635
|
unreadCount={unreadCount}
|
446
636
|
ref={listRef}
|
@@ -2,9 +2,10 @@ 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 { useHMSActions } from '@100mslive/react-sdk';
|
6
|
-
import { EmojiIcon, SendIcon } from '@100mslive/react-icons';
|
7
|
-
import { Box, config as cssConfig, Flex, IconButton as BaseIconButton, Popover, styled } from '../../..';
|
5
|
+
import { selectLocalPeer, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
|
6
|
+
import { EmojiIcon, PauseCircleIcon, SendIcon, VerticalMenuIcon } from '@100mslive/react-icons';
|
7
|
+
import { Box, config as cssConfig, Flex, IconButton as BaseIconButton, Popover, styled, Text } from '../../..';
|
8
|
+
import { IconButton } from '../../../IconButton';
|
8
9
|
// @ts-ignore
|
9
10
|
import { ToastManager } from '../Toast/ToastManager';
|
10
11
|
import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
|
@@ -13,6 +14,8 @@ import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvid
|
|
13
14
|
import { useChatDraftMessage } from '../AppData/useChatState';
|
14
15
|
// @ts-ignore
|
15
16
|
import { useEmojiPickerStyles } from './useEmojiPickerStyles';
|
17
|
+
// @ts-ignore
|
18
|
+
import { SESSION_STORE_KEY } from '../../common/constants';
|
16
19
|
|
17
20
|
const TextArea = styled('textarea', {
|
18
21
|
width: '100%',
|
@@ -82,7 +85,10 @@ export const ChatFooter = ({
|
|
82
85
|
const [draftMessage, setDraftMessage] = useChatDraftMessage();
|
83
86
|
const isMobile = useMedia(cssConfig.media.md);
|
84
87
|
const { elements } = useRoomLayoutConferencingScreen();
|
88
|
+
const message_placeholder = elements?.chat?.message_placeholder || 'Send a message';
|
89
|
+
const localPeer = useHMSStore(selectLocalPeer);
|
85
90
|
const isOverlayChat = elements?.chat?.is_overlay;
|
91
|
+
const canDisableChat = !!elements?.chat?.real_time_controls?.can_disable_chat;
|
86
92
|
|
87
93
|
const sendMessage = useCallback(async () => {
|
88
94
|
const message = inputRef?.current?.value;
|
@@ -122,10 +128,54 @@ export const ChatFooter = ({
|
|
122
128
|
}, [setDraftMessage]);
|
123
129
|
|
124
130
|
return (
|
125
|
-
|
131
|
+
<Box>
|
126
132
|
{/* {screenType !== 'hls_live_streaming' ? (
|
127
133
|
<ChatSelectorContainer onSelect={onSelect} role={role} peerId={peerId} selection={selection} />
|
128
134
|
) : null} */}
|
135
|
+
{canDisableChat ? (
|
136
|
+
<Flex align="center" justify="end" css={{ w: '100%', mb: '$4' }}>
|
137
|
+
<Popover.Root>
|
138
|
+
<Popover.Trigger asChild>
|
139
|
+
<IconButton css={{ border: '1px solid $border_bright' }}>
|
140
|
+
<VerticalMenuIcon height="16" width="16" />
|
141
|
+
</IconButton>
|
142
|
+
</Popover.Trigger>
|
143
|
+
<Popover.Portal>
|
144
|
+
<Popover.Content
|
145
|
+
align="end"
|
146
|
+
side="top"
|
147
|
+
onClick={() => {
|
148
|
+
const chatState = {
|
149
|
+
enabled: false,
|
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);
|
158
|
+
}}
|
159
|
+
css={{
|
160
|
+
backgroundColor: '$surface_default',
|
161
|
+
display: 'flex',
|
162
|
+
alignItems: 'center',
|
163
|
+
gap: '$4',
|
164
|
+
borderRadius: '$1',
|
165
|
+
color: '$on_surface_high',
|
166
|
+
cursor: 'pointer',
|
167
|
+
'&:hover': { backgroundColor: '$surface_dim' },
|
168
|
+
}}
|
169
|
+
>
|
170
|
+
<PauseCircleIcon />
|
171
|
+
<Text variant="sm" css={{ fontWeight: '$semiBold' }}>
|
172
|
+
Pause Chat
|
173
|
+
</Text>
|
174
|
+
</Popover.Content>
|
175
|
+
</Popover.Portal>
|
176
|
+
</Popover.Root>
|
177
|
+
</Flex>
|
178
|
+
) : null}
|
129
179
|
<Flex align="center" css={{ gap: '$4', w: '100%' }}>
|
130
180
|
<Flex
|
131
181
|
align="center"
|
@@ -153,7 +203,7 @@ export const ChatFooter = ({
|
|
153
203
|
'& ~ .send-msg': { color: '$on_surface_low' },
|
154
204
|
'&::placeholder': { color: '$on_surface_medium' },
|
155
205
|
}}
|
156
|
-
placeholder=
|
206
|
+
placeholder={message_placeholder}
|
157
207
|
ref={inputRef}
|
158
208
|
required
|
159
209
|
autoFocus={!isMobile}
|
@@ -195,6 +245,6 @@ export const ChatFooter = ({
|
|
195
245
|
</BaseIconButton>
|
196
246
|
</Flex>
|
197
247
|
</Flex>
|
198
|
-
|
248
|
+
</Box>
|
199
249
|
);
|
200
250
|
};
|
@@ -0,0 +1,68 @@
|
|
1
|
+
import React, { useCallback } from 'react';
|
2
|
+
import { selectLocalPeer, selectSessionStore, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
|
3
|
+
import { Button } from '../../../Button';
|
4
|
+
import { Box, Flex } from '../../../Layout';
|
5
|
+
import { Text } from '../../../Text';
|
6
|
+
import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
|
7
|
+
import { SESSION_STORE_KEY } from '../../common/constants';
|
8
|
+
|
9
|
+
export const ChatPaused = () => {
|
10
|
+
const hmsActions = useHMSActions();
|
11
|
+
const { elements } = useRoomLayoutConferencingScreen();
|
12
|
+
const { can_disable_chat } = elements?.chat.real_time_controls || false;
|
13
|
+
const { enabled: isChatEnabled = true, updatedBy: chatStateUpdatedBy } =
|
14
|
+
useHMSStore(selectSessionStore(SESSION_STORE_KEY.CHAT_STATE)) || {};
|
15
|
+
|
16
|
+
const localPeer = useHMSStore(selectLocalPeer);
|
17
|
+
|
18
|
+
const unPauseChat = useCallback(
|
19
|
+
async () =>
|
20
|
+
await hmsActions.sessionStore.set(SESSION_STORE_KEY.CHAT_STATE, {
|
21
|
+
enabled: true,
|
22
|
+
updatedBy: { userName: localPeer.name, userId: localPeer?.customerUserId, peerId: localPeer.id },
|
23
|
+
updatedAt: Date.now(),
|
24
|
+
}),
|
25
|
+
[hmsActions, localPeer],
|
26
|
+
);
|
27
|
+
|
28
|
+
return isChatEnabled ? null : (
|
29
|
+
<Flex
|
30
|
+
align="center"
|
31
|
+
justify="between"
|
32
|
+
css={{ borderRadius: '$1', bg: '$surface_default', p: '$4 $4 $4 $8', w: '100%' }}
|
33
|
+
>
|
34
|
+
<Box>
|
35
|
+
<Text variant="sm" css={{ fontWeight: '$semiBold', color: '$on_surface_high' }}>
|
36
|
+
Chat paused
|
37
|
+
</Text>
|
38
|
+
<Text
|
39
|
+
variant="xs"
|
40
|
+
css={{ color: '$on_surface_medium', maxWidth: '100%', overflow: 'hidden', textOverflow: 'ellipsis' }}
|
41
|
+
>
|
42
|
+
Chat has been paused by {chatStateUpdatedBy?.peerId === localPeer.id ? 'you' : chatStateUpdatedBy?.userName}
|
43
|
+
</Text>
|
44
|
+
</Box>
|
45
|
+
{can_disable_chat ? (
|
46
|
+
<Button css={{ fontWeight: '$semiBold', fontSize: '$sm', borderRadius: '$2' }} onClick={unPauseChat}>
|
47
|
+
Resume
|
48
|
+
</Button>
|
49
|
+
) : (
|
50
|
+
<></>
|
51
|
+
)}
|
52
|
+
</Flex>
|
53
|
+
);
|
54
|
+
};
|
55
|
+
|
56
|
+
export const ChatBlocked = () => {
|
57
|
+
return (
|
58
|
+
<Flex
|
59
|
+
align="center"
|
60
|
+
justify="between"
|
61
|
+
css={{ borderRadius: '$1', bg: '$surface_default', p: '$4 $4 $4 $8', w: '100%' }}
|
62
|
+
>
|
63
|
+
<Text variant="sm" css={{ color: '$on_surface_medium', textAlign: 'center', w: '100%' }}>
|
64
|
+
You've been blocked from sending messages
|
65
|
+
</Text>
|
66
|
+
</Flex>
|
67
|
+
);
|
68
|
+
};
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { Flex } from '../../../Layout';
|
3
|
+
import { Text } from '../../../Text';
|
4
|
+
|
5
|
+
export const MwebChatOption = ({
|
6
|
+
icon,
|
7
|
+
text,
|
8
|
+
onClick,
|
9
|
+
color = '$on_surface_high',
|
10
|
+
}: {
|
11
|
+
icon: any;
|
12
|
+
text: string;
|
13
|
+
onClick: () => void | Promise<void>;
|
14
|
+
color: string;
|
15
|
+
}) => {
|
16
|
+
return (
|
17
|
+
<Flex align="center" css={{ w: '100%', color, cursor: 'pointer', gap: '$4', p: '$8' }} onClick={onClick}>
|
18
|
+
{icon}
|
19
|
+
<Text variant="sm" css={{ color, fontWeight: '$semiBold' }}>
|
20
|
+
{text}
|
21
|
+
</Text>
|
22
|
+
</Flex>
|
23
|
+
);
|
24
|
+
};
|
@@ -0,0 +1,60 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { ChevronDownIcon, ChevronUpIcon } from '@100mslive/react-icons';
|
3
|
+
import { Box, Flex } from '../../../Layout';
|
4
|
+
|
5
|
+
export const Navigation = ({
|
6
|
+
total,
|
7
|
+
index,
|
8
|
+
showPrevious,
|
9
|
+
showNext,
|
10
|
+
isMobile,
|
11
|
+
}: {
|
12
|
+
total: number;
|
13
|
+
index: number;
|
14
|
+
showPrevious: () => void;
|
15
|
+
showNext: () => void;
|
16
|
+
isMobile: boolean;
|
17
|
+
}) => {
|
18
|
+
const sticksCount = Math.min(3, total);
|
19
|
+
|
20
|
+
if (total < 2) {
|
21
|
+
return null;
|
22
|
+
}
|
23
|
+
|
24
|
+
return isMobile ? (
|
25
|
+
<Flex direction="column" css={{ gap: '$1' }}>
|
26
|
+
{[...Array(sticksCount)].map((_, i) => (
|
27
|
+
<Box
|
28
|
+
css={{
|
29
|
+
borderLeft: '2px solid',
|
30
|
+
height: '$4',
|
31
|
+
borderColor: i === index ? '$on_surface_high' : '$on_surface_low',
|
32
|
+
}}
|
33
|
+
/>
|
34
|
+
))}
|
35
|
+
</Flex>
|
36
|
+
) : (
|
37
|
+
<Flex direction="column" css={{ gap: '$4' }}>
|
38
|
+
<Flex
|
39
|
+
onClick={showPrevious}
|
40
|
+
css={
|
41
|
+
index === 0
|
42
|
+
? { cursor: 'not-allowed', color: '$on_surface_low' }
|
43
|
+
: { cursor: 'pointer', color: '$on_surface_medium' }
|
44
|
+
}
|
45
|
+
>
|
46
|
+
<ChevronUpIcon height={20} width={20} />
|
47
|
+
</Flex>
|
48
|
+
<Flex
|
49
|
+
onClick={showNext}
|
50
|
+
css={
|
51
|
+
index === total - 1
|
52
|
+
? { cursor: 'not-allowed', color: '$on_surface_low' }
|
53
|
+
: { cursor: 'pointer', color: '$on_surface_medium' }
|
54
|
+
}
|
55
|
+
>
|
56
|
+
<ChevronDownIcon height={20} width={20} />
|
57
|
+
</Flex>
|
58
|
+
</Flex>
|
59
|
+
);
|
60
|
+
};
|