import { ChatBaseSelectorProps , getLatestErrors } from './baseSelectors' ; import { ActiveErrorMessage , ErrorType } from '@internal/react-components' ; import { createSelector } from 'reselect' ; import { ChatClientState , ChatError , ChatErrors , ChatErrorTarget } from '@internal/chat-stateful-client' ; /**
 * Selector type for  ErrorBar component.
 *
 *  public export type ErrorBarSelector = ( state : ChatClientState , props : ChatBaseSelectorProps ) => { activeErrorMessages : ActiveErrorMessage [ ] ; } ; /**
 * Select the first fiew active errors from the state for the  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:
 *   -  ErrorType is never repeated in the returned errors.
 *   - Errors are returned in a fixed order by  ErrorType .
 *
 *  public export const errorBarSelector = createSelector ( [ getLatestErrors ] , ( latestErrors ) : { activeErrorMessages : ActiveErrorMessage [ ] ; } => { 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' , timestamp : sendMessageError . timestamp > ( error . timestamp ?? 0 ) ? sendMessageError . timestamp : error . timestamp } ) ; specificSendMessageErrorSeen = true ; } else { activeErrorMessages . push ( error ) ; } } } if ( ! specificSendMessageErrorSeen && sendMessageError !== undefined ) { activeErrorMessages . push ( { type : 'sendMessageGeneric' , timestamp : sendMessageError . timestamp } ) ; } activeErrorMessages . splice ( maxErrorCount ) ; return { activeErrorMessages : activeErrorMessages } ; } ) ; const maxErrorCount = 3 ; const accessErrorTargets = [ 'ChatThreadClient.getProperties' , 'ChatThreadClient.listMessages' , 'ChatThreadClient.listParticipants' , 'ChatThreadClient.sendMessage' , 'ChatThreadClient.sendTypingNotification' ] ; const latestUnableToReachChatServiceError = ( latestErrors ) : ActiveErrorMessage | undefined => { return latestActiveErrorSatisfying ( latestErrors , 'unableToReachChatService' , ( error ) : boolean => { return ! ! error && ! ! error . innerError && error . innerError [ 'code' ] === 'REQUEST_SEND_ERROR' ; } ) ; } ; const latestAccessDeniedError = ( latestErrors ) : ActiveErrorMessage | undefined => { return latestActiveErrorSatisfying ( latestErrors , 'accessDenied' , ( error ) : boolean => { return ! ! error && ! ! error . innerError && error . innerError [ 'statusCode' ] === 401 ; } ) ; } ; const latestNotInThisThreadError = ( latestErrors ) : ActiveErrorMessage | undefined => { return latestActiveErrorSatisfying ( latestErrors , 'userNotInChatThread' , ( error ) : boolean => { if ( ! error || ! error . innerError ) { return false ; } return [ 400 , 403 , 404 ] . some ( ( statusCode ) => error . innerError [ 'statusCode' ] === statusCode ) ; } ) ; } ; const latestActiveErrorSatisfying = ( errors , activeErrorType , predicate ) : ActiveErrorMessage | undefined => { 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 ; } activeErrorMessages . sort ( ( a , b ) => ( a . timestamp ?. getTime ( ) ?? 0 ) - ( b . timestamp ?. getTime ( ) ?? 0 ) ) ; return activeErrorMessages [ activeErrorMessages . length - 1 ] ; } ;