Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Notifications in prebuilt #3307

Merged
merged 6 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useEffect } from 'react';
import { HMSNotificationTypes, useHMSNotifications } from '@100mslive/react-sdk';
// @ts-ignore: No implicit Any
import { ToastManager } from '../Toast/ToastManager';

export const DeviceChangeNotifications = () => {
const notification = useHMSNotifications(HMSNotificationTypes.DEVICE_CHANGE_UPDATE);

useEffect(() => {
if (notification) {
ToastManager.addToast({
title: notification.message,
});
}
}, [notification]);

return null;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React, { useEffect } from 'react';
import { HMSNotificationTypes, useHMSNotifications } from '@100mslive/react-sdk';
import { GroupIcon } from '@100mslive/react-icons';
import { Box } from '../../../Layout';
// @ts-ignore: No implicit Any
import { ToastManager } from '../Toast/ToastManager';
// @ts-ignore: No implicit Any
import { useSubscribedNotifications } from '../AppData/useUISettings';

export const ErrorNotifications = () => {
const notification = useHMSNotifications(HMSNotificationTypes.ERROR);
const subscribedNotifications = useSubscribedNotifications() || {};

useEffect(() => {
if (!notification || !notification.data) return;

const { isTerminal, action, code, message, description } = notification.data;

if (isTerminal && action !== 'INIT') {
if ([500, 6008].includes(code)) {
ToastManager.addToast({
title: `Error: ${message}`,
});
} else if (message === 'role limit reached') {
ToastManager.addToast({
title: 'The room is currently full, try joining later',
close: true,
icon: (
<Box css={{ color: '$alert_error_default' }}>
<GroupIcon />
</Box>
),
});
} else {
ToastManager.addToast({
title: message || 'We couldn’t reconnect you. When you’re back online, try joining the room.',
close: false,
});
}
return;
}
// Autoplay error or user denied screen share (cancelled browser pop-up)
if ([3008, 3001, 3011].includes(code)) {
return;
}
if (action === 'INIT') {
return;
}
if (!subscribedNotifications.ERROR) return;
ToastManager.addToast({
title: `Error: ${message} - ${description}`,
});
}, [notification, subscribedNotifications.ERROR]);

return null;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { useEffect } from 'react';
import { HMSNotificationTypes, selectIsLocalScreenShared } from '@100mslive/hms-video-store';
import { useAwayNotifications, useHMSNotifications, useHMSStore } from '@100mslive/react-sdk';
import { useRoomLayout } from '../../provider/roomLayoutProvider';
import { usePIPWindow } from '../PIP/usePIPWindow';

export const MessageNotifications = () => {
const notification = useHMSNotifications(HMSNotificationTypes.NEW_MESSAGE);
const amIScreenSharing = useHMSStore(selectIsLocalScreenShared);
const logoURL = useRoomLayout()?.logo?.url;
const { pipWindow } = usePIPWindow();
const { showNotification } = useAwayNotifications();

useEffect(() => {
if (notification && amIScreenSharing && !notification.data?.ignored && !pipWindow) {
showNotification(`New message from ${notification.data.senderName}`, {
body: notification.data.message,
icon: logoURL,
});
}
}, [notification]);

return null;
};
Original file line number Diff line number Diff line change
@@ -1,59 +1,30 @@
/* eslint-disable no-case-declarations */
import React, { useCallback, useEffect } from 'react';
import {
HMSNotificationTypes,
HMSRoleChangeRequest,
HMSRoomState,
selectIsLocalScreenShared,
selectLocalPeerID,
selectPeerNameByID,
selectRoomState,
useAwayNotifications,
useCustomEvent,
useHMSNotifications,
useHMSStore,
useHMSVanillaStore,
} from '@100mslive/react-sdk';
import { GroupIcon } from '@100mslive/react-icons';
import { Box, Button } from '../../..';
import { useRoomLayout, useUpdateRoomLayout } from '../../provider/roomLayoutProvider';
import React, { useCallback } from 'react';
import { HMSRoleChangeRequest, HMSRoomState, selectRoomState, useCustomEvent, useHMSStore } from '@100mslive/react-sdk';
// @ts-ignore: No implicit Any
import { ToastManager } from '../Toast/ToastManager';
import { AutoplayBlockedModal } from './AutoplayBlockedModal';
import { ChatNotifications } from './ChatNotifications';
import { DeviceChangeNotifications } from './DeviceChangeNotifications';
import { ErrorNotifications } from './ErrorNotifications';
import { HandRaisedNotifications } from './HandRaisedNotifications';
import { InitErrorModal } from './InitErrorModal';
import { MessageNotifications } from './MessageNotifications';
import { PeerNotifications } from './PeerNotifications';
import { PermissionErrorNotificationModal } from './PermissionErrorModal';
import { PollNotificationModal } from './PollNotificationModal';
import { ReconnectNotifications } from './ReconnectNotifications';
import { TrackBulkUnmuteModal } from './TrackBulkUnmuteModal';
import { TrackNotifications } from './TrackNotifications';
import { TrackUnmuteModal } from './TrackUnmuteModal';
import { TranscriptionNotifications } from './TranscriptionNotifications';
import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
// @ts-ignore: No implicit Any
import { usePollViewToggle } from '../AppData/useSidepane';
// @ts-ignore: No implicit Any
import { useIsNotificationDisabled, useSubscribedNotifications } from '../AppData/useUISettings';
import { usePIPWindow } from '../PIP/usePIPWindow';
import { useIsNotificationDisabled } from '../AppData/useUISettings';
import { ROLE_CHANGE_DECLINED } from '../../common/constants';

const pollToastKey: Record<string, string> = {};

export function Notifications() {
const localPeerID = useHMSStore(selectLocalPeerID);
const notification = useHMSNotifications();
const subscribedNotifications = useSubscribedNotifications() || {};
const roomState = useHMSStore(selectRoomState);
const updateRoomLayoutForRole = useUpdateRoomLayout();
const isNotificationDisabled = useIsNotificationDisabled();
const screenProps = useRoomLayoutConferencingScreen();
const vanillaStore = useHMSVanillaStore();
const togglePollView = usePollViewToggle();
const { showNotification } = useAwayNotifications();
const amIScreenSharing = useHMSStore(selectIsLocalScreenShared);
const logoURL = useRoomLayout()?.logo?.url;
const { pipWindow } = usePIPWindow();

const handleRoleChangeDenied = useCallback((request: HMSRoleChangeRequest & { peerName: string }) => {
ToastManager.addToast({
Expand All @@ -64,129 +35,6 @@ export function Notifications() {

useCustomEvent({ type: ROLE_CHANGE_DECLINED, onEvent: handleRoleChangeDenied });

useEffect(() => {
if (!notification || isNotificationDisabled) {
return;
}
switch (notification.type) {
case HMSNotificationTypes.NAME_UPDATED:
console.log(notification.data.id + ' changed their name to ' + notification.data.name);
break;
case HMSNotificationTypes.ERROR:
if (notification.data?.isTerminal && notification.data?.action !== 'INIT') {
if ([500, 6008].includes(notification.data?.code)) {
ToastManager.addToast({
title: `Error: ${notification.data?.message}`,
});
} else if (notification.data?.message === 'role limit reached') {
ToastManager.addToast({
title: 'The room is currently full, try joining later',
close: true,
icon: (
<Box css={{ color: '$alert_error_default' }}>
<GroupIcon />
</Box>
),
});
} else {
ToastManager.addToast({
title:
notification.data?.message ||
'We couldn’t reconnect you. When you’re back online, try joining the room.',
close: false,
});
}
return;
}
// Autoplay error or user denied screen share (cancelled browser pop-up)
if (notification.data?.code === 3008 || notification.data?.code === 3001 || notification.data?.code === 3011) {
return;
}
if (notification.data?.action === 'INIT') {
return;
}
if (!subscribedNotifications.ERROR) return;
ToastManager.addToast({
title: `Error: ${notification.data?.message} - ${notification.data?.description}`,
});
break;
case HMSNotificationTypes.ROLE_UPDATED: {
if (notification.data?.isLocal && notification.data?.roleName) {
ToastManager.addToast({
title: `You are now a ${notification.data.roleName}`,
});
updateRoomLayoutForRole?.(notification.data.roleName);
}
break;
}
case HMSNotificationTypes.CHANGE_TRACK_STATE_REQUEST:
const track = notification.data?.track;
if (!notification.data.enabled) {
ToastManager.addToast({
title: `Your ${track.source} ${track.type} was muted by
${notification.data.requestedBy?.name}.`,
});
}
break;
case HMSNotificationTypes.REMOVED_FROM_ROOM:
case HMSNotificationTypes.ROOM_ENDED:
ToastManager.addToast({
title: `${notification.message}.
${notification.data.reason && `Reason: ${notification.data.reason}`}`,
});
break;
case HMSNotificationTypes.DEVICE_CHANGE_UPDATE:
ToastManager.addToast({
title: notification.message,
});
break;

case HMSNotificationTypes.POLL_STARTED:
if (notification.data.startedBy !== localPeerID && screenProps.screenType !== 'hls_live_streaming') {
const pollStartedBy = vanillaStore.getState(selectPeerNameByID(notification.data.startedBy)) || 'Participant';

const pollToastID = ToastManager.addToast({
title: `${pollStartedBy} started a ${notification.data.type}: ${notification.data.title}`,
action: (
<Button
onClick={() => togglePollView(notification.data.id)}
variant="standard"
css={{
backgroundColor: '$surface_bright',
fontWeight: '$semiBold',
color: '$on_surface_high',
p: '$xs $md',
}}
>
{notification.data.type === 'quiz' ? 'Answer' : 'Vote'}
</Button>
),
duration: Infinity,
});
pollToastKey[notification.data.id] = pollToastID;
}
break;
case HMSNotificationTypes.POLL_STOPPED:
const pollID = notification?.data.id;
if (pollID && pollToastKey?.[pollID]) {
ToastManager.removeToast(pollToastKey?.[notification.data.id]);
delete pollToastKey[notification?.data.id];
}
break;
case HMSNotificationTypes.NEW_MESSAGE:
if (amIScreenSharing && !notification.data?.ignored && !pipWindow) {
showNotification(`New message from ${notification.data.senderName}`, {
body: notification.data.message,
icon: logoURL,
});
}
break;
default:
break;
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [notification, subscribedNotifications.ERROR, subscribedNotifications.METADATA_UPDATED]);

if (isNotificationDisabled) {
return null;
}
Expand All @@ -197,7 +45,11 @@ export function Notifications() {
<TrackBulkUnmuteModal />
<TrackNotifications />
{roomState === HMSRoomState.Connected ? <PeerNotifications /> : null}
<PollNotificationModal />
<MessageNotifications />
<DeviceChangeNotifications />
<ReconnectNotifications />
<ErrorNotifications />
<AutoplayBlockedModal />
<PermissionErrorNotificationModal />
<InitErrorModal />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
import { useEffect } from 'react';
import { HMSNotificationTypes, useHMSNotifications } from '@100mslive/react-sdk';
import { useUpdateRoomLayout } from '../../provider/roomLayoutProvider';
// @ts-ignore: No implicit Any
import { ToastBatcher } from '../Toast/ToastBatcher';
// @ts-ignore: No implicit Any
import { ToastManager } from '../Toast/ToastManager';
// @ts-ignore: No implicit Any
import { useSetSubscribedChatSelector, useSubscribedNotifications } from '../AppData/useUISettings';
// @ts-ignore: No implicit Any
import { CHAT_SELECTOR, SUBSCRIBED_NOTIFICATIONS } from '../../common/constants';

const notificationTypes = [HMSNotificationTypes.PEER_JOINED, HMSNotificationTypes.PEER_LEFT];
const notificationTypes = [
HMSNotificationTypes.PEER_JOINED,
HMSNotificationTypes.PEER_LEFT,
HMSNotificationTypes.NAME_UPDATED,
HMSNotificationTypes.ROLE_UPDATED,
];

export const PeerNotifications = () => {
const notification = useHMSNotifications(notificationTypes);
const isPeerJoinSubscribed = useSubscribedNotifications(SUBSCRIBED_NOTIFICATIONS.PEER_JOINED);
const isPeerLeftSubscribed = useSubscribedNotifications(SUBSCRIBED_NOTIFICATIONS.PEER_LEFT);
const [selectedPeer, setPeerSelector] = useSetSubscribedChatSelector(CHAT_SELECTOR.PEER);
const updateRoomLayoutForRole = useUpdateRoomLayout();

useEffect(() => {
if (!notification?.data) {
Expand All @@ -35,11 +44,23 @@ export const PeerNotifications = () => {
return;
}
break;
case HMSNotificationTypes.NAME_UPDATED:
console.log(notification.data.id + ' changed their name to ' + notification.data.name);
return;
case HMSNotificationTypes.ROLE_UPDATED: {
if (notification.data?.isLocal && notification.data?.roleName) {
ToastManager.addToast({
title: `You are now a ${notification.data.roleName}`,
});
updateRoomLayoutForRole?.(notification.data.roleName);
}
return;
}
default:
return;
}
ToastBatcher.showToast({ notification });
}, [notification, isPeerJoinSubscribed, isPeerLeftSubscribed, selectedPeer.id, setPeerSelector]);
}, [notification]);

return null;
};
Loading
Loading