File

projects/prestations-ng/src/sdk-support-alert/support-alert.service.ts

Index

Properties
Methods

Constructor

constructor(http: HttpClient, router: Router, route: ActivatedRoute)
Parameters :
Name Type Optional
http HttpClient No
router Router No
route ActivatedRoute No

Methods

Private canBypassAlerts
canBypassAlerts(alertsByPassUUID: string)
Parameters :
Name Type Optional
alertsByPassUUID string No
Returns : Observable<boolean>
getDisplayableAlerts
getDisplayableAlerts()
getHasAlerts
getHasAlerts()
Returns : Observable<boolean>
getHasAtLeastOneBlockingAlert
getHasAtLeastOneBlockingAlert()
Returns : Observable<boolean>
getHasHiddenAlerts
getHasHiddenAlerts()
Returns : Observable<boolean>
hideAlert
hideAlert(alert: SupportAlert)
Parameters :
Name Type Optional
alert SupportAlert No
Returns : void
ngOnDestroy
ngOnDestroy()
Returns : void
refreshAlerts
refreshAlerts()
Returns : void
restoreAllAlerts
restoreAllAlerts()
Returns : void
setSupportAlertUrl
setSupportAlertUrl(supportAlertUrl: string)
Parameters :
Name Type Optional
supportAlertUrl string No
Returns : void

Properties

Private Readonly allAlerts
Type : Observable<SupportAlert[]>
Private checkBypassAlerts
Default value : () => {...}
Private Readonly displayableAlerts
Type : Observable<SupportAlert[]>
Private Readonly hasAlerts
Type : Observable<boolean>
Private Readonly hasAtLeastOneBlockingAlert
Type : Observable<boolean>
Private Readonly hasHiddenAlerts
Type : Observable<boolean>
Private Readonly hiddenAlertIds
Default value : new BehaviorSubject<number[]>( getPersistedDismissedAlertIds() )
Private Readonly hiddenAlertIdsSubscriptions
Type : Subscription
Private Readonly refreshTrigger
Default value : new BehaviorSubject<boolean>(true)
Private supportAlertUrl
Default value : new BehaviorSubject<string>('')
import { HttpClient, HttpParams } from '@angular/common/http';
import { Injectable, OnDestroy } from '@angular/core';
import { ActivatedRoute, NavigationStart, Router } from '@angular/router';
import {
    BehaviorSubject,
    combineLatest,
    merge,
    Observable,
    of,
    Subscription
} from 'rxjs';
import {
    catchError,
    filter,
    map,
    shareReplay,
    switchMap,
    throttleTime
} from 'rxjs/operators';

import { SupportAlert } from './support-alert.model';

// Shared between prestations.
const STORAGE_KEY = 'hidden-alerts';

/**
 * @param ids alert ids to be dismissed
 */
const persistDismissedAlertIds = (ids: number[]): void => {
    try {
        localStorage.setItem(STORAGE_KEY, JSON.stringify(ids));
    } catch (e) {
        // Nothing in case the local storage fails.
    }
};

/**
 * @returns array
 */
const getPersistedDismissedAlertIds = (): number[] => {
    try {
        const storageValue = localStorage.getItem(STORAGE_KEY);
        if (!storageValue) {
            return [];
        }

        return JSON.parse(storageValue);
    } catch (e) {
        // In case the storage fails, we don't want to impact the user.
        return [];
    }
};

@Injectable({
    providedIn: 'root'
})
export class SupportAlertService implements OnDestroy {
    private readonly allAlerts: Observable<SupportAlert[]>;
    private readonly displayableAlerts: Observable<SupportAlert[]>;
    private readonly hasAlerts: Observable<boolean>;
    private readonly hasHiddenAlerts: Observable<boolean>;
    private readonly hasAtLeastOneBlockingAlert: Observable<boolean>;
    private readonly hiddenAlertIds = new BehaviorSubject<number[]>(
        getPersistedDismissedAlertIds()
    );
    private readonly hiddenAlertIdsSubscriptions: Subscription;
    private readonly refreshTrigger = new BehaviorSubject<boolean>(true);

    private supportAlertUrl = new BehaviorSubject<string>('');

    constructor(
        private http: HttpClient,
        private router: Router,
        private route: ActivatedRoute
    ) {
        const navigationTrigger = this.router.events.pipe(
            filter(e => e instanceof NavigationStart)
        );

        const refreshAlertsTriggerAndNavigation = merge(
            this.refreshTrigger,
            navigationTrigger
        ).pipe(throttleTime(3 * 60 * 1000));

        this.allAlerts = combineLatest([
            this.supportAlertUrl,
            refreshAlertsTriggerAndNavigation
        ]).pipe(
            // Only if an url is defined
            filter(([url]) => !!url),
            // Load the alerts from the server.
            switchMap(([url]) =>
                this.http.get<SupportAlert[]>(url).pipe(
                    catchError((e: unknown) => {
                        console.error(
                            'Unable to get support alerts, returning an empty array',
                            e
                        );
                        return of([]);
                    })
                )
            ),
            map(supportAlerts => (!!supportAlerts ? supportAlerts : [])),
            // Ensures that observables that depend on this one don't re-trigger an http call.
            shareReplay(1)
        );

        this.hasAlerts = this.allAlerts.pipe(map(alerts => !!alerts.length));

        this.hasAtLeastOneBlockingAlert = this.allAlerts.pipe(
            map(alerts => alerts.some(alert => alert.blocking)),
            switchMap(this.checkBypassAlerts.bind(this))
        );

        this.displayableAlerts = combineLatest([
            this.allAlerts,
            this.hiddenAlertIds
        ]).pipe(
            // Filter the alerts that are hidden by the user, per Id.
            map(([alerts, hiddenAlertsId]) =>
                // Always display the blocking alerts, in case the alert is hidden but edited.
                alerts.filter(
                    alert =>
                        alert.blocking || !hiddenAlertsId.includes(alert.id)
                )
            )
        );

        this.hasHiddenAlerts = combineLatest([
            this.allAlerts,
            this.displayableAlerts
        ]).pipe(
            map(
                ([allAlerts, displayableAlerts]) =>
                    allAlerts.length !== displayableAlerts.length
            )
        );

        // Persist the ids that are dismissed.
        this.hiddenAlertIdsSubscriptions = this.hiddenAlertIds.subscribe(
            persistDismissedAlertIds
        );
    }

    ngOnDestroy(): void {
        this.hiddenAlertIdsSubscriptions.unsubscribe();
    }

    setSupportAlertUrl(supportAlertUrl: string): void {
        this.supportAlertUrl.next(supportAlertUrl);
    }

    hideAlert(alert: SupportAlert): void {
        if (!alert.blocking) {
            this.hiddenAlertIds.next([
                alert.id,
                ...this.hiddenAlertIds.getValue()
            ]);
        }
    }

    restoreAllAlerts(): void {
        this.hiddenAlertIds.next([]);
    }

    refreshAlerts(): void {
        this.refreshTrigger.next(true);
    }

    getDisplayableAlerts(): Observable<SupportAlert[]> {
        return this.displayableAlerts;
    }

    getHasAlerts(): Observable<boolean> {
        return this.hasAlerts;
    }

    getHasHiddenAlerts(): Observable<boolean> {
        return this.hasHiddenAlerts;
    }

    getHasAtLeastOneBlockingAlert(): Observable<boolean> {
        return this.hasAtLeastOneBlockingAlert;
    }

    private checkBypassAlerts = (
        blockingExists: boolean
    ): Observable<boolean> => {
        if (!blockingExists) {
            return of(false);
        }
        return this.route.queryParams.pipe(
            switchMap(params => {
                const alertsByPassUUID = params?.alertsByPassUUID;
                if (!alertsByPassUUID) {
                    return of(true);
                }
                return this.canBypassAlerts(alertsByPassUUID).pipe(
                    map(canBypass => !canBypass)
                );
            })
        );
    };

    private canBypassAlerts(alertsByPassUUID: string): Observable<boolean> {
        const params = !!alertsByPassUUID
            ? new HttpParams().set('alertsByPassUUID', alertsByPassUUID)
            : null;
        return this.http
            .get<boolean>('api/support-alert/alerts/can-bypass/', { params })
            .pipe(catchError(() => of(false)));
    }
}

results matching ""

    No results matching ""