File

projects/prestations-ng/src/foehn-navigation/foehn-navigation.service.ts

Index

Properties
Methods
Accessors

Constructor

constructor(router: Router, gesdemService: GesdemHandlerService, gesdemActionRecoveryService: GesdemActionRecoveryService, route: ActivatedRoute, location: Location, demandeTransmitInterceptor: DemandeTransmitInterceptor, eventsLoggerService: SdkEventsLoggerService)
Parameters :
Name Type Optional
router Router No
gesdemService GesdemHandlerService No
gesdemActionRecoveryService GesdemActionRecoveryService No
route ActivatedRoute No
location Location No
demandeTransmitInterceptor DemandeTransmitInterceptor No
eventsLoggerService SdkEventsLoggerService No

Methods

current
current()
Returns : Promise<boolean>
Private evaluateGuard
evaluateGuard(guardFn: CanActivateFn)
Parameters :
Name Type Optional
guardFn CanActivateFn No
Returns : boolean
Private flattenRoutes
flattenRoutes(routesToCrawl: Route[], result: Route[])
Parameters :
Name Type Optional Default value
routesToCrawl Route[] No
result Route[] No []
Returns : Route[]
getAvailableRoutes
getAvailableRoutes()
Returns : Route[]
Private getCurrentRoute
getCurrentRoute(availableRoutes: Route[])
Parameters :
Name Type Optional
availableRoutes Route[] No
Returns : Route
getCurrentRouteIndex
getCurrentRouteIndex()
Returns : number
getFirstRoute
getFirstRoute()
Returns : Route
getLastRouteOrder
getLastRouteOrder()
Returns : number
getNextAvailableRoute
getNextAvailableRoute(direction: NavigationDirection)
Parameters :
Name Type Optional
direction NavigationDirection No
Returns : Route
getNextRouteIndex
getNextRouteIndex()
Returns : number
getPreviousRouteIndex
getPreviousRouteIndex()
Returns : number
getQueryParamsToForward
getQueryParamsToForward()
Returns : Params
getQueryParamsToForwardAsString
getQueryParamsToForwardAsString()
Returns : string
Static getRootRouteRecursive
getRootRouteRecursive(route: ActivatedRouteSnapshot)
Parameters :
Name Type Optional
route ActivatedRouteSnapshot No
Returns : Route
getTotalRoutesSize
getTotalRoutesSize()
Returns : number
hasBeenInitialized
hasBeenInitialized()
Returns : Observable<boolean>
Private indexRoutesByOrder
indexRoutesByOrder(applicationRoute: Route)

reindexe les routes par "order"

Parameters :
Name Type Optional Description
applicationRoute Route No

as route

Returns : Route[]

Route[]

initRoute
initRoute(route: Route)
Parameters :
Name Type Optional
route Route No
Returns : void
isFirstFormPage
isFirstFormPage()
Returns : boolean
isForcedOnRecapForPendingPayment
isForcedOnRecapForPendingPayment()
Returns : boolean
isLastFormPage
isLastFormPage()
Returns : boolean
isLinearRouting
isLinearRouting()
Returns : boolean
Private isRouteAvailable
isRouteAvailable(route: Route)
Parameters :
Name Type Optional
route Route No
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 :
Name Type Optional
newPath string No
Returns : Promise<boolean>
Private redirectToAvailableRoute
redirectToAvailableRoute(direction: NavigationDirection)
Parameters :
Name Type Optional
direction NavigationDirection No
Returns : Promise<boolean>
Private setFocusOnPageTitle
setFocusOnPageTitle()
Returns : void
throwIfNotInit
throwIfNotInit()
Returns : void
updateRouteInformations
updateRouteInformations()
Returns : void

Properties

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[]

Accessors

initialized
getinitialized()
activatedRoute
setactivatedRoute(value: ActivatedRoute)
Parameters :
Name Type Optional
value ActivatedRoute No
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);
    }
}

results matching ""

    No results matching ""