communication-react-19
Version:
React library for building modern communication user experiences utilizing Azure Communication Services (React 19 compatible fork)
247 lines • 14.1 kB
JavaScript
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { getAssignedBreakoutRoom, getDeviceManager, getDiagnostics, getLatestErrors, getEnvironmentInfo, getCallState } from './baseSelectors';
import { getLatestNotifications } from './baseSelectors';
import { getMeetingConferencePhones } from './baseSelectors';
import { createSelector } from 'reselect';
import { DiagnosticQuality } from '@azure/communication-calling';
/**
* Select the active errors from the state for the `Notification` component.
*
* Invariants:
* - `ErrorType` is never repeated in the returned errors.
* - Errors are returned in a fixed order by `ErrorType`.
*
* @public
*/
export const notificationStackSelector = createSelector([
getLatestErrors,
getLatestNotifications,
getDiagnostics,
getDeviceManager,
getCallState,
getEnvironmentInfo,
getMeetingConferencePhones,
getAssignedBreakoutRoom
], (latestErrors, latestNotifications, diagnostics, deviceManager, callStatus, environmentInfo, meetingConference, assignedBreakoutRoom) => {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
// The order in which the errors are returned is significant: The `Notification` shows errors on the UI in that order.
// There are several options for the ordering:
// - Sorted by when the errors happened (latest first / oldest first).
// - Stable sort by error type.
//
// We chose to stable sort by error type: We intend to show only a small number of errors on the UI and we do not
// have timestamps for errors.
const activeErrorMessages = [];
const isSafari = () => {
return (environmentInfo === null || environmentInfo === void 0 ? void 0 : environmentInfo.environment.browser) === 'safari';
};
const isMacOS = () => {
return (environmentInfo === null || environmentInfo === void 0 ? void 0 : environmentInfo.environment.platform) === 'mac';
};
// Errors reported via diagnostics are more reliable than from API method failures, so process those first.
let isTeamsMeetingWithPhones = false;
if (meetingConference && meetingConference.length > 0) {
isTeamsMeetingWithPhones = true;
}
if (((_a = diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.network.latest.networkReceiveQuality) === null || _a === void 0 ? void 0 : _a.value) === DiagnosticQuality.Bad ||
((_b = diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.network.latest.networkReceiveQuality) === null || _b === void 0 ? void 0 : _b.value) === DiagnosticQuality.Poor) {
if (isTeamsMeetingWithPhones) {
activeErrorMessages.push({ type: 'teamsMeetingCallNetworkQualityLow' });
}
else {
activeErrorMessages.push({ type: 'callNetworkQualityLow' });
}
}
if (((_c = diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.media.latest.noSpeakerDevicesEnumerated) === null || _c === void 0 ? void 0 : _c.value) === true) {
activeErrorMessages.push({ type: 'callNoSpeakerFound' });
}
if (((_d = diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.media.latest.noMicrophoneDevicesEnumerated) === null || _d === void 0 ? void 0 : _d.value) === true) {
activeErrorMessages.push({ type: 'callNoMicrophoneFound' });
}
if (((_e = deviceManager.deviceAccess) === null || _e === void 0 ? void 0 : _e.audio) === false && isSafari()) {
activeErrorMessages.push({ type: 'callMicrophoneAccessDeniedSafari' });
}
if (((_f = diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.media.latest.microphonePermissionDenied) === null || _f === void 0 ? void 0 : _f.value) === true && isMacOS()) {
activeErrorMessages.push({ type: 'callMacOsMicrophoneAccessDenied' });
}
else if ((((_g = deviceManager.deviceAccess) === null || _g === void 0 ? void 0 : _g.audio) === false && !isSafari()) ||
(((_h = diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.media.latest.microphonePermissionDenied) === null || _h === void 0 ? void 0 : _h.value) === true && !isMacOS())) {
activeErrorMessages.push({ type: 'callMicrophoneAccessDenied' });
}
const microphoneMuteUnexpectedlyDiagnostic = (diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.media.latest.microphoneMuteUnexpectedly) || (diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.media.latest.microphoneNotFunctioning);
if (microphoneMuteUnexpectedlyDiagnostic) {
if (microphoneMuteUnexpectedlyDiagnostic.value === DiagnosticQuality.Bad) {
// Inform the user that microphone stopped working and inform them to start microphone again
activeErrorMessages.push({ type: 'callMicrophoneMutedBySystem' });
}
else if (microphoneMuteUnexpectedlyDiagnostic.value === DiagnosticQuality.Good) {
// Inform the user that microphone recovered
activeErrorMessages.push({ type: 'callMicrophoneUnmutedBySystem' });
}
}
const cameraStoppedUnexpectedlyDiagnostic = diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.media.latest.cameraStoppedUnexpectedly;
if (cameraStoppedUnexpectedlyDiagnostic) {
if (cameraStoppedUnexpectedlyDiagnostic.value === DiagnosticQuality.Bad) {
// Inform the user that camera stopped working and inform them to start video again
activeErrorMessages.push({ type: 'callVideoStoppedBySystem' });
}
else if (cameraStoppedUnexpectedlyDiagnostic.value === DiagnosticQuality.Good) {
// Inform the user that camera recovered
activeErrorMessages.push({ type: 'callVideoRecoveredBySystem' });
}
}
if (((_j = deviceManager.deviceAccess) === null || _j === void 0 ? void 0 : _j.video) === false && isSafari()) {
activeErrorMessages.push({ type: 'callCameraAccessDeniedSafari' });
}
else if (((_k = deviceManager.deviceAccess) === null || _k === void 0 ? void 0 : _k.video) === false) {
activeErrorMessages.push({ type: 'callCameraAccessDenied' });
}
else {
if (((_l = diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.media.latest.cameraFreeze) === null || _l === void 0 ? void 0 : _l.value) === true) {
activeErrorMessages.push({ type: 'cameraFrozenForRemoteParticipants' });
}
}
/**
* show the Mac specific strings if the platform is detected as mac
*/
if (((_m = diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.media.latest.cameraPermissionDenied) === null || _m === void 0 ? void 0 : _m.value) === true && isMacOS()) {
activeErrorMessages.push({ type: 'callMacOsCameraAccessDenied' });
}
/**
* This UFD only works on mac still so we should only see it fire on mac.
*/
if (((_o = diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.media.latest.screenshareRecordingDisabled) === null || _o === void 0 ? void 0 : _o.value) === true && isMacOS()) {
activeErrorMessages.push({ type: 'callMacOsScreenShareAccessDenied' });
}
else if (((_p = diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.media.latest.screenshareRecordingDisabled) === null || _p === void 0 ? void 0 : _p.value) === true) {
activeErrorMessages.push({ type: 'startScreenShareGeneric' });
}
// Prefer to show errors with privacy implications.
appendActiveErrorIfDefined(activeErrorMessages, latestErrors, 'Call.stopVideo', 'stopVideoGeneric');
appendActiveErrorIfDefined(activeErrorMessages, latestErrors, 'Call.mute', 'muteGeneric');
appendActiveErrorIfDefined(activeErrorMessages, latestErrors, 'Call.stopScreenSharing', 'stopScreenShareGeneric');
if (((_q = latestErrors['Call.startVideo']) === null || _q === void 0 ? void 0 : _q.message) === 'Call.startVideo: Video operation failure SourceUnavailableError') {
appendActiveErrorIfDefined(activeErrorMessages, latestErrors, 'Call.startVideo', 'callCameraAlreadyInUse');
}
else if (((_r = latestErrors['Call.startVideo']) === null || _r === void 0 ? void 0 : _r.message) === 'Call.startVideo: Video operation failure permissionDeniedError') {
appendActiveErrorIfDefined(activeErrorMessages, latestErrors, 'Call.startVideo', 'callCameraAccessDenied');
}
else {
appendActiveErrorIfDefined(activeErrorMessages, latestErrors, 'Call.startVideo', 'startVideoGeneric');
}
appendActiveErrorIfDefined(activeErrorMessages, latestErrors, 'Call.unmute', 'unmuteGeneric');
if (latestNotifications &&
!latestNotifications['capabilityUnmuteMicAbsent'] &&
!latestNotifications['capabilityUnmuteMicPresent']) {
appendActiveErrorIfDefined(activeErrorMessages, latestErrors, 'Call.mutedByOthers', 'mutedByRemoteParticipant');
}
appendActiveErrorIfDefined(activeErrorMessages, latestErrors, 'VideoEffectsFeature.startEffects', 'unableToStartVideoEffect');
if (((_s = latestErrors['CallAgent.join']) === null || _s === void 0 ? void 0 : _s.message) === 'CallAgent.join: Invalid meeting link') {
appendActiveErrorIfDefined(activeErrorMessages, latestErrors, 'CallAgent.join', 'failedToJoinCallInvalidMeetingLink');
}
else {
appendActiveErrorIfDefined(activeErrorMessages, latestErrors, 'CallAgent.join', 'failedToJoinCallGeneric');
}
if ((_t = latestErrors['Call.feature']) === null || _t === void 0 ? void 0 : _t.message.match(/Call\.feature: startSpotlight failed\. \d+ is the max number of participants that can be Spotlighted/g)) {
appendActiveErrorIfDefined(activeErrorMessages, latestErrors, 'Call.feature', 'startSpotlightWhileMaxParticipantsAreSpotlighted');
}
//below is for active notifications
const activeNotifications = [];
if (((_u = diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.media.latest.speakingWhileMicrophoneIsMuted) === null || _u === void 0 ? void 0 : _u.value) &&
// only show this notification when the participant is in an active call and not on screens such as Lobby
callStatus === 'Connected') {
activeNotifications.push({
type: 'speakingWhileMuted',
timestamp: new Date(Date.now()),
autoDismiss: true,
ariaLive: 'off' // "You're muted" is too noisy, so we don't want to announce it.
});
}
if (latestNotifications['assignedBreakoutRoomOpened']) {
activeNotifications.push({
type: 'assignedBreakoutRoomOpened',
timestamp: latestNotifications['assignedBreakoutRoomOpened'].timestamp
});
}
if (latestNotifications['assignedBreakoutRoomOpenedPromptJoin'] && assignedBreakoutRoom) {
activeNotifications.push({
type: 'assignedBreakoutRoomOpenedPromptJoin',
timestamp: latestNotifications['assignedBreakoutRoomOpenedPromptJoin'].timestamp,
onClickPrimaryButton: () => assignedBreakoutRoom.join()
});
}
if (latestNotifications['assignedBreakoutRoomChanged']) {
activeNotifications.push({
type: 'assignedBreakoutRoomChanged',
timestamp: latestNotifications['assignedBreakoutRoomChanged'].timestamp
});
}
if (latestNotifications['assignedBreakoutRoomClosed']) {
activeNotifications.push({
type: 'assignedBreakoutRoomClosed',
timestamp: latestNotifications['assignedBreakoutRoomClosed'].timestamp
});
}
if (latestNotifications['breakoutRoomJoined']) {
activeNotifications.push({
type: 'breakoutRoomJoined',
timestamp: latestNotifications['breakoutRoomJoined'].timestamp
});
}
if (latestNotifications['breakoutRoomClosingSoon']) {
activeNotifications.push({
type: 'breakoutRoomClosingSoon',
timestamp: latestNotifications['breakoutRoomClosingSoon'].timestamp
});
}
if (latestNotifications['capabilityTurnVideoOnPresent']) {
activeNotifications.push({
type: 'capabilityTurnVideoOnPresent',
timestamp: latestNotifications['capabilityTurnVideoOnPresent'].timestamp
});
}
if (latestNotifications['capabilityTurnVideoOnAbsent']) {
activeNotifications.push({
type: 'capabilityTurnVideoOnAbsent',
timestamp: latestNotifications['capabilityTurnVideoOnAbsent'].timestamp
});
}
if (latestNotifications['capabilityUnmuteMicPresent']) {
activeNotifications.push({
type: 'capabilityUnmuteMicPresent',
timestamp: latestNotifications['capabilityUnmuteMicPresent'].timestamp
});
}
if (latestNotifications['capabilityUnmuteMicAbsent']) {
activeNotifications.push({
type: 'capabilityUnmuteMicAbsent',
timestamp: latestNotifications['capabilityUnmuteMicAbsent'].timestamp
});
}
if (latestNotifications['togetherModeStarted']) {
activeNotifications.push({
type: 'togetherModeStarted',
timestamp: latestNotifications['togetherModeStarted'].timestamp,
autoDismiss: true
});
}
if (latestNotifications['togetherModeEnded']) {
activeNotifications.push({
type: 'togetherModeEnded',
timestamp: latestNotifications['togetherModeEnded'].timestamp,
autoDismiss: true
});
}
return { activeErrorMessages: activeErrorMessages, activeNotifications: activeNotifications };
});
const appendActiveErrorIfDefined = (activeErrorMessages, latestErrors, target, activeErrorType) => {
if (latestErrors[target] === undefined) {
return;
}
activeErrorMessages.push({
type: activeErrorType,
timestamp: latestErrors[target].timestamp
});
};
//# sourceMappingURL=notificationStackSelector.js.map