projects/prestations-ng/src/sdk-support-alert/support-alert.service.ts
Properties |
|
Methods |
constructor(http: HttpClient, router: Router, route: ActivatedRoute)
|
||||||||||||
Parameters :
|
Private canBypassAlerts | ||||||
canBypassAlerts(alertsByPassUUID: string)
|
||||||
Parameters :
Returns :
Observable<boolean>
|
getDisplayableAlerts |
getDisplayableAlerts()
|
Returns :
Observable<SupportAlert[]>
|
getHasAlerts |
getHasAlerts()
|
Returns :
Observable<boolean>
|
getHasAtLeastOneBlockingAlert |
getHasAtLeastOneBlockingAlert()
|
Returns :
Observable<boolean>
|
getHasHiddenAlerts |
getHasHiddenAlerts()
|
Returns :
Observable<boolean>
|
hideAlert | ||||||
hideAlert(alert: SupportAlert)
|
||||||
Parameters :
Returns :
void
|
ngOnDestroy |
ngOnDestroy()
|
Returns :
void
|
refreshAlerts |
refreshAlerts()
|
Returns :
void
|
restoreAllAlerts |
restoreAllAlerts()
|
Returns :
void
|
setSupportAlertUrl | ||||||
setSupportAlertUrl(supportAlertUrl: string)
|
||||||
Parameters :
Returns :
void
|
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)));
}
}