@100mslive/roomkit-react 0.1.18-alpha.0 → 0.1.18
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-GYHK4ION.js → HLSView-XU2WQ4VV.js} +2 -2
- package/dist/Prebuilt/components/Chat/Chat.d.ts +2 -0
- package/dist/Prebuilt/components/Chat/ChatActions.d.ts +12 -0
- package/dist/Prebuilt/components/Chat/ChatBody.d.ts +8 -0
- package/dist/Prebuilt/components/Chat/ChatFooter.d.ts +2 -2
- package/dist/Prebuilt/components/Chat/ChatStates.d.ts +1 -1
- package/dist/Prebuilt/components/Chat/MwebChatOption.d.ts +1 -1
- package/dist/Prebuilt/components/Chat/PinnedMessage.d.ts +1 -3
- package/dist/Prebuilt/components/hooks/useChatBlacklist.d.ts +1 -0
- package/dist/Prebuilt/components/hooks/useSetPinnedMessages.d.ts +3 -10
- package/dist/Prebuilt/components/hooks/useUnreadPollQuizPresent.d.ts +5 -0
- package/dist/{chunk-75O2M72S.js → chunk-2FX6MFDM.js} +4541 -4502
- package/dist/chunk-2FX6MFDM.js.map +7 -0
- package/dist/index.cjs.js +5113 -5059
- package/dist/index.cjs.js.map +4 -4
- package/dist/index.js +1 -1
- package/dist/meta.cjs.json +343 -225
- package/dist/meta.esbuild.json +353 -235
- package/package.json +6 -6
- package/src/Prebuilt/components/Chat/Chat.tsx +108 -0
- package/src/Prebuilt/components/Chat/ChatActions.tsx +295 -0
- package/src/Prebuilt/components/Chat/ChatBody.tsx +444 -0
- package/src/Prebuilt/components/Chat/ChatFooter.tsx +9 -3
- package/src/Prebuilt/components/Chat/ChatStates.tsx +5 -0
- package/src/Prebuilt/components/Chat/MwebChatOption.tsx +1 -1
- package/src/Prebuilt/components/Chat/PinnedMessage.tsx +4 -2
- package/src/Prebuilt/components/Footer/PollsToggle.tsx +12 -3
- package/src/Prebuilt/components/Leave/DesktopLeaveRoom.tsx +4 -3
- package/src/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.tsx +5 -1
- package/src/Prebuilt/components/Polls/common/MultipleChoiceOptions.jsx +1 -1
- package/src/Prebuilt/components/SidePaneTabs.tsx +33 -11
- package/src/Prebuilt/components/hooks/useChatBlacklist.ts +7 -1
- package/src/Prebuilt/components/hooks/useSetPinnedMessages.ts +19 -11
- package/src/Prebuilt/components/hooks/useUnreadPollQuizPresent.tsx +20 -0
- package/dist/chunk-75O2M72S.js.map +0 -7
- package/src/Prebuilt/components/Chat/Chat.jsx +0 -124
- package/src/Prebuilt/components/Chat/ChatBody.jsx +0 -726
- /package/dist/{HLSView-GYHK4ION.js.map → HLSView-XU2WQ4VV.js.map} +0 -0
@@ -0,0 +1,444 @@
|
|
1
|
+
import React, { Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
2
|
+
import { useMedia } from 'react-use';
|
3
|
+
import AutoSizer from 'react-virtualized-auto-sizer';
|
4
|
+
import { VariableSizeList } from 'react-window';
|
5
|
+
import {
|
6
|
+
HMSMessage,
|
7
|
+
HMSPeerID,
|
8
|
+
HMSRoleName,
|
9
|
+
selectHMSMessages,
|
10
|
+
selectHMSMessagesCount,
|
11
|
+
selectLocalPeerID,
|
12
|
+
selectLocalPeerRoleName,
|
13
|
+
selectPeerNameByID,
|
14
|
+
selectSessionStore,
|
15
|
+
useHMSActions,
|
16
|
+
useHMSStore,
|
17
|
+
useHMSVanillaStore,
|
18
|
+
} from '@100mslive/react-sdk';
|
19
|
+
import { Box, Flex } from '../../../Layout';
|
20
|
+
import { Text } from '../../../Text';
|
21
|
+
import { config as cssConfig, styled } from '../../../Theme';
|
22
|
+
import { Tooltip } from '../../../Tooltip';
|
23
|
+
// @ts-ignore
|
24
|
+
import emptyChat from '../../images/empty-chat.svg';
|
25
|
+
import { ChatActions } from './ChatActions';
|
26
|
+
import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
|
27
|
+
// @ts-ignore: No implicit Any
|
28
|
+
import { useSetSubscribedChatSelector } from '../AppData/useUISettings';
|
29
|
+
import { CHAT_SELECTOR, SESSION_STORE_KEY } from '../../common/constants';
|
30
|
+
|
31
|
+
const formatTime = (date: Date) => {
|
32
|
+
if (!(date instanceof Date)) {
|
33
|
+
return '';
|
34
|
+
}
|
35
|
+
const hours = date.getHours();
|
36
|
+
const minutes = date.getMinutes();
|
37
|
+
const suffix = hours > 11 ? 'PM' : 'AM';
|
38
|
+
return `${hours < 10 ? '0' : ''}${hours}:${minutes < 10 ? '0' : ''}${minutes} ${suffix}`;
|
39
|
+
};
|
40
|
+
|
41
|
+
const rowHeights: Record<number, number> = {};
|
42
|
+
function getRowHeight(index: number) {
|
43
|
+
// 72 will be default row height for any message length
|
44
|
+
// 16 will add margin value as clientHeight don't include margin
|
45
|
+
return rowHeights[index] + 16 || 72;
|
46
|
+
}
|
47
|
+
|
48
|
+
const setRowHeight = (index: number, size: number) => {
|
49
|
+
Object.assign(rowHeights, { [index]: size });
|
50
|
+
};
|
51
|
+
|
52
|
+
const MessageTypeContainer = ({ left, right }: { left?: string; right?: string }) => {
|
53
|
+
return (
|
54
|
+
<Flex
|
55
|
+
align="center"
|
56
|
+
css={{
|
57
|
+
ml: '$2',
|
58
|
+
mr: '$4',
|
59
|
+
gap: '$space$2',
|
60
|
+
}}
|
61
|
+
>
|
62
|
+
{left && (
|
63
|
+
<SenderName
|
64
|
+
variant="xs"
|
65
|
+
as="span"
|
66
|
+
css={{ color: '$on_surface_medium', textTransform: 'capitalize', fontWeight: '$regular' }}
|
67
|
+
>
|
68
|
+
{left}
|
69
|
+
</SenderName>
|
70
|
+
)}
|
71
|
+
{right && (
|
72
|
+
<SenderName
|
73
|
+
as="span"
|
74
|
+
variant="overline"
|
75
|
+
css={{
|
76
|
+
color: '$on_surface_medium',
|
77
|
+
fontWeight: '$regular',
|
78
|
+
}}
|
79
|
+
>
|
80
|
+
{right}
|
81
|
+
</SenderName>
|
82
|
+
)}
|
83
|
+
</Flex>
|
84
|
+
);
|
85
|
+
};
|
86
|
+
|
87
|
+
const MessageType = ({
|
88
|
+
roles,
|
89
|
+
hasCurrentUserSent,
|
90
|
+
receiver,
|
91
|
+
}: {
|
92
|
+
roles?: HMSRoleName[];
|
93
|
+
hasCurrentUserSent: boolean;
|
94
|
+
receiver?: HMSPeerID;
|
95
|
+
}) => {
|
96
|
+
const peerName = useHMSStore(selectPeerNameByID(receiver));
|
97
|
+
const localPeerRoleName = useHMSStore(selectLocalPeerRoleName);
|
98
|
+
if (receiver) {
|
99
|
+
return (
|
100
|
+
<MessageTypeContainer left={hasCurrentUserSent ? `${peerName ? `to ${peerName}` : ''}` : 'to You'} right="(DM)" />
|
101
|
+
);
|
102
|
+
}
|
103
|
+
|
104
|
+
if (roles && roles.length) {
|
105
|
+
return <MessageTypeContainer left={`to ${hasCurrentUserSent ? roles[0] : localPeerRoleName}`} right="(Group)" />;
|
106
|
+
}
|
107
|
+
return null;
|
108
|
+
};
|
109
|
+
|
110
|
+
const URL_REGEX =
|
111
|
+
/^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
|
112
|
+
|
113
|
+
const Link = styled('a', {
|
114
|
+
color: '$primary_default',
|
115
|
+
wordBreak: 'break-word',
|
116
|
+
'&:hover': {
|
117
|
+
textDecoration: 'underline',
|
118
|
+
},
|
119
|
+
});
|
120
|
+
|
121
|
+
export const AnnotisedMessage = ({ message }: { message: string }) => {
|
122
|
+
if (!message) {
|
123
|
+
return <Fragment />;
|
124
|
+
}
|
125
|
+
|
126
|
+
return (
|
127
|
+
<Fragment>
|
128
|
+
{message
|
129
|
+
.trim()
|
130
|
+
.split(/(\s)/)
|
131
|
+
.map(part =>
|
132
|
+
URL_REGEX.test(part) ? (
|
133
|
+
<Link href={part} key={part} target="_blank" rel="noopener noreferrer">
|
134
|
+
{part}
|
135
|
+
</Link>
|
136
|
+
) : (
|
137
|
+
part
|
138
|
+
),
|
139
|
+
)}
|
140
|
+
</Fragment>
|
141
|
+
);
|
142
|
+
};
|
143
|
+
|
144
|
+
const getMessageType = ({ roles, receiver }: { roles?: HMSRoleName[]; receiver?: HMSPeerID }) => {
|
145
|
+
if (roles && roles.length > 0) {
|
146
|
+
return 'role';
|
147
|
+
}
|
148
|
+
return receiver ? 'private' : '';
|
149
|
+
};
|
150
|
+
const SenderName = styled(Text, {
|
151
|
+
overflow: 'hidden',
|
152
|
+
textOverflow: 'ellipsis',
|
153
|
+
whiteSpace: 'nowrap',
|
154
|
+
maxWidth: '14ch',
|
155
|
+
minWidth: 0,
|
156
|
+
color: '$on_surface_high',
|
157
|
+
fontWeight: '$semiBold',
|
158
|
+
});
|
159
|
+
|
160
|
+
const ChatMessage = React.memo(
|
161
|
+
({ index, style = {}, message }: { message: HMSMessage; index: number; style: React.CSSProperties }) => {
|
162
|
+
const { elements } = useRoomLayoutConferencingScreen();
|
163
|
+
const rowRef = useRef<HTMLDivElement | null>(null);
|
164
|
+
const isMobile = useMedia(cssConfig.media.md);
|
165
|
+
const isPrivateChatEnabled = !!elements?.chat?.private_chat_enabled;
|
166
|
+
const roleWhiteList = elements?.chat?.roles_whitelist || [];
|
167
|
+
const isOverlay = elements?.chat?.is_overlay && isMobile;
|
168
|
+
const localPeerId = useHMSStore(selectLocalPeerID);
|
169
|
+
const [selectedRole, setRoleSelector] = useSetSubscribedChatSelector(CHAT_SELECTOR.ROLE);
|
170
|
+
const [selectedPeer, setPeerSelector] = useSetSubscribedChatSelector(CHAT_SELECTOR.PEER);
|
171
|
+
const messageType = getMessageType({
|
172
|
+
roles: message.recipientRoles,
|
173
|
+
receiver: message.recipientPeer,
|
174
|
+
});
|
175
|
+
const [openSheet, setOpenSheet] = useState(false);
|
176
|
+
const showPinAction = !!elements?.chat?.allow_pinning_messages;
|
177
|
+
let showReply = false;
|
178
|
+
if (message.recipientRoles && roleWhiteList.includes(message.recipientRoles[0])) {
|
179
|
+
showReply = true;
|
180
|
+
} else if (message.sender !== selectedPeer.id && message.sender !== localPeerId && isPrivateChatEnabled) {
|
181
|
+
showReply = true;
|
182
|
+
}
|
183
|
+
|
184
|
+
useEffect(() => {
|
185
|
+
if (rowRef.current) {
|
186
|
+
setRowHeight(index, rowRef.current.clientHeight);
|
187
|
+
}
|
188
|
+
}, [index]);
|
189
|
+
|
190
|
+
return (
|
191
|
+
<Box
|
192
|
+
css={{
|
193
|
+
mb: '$5',
|
194
|
+
pr: '$10',
|
195
|
+
mt: '$4',
|
196
|
+
'&:not(:hover} .chat_actions': { display: 'none' },
|
197
|
+
'&:hover .chat_actions': { display: 'flex', opacity: 1 },
|
198
|
+
}}
|
199
|
+
style={style}
|
200
|
+
>
|
201
|
+
<Flex
|
202
|
+
ref={rowRef}
|
203
|
+
align="center"
|
204
|
+
css={{
|
205
|
+
flexWrap: 'wrap',
|
206
|
+
position: 'relative',
|
207
|
+
// Theme independent color, token should not be used for transparent chat
|
208
|
+
bg:
|
209
|
+
messageType && !(selectedPeer.id || selectedRole)
|
210
|
+
? isOverlay
|
211
|
+
? 'rgba(0, 0, 0, 0.64)'
|
212
|
+
: '$surface_default'
|
213
|
+
: undefined,
|
214
|
+
r: '$1',
|
215
|
+
p: '$4',
|
216
|
+
userSelect: 'none',
|
217
|
+
'@md': {
|
218
|
+
cursor: 'pointer',
|
219
|
+
},
|
220
|
+
'&:hover': {
|
221
|
+
background: 'linear-gradient(277deg, $surface_default 0%, $surface_dim 60.87%)',
|
222
|
+
},
|
223
|
+
}}
|
224
|
+
data-testid="chat_msg"
|
225
|
+
onClick={() => {
|
226
|
+
if (isMobile) {
|
227
|
+
setOpenSheet(true);
|
228
|
+
}
|
229
|
+
}}
|
230
|
+
>
|
231
|
+
<Text
|
232
|
+
css={{
|
233
|
+
color: isOverlay ? '#FFF' : '$on_surface_high',
|
234
|
+
fontWeight: '$semiBold',
|
235
|
+
display: 'flex',
|
236
|
+
alignItems: 'center',
|
237
|
+
alignSelf: 'stretch',
|
238
|
+
width: '100%',
|
239
|
+
}}
|
240
|
+
as="div"
|
241
|
+
>
|
242
|
+
<Flex align="baseline">
|
243
|
+
{message.senderName === 'You' || !message.senderName ? (
|
244
|
+
<SenderName
|
245
|
+
as="span"
|
246
|
+
variant="sub2"
|
247
|
+
css={{ color: isOverlay ? '#FFF' : '$on_surface_high', fontWeight: '$semiBold' }}
|
248
|
+
>
|
249
|
+
{message.senderName || 'Anonymous'}
|
250
|
+
</SenderName>
|
251
|
+
) : (
|
252
|
+
<Tooltip title={message.senderName} side="top" align="start">
|
253
|
+
<SenderName
|
254
|
+
as="span"
|
255
|
+
variant="sub2"
|
256
|
+
css={{ color: isOverlay ? '#FFF' : '$on_surface_high', fontWeight: '$semiBold' }}
|
257
|
+
>
|
258
|
+
{message.senderName}
|
259
|
+
</SenderName>
|
260
|
+
</Tooltip>
|
261
|
+
)}
|
262
|
+
<MessageType
|
263
|
+
hasCurrentUserSent={message.sender === localPeerId}
|
264
|
+
receiver={message.recipientPeer}
|
265
|
+
roles={message.recipientRoles}
|
266
|
+
/>
|
267
|
+
</Flex>
|
268
|
+
|
269
|
+
{!isOverlay ? (
|
270
|
+
<Text
|
271
|
+
as="span"
|
272
|
+
variant="caption"
|
273
|
+
css={{
|
274
|
+
color: '$on_surface_medium',
|
275
|
+
flexShrink: 0,
|
276
|
+
position: 'absolute',
|
277
|
+
right: 0,
|
278
|
+
zIndex: 1,
|
279
|
+
mr: '$4',
|
280
|
+
p: '$2',
|
281
|
+
}}
|
282
|
+
>
|
283
|
+
{formatTime(message.time)}
|
284
|
+
</Text>
|
285
|
+
) : null}
|
286
|
+
<ChatActions
|
287
|
+
showPinAction={showPinAction}
|
288
|
+
message={message}
|
289
|
+
sentByLocalPeer={message.sender === localPeerId}
|
290
|
+
onReply={() => {
|
291
|
+
if (message.recipientRoles?.length) {
|
292
|
+
setRoleSelector(message.recipientRoles[0]);
|
293
|
+
setPeerSelector({});
|
294
|
+
} else {
|
295
|
+
setRoleSelector('');
|
296
|
+
setPeerSelector({ id: message.sender, name: message.senderName });
|
297
|
+
}
|
298
|
+
}}
|
299
|
+
showReply={showReply}
|
300
|
+
isMobile={isMobile}
|
301
|
+
openSheet={openSheet}
|
302
|
+
setOpenSheet={setOpenSheet}
|
303
|
+
/>
|
304
|
+
</Text>
|
305
|
+
<Text
|
306
|
+
variant="sm"
|
307
|
+
css={{
|
308
|
+
w: '100%',
|
309
|
+
mt: '$2',
|
310
|
+
wordBreak: 'break-word',
|
311
|
+
whiteSpace: 'pre-wrap',
|
312
|
+
userSelect: 'all',
|
313
|
+
color: isOverlay ? '#FFF' : '$on_surface_high',
|
314
|
+
}}
|
315
|
+
onClick={e => {
|
316
|
+
e.stopPropagation();
|
317
|
+
setOpenSheet(true);
|
318
|
+
}}
|
319
|
+
>
|
320
|
+
<AnnotisedMessage message={message.message} />
|
321
|
+
</Text>
|
322
|
+
</Flex>
|
323
|
+
</Box>
|
324
|
+
);
|
325
|
+
},
|
326
|
+
);
|
327
|
+
|
328
|
+
const MessageWrapper = React.memo(
|
329
|
+
({ index, style, data }: { index: number; style: React.CSSProperties; data: HMSMessage[] }) => {
|
330
|
+
return <ChatMessage style={style} index={index} key={data[index].id} message={data[index]} />;
|
331
|
+
},
|
332
|
+
);
|
333
|
+
|
334
|
+
const VirtualizedChatMessages = React.forwardRef<
|
335
|
+
VariableSizeList,
|
336
|
+
{ messages: HMSMessage[]; scrollToBottom: (count: number) => void }
|
337
|
+
>(({ messages, scrollToBottom }, listRef) => {
|
338
|
+
const hmsActions = useHMSActions();
|
339
|
+
const itemKey = useCallback((index: number, data: HMSMessage[]) => {
|
340
|
+
return data[index].id;
|
341
|
+
}, []);
|
342
|
+
useEffect(() => {
|
343
|
+
requestAnimationFrame(() => scrollToBottom(1));
|
344
|
+
}, [scrollToBottom]);
|
345
|
+
return (
|
346
|
+
<Box
|
347
|
+
css={{
|
348
|
+
mr: '-$10',
|
349
|
+
h: '100%',
|
350
|
+
}}
|
351
|
+
>
|
352
|
+
<AutoSizer
|
353
|
+
style={{
|
354
|
+
width: '90%',
|
355
|
+
}}
|
356
|
+
>
|
357
|
+
{({ height, width }: { height: number; width: number }) => (
|
358
|
+
<VariableSizeList
|
359
|
+
ref={listRef}
|
360
|
+
itemCount={messages.length}
|
361
|
+
itemSize={getRowHeight}
|
362
|
+
itemData={messages}
|
363
|
+
width={width}
|
364
|
+
height={height}
|
365
|
+
style={{
|
366
|
+
overflowX: 'hidden',
|
367
|
+
}}
|
368
|
+
itemKey={itemKey}
|
369
|
+
onItemsRendered={({ visibleStartIndex, visibleStopIndex }) => {
|
370
|
+
for (let i = visibleStartIndex; i <= visibleStopIndex; i++) {
|
371
|
+
if (!messages[i].read) {
|
372
|
+
hmsActions.setMessageRead(true, messages[i].id);
|
373
|
+
}
|
374
|
+
}
|
375
|
+
}}
|
376
|
+
>
|
377
|
+
{MessageWrapper}
|
378
|
+
</VariableSizeList>
|
379
|
+
)}
|
380
|
+
</AutoSizer>
|
381
|
+
</Box>
|
382
|
+
);
|
383
|
+
});
|
384
|
+
|
385
|
+
export const ChatBody = React.forwardRef<VariableSizeList, { scrollToBottom: (count: number) => void }>(
|
386
|
+
({ scrollToBottom }: { scrollToBottom: (count: number) => void }, listRef) => {
|
387
|
+
const messages = useHMSStore(selectHMSMessages);
|
388
|
+
const blacklistedMessageIDs = useHMSStore(selectSessionStore(SESSION_STORE_KEY.CHAT_MESSAGE_BLACKLIST));
|
389
|
+
const filteredMessages = useMemo(() => {
|
390
|
+
const blacklistedMessageIDSet = new Set(blacklistedMessageIDs || []);
|
391
|
+
return messages?.filter(message => message.type === 'chat' && !blacklistedMessageIDSet.has(message.id)) || [];
|
392
|
+
}, [blacklistedMessageIDs, messages]);
|
393
|
+
|
394
|
+
const isMobile = useMedia(cssConfig.media.md);
|
395
|
+
const { elements } = useRoomLayoutConferencingScreen();
|
396
|
+
const vanillaStore = useHMSVanillaStore();
|
397
|
+
|
398
|
+
useEffect(() => {
|
399
|
+
const unsubscribe = vanillaStore.subscribe(() => {
|
400
|
+
// @ts-ignore
|
401
|
+
if (!listRef?.current) {
|
402
|
+
return;
|
403
|
+
}
|
404
|
+
// @ts-ignore
|
405
|
+
const outerElement = listRef.current._outerRef;
|
406
|
+
// @ts-ignore
|
407
|
+
if (outerElement.scrollHeight - (listRef.current.state.scrollOffset + outerElement.offsetHeight) <= 10) {
|
408
|
+
scrollToBottom(1);
|
409
|
+
}
|
410
|
+
}, selectHMSMessagesCount);
|
411
|
+
return unsubscribe;
|
412
|
+
}, [vanillaStore, listRef, scrollToBottom]);
|
413
|
+
|
414
|
+
if (filteredMessages.length === 0 && !(isMobile && elements?.chat?.is_overlay)) {
|
415
|
+
return (
|
416
|
+
<Flex
|
417
|
+
css={{
|
418
|
+
width: '100%',
|
419
|
+
flex: '1 1 0',
|
420
|
+
textAlign: 'center',
|
421
|
+
px: '$4',
|
422
|
+
}}
|
423
|
+
align="center"
|
424
|
+
justify="center"
|
425
|
+
>
|
426
|
+
<Box>
|
427
|
+
<img src={emptyChat} alt="Empty Chat" height={132} width={185} style={{ margin: '0 auto' }} />
|
428
|
+
<Text variant="h5" css={{ mt: '$8', c: '$on_surface_high' }}>
|
429
|
+
Start a conversation
|
430
|
+
</Text>
|
431
|
+
<Text
|
432
|
+
variant="sm"
|
433
|
+
css={{ mt: '$4', maxWidth: '80%', textAlign: 'center', mx: 'auto', c: '$on_surface_medium' }}
|
434
|
+
>
|
435
|
+
There are no messages here yet. Start a conversation by sending a message.
|
436
|
+
</Text>
|
437
|
+
</Box>
|
438
|
+
</Flex>
|
439
|
+
);
|
440
|
+
}
|
441
|
+
|
442
|
+
return <VirtualizedChatMessages messages={filteredMessages} ref={listRef} scrollToBottom={scrollToBottom} />;
|
443
|
+
},
|
444
|
+
);
|
@@ -10,11 +10,11 @@ import { IconButton } from '../../../IconButton';
|
|
10
10
|
import { ToastManager } from '../Toast/ToastManager';
|
11
11
|
import { ChatSelectorContainer } from './ChatSelectorContainer';
|
12
12
|
import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
|
13
|
-
// import { ChatSelectorContainer } from './ChatSelectorContainer';
|
14
13
|
// @ts-ignore
|
15
14
|
import { useChatDraftMessage } from '../AppData/useChatState';
|
16
15
|
// @ts-ignore
|
17
16
|
import { useSetSubscribedChatSelector, useSubscribeChatSelector } from '../AppData/useUISettings';
|
17
|
+
import { useIsLocalPeerBlacklisted } from '../hooks/useChatBlacklist';
|
18
18
|
// @ts-ignore
|
19
19
|
import { useEmojiPickerStyles } from './useEmojiPickerStyles';
|
20
20
|
import { useDefaultChatSelection } from '../../common/hooks';
|
@@ -72,7 +72,7 @@ function EmojiPicker({ onSelect }: { onSelect: (emoji: any) => void }) {
|
|
72
72
|
);
|
73
73
|
}
|
74
74
|
|
75
|
-
export const ChatFooter = ({ onSend, children }: { onSend: () => void; children: ReactNode }) => {
|
75
|
+
export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => void; children: ReactNode }) => {
|
76
76
|
const hmsActions = useHMSActions();
|
77
77
|
const inputRef = useRef<HTMLTextAreaElement>(null);
|
78
78
|
const [draftMessage, setDraftMessage] = useChatDraftMessage();
|
@@ -86,6 +86,8 @@ export const ChatFooter = ({ onSend, children }: { onSend: () => void; children:
|
|
86
86
|
const [selectedRole, setRoleSelector] = useSetSubscribedChatSelector(CHAT_SELECTOR.ROLE);
|
87
87
|
const defaultSelection = useDefaultChatSelection();
|
88
88
|
const selection = selectedPeer.name || selectedRole || defaultSelection;
|
89
|
+
const isLocalPeerBlacklisted = useIsLocalPeerBlacklisted();
|
90
|
+
|
89
91
|
useEffect(() => {
|
90
92
|
if (!selectedPeer.id && !selectedRole && !['Everyone', ''].includes(defaultSelection)) {
|
91
93
|
setRoleSelector(defaultSelection);
|
@@ -108,7 +110,7 @@ export const ChatFooter = ({ onSend, children }: { onSend: () => void; children:
|
|
108
110
|
}
|
109
111
|
inputRef.current.value = '';
|
110
112
|
setTimeout(() => {
|
111
|
-
onSend();
|
113
|
+
onSend(1);
|
112
114
|
}, 0);
|
113
115
|
} catch (error) {
|
114
116
|
const err = error as HMSException;
|
@@ -132,6 +134,10 @@ export const ChatFooter = ({ onSend, children }: { onSend: () => void; children:
|
|
132
134
|
};
|
133
135
|
}, [setDraftMessage]);
|
134
136
|
|
137
|
+
if (isLocalPeerBlacklisted) {
|
138
|
+
return null;
|
139
|
+
}
|
140
|
+
|
135
141
|
return (
|
136
142
|
<Box>
|
137
143
|
<Flex>
|
@@ -4,6 +4,7 @@ import { Button } from '../../../Button';
|
|
4
4
|
import { Box, Flex } from '../../../Layout';
|
5
5
|
import { Text } from '../../../Text';
|
6
6
|
import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
|
7
|
+
import { useIsLocalPeerBlacklisted } from '../hooks/useChatBlacklist';
|
7
8
|
import { SESSION_STORE_KEY } from '../../common/constants';
|
8
9
|
|
9
10
|
export const ChatPaused = () => {
|
@@ -54,6 +55,10 @@ export const ChatPaused = () => {
|
|
54
55
|
};
|
55
56
|
|
56
57
|
export const ChatBlocked = () => {
|
58
|
+
const isLocalPeerBlacklisted = useIsLocalPeerBlacklisted();
|
59
|
+
if (!isLocalPeerBlacklisted) {
|
60
|
+
return null;
|
61
|
+
}
|
57
62
|
return (
|
58
63
|
<Flex
|
59
64
|
align="center"
|
@@ -11,7 +11,7 @@ export const MwebChatOption = ({
|
|
11
11
|
icon: any;
|
12
12
|
text: string;
|
13
13
|
onClick: () => void | Promise<void>;
|
14
|
-
color
|
14
|
+
color?: string;
|
15
15
|
}) => {
|
16
16
|
return (
|
17
17
|
<Flex align="center" css={{ w: '100%', color, cursor: 'pointer', gap: '$4', p: '$8' }} onClick={onClick}>
|
@@ -11,13 +11,15 @@ import { ArrowNavigation } from './ArrowNavigation';
|
|
11
11
|
import { AnnotisedMessage } from './ChatBody';
|
12
12
|
import { StickIndicator } from './StickIndicator';
|
13
13
|
import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
|
14
|
+
import { useSetPinnedMessages } from '../hooks/useSetPinnedMessages';
|
14
15
|
import { SESSION_STORE_KEY } from '../../common/constants';
|
15
16
|
|
16
17
|
const PINNED_MESSAGE_LENGTH = 75;
|
17
18
|
|
18
|
-
export const PinnedMessage = (
|
19
|
+
export const PinnedMessage = () => {
|
19
20
|
const pinnedMessages = useHMSStore(selectSessionStore(SESSION_STORE_KEY.PINNED_MESSAGES));
|
20
21
|
const [pinnedMessageIndex, setPinnedMessageIndex] = useState(0);
|
22
|
+
const { removePinnedMessage } = useSetPinnedMessages();
|
21
23
|
const isMobile = useMedia(cssConfig.media.md);
|
22
24
|
|
23
25
|
const { elements } = useRoomLayoutConferencingScreen();
|
@@ -117,7 +119,7 @@ export const PinnedMessage = ({ clearPinnedMessage }: { clearPinnedMessage: (ind
|
|
117
119
|
{canUnpinMessage ? (
|
118
120
|
<Flex
|
119
121
|
onClick={() => {
|
120
|
-
|
122
|
+
removePinnedMessage(pinnedMessageIndex);
|
121
123
|
setPinnedMessageIndex(Math.max(0, pinnedMessageIndex - 1));
|
122
124
|
}}
|
123
125
|
css={{
|
@@ -1,21 +1,30 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import { QuizIcon } from '@100mslive/react-icons';
|
2
|
+
import { QuizActiveIcon, QuizIcon } from '@100mslive/react-icons';
|
3
3
|
import { Tooltip } from '../../..';
|
4
4
|
// @ts-ignore: No implicit Any
|
5
5
|
import IconButton from '../../IconButton';
|
6
6
|
// @ts-ignore: No implicit Any
|
7
7
|
import { useIsSidepaneTypeOpen, usePollViewToggle } from '../AppData/useSidepane';
|
8
|
+
import { useUnreadPollQuizPresent } from '../hooks/useUnreadPollQuizPresent';
|
8
9
|
// @ts-ignore: No implicit Any
|
9
10
|
import { SIDE_PANE_OPTIONS } from '../../common/constants';
|
10
11
|
|
11
12
|
export const PollsToggle = () => {
|
12
13
|
const isPollsOpen = useIsSidepaneTypeOpen(SIDE_PANE_OPTIONS.POLLS);
|
13
14
|
const togglePollView = usePollViewToggle();
|
15
|
+
const { unreadPollQuiz, setUnreadPollQuiz } = useUnreadPollQuizPresent();
|
14
16
|
|
15
17
|
return (
|
16
18
|
<Tooltip key="polls" title={`${isPollsOpen ? 'Close' : 'Open'} polls and quizzes`}>
|
17
|
-
<IconButton
|
18
|
-
|
19
|
+
<IconButton
|
20
|
+
onClick={() => {
|
21
|
+
togglePollView();
|
22
|
+
setUnreadPollQuiz(false);
|
23
|
+
}}
|
24
|
+
active={!isPollsOpen}
|
25
|
+
data-testid="polls_btn"
|
26
|
+
>
|
27
|
+
{unreadPollQuiz ? <QuizActiveIcon /> : <QuizIcon />}
|
19
28
|
</IconButton>
|
20
29
|
</Tooltip>
|
21
30
|
);
|
@@ -77,8 +77,8 @@ export const DesktopLeaveRoom = ({
|
|
77
77
|
bg: '$surface_dim',
|
78
78
|
color: '$on_surface_medium',
|
79
79
|
'&:hover': { bg: '$surface_default', color: '$on_surface_high' },
|
80
|
+
p: '0',
|
80
81
|
}}
|
81
|
-
onClick={async () => await leaveRoom()}
|
82
82
|
data-testid="just_leave_btn"
|
83
83
|
>
|
84
84
|
<LeaveCard
|
@@ -90,7 +90,7 @@ export const DesktopLeaveRoom = ({
|
|
90
90
|
titleColor="$on_surface_high"
|
91
91
|
icon={<ExitIcon height={24} width={24} style={{ transform: 'rotate(180deg)' }} />}
|
92
92
|
onClick={async () => await leaveRoom()}
|
93
|
-
css={{ p:
|
93
|
+
css={{ p: '$8 $4' }}
|
94
94
|
/>
|
95
95
|
</Dropdown.Item>
|
96
96
|
|
@@ -99,6 +99,7 @@ export const DesktopLeaveRoom = ({
|
|
99
99
|
bg: '$alert_error_dim',
|
100
100
|
color: '$alert_error_bright',
|
101
101
|
'&:hover': { bg: '$alert_error_dim', color: '$alert_error_brighter' },
|
102
|
+
p: '0',
|
102
103
|
}}
|
103
104
|
data-testid="end_room_btn"
|
104
105
|
>
|
@@ -114,7 +115,7 @@ export const DesktopLeaveRoom = ({
|
|
114
115
|
setOpen(false);
|
115
116
|
setShowEndStreamAlert(true);
|
116
117
|
}}
|
117
|
-
css={{ p:
|
118
|
+
css={{ p: '$8 $4' }}
|
118
119
|
/>
|
119
120
|
</Dropdown.Item>
|
120
121
|
</Dropdown.Content>
|
@@ -18,6 +18,7 @@ import {
|
|
18
18
|
HandIcon,
|
19
19
|
HandRaiseSlashedIcon,
|
20
20
|
PeopleIcon,
|
21
|
+
QuizActiveIcon,
|
21
22
|
QuizIcon,
|
22
23
|
RecordIcon,
|
23
24
|
SettingsIcon,
|
@@ -48,6 +49,7 @@ import { useShowPolls } from '../../AppData/useUISettings';
|
|
48
49
|
import { useDropdownList } from '../../hooks/useDropdownList';
|
49
50
|
// @ts-ignore: No implicit any
|
50
51
|
import { useMyMetadata } from '../../hooks/useMetadata';
|
52
|
+
import { useUnreadPollQuizPresent } from '../../hooks/useUnreadPollQuizPresent';
|
51
53
|
// @ts-ignore: No implicit any
|
52
54
|
import { getFormattedCount } from '../../../common/utils';
|
53
55
|
// @ts-ignore: No implicit any
|
@@ -92,6 +94,7 @@ export const MwebOptions = ({
|
|
92
94
|
const { isBRBOn, toggleBRB, isHandRaised, toggleHandRaise } = useMyMetadata();
|
93
95
|
const { toggleAudio, toggleVideo } = useAVToggle();
|
94
96
|
const noAVPermissions = !(toggleAudio || toggleVideo);
|
97
|
+
const { unreadPollQuiz, setUnreadPollQuiz } = useUnreadPollQuizPresent();
|
95
98
|
// const isVideoOn = useHMSStore(selectIsLocalVideoEnabled);
|
96
99
|
|
97
100
|
useDropdownList({ open: openModals.size > 0 || openOptionsSheet || openSettingsSheet, name: 'MoreSettings' });
|
@@ -202,9 +205,10 @@ export const MwebOptions = ({
|
|
202
205
|
onClick={() => {
|
203
206
|
togglePollView();
|
204
207
|
setOpenOptionsSheet(false);
|
208
|
+
setUnreadPollQuiz(false);
|
205
209
|
}}
|
206
210
|
>
|
207
|
-
<QuizIcon />
|
211
|
+
{unreadPollQuiz ? <QuizActiveIcon /> : <QuizIcon />}
|
208
212
|
<ActionTile.Title>Polls and Quizzes</ActionTile.Title>
|
209
213
|
</ActionTile.Root>
|
210
214
|
)}
|
@@ -51,7 +51,7 @@ export const MultipleChoiceOptions = ({
|
|
51
51
|
</Checkbox.Root>
|
52
52
|
) : null}
|
53
53
|
|
54
|
-
{isStopped && correctOptionIndexes
|
54
|
+
{isStopped && correctOptionIndexes?.includes(option.index) ? (
|
55
55
|
<Flex css={{ color: '$on_surface_high' }}>
|
56
56
|
<CheckCircleIcon />
|
57
57
|
</Flex>
|