npm package: @smartbit4all/ng-client
Description: ---
Latest version: 4.3.34

# Smart Ng Client

---

## How to use

### Installation

Go to your project, open the terminal and use the following command:

    npm i @smartbit4all/ng-client

Provide the `SmartNgClientModule` in the app.module:

`app.module.ts:`

    @NgModule({
        declarations: [...],
        imports: [
            SmartNgClientModule,
            ...
        ],
        providers: [
            SmartSessionService,
    	    SmartViewContextService,
            ...
        ],
        ...
    })

### Usage

In order to use the SmartSessionService I recommend to follow the guideline belove.

**Generate a service** which will **handle the session and the authentication**.

`Terminal:`

    >>> cd src/app

    >>> mkdir services

    >>> cd ./services

    >>> ng g s authentication

Provide this new service as a **global service**:

`app.module.ts:`

    @NgModule({
        declarations: [...],
        imports: [...],
        providers: [
            SmartSessionService,
            AuthenticationService,
            ...
        ],
        ...
    })

### Authentication state changed

The change of authentication state can be detected in any components. To handle it you must subscribe to the change itself.

**Note that in this version a user is authenticated when the response of the GET session contains a list of authentications.**

    this.isAuthenticated = response.authentications.length > 0

`any.component.ts:`

    constructor(
    	private auth: AuthenticationService,
    	private session: SmartSessionService
    ) {
    	this.session.authenticationStateChanged.subscribe((isAuth: boolean) => {
    		if (!isAuth) {
    			this.router.navigate(['/login']);
    		}
    	});
    }

### Using locales

The `SmartSessionService` supports the usage of locales in you application. It is important to note that the language is related to the session!

This example uses the [NgxTranslate/core](https://www.npmjs.com/package/@ngx-translate/core) package.

`authentication.service.ts:`

    import { TranslateService } from '@ngx-translate/core';
    ...

    export class AuthenticationService {
        ...

        constructor(
            ...
            private translate: TranslateService
        ) {
            this.session.localeChanged.subscribe(() => {
                this.translate.use(this.session.getLocale());
            });
        }

        async changeLocale(locale: string): Promise<void> {
            await this.session.changeLocale(locale);
        }

        getLocale(): string {
            return this.session.getLocale();
        }
    }

### SmartDevTool usage

Turn on and off the devTool:

    // active
    localStorage.setItem('smartDevToolActive', 'true');
    // inactive
    localStorage.setItem('smartDevToolActive', 'false');

Set the devTool's button visibility

    // visible
    localStorage.setItem('useDevTool', 'true');
    // invisible
    localStorage.setItem('useDevTool', 'false');

In order to use this package properly, please create a folder called `viewcontext` in which a `view-context.pages.model.ts` shall be created:

-   src/app/viewcontext/
    -   view-context.pages.ts
    -   view-context.handlers.ts

`view-context.pages.ts:`

    export enum Pages {
        // mandatory
        VIEW_CONTEXT = 'viewContextUuid',

        // optionals
        ANY_PAGE = 'anyPage',
        ANY_DIALOG = 'anyDialog,
        ANY_COMPONENT = 'anyComponent,
        ...
    }

`view-context.handlers.ts:`

    import { SmartViewHandlerModel, ViewType } from '@smartbit4all/view-context';
    import { Pages } from './view-context.pages';
    import { AnyDialogService } from '../any-dialog/any-dialog.service';

    export const viewContextHandlers: SmartViewHandlerModel[] = [
        // ViewType.Normal
        {
            name: Pages.ANY_PAGE,
            route: 'any'
        },
        // ViewType.Dialog
        {
            name: Pages.ANY_DIALOG,
            component: AnyDialogComponent
        },
        // ViewType.Normal or ViewType.Dialog
        {
            name: Pages.ANY_COMPONENT,
            route: 'any',
            component: AnyComponent
        }
    ];

Don't forget to define some ApiErrors and inject it into the **AuthenticationService**:

`view-context.api-errors.ts:`

    const viewContextApiErrors: SmartViewContextApiErrors = {
        viewContextApiErrors:  [
            {
                code: "001",
                dialogTitle?: "Error"
                message: "An error message"
                buttonLabel?: "Ok"
            }
        ]
    }

### SmartLink

In order to use SmartLinks in your application, follow the instruction:

Firstly, set up the routing:

`app-routing.module.ts:`

    const routes: Routes = [
        // Out of the box solution
        {
            path: `redirect/:${SmartLinkChannelVariableInPath}/:${SmartLinkUuidVariableInPath}`,
            component: SmartViewRedirect,
        },
        // Custom solution
        {
            path: `customRedirect/:${SmartLinkChannelVariableInPath}/:${SmartLinkUuidVariableInPath}`,
            component: RedirectComponent,
        },
        ...
    ]

Then you can set up your custom redirect component as you wish:

`redirect.component.ts:`

    @Component({
        selector: "app-redirect",
        templateUrl: "./redirect.component.html",
        styleUrls: ["./redirect.component.css"],
    })
    export class RedirectComponent extends SmartViewRedirect {
        constructor(
            service: SmartViewContextService,
            navigation: SmartNavigationService,
            route: ActivatedRoute
        ) {
            super(
                service,
                navigation,
                route
            );
        }
    }

Then subscribe for the _openSmartLink_ event and handle it in your AuthenticationService:

`authentication.service.ts:`

    constructor(...) {
        ...
        this.viewContext.openSmartLink.subscribe(() => {
            this.handleOpenSmartLinkEvent();
        })
    }

    private async handleOpenSmartLinkEvent(): Promise<void> {
        // Do your business logic here

        // If authentication is needed to open the link:
        let isAuthenticated = await this.isAuthenticated();
        if (isAuthenticated) {
            this.viewContext.openSmartLink.complete();
        } else {
            // Navigate to login screen without reloading the site!
        }
    }

    // Modify this if authentication is needed to open links
    async login(request: LocalAuthenticationLoginRequest): Promise<boolean> {
        await this.auth.login(request);
        let isAuth = await this.session.getIsAuthenticated();
        if (isAuth) {
            await this.viewContext.initialize();

            await this.anyBffApi.startAnyPage().toPromise();

            // If there is a smart link waiting for opening...
            if (this.viewContext.isOpeningSmartLink) {
                this.viewContext.openSmartLink.complete();
                return isAuth;
            }

            let uuid = this.viewContext.getUuidOfPage(Pages.VIEW_CONTEXT);
            await this.viewContext.getAndSyncViewContext(uuid);
        }
        return isAuth;
    }

### UiActions

The ViewContext package contains a common manager for the UiActions. To use this tool, please follow the instructions.

`action.descriptors.ts:`

    import {
        UiActionButtonIconPos,
        UiActionButtonType,
        UiActionDescriptor
    } from '@smartbit4all/view-context';

    // Build your own action descriptors
    export const ActionDescriptors: Map<string, UiActionDescriptor> = new Map([
        [
            'EXAMPLE',
            {
                title: 'Example action',
    	        type: UiActionButtonType.Raised,
    	        color: 'primary',
                dialog: {
                    title: 'Example dialog title',
                    text: 'Example dialog text',
                    actionButton: {
                        caption: 'Example action',
                        color: 'primary'
                    },
                    cancelButton: {
                        caption: 'Cancel',
                        color: ''
                    }
                },
                inputDialog: { ... },
                confirmDialog: { ... },
                feedbackType: UiActionFeedbackType.SNACKBAR;
                feedbackText: "Example feedback";
            }
        ]
    ])

`authentication.service.ts:`

    constructor(...) {
        ...
        // Set your descriptors
        this.viewContext.setActionDescriptors(ActionDescriptors);

        // Set basic feedback
        this.viewContext.commonFeedbackText = "Basic feedback."
        ...
    }

`example.component.ts:`

    @Component({
        selector: 'app-example',
        templateUrl: './example.component.html',
        styleUrls: ['./example.component.css']
    })
    export class ExampleComponent implements UseUiAction {
        possibleActions: UiAction[]; // Comes from the backend
        actions: UiActionModel[] = [];

        // UseUiAction properties
        submit: Subject<void> = new Subject();
    	reSubscribeToChange: Subject<void> = new Subject();

        constructor(private service: ExampleService) {}

        // UseUiAction functions
        getAdditionalParams(uiAction: UiAction): UiActionAdditionalParams {
            // return additional parameters if needed
            throw new Error('Method not implemented.');
        }
        getModel() {
            // return the model of the page
            throw new Error('Method not implemented.');
        }
        async performUiActionRequest(uiActionRequest: UiActionRequest): Promise<any> {
            // perform the uiActionRequest on the proper service
            await this.service.performAction(uiActionRequest)
        }
        handleSpecificDemandsAsynchronously(uiAction: UiAction): Promise<UiActionSpecificDemandResponse> {
            // handle specific demands if needed
            throw new Error('Method not implemented.');
        }

        // Construct
        constructActions(): void {
            this.actions = [];
            let exceptions = ['EXCEPTION'];
            this.possibleActions.map((uiAction: UiAction) => {
                this.actions?.push({
                    uiAction,
                    serviceToUse: this, // bind a class which implements the UseUiAction
                    exception: exceptions.includes(uiAction.code!)
                });
            });
        }
    }

`example.component.html:`

    <smart-ui-action-toolbar [uiActionModels]="actions"></smart-ui-action-toolbar>

---

## Version logs