@100mslive/roomkit-react 0.3.16-alpha.1 → 0.3.16-alpha.11
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-ERPYXVOY.js → HLSView-CTSCXXFA.js} +2 -2
- package/dist/{HLSView-T2PXKR6I.css → HLSView-Y2452RZU.css} +3 -3
- package/dist/{HLSView-T2PXKR6I.css.map → HLSView-Y2452RZU.css.map} +1 -1
- package/dist/Prebuilt/components/IconButtonWithOptions/IconButtonWithOptions.d.ts +2 -1
- package/dist/{chunk-NKC36NL4.js → chunk-I7DPNCT4.js} +1066 -968
- package/dist/chunk-I7DPNCT4.js.map +7 -0
- package/dist/index.cjs.css +2 -2
- package/dist/index.cjs.css.map +1 -1
- package/dist/index.cjs.js +1480 -1384
- package/dist/index.cjs.js.map +4 -4
- package/dist/index.css +2 -2
- package/dist/index.css.map +1 -1
- package/dist/index.js +1 -1
- package/dist/meta.cjs.json +110 -80
- package/dist/meta.esbuild.json +123 -93
- package/package.json +7 -7
- package/src/Prebuilt/App.tsx +21 -18
- package/src/Prebuilt/components/AudioVideoToggle.tsx +6 -12
- package/src/Prebuilt/components/ConferenceScreen.tsx +13 -1
- package/src/Prebuilt/components/Footer/ParticipantList.tsx +1 -4
- package/src/Prebuilt/components/IconButtonWithOptions/IconButtonWithOptions.tsx +9 -1
- package/src/Prebuilt/components/MoreSettings/MoreSettings.tsx +1 -4
- package/src/Prebuilt/components/MoreSettings/SplitComponents/DesktopOptions.tsx +12 -2
- package/src/Prebuilt/components/Notifications/HandRaisedNotifications.tsx +33 -0
- package/src/Prebuilt/components/Notifications/Notifications.tsx +3 -1
- package/src/Prebuilt/components/PIP/PIPChat.tsx +62 -14
- package/src/Prebuilt/components/PIP/PIPWindow.tsx +1 -1
- package/src/Prebuilt/components/PIP/usePIPChat.tsx +2 -0
- package/src/Prebuilt/components/Preview/PreviewJoin.tsx +3 -1
- package/src/Prebuilt/components/Toast/ToastConfig.jsx +2 -2
- package/src/Prebuilt/components/VirtualBackground/VBOption.tsx +1 -1
- package/dist/chunk-NKC36NL4.js.map +0 -7
- /package/dist/{HLSView-ERPYXVOY.js.map → HLSView-CTSCXXFA.js.map} +0 -0
package/src/Prebuilt/App.tsx
CHANGED
|
@@ -23,6 +23,7 @@ import { KeyboardHandler } from './components/Input/KeyboardInputManager';
|
|
|
23
23
|
import { LeaveScreen } from './components/LeaveScreen';
|
|
24
24
|
import { MwebLandscapePrompt } from './components/MwebLandscapePrompt';
|
|
25
25
|
import { Notifications } from './components/Notifications';
|
|
26
|
+
import { PIPProvider } from './components/PIP/PIPProvider';
|
|
26
27
|
import { PreviewScreen } from './components/Preview/PreviewScreen';
|
|
27
28
|
// @ts-ignore: No implicit Any
|
|
28
29
|
import { ToastContainer } from './components/Toast/ToastContainer';
|
|
@@ -218,24 +219,26 @@ export const HMSPrebuilt = React.forwardRef<HMSPrebuiltRefType, HMSPrebuiltProps
|
|
|
218
219
|
},
|
|
219
220
|
}}
|
|
220
221
|
>
|
|
221
|
-
<
|
|
222
|
-
|
|
223
|
-
<
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
222
|
+
<PIPProvider>
|
|
223
|
+
<Init />
|
|
224
|
+
<DialogContainerProvider dialogContainerSelector={containerSelector}>
|
|
225
|
+
<Box
|
|
226
|
+
className={DEFAULT_PORTAL_CONTAINER.slice(1)} // Skips the '.' in the selector
|
|
227
|
+
css={{
|
|
228
|
+
bg: '$background_dim',
|
|
229
|
+
size: '100%',
|
|
230
|
+
lineHeight: '1.5',
|
|
231
|
+
'-webkit-text-size-adjust': '100%',
|
|
232
|
+
position: 'relative',
|
|
233
|
+
}}
|
|
234
|
+
>
|
|
235
|
+
<AppRoutes
|
|
236
|
+
authTokenByRoomCodeEndpoint={tokenByRoomCodeEndpoint}
|
|
237
|
+
defaultAuthToken={authToken}
|
|
238
|
+
/>
|
|
239
|
+
</Box>
|
|
240
|
+
</DialogContainerProvider>
|
|
241
|
+
</PIPProvider>
|
|
239
242
|
</HMSThemeProvider>
|
|
240
243
|
);
|
|
241
244
|
}}
|
|
@@ -44,7 +44,7 @@ import { useRoomLayoutConferencingScreen } from '../provider/roomLayoutProvider/
|
|
|
44
44
|
// @ts-ignore: No implicit Any
|
|
45
45
|
import { useIsNoiseCancellationEnabled, useSetNoiseCancellation } from './AppData/useUISettings';
|
|
46
46
|
import { useAudioOutputTest } from './hooks/useAudioOutputTest';
|
|
47
|
-
import { isMacOS, TEST_AUDIO_URL } from '../common/constants';
|
|
47
|
+
import { isAndroid, isIOS, isMacOS, TEST_AUDIO_URL } from '../common/constants';
|
|
48
48
|
|
|
49
49
|
const krispPlugin = new HMSKrispPlugin();
|
|
50
50
|
// const optionsCSS = { fontWeight: '$semiBold', color: '$on_surface_high', w: '100%' };
|
|
@@ -310,10 +310,9 @@ export const AudioVideoToggle = ({ hideOptions = false }: { hideOptions?: boolea
|
|
|
310
310
|
disabled={!toggleAudio}
|
|
311
311
|
hideOptions={hideOptions || !hasAudioDevices}
|
|
312
312
|
onDisabledClick={toggleAudio}
|
|
313
|
+
testid="audio_toggle_btn"
|
|
313
314
|
tooltipMessage={`Turn ${isLocalAudioEnabled ? 'off' : 'on'} audio (${isMacOS ? '⌘' : 'ctrl'} + d)`}
|
|
314
|
-
icon={
|
|
315
|
-
!isLocalAudioEnabled ? <MicOffIcon data-testid="audio_off_btn" /> : <MicOnIcon data-testid="audio_on_btn" />
|
|
316
|
-
}
|
|
315
|
+
icon={!isLocalAudioEnabled ? <MicOffIcon /> : <MicOnIcon />}
|
|
317
316
|
active={isLocalAudioEnabled}
|
|
318
317
|
onClick={toggleAudio}
|
|
319
318
|
key="toggleAudio"
|
|
@@ -353,13 +352,8 @@ export const AudioVideoToggle = ({ hideOptions = false }: { hideOptions?: boolea
|
|
|
353
352
|
hideOptions={hideOptions || !hasVideoDevices}
|
|
354
353
|
onDisabledClick={toggleVideo}
|
|
355
354
|
tooltipMessage={`Turn ${isLocalVideoEnabled ? 'off' : 'on'} video (${isMacOS ? '⌘' : 'ctrl'} + e)`}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
<VideoOffIcon data-testid="video_off_btn" />
|
|
359
|
-
) : (
|
|
360
|
-
<VideoOnIcon data-testid="video_on_btn" />
|
|
361
|
-
)
|
|
362
|
-
}
|
|
355
|
+
testid="video_toggle_btn"
|
|
356
|
+
icon={!isLocalVideoEnabled ? <VideoOffIcon /> : <VideoOnIcon />}
|
|
363
357
|
key="toggleVideo"
|
|
364
358
|
active={isLocalVideoEnabled}
|
|
365
359
|
onClick={toggleVideo}
|
|
@@ -372,7 +366,7 @@ export const AudioVideoToggle = ({ hideOptions = false }: { hideOptions?: boolea
|
|
|
372
366
|
</IconButtonWithOptions>
|
|
373
367
|
) : null}
|
|
374
368
|
|
|
375
|
-
{localVideoTrack?.facingMode && roomState === HMSRoomState.Preview ? (
|
|
369
|
+
{localVideoTrack?.facingMode && roomState === HMSRoomState.Preview && (isIOS || isAndroid) ? (
|
|
376
370
|
<Tooltip title="Switch Camera" key="switchCamera">
|
|
377
371
|
<IconButton
|
|
378
372
|
onClick={async () => {
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
selectAppData,
|
|
7
7
|
selectIsConnectedToRoom,
|
|
8
8
|
selectRoomState,
|
|
9
|
+
useAwayNotifications,
|
|
9
10
|
useHMSActions,
|
|
10
11
|
useHMSStore,
|
|
11
12
|
} from '@100mslive/react-sdk';
|
|
@@ -50,6 +51,7 @@ export const ConferenceScreen = () => {
|
|
|
50
51
|
const isMobileDevice = isAndroid || isIOS || isIPadOS;
|
|
51
52
|
const dropdownListRef = useRef<string[]>();
|
|
52
53
|
const [isHLSStarted] = useSetAppDataByKey(APP_DATA.hlsStarted);
|
|
54
|
+
const { requestPermission } = useAwayNotifications();
|
|
53
55
|
|
|
54
56
|
// using it in hls stream to show action button when chat is disabled
|
|
55
57
|
const showChat = !!screenProps.elements?.chat;
|
|
@@ -99,10 +101,20 @@ export const ConferenceScreen = () => {
|
|
|
99
101
|
speakerAutoSelectionBlacklist: ['Yeti Stereo Microphone'],
|
|
100
102
|
},
|
|
101
103
|
})
|
|
104
|
+
.then(() => requestPermission())
|
|
102
105
|
.catch(console.error);
|
|
103
106
|
autoRoomJoined.current = true;
|
|
104
107
|
}
|
|
105
|
-
}, [
|
|
108
|
+
}, [
|
|
109
|
+
authTokenInAppData,
|
|
110
|
+
endpoints?.init,
|
|
111
|
+
hmsActions,
|
|
112
|
+
isConnectedToRoom,
|
|
113
|
+
isPreviewScreenEnabled,
|
|
114
|
+
roomState,
|
|
115
|
+
userName,
|
|
116
|
+
requestPermission,
|
|
117
|
+
]);
|
|
106
118
|
|
|
107
119
|
useEffect(() => {
|
|
108
120
|
onJoinFunc?.();
|
|
@@ -194,7 +194,6 @@ export const Participant = ({
|
|
|
194
194
|
<ParticipantActions
|
|
195
195
|
peerId={peer.id}
|
|
196
196
|
peerType={peer.type}
|
|
197
|
-
isLocal={peer.id === localPeerId}
|
|
198
197
|
role={peer.roleName}
|
|
199
198
|
isHandRaisedAccordion={isHandRaisedAccordion}
|
|
200
199
|
/>
|
|
@@ -273,12 +272,10 @@ const ParticipantActions = React.memo(
|
|
|
273
272
|
peerId,
|
|
274
273
|
peerType,
|
|
275
274
|
role,
|
|
276
|
-
isLocal,
|
|
277
275
|
isHandRaisedAccordion,
|
|
278
276
|
}: {
|
|
279
277
|
peerId: string;
|
|
280
278
|
role: string;
|
|
281
|
-
isLocal: boolean;
|
|
282
279
|
isHandRaisedAccordion?: boolean;
|
|
283
280
|
peerType: HMSPeerType;
|
|
284
281
|
}) => {
|
|
@@ -331,7 +328,7 @@ const ParticipantActions = React.memo(
|
|
|
331
328
|
</Flex>
|
|
332
329
|
) : null}
|
|
333
330
|
|
|
334
|
-
{shouldShowMoreActions
|
|
331
|
+
{shouldShowMoreActions ? <ParticipantMoreActions peerId={peerId} role={role} /> : null}
|
|
335
332
|
</>
|
|
336
333
|
)}
|
|
337
334
|
</Flex>
|
|
@@ -90,6 +90,7 @@ export const IconButtonWithOptions = ({
|
|
|
90
90
|
onDisabledClick = () => {
|
|
91
91
|
return;
|
|
92
92
|
},
|
|
93
|
+
testid = '',
|
|
93
94
|
tooltipMessage = '',
|
|
94
95
|
icon,
|
|
95
96
|
children,
|
|
@@ -103,6 +104,7 @@ export const IconButtonWithOptions = ({
|
|
|
103
104
|
onDisabledClick: () => void;
|
|
104
105
|
icon: React.ReactNode;
|
|
105
106
|
children: React.ReactNode;
|
|
107
|
+
testid?: string;
|
|
106
108
|
hideOptions?: boolean;
|
|
107
109
|
active: boolean;
|
|
108
110
|
disabled?: boolean;
|
|
@@ -111,7 +113,13 @@ export const IconButtonWithOptions = ({
|
|
|
111
113
|
const commonProps = { disabled, active };
|
|
112
114
|
return (
|
|
113
115
|
<Flex>
|
|
114
|
-
<IconSection
|
|
116
|
+
<IconSection
|
|
117
|
+
data-testid={testid}
|
|
118
|
+
{...commonProps}
|
|
119
|
+
onClick={onClick}
|
|
120
|
+
hideOptions={hideOptions}
|
|
121
|
+
className="__cancel-drag-event"
|
|
122
|
+
>
|
|
115
123
|
<Tooltip disabled={!tooltipMessage} title={tooltipMessage}>
|
|
116
124
|
<Icon {...commonProps}>{icon}</Icon>
|
|
117
125
|
</Tooltip>
|
|
@@ -10,7 +10,6 @@ import { DesktopOptions } from './SplitComponents/DesktopOptions';
|
|
|
10
10
|
// @ts-ignore: No implicit Any
|
|
11
11
|
import { MwebOptions } from './SplitComponents/MwebOptions';
|
|
12
12
|
import { config as cssConfig } from '../../..';
|
|
13
|
-
import { PIPProvider } from '../PIP/PIPProvider';
|
|
14
13
|
import { useLandscapeHLSStream } from '../../common/hooks';
|
|
15
14
|
|
|
16
15
|
export const MoreSettings = ({
|
|
@@ -25,8 +24,6 @@ export const MoreSettings = ({
|
|
|
25
24
|
return isMobile || isLandscapeHLSStream ? (
|
|
26
25
|
<MwebOptions elements={elements} screenType={screenType} />
|
|
27
26
|
) : (
|
|
28
|
-
<
|
|
29
|
-
<DesktopOptions elements={elements} screenType={screenType} />
|
|
30
|
-
</PIPProvider>
|
|
27
|
+
<DesktopOptions elements={elements} screenType={screenType} />
|
|
31
28
|
);
|
|
32
29
|
};
|
|
@@ -48,12 +48,14 @@ import { CaptionModal } from '../CaptionModal';
|
|
|
48
48
|
import { FullScreenItem } from '../FullScreenItem';
|
|
49
49
|
import { MuteAllModal } from '../MuteAllModal';
|
|
50
50
|
// @ts-ignore: No implicit any
|
|
51
|
+
import { useIsSidepaneTypeOpen, useSidepaneToggle } from '../../AppData/useSidepane';
|
|
52
|
+
// @ts-ignore: No implicit any
|
|
51
53
|
import { useDropdownList } from '../../hooks/useDropdownList';
|
|
52
54
|
import { useMyMetadata } from '../../hooks/useMetadata';
|
|
53
55
|
// @ts-ignore: No implicit any
|
|
54
56
|
import { usePIPChat } from '../../PIP/usePIPChat';
|
|
55
57
|
// @ts-ignore: No implicit any
|
|
56
|
-
import { APP_DATA, isMacOS } from '../../../common/constants';
|
|
58
|
+
import { APP_DATA, isMacOS, SIDE_PANE_OPTIONS } from '../../../common/constants';
|
|
57
59
|
|
|
58
60
|
const MODALS = {
|
|
59
61
|
CHANGE_NAME: 'changeName',
|
|
@@ -85,6 +87,8 @@ export const DesktopOptions = ({
|
|
|
85
87
|
const isTranscriptionAllowed = useHMSStore(selectIsTranscriptionAllowedByMode(HMSTranscriptionMode.CAPTION));
|
|
86
88
|
const isTranscriptionEnabled = useHMSStore(selectIsTranscriptionEnabled);
|
|
87
89
|
const { isSupported, pipWindow, requestPipWindow } = usePIPChat();
|
|
90
|
+
const isChatOpen = useIsSidepaneTypeOpen(SIDE_PANE_OPTIONS.CHAT);
|
|
91
|
+
const toggleChat = useSidepaneToggle(SIDE_PANE_OPTIONS.CHAT);
|
|
88
92
|
const showPipChatOption = !!elements?.chat && isSupported;
|
|
89
93
|
|
|
90
94
|
useDropdownList({ open: openModals.size > 0, name: 'MoreSettings' });
|
|
@@ -180,7 +184,13 @@ export const DesktopOptions = ({
|
|
|
180
184
|
</Dropdown.Item>
|
|
181
185
|
) : null}
|
|
182
186
|
|
|
183
|
-
<PIPChatOption
|
|
187
|
+
<PIPChatOption
|
|
188
|
+
showPIPChat={showPipChatOption}
|
|
189
|
+
openChat={async () => {
|
|
190
|
+
isChatOpen && toggleChat();
|
|
191
|
+
await requestPipWindow(350, 500);
|
|
192
|
+
}}
|
|
193
|
+
/>
|
|
184
194
|
<FullScreenItem />
|
|
185
195
|
<Dropdown.ItemSeparator css={{ mx: 0 }} />
|
|
186
196
|
<Dropdown.Item onClick={() => updateState(MODALS.DEVICE_SETTINGS, true)} data-testid="device_settings_btn">
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import { useEffect } from 'react';
|
|
2
|
+
import { useDebounce } from 'react-use';
|
|
2
3
|
import {
|
|
3
4
|
HMSNotificationTypes,
|
|
4
5
|
HMSRoomState,
|
|
6
|
+
selectHandRaisedPeers,
|
|
5
7
|
selectHasPeerHandRaised,
|
|
8
|
+
selectIsLocalScreenShared,
|
|
6
9
|
selectPeerByID,
|
|
7
10
|
selectRoomState,
|
|
11
|
+
useAwayNotifications,
|
|
8
12
|
useHMSNotifications,
|
|
9
13
|
useHMSStore,
|
|
10
14
|
useHMSVanillaStore,
|
|
11
15
|
} from '@100mslive/react-sdk';
|
|
16
|
+
import { useRoomLayout } from '../../provider/roomLayoutProvider';
|
|
12
17
|
// @ts-ignore: No implicit Any
|
|
13
18
|
import { ToastBatcher } from '../Toast/ToastBatcher';
|
|
14
19
|
import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
|
|
@@ -22,6 +27,9 @@ export const HandRaisedNotifications = () => {
|
|
|
22
27
|
const vanillaStore = useHMSVanillaStore();
|
|
23
28
|
const { on_stage_exp } = useRoomLayoutConferencingScreen().elements || {};
|
|
24
29
|
const isSubscribing = !!useSubscribedNotifications(SUBSCRIBED_NOTIFICATIONS.METADATA_UPDATED);
|
|
30
|
+
const amIScreenSharing = useHMSStore(selectIsLocalScreenShared);
|
|
31
|
+
const { showNotification } = useAwayNotifications();
|
|
32
|
+
const logoURL = useRoomLayout()?.logo?.url;
|
|
25
33
|
|
|
26
34
|
useEffect(() => {
|
|
27
35
|
if (!notification?.data) {
|
|
@@ -32,6 +40,7 @@ export const HandRaisedNotifications = () => {
|
|
|
32
40
|
if (roomState !== HMSRoomState.Connected || notification.data.isLocal || !isSubscribing) {
|
|
33
41
|
return;
|
|
34
42
|
}
|
|
43
|
+
|
|
35
44
|
const hasPeerHandRaised = vanillaStore.getState(selectHasPeerHandRaised(notification.data.id));
|
|
36
45
|
const peer = vanillaStore.getState(selectPeerByID(notification.data.id));
|
|
37
46
|
if (hasPeerHandRaised) {
|
|
@@ -41,5 +50,29 @@ export const HandRaisedNotifications = () => {
|
|
|
41
50
|
}
|
|
42
51
|
}, [isSubscribing, notification, on_stage_exp, roomState, vanillaStore]);
|
|
43
52
|
|
|
53
|
+
useDebounce(
|
|
54
|
+
() => {
|
|
55
|
+
if (!notification?.data) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Don't show toast message in case of local peer.
|
|
60
|
+
if (roomState !== HMSRoomState.Connected || notification.data.isLocal || !isSubscribing) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const hasPeerHandRaised = vanillaStore.getState(selectHasPeerHandRaised(notification.data.id));
|
|
65
|
+
const peer = vanillaStore.getState(selectPeerByID(notification.data.id));
|
|
66
|
+
const handRaisedPeers = vanillaStore.getState(selectHandRaisedPeers);
|
|
67
|
+
if (amIScreenSharing && hasPeerHandRaised) {
|
|
68
|
+
const title = `${peer?.name} ${
|
|
69
|
+
handRaisedPeers.length > 1 ? `and ${handRaisedPeers.length - 1} others` : ''
|
|
70
|
+
} raised hand`;
|
|
71
|
+
showNotification(title, { icon: logoURL });
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
1000,
|
|
75
|
+
[isSubscribing, notification, roomState, vanillaStore, amIScreenSharing],
|
|
76
|
+
);
|
|
44
77
|
return null;
|
|
45
78
|
};
|
|
@@ -35,6 +35,7 @@ import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvid
|
|
|
35
35
|
import { usePollViewToggle } from '../AppData/useSidepane';
|
|
36
36
|
// @ts-ignore: No implicit Any
|
|
37
37
|
import { useIsNotificationDisabled, useSubscribedNotifications } from '../AppData/useUISettings';
|
|
38
|
+
import { usePIPWindow } from '../PIP/usePIPWindow';
|
|
38
39
|
import { ROLE_CHANGE_DECLINED } from '../../common/constants';
|
|
39
40
|
|
|
40
41
|
const pollToastKey: Record<string, string> = {};
|
|
@@ -52,6 +53,7 @@ export function Notifications() {
|
|
|
52
53
|
const { showNotification } = useAwayNotifications();
|
|
53
54
|
const amIScreenSharing = useHMSStore(selectIsLocalScreenShared);
|
|
54
55
|
const logoURL = useRoomLayout()?.logo?.url;
|
|
56
|
+
const { pipWindow } = usePIPWindow();
|
|
55
57
|
|
|
56
58
|
const handleRoleChangeDenied = useCallback((request: HMSRoleChangeRequest & { peerName: string }) => {
|
|
57
59
|
ToastManager.addToast({
|
|
@@ -172,7 +174,7 @@ export function Notifications() {
|
|
|
172
174
|
}
|
|
173
175
|
break;
|
|
174
176
|
case HMSNotificationTypes.NEW_MESSAGE:
|
|
175
|
-
if (amIScreenSharing && !notification.data?.ignored) {
|
|
177
|
+
if (amIScreenSharing && !notification.data?.ignored && !pipWindow) {
|
|
176
178
|
showNotification(`New message from ${notification.data.senderName}`, {
|
|
177
179
|
body: notification.data.message,
|
|
178
180
|
icon: logoURL,
|
|
@@ -2,6 +2,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
|
2
2
|
import {
|
|
3
3
|
selectHMSMessages,
|
|
4
4
|
selectLocalPeerID,
|
|
5
|
+
selectPeerNameByID,
|
|
5
6
|
selectSessionStore,
|
|
6
7
|
selectUnreadHMSMessagesCount,
|
|
7
8
|
useHMSStore,
|
|
@@ -14,6 +15,7 @@ import { Tooltip } from '../../../Tooltip';
|
|
|
14
15
|
import IconButton from '../../IconButton';
|
|
15
16
|
import { AnnotisedMessage } from '../Chat/ChatBody';
|
|
16
17
|
import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
|
|
18
|
+
import { useIsPeerBlacklisted } from '../hooks/useChatBlacklist';
|
|
17
19
|
import { CHAT_MESSAGE_LIMIT, formatTime } from '../Chat/utils';
|
|
18
20
|
import { SESSION_STORE_KEY } from '../../common/constants';
|
|
19
21
|
|
|
@@ -43,10 +45,29 @@ export const PIPChat = () => {
|
|
|
43
45
|
const blacklistedMessageIDSet = new Set(blacklistedMessageIDs || []);
|
|
44
46
|
return messages?.filter(message => message.type === 'chat' && !blacklistedMessageIDSet.has(message.id)) || [];
|
|
45
47
|
}, [blacklistedMessageIDs, messages]);
|
|
48
|
+
const { enabled: isChatEnabled = true, updatedBy: chatStateUpdatedBy = '' } =
|
|
49
|
+
useHMSStore(selectSessionStore(SESSION_STORE_KEY.CHAT_STATE)) || {};
|
|
50
|
+
const isLocalPeerBlacklisted = useIsPeerBlacklisted({ local: true });
|
|
46
51
|
const { elements } = useRoomLayoutConferencingScreen();
|
|
47
52
|
const message_placeholder = elements?.chat?.message_placeholder || 'Send a message';
|
|
48
53
|
const canSendChatMessages = !!elements?.chat?.public_chat_enabled || !!elements?.chat?.roles_whitelist?.length;
|
|
49
54
|
|
|
55
|
+
const getChatStatus = useCallback(() => {
|
|
56
|
+
if (isLocalPeerBlacklisted) return "You've been blocked from sending messages";
|
|
57
|
+
if (!isChatEnabled)
|
|
58
|
+
return `Chat has been paused by ${
|
|
59
|
+
chatStateUpdatedBy.peerId === localPeerID ? 'you' : chatStateUpdatedBy?.userName
|
|
60
|
+
}`;
|
|
61
|
+
return message_placeholder;
|
|
62
|
+
}, [
|
|
63
|
+
chatStateUpdatedBy.peerId,
|
|
64
|
+
chatStateUpdatedBy?.userName,
|
|
65
|
+
isChatEnabled,
|
|
66
|
+
isLocalPeerBlacklisted,
|
|
67
|
+
localPeerID,
|
|
68
|
+
message_placeholder,
|
|
69
|
+
]);
|
|
70
|
+
|
|
50
71
|
return (
|
|
51
72
|
<div style={{ height: '100%' }}>
|
|
52
73
|
<Box
|
|
@@ -55,7 +76,7 @@ export const PIPChat = () => {
|
|
|
55
76
|
bg: '$surface_dim',
|
|
56
77
|
overflowY: 'auto',
|
|
57
78
|
// Subtracting height of footer
|
|
58
|
-
h: canSendChatMessages ? 'calc(100% -
|
|
79
|
+
h: canSendChatMessages ? 'calc(100% - 87px)' : '100%',
|
|
59
80
|
position: 'relative',
|
|
60
81
|
}}
|
|
61
82
|
>
|
|
@@ -108,16 +129,11 @@ export const PIPChat = () => {
|
|
|
108
129
|
</Text>
|
|
109
130
|
</Tooltip>
|
|
110
131
|
)}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
{message.recipientPeer ? (
|
|
117
|
-
<Text as="span" variant="sub2" css={{ color: '$on_surface_high', fontWeight: '$semiBold' }}>
|
|
118
|
-
(DM)
|
|
119
|
-
</Text>
|
|
120
|
-
) : null}
|
|
132
|
+
<MessageTitle
|
|
133
|
+
localPeerID={localPeerID}
|
|
134
|
+
recipientPeer={message.recipientPeer}
|
|
135
|
+
recipientRoles={message.recipientRoles}
|
|
136
|
+
/>
|
|
121
137
|
</Flex>
|
|
122
138
|
|
|
123
139
|
<Text
|
|
@@ -193,13 +209,16 @@ export const PIPChat = () => {
|
|
|
193
209
|
<TextArea
|
|
194
210
|
id="chat-input"
|
|
195
211
|
maxLength={CHAT_MESSAGE_LIMIT}
|
|
196
|
-
|
|
212
|
+
disabled={!isChatEnabled || isLocalPeerBlacklisted}
|
|
213
|
+
rows={1}
|
|
197
214
|
css={{
|
|
198
215
|
w: '100%',
|
|
199
216
|
c: '$on_surface_high',
|
|
200
|
-
|
|
217
|
+
p: '0.75rem 0.75rem !important',
|
|
218
|
+
border: 'none',
|
|
219
|
+
resize: 'none',
|
|
201
220
|
}}
|
|
202
|
-
placeholder={
|
|
221
|
+
placeholder={getChatStatus()}
|
|
203
222
|
required
|
|
204
223
|
autoComplete="off"
|
|
205
224
|
aria-autocomplete="none"
|
|
@@ -207,6 +226,8 @@ export const PIPChat = () => {
|
|
|
207
226
|
|
|
208
227
|
<IconButton
|
|
209
228
|
id="send-btn"
|
|
229
|
+
disabled={!isChatEnabled || isLocalPeerBlacklisted}
|
|
230
|
+
title={getChatStatus()}
|
|
210
231
|
css={{
|
|
211
232
|
ml: 'auto',
|
|
212
233
|
height: 'max-content',
|
|
@@ -223,3 +244,30 @@ export const PIPChat = () => {
|
|
|
223
244
|
</div>
|
|
224
245
|
);
|
|
225
246
|
};
|
|
247
|
+
|
|
248
|
+
const MessageTitle = ({
|
|
249
|
+
recipientPeer,
|
|
250
|
+
recipientRoles,
|
|
251
|
+
localPeerID,
|
|
252
|
+
}: {
|
|
253
|
+
recipientPeer?: string;
|
|
254
|
+
recipientRoles?: string[];
|
|
255
|
+
localPeerID: string;
|
|
256
|
+
}) => {
|
|
257
|
+
const peerName = useHMSStore(selectPeerNameByID(recipientPeer));
|
|
258
|
+
|
|
259
|
+
return (
|
|
260
|
+
<>
|
|
261
|
+
{recipientRoles ? (
|
|
262
|
+
<Text as="span" variant="sub2" css={{ color: '$on_surface_high', fontWeight: '$semiBold' }}>
|
|
263
|
+
to {recipientRoles} (Group)
|
|
264
|
+
</Text>
|
|
265
|
+
) : null}
|
|
266
|
+
{recipientPeer ? (
|
|
267
|
+
<Text as="span" variant="sub2" css={{ color: '$on_surface_high', fontWeight: '$semiBold' }}>
|
|
268
|
+
to {recipientPeer === localPeerID ? 'You' : peerName} (DM)
|
|
269
|
+
</Text>
|
|
270
|
+
) : null}
|
|
271
|
+
</>
|
|
272
|
+
);
|
|
273
|
+
};
|
|
@@ -8,6 +8,6 @@ type PIPWindowProps = {
|
|
|
8
8
|
|
|
9
9
|
export const PIPWindow = ({ pipWindow, children }: PIPWindowProps) => {
|
|
10
10
|
pipWindow.document.body.style.margin = '0';
|
|
11
|
-
pipWindow.document.body.style.
|
|
11
|
+
pipWindow.document.body.style.overflow = 'clip';
|
|
12
12
|
return createPortal(children, pipWindow.document.body);
|
|
13
13
|
};
|
|
@@ -25,6 +25,8 @@ export const usePIPChat = () => {
|
|
|
25
25
|
const pipChatInput = pipWindow.document.getElementById('chat-input') as HTMLTextAreaElement;
|
|
26
26
|
const marker = pipWindow.document.getElementById('marker');
|
|
27
27
|
|
|
28
|
+
marker?.scrollIntoView({ block: 'end' });
|
|
29
|
+
|
|
28
30
|
const observer = new IntersectionObserver(
|
|
29
31
|
entries => {
|
|
30
32
|
entries.forEach(entry => {
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
selectRoomState,
|
|
9
9
|
selectVideoTrackByID,
|
|
10
10
|
useAVToggle,
|
|
11
|
+
useAwayNotifications,
|
|
11
12
|
useHMSStore,
|
|
12
13
|
useParticipants,
|
|
13
14
|
usePreviewJoin,
|
|
@@ -100,6 +101,7 @@ const PreviewJoin = ({
|
|
|
100
101
|
},
|
|
101
102
|
asRole,
|
|
102
103
|
});
|
|
104
|
+
const { requestPermission } = useAwayNotifications();
|
|
103
105
|
const roomState = useHMSStore(selectRoomState);
|
|
104
106
|
const savePreferenceAndJoin = useCallback(() => {
|
|
105
107
|
setPreviewPreference({
|
|
@@ -115,7 +117,7 @@ const PreviewJoin = ({
|
|
|
115
117
|
if (skipPreview) {
|
|
116
118
|
savePreferenceAndJoin();
|
|
117
119
|
} else {
|
|
118
|
-
preview();
|
|
120
|
+
preview().then(() => requestPermission());
|
|
119
121
|
}
|
|
120
122
|
}
|
|
121
123
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
@@ -111,7 +111,7 @@ export const ToastConfig = {
|
|
|
111
111
|
const count = new Set(notifications.map(notification => notification.data?.id)).size;
|
|
112
112
|
return {
|
|
113
113
|
title: `${notifications[notifications.length - 1].data?.name} ${
|
|
114
|
-
count > 1 ?
|
|
114
|
+
count > 1 ? `and ${count} others` : ''
|
|
115
115
|
} raised hand`,
|
|
116
116
|
icon: <HandIcon />,
|
|
117
117
|
};
|
|
@@ -129,7 +129,7 @@ export const ToastConfig = {
|
|
|
129
129
|
const count = new Set(notifications.map(notification => notification.data?.id)).size;
|
|
130
130
|
return {
|
|
131
131
|
title: `${notifications[notifications.length - 1].data?.name} ${
|
|
132
|
-
count > 1 ?
|
|
132
|
+
count > 1 ? `and ${count} others` : ''
|
|
133
133
|
} raised hand`,
|
|
134
134
|
icon: <HandIcon />,
|
|
135
135
|
action: <HandRaiseAction isSingleHandRaise={false} />,
|
|
@@ -26,7 +26,7 @@ const Root = ({
|
|
|
26
26
|
border: `4px solid ${isActive ? '$primary_default' : '$surface_dim'}`,
|
|
27
27
|
cursor: 'pointer',
|
|
28
28
|
'&:hover': { border: '4px solid $primary_dim' },
|
|
29
|
-
...(mediaURL ? { height: '$20', backgroundImage: `url(${mediaURL})`, backgroundSize: 'cover' } : {}),
|
|
29
|
+
...(mediaURL ? { height: '$20', backgroundImage: `url("${mediaURL}")`, backgroundSize: 'cover' } : {}),
|
|
30
30
|
}}
|
|
31
31
|
onClick={async () => {
|
|
32
32
|
await onClick?.();
|