projects/prestations-ng/src/foehn-navigation/foehn-navigation.service.ts
Properties |
|
Methods |
|
Accessors |
constructor(router: Router, gesdemService: GesdemHandlerService, gesdemActionRecoveryService: GesdemActionRecoveryService, route: ActivatedRoute, location: Location, demandeTransmitInterceptor: DemandeTransmitInterceptor, eventsLoggerService: SdkEventsLoggerService)
|
||||||||||||||||||||||||
Parameters :
|
current |
current()
|
Returns :
Promise<boolean>
|
Private evaluateGuard | ||||||
evaluateGuard(guardFn: CanActivateFn)
|
||||||
Parameters :
Returns :
boolean
|
Private flattenRoutes | ||||||||||||
flattenRoutes(routesToCrawl: Route[], result: Route[])
|
||||||||||||
Parameters :
Returns :
Route[]
|
getAvailableRoutes |
getAvailableRoutes()
|
Returns :
Route[]
|
Private getCurrentRoute | ||||||
getCurrentRoute(availableRoutes: Route[])
|
||||||
Parameters :
Returns :
Route
|
getCurrentRouteIndex |
getCurrentRouteIndex()
|
Returns :
number
|
getFirstRoute |
getFirstRoute()
|
Returns :
Route
|
getLastRouteOrder |
getLastRouteOrder()
|
Returns :
number
|
getNextAvailableRoute | ||||||
getNextAvailableRoute(direction: NavigationDirection)
|
||||||
Parameters :
Returns :
Route
|
getNextRouteIndex |
getNextRouteIndex()
|
Returns :
number
|
getPreviousRouteIndex |
getPreviousRouteIndex()
|
Returns :
number
|
getQueryParamsToForward |
getQueryParamsToForward()
|
Returns :
Params
|
getQueryParamsToForwardAsString |
getQueryParamsToForwardAsString()
|
Returns :
string
|
Static getRootRouteRecursive | ||||||
getRootRouteRecursive(route: ActivatedRouteSnapshot)
|
||||||
Parameters :
Returns :
Route
|
getTotalRoutesSize |
getTotalRoutesSize()
|
Returns :
number
|
hasBeenInitialized |
hasBeenInitialized()
|
Returns :
Observable<boolean>
|
initRoute | ||||||
initRoute(route: Route)
|
||||||
Parameters :
Returns :
void
|
isFirstFormPage |
isFirstFormPage()
|
Returns :
boolean
|
isForcedOnRecapForPendingPayment |
isForcedOnRecapForPendingPayment()
|
Returns :
boolean
|
isLastFormPage |
isLastFormPage()
|
Returns :
boolean
|
isLinearRouting |
isLinearRouting()
|
Returns :
boolean
|
Private isRouteAvailable | ||||||
isRouteAvailable(route: Route)
|
||||||
Parameters :
Returns :
boolean
|
last |
last()
|
Returns :
Promise<boolean>
|
next |
next()
|
Returns :
Promise<boolean>
|
previous |
previous()
|
Returns :
Promise<boolean>
|
recap |
recap()
|
Returns :
Promise<boolean>
|
redirect | ||||||
redirect(newPath: string)
|
||||||
Parameters :
Returns :
Promise<boolean>
|
Private redirectToAvailableRoute | ||||||
redirectToAvailableRoute(direction: NavigationDirection)
|
||||||
Parameters :
Returns :
Promise<boolean>
|
Private setFocusOnPageTitle |
setFocusOnPageTitle()
|
Returns :
void
|
throwIfNotInit |
throwIfNotInit()
|
Returns :
void
|
updateRouteInformations |
updateRouteInformations()
|
Returns :
void
|
Private _activatedRoute |
Type : ActivatedRoute
|
currentRouteOrder |
Type : number
|
Private initializedAndRouteActivated |
Type : BehaviorSubject<boolean>
|
Default value : new BehaviorSubject<boolean>(false)
|
Private isInit |
Default value : false
|
Private linearRouting |
Default value : true
|
orderedRoutes |
Type : Route[]
|
initialized |
getinitialized()
|
activatedRoute | ||||||
setactivatedRoute(value: ActivatedRoute)
|
||||||
Parameters :
Returns :
void
|
import { Location } from '@angular/common';
import { Injectable } from '@angular/core';
import {
ActivatedRoute,
ActivatedRouteSnapshot,
CanActivateFn,
Params,
Route,
Router
} from '@angular/router';
import { BehaviorSubject, Observable } from 'rxjs';
import { DemandeTransmitInterceptor } from '../foehn-page/foehn-transmit-waiting-modal/demande-transmit-interceptor';
import { GesdemHandlerService } from '../gesdem/gesdem-handler.service';
import { GesdemActionRecoveryService } from '../gesdem-action-recovery/gesdem-action-recovery.service';
import { SdkEventType } from '../sdk-events-logger/sdk-event-type';
import { SdkEventsLoggerService } from '../sdk-events-logger/sdk-events-logger.service';
export enum NavigationDirection {
FORWARD = +1,
BACKWARD = -1
}
@Injectable({
providedIn: 'root'
})
export class FoehnNavigationService {
currentRouteOrder: number;
orderedRoutes: Route[];
private _activatedRoute: ActivatedRoute;
private isInit = false;
private initializedAndRouteActivated: BehaviorSubject<boolean> =
new BehaviorSubject<boolean>(false);
private linearRouting = true;
constructor(
private router: Router,
private gesdemService: GesdemHandlerService,
private gesdemActionRecoveryService: GesdemActionRecoveryService,
private route: ActivatedRoute,
private location: Location,
private demandeTransmitInterceptor: DemandeTransmitInterceptor,
private eventsLoggerService: SdkEventsLoggerService
) {}
get initialized(): boolean {
return this.isInit;
}
set activatedRoute(value: ActivatedRoute) {
this.throwIfNotInit();
this._activatedRoute = value;
this.initializedAndRouteActivated.next(true);
}
static getRootRouteRecursive(route: ActivatedRouteSnapshot): Route {
if (route) {
if (
route.routeConfig &&
route.routeConfig.data &&
route.routeConfig.data.root
) {
return route.routeConfig;
}
return this.getRootRouteRecursive(route.parent);
}
return null;
}
initRoute(route: Route): void {
if (route) {
this.orderedRoutes = this.indexRoutesByOrder(route);
// By default the prefix should be the path of the route. (e.g. in /validation/123123-12321/page1,
// the prefix is "validation"). However, if the application is code-splitted with the routing defined
// in a module, this won't work. In this case, you can specify the path in $.data.basePath so the GesDem
// service knows where to send the request to the backend.
const prefix = route.data.basePath || route.path;
this.gesdemService.prefix = prefix;
this.gesdemActionRecoveryService.prefix = prefix;
this.demandeTransmitInterceptor.prefix = prefix;
this.linearRouting = route.data.linearRouting !== false;
}
this.throwIfNotInit();
}
throwIfNotInit(): void {
if (!this.isInit) {
throw new TypeError(
"No route is identified as 'root'. Have you called initRoute() ?"
);
}
}
updateRouteInformations(): void {
this.throwIfNotInit();
const currentRoute = this._activatedRoute.routeConfig;
let currentRouteOrder = 1;
if (
!!currentRoute &&
!!currentRoute.data &&
!!currentRoute.data.order
) {
currentRouteOrder = currentRoute.data.order;
}
this.currentRouteOrder = currentRouteOrder;
}
getFirstRoute(): Route {
return this.orderedRoutes[1];
}
current(): Promise<boolean> {
this.throwIfNotInit();
if (!this.gesdemService.lastResponse) {
return Promise.reject('Erreur navigationService#current');
}
const currentRoute = this.orderedRoutes[this.currentRouteOrder];
const prefix = this.gesdemService.prefix;
const commands: string[] = [];
if (prefix) {
commands.push(prefix);
}
if (this.gesdemService.lastResponse.meta.reference) {
commands.push(
this.gesdemService.lastResponse.meta.reference,
currentRoute.path
);
const tree = this.router.createUrlTree(commands);
const url =
this.router.serializeUrl(tree) +
this.getQueryParamsToForwardAsString();
this.location.replaceState(url);
}
return Promise.resolve(true);
}
hasBeenInitialized(): Observable<boolean> {
return this.initializedAndRouteActivated.asObservable();
}
getQueryParamsToForwardAsString(): string {
const params = this.getQueryParamsToForward() || [];
let stringParams = '';
for (const key of Object.keys(params)) {
const value = params[key];
stringParams += stringParams ? '&' : '?';
stringParams += `${key}=${value}`;
}
return stringParams;
}
getQueryParamsToForward(): Params {
const reCaptchaByPassUUID =
this.route.snapshot.queryParams.reCaptchaByPassUUID;
const scrollTo = this.route.snapshot.queryParams.scrollTo;
const alertsByPassUUID =
this.route.snapshot.queryParams.alertsByPassUUID;
if (!!reCaptchaByPassUUID || !!scrollTo || !!alertsByPassUUID) {
const params: Params = {};
if (!!reCaptchaByPassUUID) {
params.reCaptchaByPassUUID = reCaptchaByPassUUID;
}
if (!!scrollTo) {
params.scrollTo = scrollTo;
}
if (!!alertsByPassUUID) {
params.alertsByPassUUID = alertsByPassUUID;
}
return params;
}
return null;
}
next(): Promise<boolean> {
this.throwIfNotInit();
return this.redirectToAvailableRoute(NavigationDirection.FORWARD);
}
previous(): Promise<boolean> {
this.throwIfNotInit();
return this.redirectToAvailableRoute(NavigationDirection.BACKWARD);
}
last(): Promise<boolean> {
this.throwIfNotInit();
const route = this.getAvailableRoutes();
const nextRoutePath = route[route.length - 1].path;
return this.redirect(nextRoutePath);
}
recap(): Promise<boolean> {
this.throwIfNotInit();
const route = this.getAvailableRoutes();
const nextRoutePath = route[route.length - 2].path;
return this.redirect(nextRoutePath);
}
redirect(newPath: string): Promise<boolean> {
const routes = [];
if (this.gesdemService.prefix) {
routes.push(this.gesdemService.prefix);
}
routes.push(this.gesdemService.lastResponse.meta.reference, newPath);
return this.router
.navigate(routes, {
queryParams: this.getQueryParamsToForward()
})
.then(success => {
if (success) {
this.setFocusOnPageTitle();
}
return success;
});
}
getAvailableRoutes(): Route[] {
return this.orderedRoutes.filter(route => this.isRouteAvailable(route));
}
getCurrentRouteIndex(): number {
// This evaluates all the guards
const availableRoutes = this.getAvailableRoutes();
const currentRoute = availableRoutes.find(
route => route.data.order === this.currentRouteOrder
);
if (!currentRoute) {
return null;
}
return availableRoutes.indexOf(currentRoute);
}
getTotalRoutesSize(): number {
return this.getAvailableRoutes().length;
}
getLastRouteOrder(): number {
const routes = this.getAvailableRoutes();
return routes[routes.length - 1].data.order;
}
getNextAvailableRoute(direction: NavigationDirection): Route {
// This evaluates all the guards
const availableRoutes = this.getAvailableRoutes();
// Assumes that the next or previous route is the next or previous on the array of available routes.
const currentRoute = this.getCurrentRoute(availableRoutes);
if (!currentRoute) {
throw new Error(
'Invalid routing, at least one route must be available'
);
}
const currentRouteIndex = availableRoutes.indexOf(currentRoute);
const targetRoute = availableRoutes[currentRouteIndex + direction];
if (!targetRoute) {
return null;
}
// The display index isn't always the route order as we support guards on available routes.
// The display index is 1-based.
targetRoute.data.displayIndex =
availableRoutes.indexOf(targetRoute) + 1;
return targetRoute;
}
isFirstFormPage(): boolean {
if (!this.getCurrentRoute(this.getAvailableRoutes())) {
return true;
}
return (
this.getNextAvailableRoute(NavigationDirection.BACKWARD) === null
);
}
isForcedOnRecapForPendingPayment(): boolean {
return this.isLastFormPage() && this.gesdemService.isPendingPayment();
}
isLastFormPage(): boolean {
// === page de recap avant transmission
if (!this.orderedRoutes?.length) {
return false;
}
if (!this.getCurrentRoute(this.getAvailableRoutes())) {
return true;
}
const nextRoute = this.getNextAvailableRoute(
NavigationDirection.FORWARD
);
if (!nextRoute) {
return true;
}
return nextRoute.data.order === this.getLastRouteOrder();
}
getNextRouteIndex(): number {
const nextRoute = this.getNextAvailableRoute(
NavigationDirection.FORWARD
);
if (!nextRoute) {
return null;
}
return nextRoute.data.displayIndex;
}
getPreviousRouteIndex(): number {
const previousRoute = this.getNextAvailableRoute(
NavigationDirection.BACKWARD
);
if (!previousRoute) {
return null;
}
return previousRoute.data.displayIndex;
}
isLinearRouting(): boolean {
return this.linearRouting;
}
private getCurrentRoute(availableRoutes: Route[]): Route {
return availableRoutes.find(
route => route.data.order === this.currentRouteOrder
);
}
private redirectToAvailableRoute(
direction: NavigationDirection
): Promise<boolean> {
const route = this.getNextAvailableRoute(direction);
const eventType =
direction === NavigationDirection.FORWARD
? SdkEventType.NAVIGATION_FORWARD
: SdkEventType.NAVIGATION_BACKWARD;
this.eventsLoggerService.addEvent(eventType, route.path);
return this.redirect(route.path);
}
private isRouteAvailable(route: Route): boolean {
const { canActivate } = route;
if (!canActivate || !canActivate.length) {
return true;
}
// All the guards must be evaluated to true
return !canActivate.some(
(guardFn: CanActivateFn) => !this.evaluateGuard(guardFn)
);
}
private evaluateGuard(guardFn: CanActivateFn): boolean {
const guardResult = guardFn(this.route.snapshot, null);
if (typeof guardResult !== 'boolean') {
throw new Error(
'Not implemented: Dynamic routing guards only support boolean results'
);
}
return guardResult;
}
/**
* reindexe les routes par "order"
* @param applicationRoute as route
* @returns Route[]
*/
private indexRoutesByOrder(applicationRoute: Route): Route[] {
this.isInit = false;
const routesToCrawl = applicationRoute.children;
if (!routesToCrawl.length) {
return [];
}
const result = this.flattenRoutes(routesToCrawl);
if (result.length > 0) {
this.isInit = true;
}
return result;
}
private flattenRoutes(
routesToCrawl: Route[],
result: Route[] = []
): Route[] {
routesToCrawl.forEach(value => {
if (value.children && value.children.length) {
this.flattenRoutes(value.children, result);
}
if (!!value.data && !!value.data.order) {
result[value.data.order] = value;
}
return result;
});
return result;
}
private setFocusOnPageTitle(): void {
// Ensures that the focus is properly set after the page is updated.
setTimeout(() => {
const title = document.getElementById('page-title');
if (title) {
title.focus();
}
}, 0);
}
}