GSaha567/seq_level_training_data
052
1text,length,is_long_context,metric_val,label_metric2":toc: macro3toc::[]4:idprefix:5:idseparator: -6ifdef::env-github[]7:tip-caption: :bulb:8:note-caption: :information_source:9:important-caption: :heavy_exclamation_mark:10:caution-caption: :fire:11:warning-caption: :warning:12endif::[]13 14= devon4j adding Custom Functionality15 16Now we have a fully functional blank project. All we have to do now is to create the components and services which will compose our application.17 18First, we are going to develop the views of the app through its components, then we will create the services with the logic, security and back-end connection.19 20[NOTE]21====22This tutorial is only going to develop a mobile view. The app is not going to be responsive or well suited for desktop use. The new https://github.com/devonfw-forge/jump-the-queue-v2[JumpTheQueue V2] implements these features, but currently no tutorial walkthrough exists for it.23====24 25== Creating Components26 27[NOTE]28====29You have already learned about creating Components in devon4ng https://github.com/devonfw/jump-the-queue/wiki/devon4ng-components#create-a-new-component[here]. +30You can go back and read that section again to refresh your memory.31====32 33Our app is going to consist of 3 main views:34 35* Login36* Register37* ViewQueue38 39To navigate between these views/components, we are going to implement routes using the Angular Router.40 41To see our progress, move to the root folder of the `angular` project and run `ng serve -o` again. This will recompile and publish our client app to http://localhost:4200. Angular will keep watching for changes, so whenever we modify the code, the app will automatically reload.42 43=== Root Component44 45`app.component.ts` inside `angular/src/app` will be our root component, so we don't have to create a new file yet. We are going to add elements to the root component that will be common no matter what view will be displayed.46 47[NOTE]48====49You have already learned about the Root Component in devon4ng https://github.com/devonfw/jump-the-queue/wiki/devon4ng-components#root-component[here]. +50You can go back and read that section again to refresh your memory.51====52 53This applies to the header element which will be on top of the window and on top of all other components. If you want, you can read more about https://teradata.github.io/covalent/#/layouts[Covalent layouts], which we are going to use a lot from now on, for every view component.54 55[NOTE]56====57You have already learned about Covalent Layouts in devon4ng https://github.com/devonfw/jump-the-queue/wiki/devon4ng-components#teradata-covalent-layouts[here]. +58You can go back and read that section again to refresh your memory.59====60 61We don't really need anything more than a header, so we are going to use the simplest layout for this purpose; the *nav view*.62 63In order to be able to use Covalent and Angular Material we are going to create a core module, which we will import into every other module where we want to use Covalent and Angular Material. First, we create a folder called `shared` in the `angular/src/app` directory. Inside there we are going to create a file called `core.module.ts` and will fill it with the following content:64 65[source, typescript]66----67import { NgModule } from '@angular/core';68import { RouterModule } from '@angular/router';69import { CommonModule } from '@angular/common';70import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';71import { BrowserAnimationsModule } from '@angular/platform-browser/animations';72import {73 MatAutocompleteModule,74 MatButtonModule,75 MatButtonToggleModule,76 MatCardModule,77 MatCheckboxModule,78 MatChipsModule,79 MatDatepickerModule,80 MatDialogModule,81 MatExpansionModule,82 MatGridListModule,83 MatIconModule,84 MatInputModule,85 MatListModule,86 MatMenuModule,87 MatNativeDateModule,88 MatPaginatorModule,89 MatProgressBarModule,90 MatProgressSpinnerModule,91 MatRadioModule,92 MatRippleModule,93 MatSelectModule,94 MatSidenavModule,95 MatSliderModule,96 MatSlideToggleModule,97 MatSnackBarModule,98 MatSortModule,99 MatTableModule,100 MatTabsModule,101 MatToolbarModule,102 MatTooltipModule,103} from '@angular/material';104import { CdkTableModule } from '@angular/cdk/table';105import {106 CovalentChipsModule,107 CovalentLayoutModule,108 CovalentExpansionPanelModule,109 CovalentDataTableModule,110 CovalentPagingModule,111 CovalentDialogsModule,112 CovalentLoadingModule,113 CovalentMediaModule,114 CovalentNotificationsModule,115 CovalentCommonModule,116} from '@covalent/core';117 118@NgModule({119 imports: [120 RouterModule,121 BrowserAnimationsModule,122 MatCardModule,123 MatButtonModule,124 MatIconModule,125 CovalentMediaModule,126 CovalentLayoutModule,127 CdkTableModule,128 ],129 exports: [130 CommonModule,131 CovalentChipsModule,132 CovalentLayoutModule,133 CovalentExpansionPanelModule,134 CovalentDataTableModule,135 CovalentPagingModule,136 CovalentDialogsModule,137 CovalentLoadingModule,138 CovalentMediaModule,139 CovalentNotificationsModule,140 CovalentCommonModule,141 CdkTableModule,142 MatAutocompleteModule,143 MatButtonModule,144 MatButtonToggleModule,145 MatCardModule,146 MatCheckboxModule,147 MatChipsModule,148 MatDatepickerModule,149 MatDialogModule,150 MatExpansionModule,151 MatGridListModule,152 MatIconModule,153 MatInputModule,154 MatListModule,155 MatMenuModule,156 MatNativeDateModule,157 MatPaginatorModule,158 MatProgressBarModule,159 MatProgressSpinnerModule,160 MatRadioModule,161 MatRippleModule,162 MatSelectModule,163 MatSidenavModule,164 MatSliderModule,165 MatSlideToggleModule,166 MatSnackBarModule,167 MatSortModule,168 MatTableModule,169 MatTabsModule,170 MatToolbarModule,171 MatTooltipModule,172 HttpClientModule,173 ],174 declarations: [],175 providers: [176 HttpClientModule177 ],178})179export class CoreModule {}180----181 182[NOTE]183====184This `CoreModule` has almost every module of the different components for *Angular Material* and *Covalent Teradata*. If you decide to use a component that is not included yet, you need to add the corresponding module here.185====186 187Remember that we need to import this `CoreModule` module into the `AppModule` and inside every module of the different components that use *Angular Material* and *Covalent Teradata*. If a component does not have a module, it will be imported in the `AppModule` and hence automatically have the `CoreModule`. Our `app.module.ts` should have the following content:188 189[source, typescript]190----191import { BrowserModule } from '@angular/platform-browser';192import { NgModule } from '@angular/core';193 194// Application components and services195import { AppRoutingModule } from './app-routing.module';196import { AppComponent } from './app.component';197import { CoreModule } from './shared/core.module';198 199@NgModule({200 declarations: [201 AppComponent202 ],203 imports: [204 BrowserModule,205 AppRoutingModule,206 CoreModule,207 ],208 providers: [209 ],210 bootstrap: [AppComponent]211})212export class AppModule { }213----214 215[NOTE]216====217Remember this step because you will have to repeat it for every other component from Teradata you use in your app.218====219 220Now we can use this layout, so let's implement it in `app.component.html`. Use the following code:221 222[source, html]223----224<td-layout-nav> <!-- Layout tag-->225 <div td-toolbar-content>226 Jump The Queue <!-- Header container-->227 </div>228 <h1>229 app works! <!-- Main content-->230 </h1>231</td-layout-nav>232----233 234[NOTE]235====236You have already learned about Toolbars in devon4ng https://github.com/devonfw/jump-the-queue/wiki/devon4ng-components#toolbars[here]. +237You can go back and read that section again to refresh your memory.238====239 240Once this is done, our app should have a header and ""app works!"" should appear in the body of the page:241 242image::images/devon4ng/3.BuildYourOwn/root_header.jpg[Root Header, 250]243 244To go a step further, we have to modify the body of the root component because it should be the *output of the router*. Now it's time to prepare the routing system.245 246First, we need to create a component to show as default which will be our access view. We will modify it later. Stop `ng serve` and run:247 248----249ng generate component form-login250----251 252It will add a folder to our project with all the files needed for a component. Now we can move on to the router task again. Run `ng serve` again to continue the development.253 254Let's create a module that navigates between components when the Router checks for routes. The file `app-routing.module.ts` was created automatically when we chose to include Angular Routing during project creation and we only need to modify it now:255 256[source, typescript]257----258import { NgModule } from '@angular/core';259import { RouterModule, Routes } from '@angular/router';260import { FormLoginComponent } from './form-login/form-login.component';261 262const appRoutes: Routes = [263 { path: 'FormLogin', component: FormLoginComponent}, // Redirect if url path is /FormLogin.264 { path: '**', redirectTo: '/FormLogin', pathMatch: 'full' } // Redirect if url path do not match any other route.265];266 267@NgModule({268 imports: [269 RouterModule.forRoot(270 appRoutes,271 { enableTracing: true }, // <-- debugging purposes only272 ),273 ],274 exports: [RouterModule],275})276export class AppRoutingModule {}277----278 279[NOTE]280====281You have already learned about Routing in devon4ng https://github.com/devonfw/jump-the-queue/wiki/devon4ng-components#routing[here]. +282You can go back and read that section again to refresh your memory.283====284 285Finally, we remove the `<h1>app works!</h1>` from `app.component.html` and replace it with a `<router-outlet></router-outlet>` tag. The final result of our root component will look like this:286 287image::images/devon4ng/3.BuildYourOwn/root_router.jpg[Root Router, 250]288 289As you can see, now the body content is the HTML of `FormLoginComponent`. This is because we told the Router to redirect to formlogin when the path is `/FormLogin`, but also, redirect to it by default if any of the other routes match the given path.290 291For now we are going to leave the header like this. In the future we will separate it into another component inside a layout folder.292 293=== LoginForm Component294 295As we have already created this component from the section before, let's move on to building the template of the login view.296 297First, we need to add the Covalent Layout and the card to the file `form-login.component.html`:298 299[source, html]300----301<td-layout>302 <mat-card>303 <mat-card-title>Login</mat-card-title>304 </mat-card>305</td-layout>306----307 308This will add a grey background to the view and a card on top of it with the title ""Login"" now that we have the basic structure of the view.309 310Now we are going to add this image:311 312image::images/devon4ng/3.BuildYourOwn/jumptheq.png[JumpTheQueue Logo Image, 250]313 314In order to have it available, save it in the following path of the project: `angular/src/assets/images/` and name it `jumptheq.png`.315 316The final code with the form added will look like this:317 318[source, html]319----320<td-layout>321 <mat-card>322 <img mat-card-image src=""assets/images/jumptheq.png"">323 </mat-card>324</td-layout>325----326 327This code will give us as a result similar to this:328 329image::images/devon4ng/3.BuildYourOwn/formlogin.png[Form Login, 250]330 331This is going to be the container for the login. +332Now we will continue with the second component: Login.333 334=== Login Component335 336Our first step will be to create the component in the exact same way we created the `FormLogin` component but this time we are going to generate it in a new folder called components inside formlogin. Putting every child component inside that folder will allow us to keep a good and clear structure. In order to do this, we use the command:337 338----339ng generate component form-login/components/login340----341 342After _Angular/CLI_ has finished generating the component, we have to create two modules, one for the form-login and one for the login:343 3441.- We create a new file called `login-module.ts` in the login root:345 346[source, typescript]347----348import { NgModule } from '@angular/core';349import { CommonModule } from '@angular/common';350import { CoreModule } from 'src/app/shared/core.module';351import { LoginComponent } from './login.component';352 353@NgModule({354 imports: [CommonModule, CoreModule],355 providers: [],356 declarations: [LoginComponent],357 exports: [LoginComponent],358})359export class LoginModule {}360----361 3622.- We create a new file called `form-login-module.ts` in the form-login root:363 364[source, typescript]365----366import { NgModule } from '@angular/core';367import { CommonModule } from '@angular/common';368import { FormLoginComponent } from './form-login.component';369import { CoreModule } from '../shared/core.module';370import { LoginModule } from './components/login/login-module';371 372@NgModule({373 imports: [CommonModule, CoreModule, LoginModule],374 providers: [],375 declarations: [FormLoginComponent],376 exports: [FormLoginComponent],377})378export class FormLoginModule {}379----380 381As you can see, the `LoginModule` is already added to the `FormLoginModule`. Once this is done, we need to remove the `FormLoginComponent` and the `LoginComponent` from the `declarations` since they are already declared in their own modules. Then add the `FormLoginModule`. This will be done inside `AppModule`:382 383[source, typescript]384----385...386import { FormLoginModule } from './form-login/form-login-module';387...388 declarations: [389 AppComponent,390 ]391 392 imports: [393 BrowserModule,394 FormLoginModule,395 CoreModule,396 AppRoutingModule397 ]398...399----400 401[NOTE]402====403This is done so the `form-login` (container/wrapper) and the `login` stay separated allowing us to reuse the login without having the card around in other views.404====405 406After this, we modify the `login.component.html` and add the form: 407 408[source, typescript]409----410<form #loginForm=""ngForm"" layout-padding>411 <div layout=""row"" flex>412 <mat-form-field flex>413 <input matInput placeholder=""Email"" ngModel email name=""username"" required>414 </mat-form-field>415 </div>416 <div layout=""row"" flex>417 <mat-form-field flex>418 <input matInput placeholder=""Password"" ngModel name=""password"" type=""password"" required>419 </mat-form-field>420 </div>421 <div layout=""row"" flex>422 </div>423 <div layout=""row"" flex layout-margin>424 <div layout=""column"" flex>425 <button mat-raised-button [disabled]=""!loginForm.form.valid"">Login</button>426 </div>427 <div layout=""column"" flex>428 <button mat-raised-button color=""primary"">Register</button>429 </div>430 </div>431</form>432----433 434[NOTE]435====436You have already learned about Forms in devon4ng https://github.com/devonfw/jump-the-queue/wiki/devon4ng-components#forms[here]. +437You can go back and read that section again to refresh your memory.438====439 440This form contains two input containers from Material. The containers enclose the input with the properties listed above.441 442We also need to add a button to send the information and redirect to the `QueueViewer` or show an error if something went wrong in the process. But for the moment, as we neither have another component nor the auth service yet, we will implement the button visually, as well as the validator to disable it if the form is not correct. We will tackle the on-click-event later.443 444As a last step we will add this component to the `form-login-component.html`:445 446[source, html]447----448<td-layout>449 <mat-card>450 <img mat-card-image src=""assets/images/jumptheq.png"">451 <app-login></app-login>452 </mat-card>453</td-layout>454----455 456Now you should see something like this:457 458image::images/devon4ng/3.BuildYourOwn/login.png[JumpTheQueue Login Screen, 250]459 460With two components already created, we need to use the router to navigate between them. Following the application flow of events, we are going to add a _navigate_ function to the register button. When we press it, we will be redirected to our future register component.461 462=== Register Component463 464First, we are going to generate the register component via:465 466----467ng generate component register`468----469 470This will create our component so we can start working on it. Turning back to `login.component.html` we have to modify these lines of code:471 472[source, html]473----474<form (ngSubmit)=""submitLogin()"" #loginForm=""ngForm"" layout-padding>475... 476<button mat-raised-button type=""submit"" [disabled]=""!loginForm.form.valid"">Login</button>477... 478<button mat-raised-button (click)=""onRegisterClick()"" color=""primary"">Register</button>479----480 481Two events were added. First, when we submit the form, the method `submitLogin()` is going to be called. Second, when the user clicks the button `(click)` will send an event to the function `onRegisterClick()`. This function should be inside `login.component.ts` which is going to be created now:482 483[source, typescript]484----485 ...486 import { Router } from '@angular/router';487 ...488 constructor(private router: Router) { }489 ...490 onRegisterClick(): void {491 this.router.navigate(['Register']);492 }493 494 submitLogin(): void {495 }496----497 498We need to inject an instance of the Router object and declare it with the name _router_ in order to use it in the code, as we did with `onRegisterClick()`. Doing this will use the navigate function and redirect to the next view. In our case, it will redirect using the route we are going to define in `app.routing.module.ts`:499 500[source, typescript]501----502...503import { RegisterComponent } from './register/register.component';504...505const appRoutes: Routes = [506 { path: 'FormLogin', component: FormLoginComponent}, // Redirect if url path is /FormLogin.507 { path: 'Register', component: RegisterComponent}, // Redirect if url path is /Register.508 { path: '**', redirectTo: '/FormLogin', pathMatch: 'full' } // Redirect if url path do not match any other route.509];510...511----512 513[NOTE]514====515You have already learned about Dependency Injection in devon4ng https://github.com/devonfw/jump-the-queue/wiki/devon4ng-services#dependency-injection[here]. +516You can go back and read that section again to refresh your memory.517====518 519Now we are going to imitate the `login` to shape our `register.component.html`:520 521[source, html]522----523<form layout-padding (ngSubmit)=""submitRegister()"" #registerForm=""ngForm"">524 <div layout=""row"" flex>525 <mat-form-field flex>526 <input matInput placeholder=""Email"" ngModel email name=""username"" required>527 </mat-form-field>528 </div>529 <div layout=""row"" flex>530 <mat-form-field flex>531 <input matInput placeholder=""Password"" ngModel name=""password"" type=""password"" required>532 </mat-form-field>533 </div>534 <div layout=""row"" flex>535 <mat-form-field flex>536 <input matInput placeholder=""Name"" ngModel name=""name"" required>537 </mat-form-field>538 </div>539 <div layout=""row"" flex>540 <mat-form-field flex>541 <input matInput placeholder=""Phone Number"" ngModel name=""phoneNumber"" required>542 </mat-form-field>543 </div>544 <div layout-xs=""row"" flex>545 <div layout=""column"" flex>546 <mat-checkbox name=""acceptedTerms"" ngModel required>Accept Terms And conditions</mat-checkbox>547 </div>548 </div>549 <div layout-xs=""row"" flex>550 <div layout=""column"" flex>551 <mat-checkbox name=""acceptedCommercial"" ngModel required>I want to receive notifications</mat-checkbox>552 </div>553 </div>554 <div layout=""row"" flex>555 </div>556 <div layout=""row"" flex>557 <div layout=""column"" flex=""10"">558 </div>559 <div layout=""column"" flex>560 <button mat-raised-button type=""submit"" [disabled]=""!registerForm.form.valid"">Register</button>561 </div>562 <div layout=""column"" flex=""10"">563 </div>564 </div>565</form>566----567 568Now that we have a minimum of navigation flow inside our application, we are going to generate our first service using the command:569 570----571ng generate service register/services/register572----573 574This will create a folder ""services"" inside ""register"" and create the service itself. Services are where we keep the logic that connects to our database and fetches data which is going to be used by our `component.ts`.575 576In order to use the service, we are going to create some interface models. Let's create a folder called `backendModels` inside ""shared"" and inside this folder a file called `interfaces.ts` in which we are going to add the model interfaces that will match our backend:577 578[source, typescript]579----580export class Visitor {581 id?: number;582 username: string;583 name: string;584 password: string;585 phoneNumber: string;586 acceptedCommercial: boolean;587 acceptedTerms: boolean;588 userType: boolean;589}590----591 592[NOTE]593====594You have already learned about creating new services in devon4ng https://github.com/devonfw/jump-the-queue/wiki/devon4ng-services#create-a-new-service[here]. +595You can go back and read that section again to refresh your memory.596====597 598If we take a closer look, we can see that id has a `?` behind it. This indicates that the id is optional.599 600[NOTE]601====602At this point we are going to assume that you have finished the https://github.com/devonfw/jump-the-queue/wiki/build-devon4j-application[devon4j] part of this tutorial, or have at least downloaded the project and have the back end running locally on http://localhost:8081.603====604 605After doing this, we are going to add an environment variable with our base-URL for the REST services. This way we won't have to change every URL when we switch to production. Inside `environments/environment.ts` we add:606 607[source, typescript]608----609export const environment: {production: boolean, baseUrlRestServices: string} = {610 production: false,611 baseUrlRestServices: 'http://localhost:8081/jumpthequeue/services/rest'612};613----614 615Now in the service, we are going to add a `registerVisitor` method.616 617To call the server in this method we are going to inject the Angular `HttpClient` class from `@angular/common/http`. This class is the standard used by Angular to perform HTTP calls. The register call demands a `Visitor` model which we created in the `interfaces` file. We are going to build a POST call and send the information to the proper URL of the server service. The call will return an observable:618 619[source, typescript]620----621import { Injectable } from '@angular/core';622import { HttpClient } from '@angular/common/http';623import { Visitor} from 'src/app/shared/backendModels/interfaces';624import { Observable } from 'rxjs';625import { environment } from 'src/environments/environment';626 627@Injectable({628 providedIn: 'root'629})630export class RegisterService {631 632 private baseUrl = environment.baseUrlRestServices;633 634 constructor(private http: HttpClient) { }635 636 registerVisitor(visitor: Visitor): Observable<Visitor> {637 return this.http.post<Visitor>(`${this.baseUrl}` + '/visitormanagement/v1/visitor', visitor);638 }639}640----641 642This method will send our model to the backend and return an Observable that we will use on the `component.ts`.643 644[NOTE]645====646You have already learned about Observables and RxJs in devon4ng https://github.com/devonfw/jump-the-queue/wiki/devon4ng-services#server-communication[here]. +647You can go back and read that section again to refresh your memory.648====649 650Now we are going to modify `register.component.ts` to call this service:651 652[source, typescript]653----654import { Component, OnInit } from '@angular/core';655import { RegisterService } from './services/register.service';656import { Visitor } from '../shared/backendModels/interfaces';657import { Router } from '@angular/router';658import { MatSnackBar } from '@angular/material/snack-bar';659 660@Component({661 selector: 'app-register',662 templateUrl: './register.component.html',663 styleUrls: ['./register.component.scss']664})665export class RegisterComponent implements OnInit {666 667 constructor(private registerService: RegisterService, private router: Router, public snackBar: MatSnackBar) { }668 669 submitRegister(formValue): void {670 const visitor: Visitor = new Visitor();671 visitor.username = formValue.username;672 visitor.name = formValue.name;673 visitor.phoneNumber = formValue.phoneNumber;674 visitor.password = formValue.password;675 visitor.acceptedCommercial = formValue.acceptedCommercial;676 visitor.acceptedTerms = formValue.acceptedTerms;677 visitor.userType = false;678 679 this.registerService.registerVisitor(visitor).subscribe(680 (visitorResult: Visitor) => console.log(JSON.stringify(visitorResult)), // When call is received681 (err) => this.snackBar.open(err.error.message, 'OK', {682 duration: 5000,683 }), // When theres an error684 );685 }686 687 ngOnInit() {688 }689}690----691 692In this file we injected `RegisterService` and `Router` to use them. Then, inside the method `submitRegister`, we created a visitor that we are going to pass to the service. We called the service method `registerVisitor`, we passed the visitor and we subscribed to the `Observable<Visitor>`, which we returned from the service. This subscription allows us to control three things:693 694. What to do when the data is received.695 696. What to do when there's an error.697 698. What to do when the call is complete.699 700Finally, we modify the `register.component.html` to send the form values to the method:701 702[source, html]703----704...705<form layout-padding (ngSubmit)=""submitRegister(registerForm.form.value)"" #registerForm=""ngForm"">706...707----708 709image::images/devon4ng/3.BuildYourOwn/register.png[Register Page, 250]710 711Using the method and taking a look at the browser console, we should see the visitor model being returned.712 713== Creating Services714 715Now that we registered a `Visitor`, it's time to create 3 important services:716 717- AuthService718- AuthGuardService719- LoginService720 721The `AuthService` will be the one that contains the login info, the `AuthGuardService` will check if a user is authorized to use a component (via the `canActivate` method), and the `LoginService` will be used to fill the `AuthService`.722 723[NOTE]724====725To keep this tutorial simple, we are going to perform the password check client side. *THIS IS NOT CORRECT!* Usually, you would send the username and password to the backend, check that the values are correct, and create a corresponding token which you would pass in the header and use it inside the `AuthService` -- checking with some interceptors that the token is both in the `AuthService` and in the request.726====727 728=== Login, Auth and AuthGuard Services729 730We are going to create the 3 services via `ng generate service <path>`:731 732. `LoginService` via: +733`ng generate service form-login/components/login/services/login`734 735. `Auth` service via: +736`ng generate service core/authentication/auth`737 738. `AuthGuard` service via: +739`ng generate service core/authentication/auth-guard`740 741After generating the services, we are going to start modyfing the interfaces. Inside `angular/src/app/shared/backendModels/interfaces` we are going to add `Role`, `FilterVisitor`, `Pageable` and a `Sort` interface:742 743[source, typescript]744----745...746export class FilterVisitor {747 pageable: Pageable;748 username?: string;749 password?: string;750}751 752export class Pageable {753 pageSize: number;754 pageNumber: number;755 sort?: Sort[];756}757 758export class Sort {759 property: string;760 direction: string;761}762 763export class Role {764 name: string;765 permission: number;766}767----768 769[NOTE]770====771As you can see, we added a `Pageable`, since a lot of the search methods in the backend are using `SearchCriterias`. These need pageables which specify a `paseSize` and `pageNumber`. Also, we can see that in this case `FilterVisitor` uses a pageable and adds parameters as a filter (`username` and `password`), which are optional.772====773 774Then we are going to create a `config.ts` file inside the root (`angular/app`). We are going to use that file to set up default config variables, for example: role names with their permission number, default pagination settings etc. For now we are just adding the roles:775 776[source, typescript]777----778export const config: any = {779 roles: [780 { name: 'VISITOR', permission: 0 },781 { name: 'BOSS', permission: 1 },782 ],783};784----785 786After that, we are going to modify the `auth.service.ts`:787 788[source, typescript]789----790import { Injectable } from '@angular/core';791import { find } from 'lodash';792import { Role } from 'src/app/shared/backendModels/interfaces';793import { config } from 'src/app/config';794 795@Injectable({796 providedIn: 'root'797})798export class AuthService {799 private logged = false;800 private user = '';801 private userId = 0;802 private currentRole = 'NONE';803 private token: string;804 805 public isLogged(): boolean {806 return this.logged;807 }808 809 public setLogged(login: boolean): void {810 this.logged = login;811 }812 813 public getUser(): string {814 return this.user;815 }816 817 public setUser(username: string): void {818 this.user = username;819 }820 821 public getUserId(): number {822 return this.userId;823 }824 825 public setUserId(userId: number): void {826 this.userId = userId;827 }828 829 public getToken(): string {830 return this.token;831 }832 833 public setToken(token: string): void {834 this.token = token;835 }836 837 public setRole(role: string): void {838 this.currentRole = role;839 }840 841 public getPermission(roleName: string): number {842 const role: Role = <Role>find(config.roles, { name: roleName });843 return role.permission;844 }845 846 public isPermited(userRole: string): boolean {847 return (848 this.getPermission(this.currentRole) === this.getPermission(userRole)849 );850 }851}852----853 854We will use this service to fill it with information from the logged-in user once the user logs in. This will allow us to check the information of the logged-in user in any way necessary.855 856[NOTE]857====858You have already learned about Authentication in devon4ng https://github.com/devonfw/jump-the-queue/wiki/devon4ng-services#authentication[here]. +859You can go back and read that section again to refresh your memory.860====861 862Now we are going to use this class to fill the `auth-guard.service.ts`:863 864[source, typescript]865----866import { Injectable } from '@angular/core';867import {868 CanActivate,869 Router,870 ActivatedRouteSnapshot,871 RouterStateSnapshot,872} from '@angular/router';873import { AuthService } from './auth.service';874 875@Injectable({876 providedIn: 'root'877})878export class AuthGuardService implements CanActivate {879 constructor(880 private authService: AuthService,881 private router: Router,882 ) {}883 884 canActivate(885 route: ActivatedRouteSnapshot,886 state: RouterStateSnapshot,887 ): boolean {888 if (this.authService.isLogged() && this.authService.isPermited('VISITOR')) { // If its logged in and its role is visitor889 return true;890 }891 892 if (!this.authService.isLogged()) { // if its not logged in893 console.log('Error login');894 }895 896 if (this.router.url === '/') { // if the router is the app route897 this.router.navigate(['/login']);898 }899 return false;900 }901}902----903 904This service will be slightly different because we have to implement an interface called `CanActivate`. It has a method called `canActivate()` returning a boolean. This method will be called when navigating to a specified route, and -- depending on the return value of this implemented method -- the navigation will proceed or be rejected.905 906[NOTE]907====908You have already learned about Guards in devon4ng https://github.com/devonfw/jump-the-queue/wiki/devon4ng-services#guards[here]. +909You can go back and read that section again to refresh your memory.910====911 912Once this is done, the last step is to fill the `login.service.ts`. In this case, there's going to be three methods:913 914. `getVisitorByUsername(username: string)`: +915A method that recovers a single user corresponding to the email.916 917. `login(username: string, password: string)`: +918A method, which is going to use the previous method, to check that the username and password match the form input and then fill the `AuthService`.919 920. `logout()`: +921This is going to be used to reset the `AuthService` and log out the user.922 923Also, we see the first use of `pipe` and `map`: +924`pipe` allows us to execute a chain of functions, then `map` allows us to return the single visitor instead of all the parameters that the server will send us.925 926[source, typescript]927----928import { map, tap } from 'rxjs/operators';929import { Injectable } from '@angular/core';930import { Observable } from 'rxjs';931import { Visitor, FilterVisitor, Pageable } from 'src/app/shared/backendModels/interfaces';932import { HttpClient } from '@angular/common/http';933import { environment } from 'src/environments/environment';934import { AuthService } from 'src/app/core/authentication/auth.service';935import { Router } from '@angular/router';936import { MatSnackBar } from '@angular/material/snack-bar';937 938@Injectable({939 providedIn: 'root'940})941export class LoginService {942 943 private baseUrl = environment.baseUrlRestServices;944 constructor(private router: Router, private http: HttpClient, private authService: AuthService, public snackBar: MatSnackBar) { }945 946 getVisitorByUsername(username: string): Observable<Visitor> {947 const filters: FilterVisitor = new FilterVisitor();948 const pageable: Pageable = new Pageable();949 950 pageable.pageNumber = 0;951 pageable.pageSize = 1;952 filters.username = username;953 filters.pageable = pageable;954 return this.http.post<Visitor>(`${this.baseUrl}` + '/visitormanagement/v1/visitor/search', filters)955 .pipe(956 map(visitors => visitors['content'][0]),957 );958 }959 960 login(username: string, password: string): void {961 // Checks if given username and password are the ones aved in the database962 this.getVisitorByUsername(username).subscribe(963 (visitorFound) => {964 if (visitorFound.username === username && visitorFound.password === password) {965 this.authService.setUserId(visitorFound.id);966 this.authService.setLogged(true);967 this.authService.setUser(visitorFound.username);968 if (visitorFound.userType === false) {969 this.authService.setRole('VISITOR');970 this.router.navigate(['ViewQueue']);971 } else {972 this.authService.setLogged(false);973 this.snackBar.open('access error', 'OK', {974 duration: 2000,975 });976 }977 } else {978 this.snackBar.open('access error', 'OK', {979 duration: 2000,980 });981 }982 },983 (err: any) => {984 this.snackBar.open('access error', 'OK', {985 duration: 2000,986 });987 },988 );989 }990 991 logout(): void {992 this.authService.setLogged(false);993 this.authService.setUser('');994 this.authService.setUserId(0);995 this.router.navigate(['FormLogin']);996 }997}998----999 1000If you remember the devon4j tutorial, we used `Criteria` in order to filter and to search the DB. The `Criteria` require a pageable and you can add extra parameters to get specific results. In `getVisitorByUsername()` you can see the creation of a `FilterVisitor` corresponding to the `Criteria` in the backend. This `FilterVisitor` gets a `Pageable` and a `username` and will return a single result as soon as the POST call is performed. That's why we return the first page and only a single result.1001 1002[NOTE]1003====1004For the tutorial we are only considering the visitor side of the application. That's why we `setLogged(false)` if it's `userType === true` (BOSS side).1005====1006 1007Then we add to the `login-module.ts` and `LoginService`:1008 1009[source, typescript]1010----1011...1012import { LoginService } from './services/login.service';1013 1014@NgModule({1015 ...1016 providers: [LoginService],1017 ...1018})1019...1020----1021 1022After that, we are going to add the `AuthGuard` and the `Auth` into the `shared/core-module.ts`. This will allow us to employ these two services when importing the core module avoiding having to provide these services in every component:1023 1024[source, typescript]1025----1026...1027 providers: [1028 HttpClientModule,1029 AuthService,1030 AuthGuardService,1031 ],1032...1033----1034 1035You need to import these modules as well, as shown earlier.1036 1037Finally, we modify the `login.component.html` to send the form values to the `login.component.ts` like we did with the register form. Afterwards, we are going to modify the `register.components.ts`: When the visitor registers, we can log him in automatically to avoid any nuisances. Let's start with the `login.component.html`:1038 1039[source, html]1040----1041...1042<form (ngSubmit)=""submitLogin(loginForm.form.value)"" #loginForm=""ngForm"" layout-padding>1043...1044----1045 1046As you can see, in the form we just added, the values to the `ngSubmit` allow us to call the method `submitLogin()` within the logic, sending the `loginForm.form.values` which are the form's input values. In the next step we are going to modify the `login.components.ts`, adding the `submitLogin()` method. This method calls the `LoginService`, providing the service with the necessary values received from the form (i.e. the `loginFormValues`).1047 1048[source, typescript]1049----1050...1051import { LoginService } from './services/login.service';1052...1053export class LoginComponent implements OnInit {1054 ...1055 constructor(private router: Router, private loginService: LoginService) {1056 }1057 ...1058 submitLogin(loginFormValues): void {1059 this.loginService.login(loginFormValues.username, loginFormValues.password);1060 }1061}1062----1063 1064Finally, in the `register.components.ts` we are going to inject the `LoginService` and use it to login the visitor after registering him. This will also send the user to the `ViewQueue`, which we will create and secure later in the tutorial.1065 1066[source, typescript]1067----1068import { LoginService } from '../form-login/components/login/services/login.service';1069...1070constructor(private registerService: RegisterService, private router: Router, public snackBar: MatSnackBar,1071 private loginService: LoginService) { } 1072...1073 submitRegister(formValue): void {1074 ...1075 this.registerService.registerVisitor(visitor).subscribe(1076 (visitorResult: Visitor) => {1077 this.loginService.login(visitorResult.username, visitorResult.password);1078 },1079 ...1080 );1081 }1082...1083----1084 1085== Finishing Touches1086 1087Now we only need to generate two more components (`header` and `view-queue`) and services (`AccessCodeService` and `QueueService`) in order to finish the implementation of our _JumpTheQueue_ app.1088 1089=== Separating Header from Layout1090 1091By separating the header on top of the page from the layout, we enable the reuse of this component and reach a better separation of concerns across our application. To do this, we are going to generate a new component inside `angular/src/app/layout/header` via:1092 1093----1094ng generate component layout/header1095----1096 1097Now we are going to add it to the main view `app.component.html`:1098 1099[source, html]1100----1101...1102 <div td-toolbar-content flex>1103 <app-header layout-align=""center center"" layout=""row"" flex></app-header>1104 </div> <!-- Header container-->1105...1106----1107 1108After adding the component to the header view (`app-header`), we are going to modify the HTML of the component (`header.component.html`) and the logic of the component (`header.component.ts`). As a first step, we are going to modify the HTML, adding an icon as a button, which checks whether or not the user is logged in via `*ngIf` by calling the auth service's `isLogged()` method. This will make the icon appear only if the user is logged in:1109 1110[source, html]1111----1112Jump The Queue1113<span flex></span> 1114<button mat-icon-button mdTooltip=""Log out"" (click)=onClickLogout() *ngIf=""authService.isLogged()"">1115 <mat-icon>exit_to_app</mat-icon>1116</button>1117----1118 1119In the header logic (`header.component.ts`) we are simply going to inject the `AuthService` and `LoginService`, then we are going call `logout()` from `LoginService` in the `OnClickLogout()`. Finally, the `AuthService` is needed because it's being used by the HTML template to control if the user is logged in with `isLogged()`:1120 1121[source, typescript]1122----1123...1124 constructor(private authService: AuthService, private loginService: LoginService) { }1125...1126 onClickLogout(): void {1127 this.loginService.logout();1128 }1129...1130----1131 1132Separating components will allow us to keep the code clean and easy to work with.1133 1134=== ViewQueue Component1135 1136For the last view, we are going to learn how to use our Observables on the HTML template directly without having to `subscribe()` to them.1137 1138First, we are going to generate the component via:1139 1140----1141ng generate component view-queue1142----1143 1144After that, we are going to include the component in the `app-routing.module.ts`, also adding the guard, to only allow users that are `VISITOR` to see the component. It is important to insert the following code before `{ path: '**', redirectTo: '/FormLogin', pathMatch: 'full' }`:1145 1146[source, typescript]1147----1148...1149const appRoutes: Routes = [1150 ...1151 { path: 'ViewQueue',1152 component: ViewQueueComponent,1153 canActivate: [AuthGuardService]}, // Redirect if url path is /ViewQueue, check if canActivate() with the AuthGuardService.1154 ...1155];1156...1157----1158 1159Now in order to make this view work, we are going to do these things:1160 1161. Add the `Queue` and `AccessCode` interface in our `angular/src/app/shared/backendModels/interfaces` and their corresponding filters.1162 1163. Generate the `QueueService` and `AccessCodeService` and add the necessary methods.1164 1165. Modify the `view-queue.component.html`.1166 1167. Modify the logic of the component `view-queue.component.ts`.1168 1169First, we are going to add the necessary interfaces. We modify `angular/src/app/shared/backendModels/interfaces.ts` and add the `FilterQueue`, `Queue`, `FilterAccessCode` and `AccessCode`. These are going to be necessary in order to communicate with the backend.1170 1171[source, typescript]1172----1173...1174export class FilterAccessCode {1175 pageable: Pageable;1176 visitorId?: Number;1177 endTime?: string;1178}1179 1180export class FilterQueue {1181 pageable: Pageable;1182 active: boolean;1183}1184 1185export class AccessCode {1186 id?: number;1187 ticketNumber: string;1188 creationTime: string;1189 startTime?: string;1190 endTime?: string;1191 visitorId: number;1192 queueId: number;1193}1194 1195export class Queue {1196 id?: number;1197 name: string;1198 logo: string;1199 currentNumber: string;1200 attentionTime: string;