import { HttpErrorResponse , HttpEvent , HttpHandler , HttpInterceptor , HttpRequest } from '@angular/common/http' ; import { Inject , Injectable } from '@angular/core' ; import { TranslateService } from '@ngx-translate/core' ; import { Observable , throwError } from 'rxjs' ; import { catchError , finalize , map } from 'rxjs/operators' ; import { WINDOW } from '../utilities' ; import { ObNotificationService } from '../notification/notification.module' ; import { ObSpinnerService } from '../spinner/spinner.module' ; import { ObHttpApiInterceptorConfig } from './http-api-interceptor.config' ; import { ObHttpApiInterceptorEvents } from './http-api-interceptor.events' ; import { ObIHttpApiRequest , ObIHttpApiRequestNotification , ObIObliqueHttpErrorResponse } from './http-api-interceptor.model' ; @ Injectable ( { providedIn : 'root' } ) export class ObHttpApiInterceptor implements HttpInterceptor { private readonly activeRequestUrls : string [ ] = [ ] ; constructor ( private readonly config , private readonly interceptorEvents , private readonly spinner , private readonly notificationService , private readonly translate , @ Inject ( WINDOW ) private readonly window ) { } intercept ( request , next ) { const obliqueRequest = this . broadcast ( ) ; const timer = this . setTimer ( ) ; this . activateSpinner ( obliqueRequest . spinner , request . url ) ; return next . handle ( this . setupHeader ( request ) ) . pipe ( catchError ( error => throwError ( { error , handled : false } ) ) , catchError ( error => this . handleUnknownError ( error ) ) , catchError ( error => this . handleSessionExpiredError ( error ) ) , catchError ( error => this . handleHttpError ( error , obliqueRequest ) ) , catchError ( error => throwError ( error . error ) ) , finalize ( ( ) => { clearTimeout ( timer ) ; this . deactivateSpinner ( obliqueRequest . spinner , request . url ) ; } ) ) ; } private handleUnknownError ( error ) { return this . handleError ( error , ! ( error . error instanceof HttpErrorResponse ) , ( ) => this . notificationService . error ( 'i18n.oblique.http.error.general' ) ) ; } private handleSessionExpiredError ( error ) { return this . handleError ( error , error . error . status === 401 , ( ) => this . interceptorEvents . sessionExpire ( ) ) ; } private handleHttpError ( error , obliqueRequest ) { return this . handleError ( error , obliqueRequest . notification . active , ( ) => this . notify ( obliqueRequest . notification , error . error ) ) ; } private handleError ( error , hasError , action ) { if ( ! error . handled && hasError ) { action ( ) ; error . handled = true ; } return throwError ( error ) ; } private setupHeader ( request ) { return request . clone ( this . isApiCall ( request . url ) ? { headers : request . headers . set ( 'X-Requested-With' , 'XMLHttpRequest' ) } : undefined ) ; } private setTimer ( ) { return ! this . config . timeout ? undefined : this . window . setTimeout ( ( ) => this . notificationService . warning ( 'i18n.oblique.http.error.timeout' ) , this . config . timeout ) ; } private broadcast ( ) { const evt = { notification : this . config . api . notification , spinner : this . config . api . spinner } ; this . interceptorEvents . requestIntercept ( evt ) ; return evt ; } private activateSpinner ( isSpinnerActive , url ) { if ( isSpinnerActive && this . isApiCall ( url ) ) { this . activeRequestUrls . push ( url ) ; this . spinner . activate ( ) ; } } private deactivateSpinner ( isSpinnerActive , url ) { if ( isSpinnerActive && this . isApiCall ( url ) ) { const request = this . activeRequestUrls . filter ( activeRequestUrl => activeRequestUrl === url ) . pop ( ) ; if ( request ) { this . activeRequestUrls . splice ( this . activeRequestUrls . indexOf ( request ) , 1 ) ; } if ( ! this . activeRequestUrls . length ) { this . spinner . forceDeactivate ( ) ; } } } private notify ( notification , error ) { const textKey = `i18n.oblique.http.error.status.${ error . status }` ; const titleKey = `i18n.oblique.http.error.status.${ error . status }.title` ; this . translate . get ( [ textKey , titleKey ] ) . pipe ( map ( texts => ( { text : texts [ textKey ] !== textKey ? textKey : 'i18n.oblique.http.error.general' , title : texts [ titleKey ] !== titleKey ? titleKey : error . statusText } ) ) ) . subscribe ( keys => this . notificationService . send ( { message : notification . text || keys . text , title : notification . title || keys . title , type : notification . severity , sticky : notification . sticky } ) ) ; } private isApiCall ( url ) { return url . includes ( this . config . api . url ) ; } }