UNPKG

@azure/communication-react

Version:

React library for building modern communication user experiences utilizing Azure Communication Services

118 lines 6 kB
// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. import { getLatestErrors } from './baseSelectors'; import { createSelector } from 'reselect'; /** * Select the first fiew active errors from the state for the {@link ErrorBar} component. * * In case there are many errors, only a few top errors are returned to avoid * filling up the UI with too many errors. * * Invariants: * - {@link ErrorType} is never repeated in the returned errors. * - Errors are returned in a fixed order by {@link ErrorType}. * * @public */ export const errorBarSelector = createSelector([getLatestErrors], (latestErrors) => { var _a; // The order in which the errors are returned is significant: The `ErrorBar` 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 = []; let specificSendMessageErrorSeen = false; { const error = latestUnableToReachChatServiceError(latestErrors); if (error !== undefined) { activeErrorMessages.push(error); } } { const error = latestAccessDeniedError(latestErrors); if (error !== undefined) { activeErrorMessages.push(error); } } const sendMessageError = latestErrors['ChatThreadClient.sendMessage']; { const error = latestNotInThisThreadError(latestErrors); if (error !== undefined) { if (sendMessageError !== undefined) { activeErrorMessages.push({ type: 'sendMessageNotInChatThread', // Set the latest timestamp of all the errors that translated to an active error. timestamp: sendMessageError.timestamp > ((_a = error.timestamp) !== null && _a !== void 0 ? _a : 0) ? sendMessageError.timestamp : error.timestamp }); specificSendMessageErrorSeen = true; } else { activeErrorMessages.push(error); } } } if (!specificSendMessageErrorSeen && sendMessageError !== undefined) { activeErrorMessages.push({ type: 'sendMessageGeneric', timestamp: sendMessageError.timestamp }); } // We only return the first few errors to avoid filling up the UI with too many `MessageBar`s. activeErrorMessages.splice(maxErrorCount); return { activeErrorMessages: activeErrorMessages }; }); const maxErrorCount = 3; const accessErrorTargets = ['ChatThreadClient.getProperties', 'ChatThreadClient.listMessages', 'ChatThreadClient.listParticipants', 'ChatThreadClient.sendMessage', 'ChatThreadClient.sendTypingNotification']; const latestUnableToReachChatServiceError = (latestErrors) => { return latestActiveErrorSatisfying(latestErrors, 'unableToReachChatService', (error) => { return !!error && !!error.innerError && 'code' in error.innerError && error.innerError.code === 'REQUEST_SEND_ERROR'; }); }; const latestAccessDeniedError = (latestErrors) => { return latestActiveErrorSatisfying(latestErrors, 'accessDenied', (error) => { return !!error && !!error.innerError && 'statusCode' in error.innerError && error.innerError.statusCode === 401; }); }; const latestNotInThisThreadError = (latestErrors) => { return latestActiveErrorSatisfying(latestErrors, 'userNotInChatThread', (error) => { if (!error || !error.innerError) { return false; } // Explicitly ignore 400 REST error when listParticipants() is called and a BotContact MRI is found in the participants. // This check should be removed when the chat SDK has handled this issue. Note: The this does not stop the error being logged to the console. // To the best of our ability we have confirmed this to have no impact on the participantList returned (all valid participants are still returned), nor // does it have an impact on the participant list updating on other participants joining/leaving or on individual participant actions like removeParticipant. if (isErrorDueToBotContact(error)) { return false; } // Chat service returns 403 if a user has been removed from a thread. // Chat service returns either 400 or 404 if the thread ID is malformed, depending on how the thread ID is malformed. return [400, 403, 404].some(statusCode => 'statusCode' in error.innerError && error.innerError.statusCode === statusCode); }); }; const botContactMRIPrefix = '28:'; const isErrorDueToBotContact = (error) => 'statusCode' in error.innerError && error.innerError.statusCode === 400 && error.innerError.message.includes(`Identifier format is not supported (${botContactMRIPrefix}`); const latestActiveErrorSatisfying = (errors, activeErrorType, predicate) => { const activeErrorMessages = []; for (const target of accessErrorTargets) { const error = errors[target]; if (predicate(error)) { activeErrorMessages.push({ type: activeErrorType, timestamp: error.timestamp }); } } if (activeErrorMessages.length === 0) { return undefined; } // We're actually sure that both timestamps will always exist, because we set them above. activeErrorMessages.sort((a, b) => { var _a, _b, _c, _d; return ((_b = (_a = a.timestamp) === null || _a === void 0 ? void 0 : _a.getTime()) !== null && _b !== void 0 ? _b : 0) - ((_d = (_c = b.timestamp) === null || _c === void 0 ? void 0 : _c.getTime()) !== null && _d !== void 0 ? _d : 0); }); return activeErrorMessages[activeErrorMessages.length - 1]; }; //# sourceMappingURL=errorBarSelector.js.map