Skip Navigation

com.sabre.redapp.example3.web.multimodalflow Sample

The multimodal flow sample was created to show how to use a shared data model between multiple modals that show one after another, executing business logic along the way.

In module Main.ts class:

import { Module } from 'sabre-ngv-core/modules/Module';
import { getService, registerService } from './Context';
import { RedAppSidePanelConfig } from 'sabre-ngv-xp/configs/RedAppSidePanelConfig';
import { RedAppSidePanelButton } from 'sabre-ngv-redAppSidePanel/models/RedAppSidePanelButton';
import { ExtensionPointService } from 'sabre-ngv-xp/services/ExtensionPointService';
import { LayerService } from "sabre-ngv-core/services/LayerService";
import { BasicView } from "./views/BasicView";
import { SharedModel } from "./models/SharedModel";
import { IReservationService } from 'sabre-ngv-reservation/services/IReservationService';
import { CommandMessageReservationRs } from 'sabre-ngv-pos-cdm/reservation';
import { ReservationRs } from 'sabre-ngv-pos-cdm/reservation';
import { ProcessService } from './services/ProcessService';
import { IAreaService } from 'sabre-ngv-app/app/services/impl/IAreaService';

export class Main extends Module {


    init(): void {

        super.init();

        const xp = getService(ExtensionPointService);

        const sidepanelConfig = new RedAppSidePanelConfig([
            new RedAppSidePanelButton('Open process flow', 'btn btn-secondary side-panel-button redapp-web-handlebar', () => this.showView()),
        ]);

        xp.addConfig('redAppSidePanel', sidepanelConfig); (1)

        registerService(ProcessService); (2)


    }

    private async showView() {

        let addRemarkModalOptions = {
            title: 'First step of the process',
            actions: [
                {
                    className: 'app.common.views.Button',
                    caption: 'Cancel',
                    actionName: 'cancel',
                    type: 'secondary'
                },
                {
                    className: 'app.common.views.Button',
                    caption: 'Next step - add prefix',
                    actionName: 'next',
                    type: 'success'
                }
            ]

        };

        const reservation : CommandMessageReservationRs = await getService(IReservationService).getReservation(); // (3)

        if(reservation && reservation.Data) {

            const reservationData : ReservationRs = reservation.Data;

            const psgName: string = reservationData.Passengers.Passenger[0].GivenName;

            let sharedModel: SharedModel = new SharedModel(psgName); // (4)

            let firstWindow: BasicView = new BasicView({ model: sharedModel }); // (5)

            getService(LayerService).showInModal(
                firstWindow, addRemarkModalOptions, { display: 'areaView' }
            );
        } else {
            const areaService: IAreaService = getService(IAreaService); // (6)

            areaService.showBanner('Error', 'Missing traveler in the PNR');
        }
    }
}
  1. We created a new button and modal for a custom workflow in Main, see the related sample for further details.

  2. We register ProcessServices that handles business logic.

  3. Using Reservation Service we get the reservation (PNR).

  4. Passenger name is extracted from the PNR and passed into a shared model.

  5. The first view is created with a supporting model.

  6. In case there is no passenger in the PNR, the error banner is shown.

Model

The Model handles domain data used by the Red App. The same model is passed between three views in the sample.

In module SharedModel.ts class:

import {Initial} from 'sabre-ngv-core/decorators/classes/Initial';
import {AbstractModelOptions} from 'sabre-ngv-app/app/AbstractModelOptions';
import {AbstractModel} from "sabre-ngv-app/app/AbstractModel";


@Initial<AbstractModelOptions>({
    autoPropagateData: true, // (1)
})
export class SharedModel extends AbstractModel { // (2)

    passengerName: string;
    info: string;

    constructor(name: string) {
        super();
        this.passengerName = name;
        this.info = "";
    }

    getPassengerName() : string {
        return this.passengerName;
    }

    setAdditionalInfo(addInfo: string): void {
        this.info = addInfo;
    }

}
  1. All data (fields) will be propagated to a view and will be accessible from there.

  2. Each model has to extend the AbstractModel class from SDK. Please note that some classes used by RedApps like EnhancedResponseData or AbstractAction already do extend AbstractModel themselves.

Views

A view connects data from the model with a .html template it also handles any dom events. The sample consists of three views. After submitting data in the first one, business logic is executed (from the service) and the second view is enabled. The second view executes (after the button is clicked) another set of business logic and opens up the third view.

In module BasicView.ts class:

import { AbstractView } from 'sabre-ngv-app/app/AbstractView';
import { AbstractViewOptions } from 'sabre-ngv-app/app/AbstractViewOptions';
import { SharedModel } from '../models/SharedModel';
import { Template } from "sabre-ngv-core/decorators/classes/view/Template";
import { getService } from '../Context';
import { ProcessService } from '../services/ProcessService';
import { LayerService } from "sabre-ngv-core/services/LayerService";
import { SecondView } from "../views/SecondView";

@Template('com-sabre-redapp-example3-web-multimodalflow-web-module:BasicView') // (1)
export class BasicView extends AbstractView<SharedModel> { // (2)

    constructor(options?: AbstractViewOptions) {
        super(options);
    }

    async selfNextAction() {

        const prefix: string = super.$('.brand-input').val();
        const model: SharedModel = super.getModel();

        console.log(model);

        try {

            await getService(ProcessService).createRemarkWithPrefix(model, prefix); // (3)

            let modalOptions = {
                title: 'Second step',
                actions: [
                    {
                        className: 'app.common.views.Button',
                        caption: 'Cancel',
                        actionName: 'cancel',
                        type: 'secondary'
                    },
                    {
                        className: 'app.common.views.Button',
                        caption: 'Next step - add info to model',
                        actionName: 'next',
                        type: 'success'
                    }
                ]
            };


         getService(LayerService).showInModal( // (4)
             new SecondView({model: super.getModel()}),
             modalOptions,
             {display: 'areaView'});



        } catch (e) {
            console.log("ERROR", e);
        }
    }
}
  1. Assign a template called BasicView (templates/BasicView.html) to this view.

  2. Assigns BasicModel as a data model to use with this view.

  3. Call business service.

  4. Open the second modal.

The second and the third modal work pretty much the same.

Service

import { AbstractService } from 'sabre-ngv-app/app/services/impl/AbstractService';
import { ICommandMessageService } from 'sabre-ngv-commsg/services/ICommandMessageService';
import { SharedModel } from '../models/SharedModel';
import { getService } from '../Context';

export class ProcessService extends AbstractService {

    static SERVICE_NAME: string = 'com-sabre-redapp-example3-web-multimodalflow-shopping-web-module-ProcessService';

    public async createRemarkWithPrefix (sharedModel : SharedModel, prefix: string) {
        const psgName : string = sharedModel.getPassengerName();

        await getService(ICommandMessageService).send(`5${prefix}-${psgName}`); // (1)

    }

    public additionalInfoInSharedModel(sharedModel: SharedModel, info: string) : void {
        sharedModel.setAdditionalInfo(info); // (2)
    }

}
  1. Create a remark.

  2. Add data to the model.

package.json

Dependencies for all the used APIs.

{
  "name": "com-sabre-redapp-example3-web-multimodalflow-web-module-src",
  "version": "1.0.0",
  "description": "NGV multi modal flow sample",
  "author": {
    "name": "sdk",
    "email": "",
    "url": ""
  },
  "contributors": [],
  "private": true,
  "license": "SEE LICENSE IN LICENSE.txt",
  "ngv": {
    "buildDependencies": {
      "sabre-ngv-app": "*",
      "sabre-ngv-core": "*",
      "sabre-ngv-xp": "*",
      "sabre-ngv-commsg": "*",
      "sabre-ngv-reservation": "*",
      "sabre-ngv-pos-cdm": "*"
    },
    "concierge_version_min": "5.10.0",
    "runtimeDependencies": {},
    "testDependencies": {}
  }
}