| @@ -2433,6 +2433,22 @@ | |||
| } | |||
| } | |||
| }, | |||
| "@progress/kendo-angular-upload": { | |||
| "version": "7.1.0", | |||
| "resolved": "https://registry.npmjs.org/@progress/kendo-angular-upload/-/kendo-angular-upload-7.1.0.tgz", | |||
| "integrity": "sha512-oezUH2BWZguJ6YunBHs5J4SLGWcbt87RTWp6AHlwaopgSALsu5VXpptoLjcrkVXska+nkiyuLY9zpT4HBoGgfQ==", | |||
| "requires": { | |||
| "@progress/kendo-schematics": "^1.0.0", | |||
| "tslib": "^1.9.0" | |||
| }, | |||
| "dependencies": { | |||
| "tslib": { | |||
| "version": "1.14.1", | |||
| "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", | |||
| "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" | |||
| } | |||
| } | |||
| }, | |||
| "@progress/kendo-charts": { | |||
| "version": "1.17.1", | |||
| "resolved": "https://registry.npmjs.org/@progress/kendo-charts/-/kendo-charts-1.17.1.tgz", | |||
| @@ -48,9 +48,10 @@ | |||
| "@progress/kendo-angular-progressbar": "^2.0.0", | |||
| "@progress/kendo-angular-toolbar": "^4.0.0", | |||
| "@progress/kendo-angular-treeview": "^5.1.0", | |||
| "@progress/kendo-angular-upload": "^7.1.0", | |||
| "@progress/kendo-data-query": "^1.5.4", | |||
| "@progress/kendo-drawing": "^1.9.4", | |||
| "@progress/kendo-licensing": "^1.1.3", | |||
| "@progress/kendo-licensing": "^1.0.2", | |||
| "@progress/kendo-svg-icons": "^0.1.2", | |||
| "@progress/kendo-theme-default": "latest", | |||
| "bootstrap": "^4.6.0", | |||
| @@ -70,6 +70,8 @@ import { BrokerProfileComponent } from './broker-profile/broker-profile.componen | |||
| import { ClientLoanListComponent } from './client-loan-list/client-loan-list.component'; | |||
| import { ClientProfileComponent } from './client-profile/client-profile.component'; | |||
| import { E403Component } from './e403/e403.component'; | |||
| import {FileSelectModule, UploadModule} from '@progress/kendo-angular-upload'; | |||
| @@ -140,7 +142,9 @@ import { E403Component } from './e403/e403.component'; | |||
| DateInputsModule, | |||
| DropDownsModule, | |||
| ExcelExportModule, | |||
| EditorModule | |||
| EditorModule, | |||
| UploadModule, | |||
| FileSelectModule | |||
| ], | |||
| providers: [ | |||
| MenuService, | |||
| @@ -4,7 +4,7 @@ import { Router } from '@angular/router'; | |||
| import { NotificationService } from '@progress/kendo-angular-notification'; | |||
| import { Subscription } from 'rxjs'; | |||
| import { AuthService } from '../service/auth.service'; | |||
| import {apiV1LoginResponse} from '../models/api-v1-login-response'; | |||
| import {ApiV1LoginResponse} from '../models/api-v1-login-response'; | |||
| @Component({ | |||
| selector: 'app-auth', | |||
| @@ -42,7 +42,7 @@ export class AuthComponent implements OnInit, OnDestroy{ | |||
| this.authService.login(this.userForm.value.email, this.userForm.value.password); | |||
| } | |||
| public onLogin(rsp: apiV1LoginResponse): void { | |||
| public onLogin(rsp: ApiV1LoginResponse): void { | |||
| this.loading = false; | |||
| // console.log ('found login ' , rsp ); | |||
| if (rsp.login) { | |||
| @@ -1 +1,139 @@ | |||
| <p>broker-profile works!</p> | |||
| <bkp-divider-shadow-bottom></bkp-divider-shadow-bottom> | |||
| <div class="vertical-spacer"></div> | |||
| <div class="container"> | |||
| <div class="row justify-content-center"> | |||
| <div class="col-sm-12"> | |||
| <h5> Edit : {{broker.First + ' ' + broker.Last}} </h5> | |||
| <div class="dropzone-wrapper"> | |||
| <div class="fileselect-wrapper"> | |||
| <div class="row justify-content-center"> | |||
| <div #brokerPhoto class="broker-photo" [ngStyle]="{'background-image' : avatarUrl }" ></div> | |||
| </div> | |||
| <kendo-fileselect | |||
| #fileSelect | |||
| zoneId="myZone" | |||
| [restrictions]="myRestrictions" | |||
| [showFileList]="false" | |||
| (select)="onSelect($event)" | |||
| > | |||
| </kendo-fileselect> | |||
| only jpg and png are allowed | |||
| </div> | |||
| </div> | |||
| <div class="vertical-spacer"></div> | |||
| <form class="k-form" #brokerForm="ngForm" (submit)="save(brokerForm)"> | |||
| <ng-container > | |||
| <fieldset class="k-form-fieldset"> | |||
| <kendo-formfield> | |||
| <kendo-label [for]="First" text="First Name (only Admin can change)"></kendo-label> | |||
| <kendo-textbox kendoTextBox #First name="First" [(ngModel)]="broker.First" | |||
| [showSuccessIcon]="broker.Display.length >= 3 && broker.Display.length <=44 "> </kendo-textbox> | |||
| <kendo-formerror>First name is required</kendo-formerror> | |||
| </kendo-formfield> | |||
| <div class="vertical-spacer"></div> | |||
| <kendo-formfield> | |||
| <kendo-label [for]="Last" text="Last Name (only Admin can change)"></kendo-label> | |||
| <kendo-textbox kendoTextBox #Last name="Last" [(ngModel)]="broker.Last" | |||
| [showSuccessIcon]="broker.Display.length >= 3 && broker.Display.length <=44 "></kendo-textbox> | |||
| <kendo-formerror>Last Name is required</kendo-formerror> | |||
| </kendo-formfield> | |||
| <div class="vertical-spacer"></div> | |||
| <kendo-formfield> | |||
| <kendo-label [for]="Display" text="Display As"></kendo-label> | |||
| <kendo-textbox #Display name="Display" [(ngModel)]="broker.Display" required [minlength]="3" [maxlength]="120" | |||
| [showSuccessIcon]="broker.Display.length >= 3 && broker.Display.length <=100 "> </kendo-textbox> | |||
| <kendo-formerror>Display name cannot empty</kendo-formerror> | |||
| </kendo-formfield> | |||
| <div class="vertical-spacer"></div> | |||
| <kendo-formfield> | |||
| <kendo-label [for]="License" text="License"></kendo-label> | |||
| <kendo-textbox #License name="License" [(ngModel)]="broker.License" required [minlength]="3" [maxlength]="120" | |||
| [showSuccessIcon]="broker.License.length >= 0 && broker.License.length <=20 "> </kendo-textbox> | |||
| <kendo-formerror>license is required, key in unknown if have one</kendo-formerror> | |||
| </kendo-formfield> | |||
| <div class="vertical-spacer"></div> | |||
| <kendo-formfield> | |||
| <kendo-label [for]="BSB" text="BSB"></kendo-label> | |||
| <kendo-textbox #BSB name="BSB" [(ngModel)]="broker.BSB" required [minlength]="3" [maxlength]="7" | |||
| [showSuccessIcon]="broker.BSB.length >= 0 && broker.BSB.length <=7"> </kendo-textbox> | |||
| <kendo-formerror>BSB required for accepting payment</kendo-formerror> | |||
| </kendo-formfield> | |||
| <div class="vertical-spacer"></div> | |||
| <kendo-formfield> | |||
| <kendo-label [for]="ACC" text="ACC"></kendo-label> | |||
| <kendo-textbox #ACC name="ACC" [(ngModel)]="broker.ACC" required [minlength]="3" [maxlength]="11" | |||
| [showSuccessIcon]="broker.ACC.length >= 0 && broker.ACC.length <=11 "> </kendo-textbox> | |||
| <kendo-formerror>ACC is required for accepting payment</kendo-formerror> | |||
| </kendo-formfield> | |||
| <div class="vertical-spacer"></div> | |||
| <kendo-formfield> | |||
| <kendo-label [for]="Organization" text="Organization"></kendo-label> | |||
| <kendo-textbox #Organization name="Organization" [(ngModel)]="broker.Organization" required | |||
| [disabled]="true" [minlength]="3" [maxlength]="25" | |||
| [showSuccessIcon]="broker.Organization.length >= 1 && broker.Organization.length <=25 "> | |||
| </kendo-textbox> | |||
| <kendo-formerror>Organization is required, (only changed by admin)</kendo-formerror> | |||
| </kendo-formfield> | |||
| <div class="vertical-spacer"></div> | |||
| </fieldset> | |||
| </ng-container> | |||
| <div class="k-form-buttons k-buttons-end"> | |||
| <div> | |||
| <button kendoButton class="k-button k-primary" type="submit" icon="save" | |||
| [disabled]="brokerForm.form.status !=='VALID'"> Save </button> | |||
| </div> | |||
| </div> | |||
| </form> | |||
| <kendo-switch [(ngModel)]="changePassword" ngModelOptions="{standalone: true}"> </kendo-switch> Change Password | |||
| <div class="vertical-spacer"></div> | |||
| <form *ngIf="changePassword" [formGroup]="ChangePassForm" class="k-form" (submit)="savePassword()"> | |||
| <kendo-formfield> | |||
| <kendo-label [for]="OldPassword" text="Current Password"></kendo-label> | |||
| <input kendoTextBox #OldPassword name="OldPassword" formControlName="OldPassword" | |||
| type="password" [minlength]="3" [maxlength]="25" /> | |||
| <kendo-formerror>Current password is needed (3-20 chars)</kendo-formerror> | |||
| </kendo-formfield> | |||
| <kendo-formfield> | |||
| <kendo-label [for]="NewPass" text="New Password"></kendo-label> | |||
| <input kendoTextBox #NewPass name="NewPass" formControlName="NewPass" | |||
| [minlength]="3" [maxlength]="25" type="password" /> | |||
| <kendo-formerror>New password is needed (3-20 chars)</kendo-formerror> | |||
| </kendo-formfield> | |||
| <kendo-formfield> | |||
| <kendo-label [for]="NewPass1" text="New Password (repeat) "></kendo-label> | |||
| <input kendoTextBox #NewPass1 name="NewPass1" formControlName="NewPass1" | |||
| [minlength]="3" [maxlength]="25" type="password" /> | |||
| <kendo-formerror>New password repeat is needed (3-20 chars) </kendo-formerror> | |||
| </kendo-formfield> | |||
| <div class="vertical-spacer"></div> | |||
| <button *ngIf="passEqual() && ! ChangePassForm.invalid" kendoButton class="k-button k-primary" type="submit" icon="save"> Change Password </button> | |||
| </form> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="vertical-spacer"></div> | |||
| <kendo-dialog title="Message " *ngIf="opened" (close)="close('cancel')" [minWidth]="250" [width]="450"> | |||
| <p style="margin: 30px; text-align: center;">{{ Message }}</p> | |||
| <kendo-dialog-actions> | |||
| <button kendoButton (click)="close('Ok, I got it')" primary="true">Yes</button> | |||
| </kendo-dialog-actions> | |||
| </kendo-dialog> | |||
| @@ -0,0 +1,33 @@ | |||
| div.container { | |||
| max-width: 500px; | |||
| } | |||
| div.vertical-spacer { | |||
| height:1px; | |||
| margin-bottom: 30px; | |||
| } | |||
| .dropzoneInvisible{ | |||
| opacity:0.1; | |||
| } | |||
| .avatar { | |||
| width: 100%; | |||
| } | |||
| .broker-photo { | |||
| display: inline-block; | |||
| width: 256px; | |||
| height: 256px; | |||
| border-radius: 50%; | |||
| background-size: 256px 256px; | |||
| background-position: center center; | |||
| vertical-align: middle; | |||
| line-height: 132px; | |||
| box-shadow: inset 0 0 1px #999, inset 0 0 10px rgba(0,0,0,.2); | |||
| margin-left: 5px; | |||
| margin-bottom: 10px; | |||
| background-repeat: no-repeat; | |||
| box-shadow: 1px 1px 10px black; | |||
| } | |||
| @@ -1,4 +1,13 @@ | |||
| import { Component, OnInit } from '@angular/core'; | |||
| import {Component, Input, OnInit, ViewChild} from '@angular/core'; | |||
| import {PeopleModel} from '../models/people.model'; | |||
| import {LoanSummaryService} from '../service/loan_summary.service'; | |||
| import {AuthService} from '../service/auth.service'; | |||
| import {FormControl, FormGroup, NgForm} from '@angular/forms'; | |||
| import {FileInfo, FileRestrictions, FileSelectComponent, SelectEvent} from '@progress/kendo-angular-upload'; | |||
| import {PeopleService} from '../service/people.service'; | |||
| import {BrokerModel} from '../models/broker.model'; | |||
| import {ConfirmedValidator} from '../validator/confirmed.validator'; | |||
| @Component({ | |||
| selector: 'app-broker-profile', | |||
| @@ -7,9 +16,94 @@ import { Component, OnInit } from '@angular/core'; | |||
| }) | |||
| export class BrokerProfileComponent implements OnInit { | |||
| constructor() { } | |||
| @Input() public broker: BrokerModel = BrokerModel.EmptyNew(); | |||
| @ViewChild('fileSelect', {static: true}) fs: FileSelectComponent; | |||
| public avatarUrl = 'url(https://svr2021.lawipac.com:8080/api/v1/avatar/1000)' ; | |||
| public myRestrictions: FileRestrictions = { | |||
| allowedExtensions: ['.jpg', '.png', '.jpeg'], | |||
| maxFileSize: 2194304 | |||
| }; | |||
| public opened = false; // dialog box | |||
| public Message = ''; // dialog message | |||
| public changePassword = false; | |||
| public ChangePassForm: FormGroup = new FormGroup({ | |||
| OldPassword: new FormControl(), | |||
| NewPass: new FormControl(), | |||
| NewPass1: new FormControl(), | |||
| }); | |||
| constructor( private auth: AuthService, private ps: PeopleService) { } | |||
| ngOnInit(): void { | |||
| this.broker = BrokerModel.getFromUserAndExtra(this.auth.loggedIn.user, this.auth.loggedIn.userExtra); | |||
| this.avatarUrl = 'url(' + this.auth.getUrl('avatar/' + this.broker.Id) + ')'; | |||
| } | |||
| public save(brokerForm: NgForm): void{ | |||
| if (! brokerForm.touched || brokerForm.form.pristine) { | |||
| return; | |||
| } | |||
| this.ps.saveBroker(this.broker).subscribe( () => { | |||
| this.showDialog('updated successfully '); | |||
| brokerForm.form.markAsPristine(); | |||
| }, err => { | |||
| this.showDialog('Failed to Update: ' + err.toString()); | |||
| }); | |||
| } | |||
| public savePassword(): void{ | |||
| this.ps.savePassword(this.broker.Id, this.ChangePassForm.value).subscribe( | |||
| () => { | |||
| this.showDialog('Password Changed'); | |||
| }, err => { | |||
| this.showDialog('Failed to Change Password :' + err.toString()); | |||
| } | |||
| ); | |||
| } | |||
| public passEqual(): boolean{ | |||
| const v = this.ChangePassForm.value; | |||
| if ( this.ChangePassForm.valid && v.NewPass === v.NewPass1 && this.ChangePassForm.touched) { | |||
| return true; | |||
| }else{ | |||
| this.ChangePassForm.controls['NewPass1'].setErrors({'incorrect': true}); | |||
| } | |||
| return false; | |||
| } | |||
| public onSelect(ev: SelectEvent): void { | |||
| if (ev.files) { | |||
| ev.files.every((file: FileInfo) => { | |||
| if (file.rawFile && !file.validationErrors) { | |||
| const reader = new FileReader(); | |||
| reader.onloadend = () => { | |||
| const str = reader.result as string; | |||
| this.ps.updateAvatar(str, this.broker.Id).subscribe( resp => { | |||
| this.avatarUrl = 'url(' + str + ' )'; | |||
| }, err => { | |||
| this.showDialog('Failed to Update Avatar: ' + err.toString()); | |||
| }); | |||
| this.fs.clearFiles(); | |||
| }; | |||
| reader.readAsDataURL(file.rawFile); | |||
| }else{ | |||
| this.showDialog('Only jpg, and png are supported (max 2MB)'); | |||
| setTimeout(() => { this.fs.clearFiles(); }, 10); | |||
| } | |||
| return false; // we only take first file | |||
| }); | |||
| } | |||
| } | |||
| public showDialog(msg: string): void { | |||
| this.Message = msg; | |||
| this.opened = true; // open dialog | |||
| } | |||
| public close(status): void { | |||
| this.opened = false; | |||
| } | |||
| } | |||
| @@ -10,10 +10,10 @@ | |||
| <span >{{ dataItem.Amount | currency }}</span> | |||
| </ng-template> | |||
| </kendo-grid-column> | |||
| <kendo-grid-column field="Description" title="(∑) Description" ></kendo-grid-column> | |||
| <kendo-grid-column field="Description" title="✅ Description" ></kendo-grid-column> | |||
| <kendo-grid-column field="Item" title="(∑) From Loan"></kendo-grid-column> | |||
| <kendo-grid-column field="Status" title="(∑) Loan Status"> | |||
| <kendo-grid-column field="Item" title="✅ From Loan"></kendo-grid-column> | |||
| <kendo-grid-column field="Status" title="✅ Loan Status"> | |||
| <ng-template kendoGridCellTemplate let-dataItem> | |||
| <span *ngIf="dataItem.Status != 'none'" class="badge badge-success">{{dataItem.Status}}</span> | |||
| </ng-template> | |||
| @@ -28,6 +28,6 @@ | |||
| </kendo-grid-column> | |||
| <kendo-grid-column field="Paid" title="(∑) Paid"> </kendo-grid-column> | |||
| <kendo-grid-column field="Paid" title="✅ Paid"> </kendo-grid-column> | |||
| </kendo-grid> | |||
| @@ -14,4 +14,3 @@ | |||
| /* background-color:chartreuse; */ | |||
| } | |||
| @@ -2,8 +2,9 @@ | |||
| // tslint:disable-next-line:class-name | |||
| import {PeopleModel} from './people.model'; | |||
| import {UserExtraModel} from './user-extra.model'; | |||
| export class apiV1LoginResponse { | |||
| export class ApiV1LoginResponse { | |||
| constructor( | |||
| public login: boolean, | |||
| @@ -11,7 +12,8 @@ export class apiV1LoginResponse { | |||
| public session: string, | |||
| public sessionExpire: number, // unix timestamp | |||
| public role: string, | |||
| public user: PeopleModel | |||
| public user: PeopleModel, | |||
| public userExtra?: UserExtraModel // extra user informaiton | |||
| ) { | |||
| this.login = login; | |||
| this.machineId = machineId; | |||
| @@ -19,8 +21,8 @@ export class apiV1LoginResponse { | |||
| this.sessionExpire = sessionExpire; | |||
| } | |||
| public static EmptyNew(): apiV1LoginResponse{ | |||
| return new apiV1LoginResponse( | |||
| public static EmptyNew(): ApiV1LoginResponse{ | |||
| return new ApiV1LoginResponse( | |||
| false, '', '', 0, '', PeopleModel.EmptyNew() ); | |||
| } | |||
| @@ -1,4 +1,5 @@ | |||
| import {PeopleModel} from './people.model'; | |||
| import {UserExtraModel} from './user-extra.model'; | |||
| export class BrokerModel{ | |||
| constructor( | |||
| @@ -25,4 +26,10 @@ export class BrokerModel{ | |||
| return new BrokerModel('', '', '', '', '', '', '', | |||
| '', false, '', '', '', ''); | |||
| } | |||
| public static getFromUserAndExtra(u: PeopleModel, ex: UserExtraModel): BrokerModel { | |||
| return new BrokerModel( | |||
| u.Id, u.First, u.Last, u.Middle, u.Title, u.Display, u.Nick, ex.Login, ex.Enabled, ex.BSB, ex.ACC, ex.License, ex.Organization | |||
| ); | |||
| } | |||
| } | |||
| @@ -0,0 +1,8 @@ | |||
| export class ChangePassword { | |||
| public OldPassword: string; | |||
| public NewPass: string; | |||
| public NewPass1: string; | |||
| } | |||
| @@ -0,0 +1,15 @@ | |||
| export class UserExtraModel { | |||
| public BSB: string; | |||
| public ACC: string; | |||
| public License: string; | |||
| public Organization: string; | |||
| public Enabled: boolean; | |||
| public Login: string; | |||
| constructor(payload: Partial<UserExtraModel>) { | |||
| Object.assign(this, payload); | |||
| } | |||
| } | |||
| @@ -1,8 +1,9 @@ | |||
| import {EventEmitter, Injectable, OnDestroy, OnInit} from '@angular/core'; | |||
| import {HttpClient, HttpEvent, HttpHandler, HttpInterceptor, HttpParams, HttpRequest} from '@angular/common/http'; | |||
| import {apiV1LoginResponse} from '../models/api-v1-login-response'; | |||
| import {ApiV1LoginResponse} from '../models/api-v1-login-response'; | |||
| import {Router} from '@angular/router'; | |||
| import {PeopleModel} from '../models/people.model'; | |||
| import {UserExtraModel} from '../models/user-extra.model'; | |||
| @Injectable() | |||
| export class AuthService { | |||
| @@ -11,8 +12,8 @@ export class AuthService { | |||
| public apiWsUrl = 'wss://svr2021.lawipac.com:8080/api/v1/ws'; | |||
| // public apiUrl = 'https://c5016.biukop.com.au:8080/api/v1/'; | |||
| // public apiWsUrl = 'wss://c5016.biukop.com.au:8080/api/v1/ws'; | |||
| public loggedIn = apiV1LoginResponse.EmptyNew(); | |||
| loginSuccess = new EventEmitter <apiV1LoginResponse>(); | |||
| public loggedIn = ApiV1LoginResponse.EmptyNew(); | |||
| loginSuccess = new EventEmitter <ApiV1LoginResponse>(); | |||
| constructor( private http: HttpClient , | |||
| private router: Router) { | |||
| @@ -20,21 +21,24 @@ export class AuthService { | |||
| public AutoLogin(): void { | |||
| const sfm: apiV1LoginResponse = JSON.parse(localStorage.getItem('sfm')); | |||
| const sfm: ApiV1LoginResponse = JSON.parse(localStorage.getItem('sfm')); | |||
| if (!sfm) { | |||
| console.log('no auto login'); | |||
| return; | |||
| } | |||
| this.loggedIn = new apiV1LoginResponse( | |||
| this.loggedIn = new ApiV1LoginResponse( | |||
| sfm.login, | |||
| sfm.machineId, | |||
| sfm.session, | |||
| sfm.sessionExpire, | |||
| sfm.role, | |||
| new PeopleModel( | |||
| sfm.user.Id, sfm.user.First, sfm.user.Last, sfm.user.Middle, sfm.user.Title, sfm.user.Display, sfm.user.Nick | |||
| ) | |||
| new PeopleModel(sfm.user.Id, sfm.user.First, sfm.user.Last, sfm.user.Middle, sfm.user.Title, sfm.user.Display, sfm.user.Nick) | |||
| ); | |||
| if ( sfm.userExtra !== undefined ) { | |||
| this.loggedIn.userExtra = new UserExtraModel(sfm.userExtra); | |||
| } | |||
| this.loginSuccess.emit(this.loggedIn); | |||
| // console.log ( 'auto login emit events', this.loggedIn); | |||
| } | |||
| @@ -55,7 +59,7 @@ export class AuthService { | |||
| login(email: string, password: string): void { | |||
| this.http.post<apiV1LoginResponse>(this.apiUrl + 'login', {u: email, p: password}).subscribe( | |||
| this.http.post<ApiV1LoginResponse>(this.apiUrl + 'login', {u: email, p: password}).subscribe( | |||
| responseData => { | |||
| this.loggedIn.session = responseData['Biukop-Session']; | |||
| this.loggedIn.login = responseData.login; | |||
| @@ -72,14 +76,19 @@ export class AuthService { | |||
| responseData.user.Display, | |||
| responseData.user.Nick | |||
| ); | |||
| if (responseData.userExtra !== undefined ) { | |||
| this.loggedIn.userExtra = new UserExtraModel(responseData.userExtra); | |||
| } | |||
| }else{ | |||
| this.loggedIn.user = PeopleModel.EmptyNew(); | |||
| } | |||
| this.saveSessionInfo(); | |||
| this.loginSuccess.emit(responseData); | |||
| }, | |||
| error => { | |||
| const fail = apiV1LoginResponse.EmptyNew(); | |||
| const fail = ApiV1LoginResponse.EmptyNew(); | |||
| this.loggedIn = fail; | |||
| console.log('login error', error); | |||
| this.loginSuccess.emit(this.loggedIn); | |||
| @@ -89,7 +98,7 @@ export class AuthService { | |||
| } | |||
| logout(): void { | |||
| this.loggedIn = apiV1LoginResponse.EmptyNew(); | |||
| this.loggedIn = ApiV1LoginResponse.EmptyNew(); | |||
| localStorage.removeItem('sfm'); | |||
| this.loginSuccess.emit(this.loggedIn); | |||
| this.router.navigate(['/login']).then(r => { | |||
| @@ -5,6 +5,7 @@ import {Observable} from 'rxjs'; | |||
| import {PeopleModel} from '../models/people.model'; | |||
| import {BrokerModel} from '../models/broker.model'; | |||
| import {LoanModel} from '../models/loan.model'; | |||
| import {ChangePassword} from '../models/change-password.model'; | |||
| @Injectable({providedIn: 'root'}) | |||
| export class PeopleService { | |||
| @@ -28,4 +29,16 @@ export class PeopleService { | |||
| return this.http.post<boolean>(this.auth.getUrl('sync-people/'), loan); | |||
| } | |||
| public updateAvatar(avatar: string, id: string ): Observable<boolean> { | |||
| return this.http.post<boolean>(this.auth.getUrl('avatar/' + id), avatar); | |||
| } | |||
| public savePassword(id: string, change: ChangePassword): Observable<boolean>{ | |||
| return this.http.post<boolean>(this.auth.getUrl('change-pass/' + id), change); | |||
| } | |||
| public saveBroker(broker: BrokerModel): Observable<BrokerModel>{ | |||
| return this.http.post<BrokerModel>(this.auth.getUrl('broker/' + broker.Id), broker); | |||
| } | |||
| } | |||
| @@ -2,7 +2,7 @@ import {Component, OnDestroy, OnInit} from '@angular/core'; | |||
| import {MenuService} from '../service/menu.service'; | |||
| import {AuthService} from '../service/auth.service'; | |||
| import {brokerMenuItems, mainMenuItems, peopleMenuItems, userMenuItems} from '../main-menu-items'; | |||
| import {apiV1LoginResponse} from '../models/api-v1-login-response'; | |||
| import {ApiV1LoginResponse} from '../models/api-v1-login-response'; | |||
| import {Subscription} from 'rxjs'; | |||
| import {PeopleModel} from '../models/people.model'; | |||
| @@ -38,7 +38,7 @@ export class TopBarComponent implements OnInit , OnDestroy { | |||
| this.selectMenuShow(this.authService.loggedIn.role); | |||
| this.loginSub = this.authService.loginSuccess.subscribe( | |||
| (rsp: apiV1LoginResponse) => { | |||
| (rsp: ApiV1LoginResponse) => { | |||
| this.login = rsp.login; | |||
| this.LoggedInUser = this.authService.loggedIn.user; | |||
| this.selectMenuShow(rsp.role); | |||
| @@ -0,0 +1,16 @@ | |||
| import { FormGroup } from '@angular/forms'; | |||
| export function ConfirmedValidator(controlName: string, matchingControlName: string) { | |||
| return (formGroup: FormGroup) => { | |||
| const control = formGroup.controls[controlName]; | |||
| const matchingControl = formGroup.controls[matchingControlName]; | |||
| if (matchingControl.errors && !matchingControl.errors.confirmedValidator) { | |||
| return; | |||
| } | |||
| if (control.value !== matchingControl.value) { | |||
| matchingControl.setErrors({ confirmedValidator: true }); | |||
| } else { | |||
| matchingControl.setErrors(null); | |||
| } | |||
| }; | |||
| } | |||