/**
 * Copyright (c) Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License.
 */ import * as React from 'react' ; import { bindActionCreators } from 'redux' ; import { connect } from 'react-redux' ; import * as OF from 'office-ui-fabric-react' ; import { State , ErrorState } from '../../types' ; import actions from '../../actions' ; import { ErrorHandler } from '../../Utils/ErrorHandler' ; import { injectIntl , InjectedIntlProps , InjectedIntl , FormattedMessage } from 'react-intl' ; import { AT } from '../../types/ActionTypes' ; import { FM } from '../../react-intl-messages' ; import { getTip , TipType } from '../ToolTips/ToolTips' ; import { ErrorCode } from '@conversationlearner/models' ; import * as Util from '../../Utils/util' ; interface ComponentState { errorCode : ErrorCode | null ; errorMessages : string [ ] ; customError : string | null ; } class ErrorPanel extends React . Component < Props , ComponentState > { static customErrors = { 'Network Error' : FM . CUSTOMERROR_NETWORK_ERROR } ; state : ComponentState = { errorCode : null , errorMessages : [ "" ] , customError : null } ; componentDidUpdate ( prevProps ) { if ( prevProps . error !== this . props . error ) { const errorMessages = this . getErrorMessages ( this . props . error ) ; const errorCode = this . getErrorCode ( errorMessages [ 0 ] ) ; const customError = this . getCustomError ( this . props . intl , this . props . error ) ; this . setState ( { errorCode , errorMessages , customError } ) ; } } handleClose = ( actionType ? ) => { this . props . clearErrorDisplay ( ) ; if ( actionType ) { ErrorHandler . HandleError ( actionType ) ; } if ( this . state . errorCode === ErrorCode . INVALID_BOT_CHECKSUM ) { this . props . fetchBotInfoThunkAsync ( this . props . browserId , this . props . appId ) ; } if ( this . props . error . closeCallback ) { this . props . error . closeCallback ( ) ; } } ; onRenderFooterContent ( ) { return ( < div > < OF . DefaultButton className = "cl-button-close cl-ux-flexpanel--right" style = { { marginBottom : '1em' } } onClick = { ( ) => this . handleClose ( this . props . error . actionType ) } > Close < /OF.DefaultButton> < /div>); } getCustomError ( intl , error ) { if ( ! error || ! error . title ) { return null ; } const formattedMessageId = ErrorPanel . customErrors [ error . title ] ; return formattedMessageId && Util . formatMessageId ( intl , formattedMessageId ) ; } getErrorMessages ( error ) { if ( error . messages ) { return error . messages . map ( message => { try { const errorObj = JSON . parse ( message ) ; if ( errorObj . data ) { return JSON . stringify ( errorObj . data ) ; } else { return message ; } } catch { return message ; } } ) ; } return [ ] ; } getErrorCode ( errorBody ) { if ( errorBody . includes ( ErrorCode . INVALID_BOT_CHECKSUM ) ) { return ErrorCode . INVALID_BOT_CHECKSUM ; } if ( errorBody . includes ( "LUIS_AUTHORING_KEY" ) ) { return ErrorCode . INVALID_LUIS_AUTHORING_KEY ; } return null ; } renderErrorBody ( ) { return this . state . errorMessages . map ( ( item , i ) => < p key = { i } > { item } < /p>); } renderErrorCode ( ) { switch ( this . state . errorCode ) { case ErrorCode . INVALID_LUIS_AUTHORING_KEY : return ( < div className = "cl-errorpanel" > < div > < div > { this . renderErrorBody ( ) } < /div> { getTip ( TipType . LUIS_AUTHORING_KEY ) } < /div> < /div>); case ErrorCode . INVALID_BOT_CHECKSUM : return ( < div > < div > Detected changes in running Bot that require a refresh < /div> < /div>); default : return null ; } } renderError ( ) { if ( this . state . errorCode ) { return this . renderErrorCode ( ) ; } else { return ( < div className = "cl-errorpanel" > { this . props . error . actionType && < div className = { OF . FontClassNames . large } > < FormattedMessage id = { this . props . error . actionType ?? FM . ERROR_ERROR } defaultMessage = { this . props . error . actionType ?? 'Unknown' } / > Failed < /div>} < div className = { OF . FontClassNames . medium } > { this . props . error . title } < /div> { this . renderErrorBody ( ) } { this . state . customError && < div className = { OF . FontClassNames . medium } > { this . state . customError } < /div>} < /div>); } } render ( ) { return ( < OF . Panel isOpen = { this . props . error . title != null } isLightDismiss = { true } type = { OF . PanelType . medium } onDismiss = { ( ) => this . handleClose ( this . props . error . actionType ) } isFooterAtBottom = { true } closeButtonAriaLabel = 'Close' onRenderFooterContent = { ( ) => this . onRenderFooterContent ( ) } customWidth = '600px' > { this . renderError ( ) } < /OF.Panel>); } } const mapDispatchToProps = ( dispatch ) => { return bindActionCreators ( { fetchBotInfoThunkAsync : actions . bot . fetchBotInfoThunkAsync , clearErrorDisplay : actions . display . clearErrorDisplay } , dispatch ) ; } ; const mapStateToProps = ( state ) => { return { error : state . error , browserId : state . bot . browserId , appId : state . apps . selectedAppId } ; } ; type stateProps = ReturnType < typeof mapStateToProps > ; type dispatchProps = ReturnType < typeof mapDispatchToProps > ; type Props = stateProps & dispatchProps & InjectedIntlProps ; export default connect < stateProps , dispatchProps > ( mapStateToProps , mapDispatchToProps ) ( injectIntl ( ErrorPanel ) ) ;