diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index df79bf5..5ad03e3 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -10,7 +10,7 @@ import {LoanEditComponent} from './loan-edit/loan-edit.component'; import {LenderUploadsComponent} from './lender-uploads/lender-uploads.component'; import {BrokerLoanListComponent} from './broker-loan-list/broker-loan-list.component'; import {BrokerRewardComponent} from './broker-reward/broker-reward.component'; -import {BrokerProfileComponent} from './broker-profile/broker-profile.component'; +import {BrokerProfileComponent} from './profile/broker-profile/broker-profile.component'; import {ClientLoanListComponent} from './client-loan-list/client-loan-list.component'; import {ClientProfileComponent} from './client-profile/client-profile.component'; import {E403Component} from './e403/e403.component'; @@ -22,6 +22,7 @@ import {RewardUnpaidComponent} from './reward-unpaid/reward-unpaid.component'; import {PayInComponent} from './pay-in/pay-in.component'; import {PeopleAddComponent} from './people-add/people-add.component'; import {SettingsComponent} from './settings/settings.component'; +import {ProfileComponent} from './profile/profile.component'; const routes: Routes = [ @@ -50,6 +51,7 @@ const routes: Routes = [ {path : 'lender-uploads', component: LenderUploadsComponent, canActivate: [AuthGuard] }, {path : 'list-all-people', component: LenderUploadsComponent, canActivate: [AuthGuard] }, {path : 'people-add', component: PeopleAddComponent, canActivate: [AuthGuard] }, + {path : 'profile', component: ProfileComponent, canActivate: [AuthGuard] }, {path : 'e403', component: E403Component, }, ]; diff --git a/src/app/app.module.ts b/src/app/app.module.ts index df7e9db..9b144fb 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -66,7 +66,7 @@ import { PeopleCardComponent } from './people-card/people-card.component'; import { LenderUploadsComponent } from './lender-uploads/lender-uploads.component'; import { BrokerLoanListComponent } from './broker-loan-list/broker-loan-list.component'; import { BrokerRewardComponent } from './broker-reward/broker-reward.component'; -import { BrokerProfileComponent } from './broker-profile/broker-profile.component'; +import { BrokerProfileComponent } from './profile/broker-profile/broker-profile.component'; import { ClientLoanListComponent } from './client-loan-list/client-loan-list.component'; import { ClientProfileComponent } from './client-profile/client-profile.component'; import { E403Component } from './e403/e403.component'; @@ -80,6 +80,12 @@ import { PayInComponent } from './pay-in/pay-in.component'; import { PeopleAddComponent } from './people-add/people-add.component'; import { ListAllPeopleComponent } from './list-all-people/list-all-people.component'; import { SettingsComponent } from './settings/settings.component'; +import { ProfileComponent } from './profile/profile.component'; +import { PeopleProfileComponent } from './profile/people-profile/people-profile.component'; +import { MessageBoxComponent } from './message-box/message-box.component'; +import { UserProfileComponent } from './profile/user-profile/user-profile.component'; +import { AdminProfileComponent } from './profile/admin-profile/admin-profile.component'; +import { ChangePasswordComponent } from './profile/change-password/change-password.component'; @@ -130,7 +136,13 @@ import { SettingsComponent } from './settings/settings.component'; PayInComponent, PeopleAddComponent, ListAllPeopleComponent, - SettingsComponent + SettingsComponent, + ProfileComponent, + PeopleProfileComponent, + MessageBoxComponent, + UserProfileComponent, + AdminProfileComponent, + ChangePasswordComponent ], imports: [ BrowserModule, diff --git a/src/app/broker-loan-list/broker-loan-list.component.ts b/src/app/broker-loan-list/broker-loan-list.component.ts index 25d9b4a..88c70d9 100644 --- a/src/app/broker-loan-list/broker-loan-list.component.ts +++ b/src/app/broker-loan-list/broker-loan-list.component.ts @@ -20,7 +20,7 @@ export class BrokerLoanListComponent implements OnInit { ngOnInit(): void { this.brokerLoans = this.lss; - this.broker = this.auth.loggedIn.user; + this.broker = this.auth.loggedIn.User; this.loadData(); } diff --git a/src/app/broker-profile/broker-profile.component.html b/src/app/broker-profile/broker-profile.component.html deleted file mode 100644 index ab32465..0000000 --- a/src/app/broker-profile/broker-profile.component.html +++ /dev/null @@ -1,141 +0,0 @@ -
- -
-
-
-
-
Edit : {{broker.First + ' ' + broker.Last}}
- -
-
-
-
-
- - - - only jpg and png are allowed - -
-
-
- -
- -
- - - - First name is required - -
- - - - - Last Name is required - -
- - - - - Display name cannot empty - -
- - - - - license is required, key in unknown if have one - -
- - - - - BSB required for accepting payment - -
- - - - - ACC is required for accepting payment - -
- - - - - - Organization is required, (only changed by admin) - -
- -
-
-
-
- -
-
-
- - Change Password -
-
- - - - Current password is needed (3-20 chars) - - - - - - New password is needed (3-20 chars) - - - - - - - New password repeat is needed (3-20 chars) - -
- - -
- -
-
-
-
- - - -

{{ Message }}

- - - -
-
diff --git a/src/app/broker-profile/broker-profile.component.ts b/src/app/broker-profile/broker-profile.component.ts deleted file mode 100644 index 576c585..0000000 --- a/src/app/broker-profile/broker-profile.component.ts +++ /dev/null @@ -1,109 +0,0 @@ -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', - templateUrl: './broker-profile.component.html', - styleUrls: ['./broker-profile.component.scss'] -}) -export class BrokerProfileComponent implements OnInit { - - @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; - } -} diff --git a/src/app/client-loan-list/client-loan-list.component.ts b/src/app/client-loan-list/client-loan-list.component.ts index f068ade..37325ae 100644 --- a/src/app/client-loan-list/client-loan-list.component.ts +++ b/src/app/client-loan-list/client-loan-list.component.ts @@ -15,7 +15,7 @@ export class ClientLoanListComponent implements OnInit { constructor(private ls: LoanSingleService, private auth: AuthService) { } ngOnInit(): void { - this.ls.getLoanByClient(this.auth.loggedIn.user.Id).subscribe( + this.ls.getLoanByClient(this.auth.loggedIn.User.Id).subscribe( resp => { this.Loans = []; resp.forEach( v => { diff --git a/src/app/client-profile/client-profile.component.ts b/src/app/client-profile/client-profile.component.ts index b0cf67d..e460fdf 100644 --- a/src/app/client-profile/client-profile.component.ts +++ b/src/app/client-profile/client-profile.component.ts @@ -27,7 +27,7 @@ export class ClientProfileComponent implements OnInit { ngOnInit(): void { - this.User = this.auth.loggedIn.user; + this.User = this.auth.loggedIn.User; this.avatarUrl = 'url(' + this.auth.getUrl('avatar/' + this.User.Id) + ')'; } diff --git a/src/app/main-menu-items.ts b/src/app/main-menu-items.ts index b352e87..2328f9f 100644 --- a/src/app/main-menu-items.ts +++ b/src/app/main-menu-items.ts @@ -42,7 +42,7 @@ export const mainMenuItems: any[] = [ text: 'People', icon: 'user', items: [ - { text: 'Add ', icon: 'plus', url: './#add-people' }, + { text: 'Add ', icon: 'plus', url: './#people-add' }, { text: 'List All', fa: faIdCard , url: './#list-all-people'}, { text: '--', separator: 'true' }, { text: 'Admin', icon: 'email', url: './#send-to-all-people'}, @@ -63,12 +63,6 @@ export const brokerMenuItems: any[] = [ icon: 'dollar', url: './#broker-reward' }, - { - text: 'Profile', - fa: faIdCard, - url: './#broker-profile' - }, - ]; export const userMenuItems: any[] = [ @@ -77,11 +71,6 @@ export const userMenuItems: any[] = [ icon: 'categorize', url: './#client-loan-list' }, - { - text: 'Profile', - fa: faIdCard, - url: './#client-profile' - }, ]; export const peopleMenuItems: any[] = [ diff --git a/src/app/message-box/message-box.component.html b/src/app/message-box/message-box.component.html new file mode 100644 index 0000000..eed56b4 --- /dev/null +++ b/src/app/message-box/message-box.component.html @@ -0,0 +1,7 @@ + +

{{ Message }}

+ + + + +
diff --git a/src/app/message-box/message-box.component.scss b/src/app/message-box/message-box.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/message-box/message-box.component.spec.ts b/src/app/message-box/message-box.component.spec.ts new file mode 100644 index 0000000..841e8bc --- /dev/null +++ b/src/app/message-box/message-box.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MessageBoxComponent } from './message-box.component'; + +describe('MessageBoxComponent', () => { + let component: MessageBoxComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ MessageBoxComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(MessageBoxComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/message-box/message-box.component.ts b/src/app/message-box/message-box.component.ts new file mode 100644 index 0000000..77a3c02 --- /dev/null +++ b/src/app/message-box/message-box.component.ts @@ -0,0 +1,38 @@ +import {Component, Input, OnInit, EventEmitter, Output} from '@angular/core'; + + +@Component({ + selector: 'app-message-box', + templateUrl: './message-box.component.html', + styleUrls: ['./message-box.component.scss'] +}) +export class MessageBoxComponent implements OnInit { + @Input() YesButtonText = 'Ok I got it'; + @Input() NoButtonText = 'No'; + @Input() Title = 'Please Notice'; + @Input() Mode = 'YesOnly'; + + @Output() onClose = new EventEmitter(); + + public opened = false; // dialog box + public Message = ''; // dialog message + + constructor() { } + + ngOnInit(): void { + } + + public close(status: string): void { + this.onClose.emit(status); + this.opened = false; + } + + public Show(Msg: string, mode?: string, title?: string, yesText?: string, noText?: string): void{ + this.Message = Msg; + this.Mode = mode || 'YesOnly'; + this.Title = title || 'Please notice'; + this.YesButtonText = yesText || 'Ok I got it'; + this.NoButtonText = noText || 'No'; + this.opened = true; + } +} diff --git a/src/app/models/api-v1-login-response.ts b/src/app/models/api-v1-login-response.ts index d3fc83d..b3854a7 100644 --- a/src/app/models/api-v1-login-response.ts +++ b/src/app/models/api-v1-login-response.ts @@ -12,13 +12,16 @@ export class ApiV1LoginResponse { public session: string, public sessionExpire: number, // unix timestamp public role: string, - public user: PeopleModel, - public userExtra?: UserExtraModel // extra user informaiton + public User: PeopleModel, + public UserExtra?: UserExtraModel // extra user informaiton ) { this.login = login; this.machineId = machineId; this.session = session; this.sessionExpire = sessionExpire; + this.role = role; + this.User = User; + this.UserExtra = UserExtra; } public static EmptyNew(): ApiV1LoginResponse{ diff --git a/src/app/models/user-extra.model.ts b/src/app/models/user-extra.model.ts index 4e68539..093a30d 100644 --- a/src/app/models/user-extra.model.ts +++ b/src/app/models/user-extra.model.ts @@ -11,5 +11,15 @@ export class UserExtraModel { Object.assign(this, payload); } + public static EmptyNew(): UserExtraModel { + const rt = new UserExtraModel({}); + rt.BSB = ''; + rt.ACC = ''; + rt.License = ''; + rt.Organization = ''; + rt.Enabled = false; + rt.Login = ''; + return rt; + } } diff --git a/src/app/profile/admin-profile/admin-profile.component.html b/src/app/profile/admin-profile/admin-profile.component.html new file mode 100644 index 0000000..e123ba7 --- /dev/null +++ b/src/app/profile/admin-profile/admin-profile.component.html @@ -0,0 +1 @@ +
diff --git a/src/app/profile/admin-profile/admin-profile.component.scss b/src/app/profile/admin-profile/admin-profile.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/profile/admin-profile/admin-profile.component.spec.ts b/src/app/profile/admin-profile/admin-profile.component.spec.ts new file mode 100644 index 0000000..a76462d --- /dev/null +++ b/src/app/profile/admin-profile/admin-profile.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AdminProfileComponent } from './admin-profile.component'; + +describe('AdminProfileComponent', () => { + let component: AdminProfileComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ AdminProfileComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(AdminProfileComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/profile/admin-profile/admin-profile.component.ts b/src/app/profile/admin-profile/admin-profile.component.ts new file mode 100644 index 0000000..5733e61 --- /dev/null +++ b/src/app/profile/admin-profile/admin-profile.component.ts @@ -0,0 +1,16 @@ +import {Component, Input, OnInit} from '@angular/core'; + +@Component({ + selector: 'app-admin-profile', + templateUrl: './admin-profile.component.html', + styleUrls: ['./admin-profile.component.scss'] +}) +export class AdminProfileComponent implements OnInit { + @Input() public PeopleId = '0'; + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/src/app/profile/broker-profile/broker-profile.component.html b/src/app/profile/broker-profile/broker-profile.component.html new file mode 100644 index 0000000..5b5bc10 --- /dev/null +++ b/src/app/profile/broker-profile/broker-profile.component.html @@ -0,0 +1,53 @@ +
Broker Related : {{broker.Display }}
+ +
+ +
+ +
+ + + + license is required, key in unknown if have one + +
+ + + + + BSB required for accepting payment + +
+ + + + + ACC is required for accepting payment + +
+ + + + + + Organization is required, (only changed by admin) + +
+ +
+
+
+
+ +
+
+
+ + + diff --git a/src/app/broker-profile/broker-profile.component.scss b/src/app/profile/broker-profile/broker-profile.component.scss similarity index 100% rename from src/app/broker-profile/broker-profile.component.scss rename to src/app/profile/broker-profile/broker-profile.component.scss diff --git a/src/app/broker-profile/broker-profile.component.spec.ts b/src/app/profile/broker-profile/broker-profile.component.spec.ts similarity index 100% rename from src/app/broker-profile/broker-profile.component.spec.ts rename to src/app/profile/broker-profile/broker-profile.component.spec.ts diff --git a/src/app/profile/broker-profile/broker-profile.component.ts b/src/app/profile/broker-profile/broker-profile.component.ts new file mode 100644 index 0000000..c170e65 --- /dev/null +++ b/src/app/profile/broker-profile/broker-profile.component.ts @@ -0,0 +1,40 @@ +import {Component, Input, OnInit, ViewChild} from '@angular/core'; +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 {MessageBoxComponent} from '../../message-box/message-box.component'; + + + +@Component({ + selector: 'app-broker-profile', + templateUrl: './broker-profile.component.html', + styleUrls: ['./broker-profile.component.scss'] +}) +export class BrokerProfileComponent implements OnInit { + @Input() public PeopleId = ''; + @Input() public showAdmin: false; + @Input() public broker: BrokerModel = BrokerModel.EmptyNew(); + @ViewChild('messageBox', {static: true})msgBox: MessageBoxComponent; + + constructor( private auth: AuthService, private ps: PeopleService) { } + + ngOnInit(): void { + this.broker = BrokerModel.getFromUserAndExtra(this.auth.loggedIn.User, this.auth.loggedIn.UserExtra); + } + + public save(brokerForm: NgForm): void{ + if (! brokerForm.touched || brokerForm.form.pristine) { + return; + } + this.ps.saveBroker(this.broker).subscribe( () => { + this.msgBox.Show('updated successfully '); + brokerForm.form.markAsPristine(); + }, err => { + this.msgBox.Show('Failed to Update: ' + err.toString()); + }); + } + +} diff --git a/src/app/profile/change-password/change-password.component.html b/src/app/profile/change-password/change-password.component.html new file mode 100644 index 0000000..ab5e253 --- /dev/null +++ b/src/app/profile/change-password/change-password.component.html @@ -0,0 +1,34 @@ +
+ +   Change Password +
+ +
+
+ + + + Current password is needed (3-20 chars) + + + + + + New password is needed (3-20 chars) + + + + + + + New password repeat is needed (3-20 chars) + +
+ + +
+ + diff --git a/src/app/profile/change-password/change-password.component.scss b/src/app/profile/change-password/change-password.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/profile/change-password/change-password.component.spec.ts b/src/app/profile/change-password/change-password.component.spec.ts new file mode 100644 index 0000000..0776cae --- /dev/null +++ b/src/app/profile/change-password/change-password.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ChangePasswordComponent } from './change-password.component'; + +describe('ChangePasswordComponent', () => { + let component: ChangePasswordComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ ChangePasswordComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ChangePasswordComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/profile/change-password/change-password.component.ts b/src/app/profile/change-password/change-password.component.ts new file mode 100644 index 0000000..026bb42 --- /dev/null +++ b/src/app/profile/change-password/change-password.component.ts @@ -0,0 +1,57 @@ +import {Component, Input, OnInit, ViewChild} from '@angular/core'; +import {FormControl, FormGroup} from '@angular/forms'; +import {AuthService} from '../../service/auth.service'; +import {PeopleService} from '../../service/people.service'; +import {MessageBoxComponent} from '../../message-box/message-box.component'; + +@Component({ + selector: 'app-change-password', + templateUrl: './change-password.component.html', + styleUrls: ['./change-password.component.scss'] +}) +export class ChangePasswordComponent implements OnInit { + @Input() PeopleId = ''; + @ViewChild('messageBox', {static: true}) msgBox: MessageBoxComponent; + + 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 { + } + public hidePass(): void{ + if ( this.changePassword ) { + this.ChangePassForm.reset(); + } + } + + public savePassword(): void{ + this.ps.savePassword('0', this.ChangePassForm.value).subscribe( + () => { + this.changePassword = false; + this.msgBox.Show('Password Changed'); + }, err => { + this.msgBox.Show('Failed to Change Password :' + err.toString()); + } + ); + } + + public passwordEqual(): boolean{ + const v = this.ChangePassForm.value; + if ( this.ChangePassForm.valid && v.NewPass === v.NewPass1 && this.ChangePassForm.touched && v.NewPass1 !== '') { + return true; + }else{ + this.ChangePassForm.get('NewPass1').setErrors({incorrect: true}); + } + return false; + } + + public canChangePassword(): boolean { + return this.auth.isBroker() || this.auth.isAdmin(); + } +} diff --git a/src/app/profile/people-profile/people-profile.component.html b/src/app/profile/people-profile/people-profile.component.html new file mode 100644 index 0000000..45c075c --- /dev/null +++ b/src/app/profile/people-profile/people-profile.component.html @@ -0,0 +1,60 @@ + + +
  Personal Information
+ +
+
+
+
+
+ + + +
+
+ +
+ +
+ +
+ + + + First name is required + +
+ + + + + Last Name is required + +
+ + + + + Display name cannot empty + +
+ +
+
+
+
+ +
+
+
diff --git a/src/app/profile/people-profile/people-profile.component.scss b/src/app/profile/people-profile/people-profile.component.scss new file mode 100644 index 0000000..564f891 --- /dev/null +++ b/src/app/profile/people-profile/people-profile.component.scss @@ -0,0 +1,29 @@ + +.dropzoneInvisible{ + opacity:0.1; +} + +.avatar { + width: 100%; +} + +.people-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; + margin-left: 5px; + margin-bottom: 10px; + background-repeat: no-repeat; + box-shadow: 1px 1px 10px #000000; +} + + +div.vertical-spacer { + height:1px; + margin-bottom: 30px; +} diff --git a/src/app/profile/people-profile/people-profile.component.spec.ts b/src/app/profile/people-profile/people-profile.component.spec.ts new file mode 100644 index 0000000..18cb1d7 --- /dev/null +++ b/src/app/profile/people-profile/people-profile.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PeopleProfileComponent } from './people-profile.component'; + +describe('PeopleProfileComponent', () => { + let component: PeopleProfileComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ PeopleProfileComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(PeopleProfileComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/profile/people-profile/people-profile.component.ts b/src/app/profile/people-profile/people-profile.component.ts new file mode 100644 index 0000000..543ce27 --- /dev/null +++ b/src/app/profile/people-profile/people-profile.component.ts @@ -0,0 +1,79 @@ +import {Component, Input, OnInit, ViewChild} from '@angular/core'; +import {MessageBoxComponent} from '../../message-box/message-box.component'; +import {FileInfo, FileRestrictions, FileSelectComponent, SelectEvent} from '@progress/kendo-angular-upload'; +import {AuthService} from '../../service/auth.service'; +import {PeopleService} from '../../service/people.service'; +import {NgForm} from '@angular/forms'; +import {PeopleModel} from '../../models/people.model'; + +@Component({ + selector: 'app-people-profile', + templateUrl: './people-profile.component.html', + styleUrls: ['./people-profile.component.scss'] +}) +export class PeopleProfileComponent implements OnInit { + @Input() PeopleId = ''; + public People: PeopleModel = PeopleModel.EmptyNew(); + public avatarUrl = 'url(https://svr2021.lawipac.com:8080/api/v1/avatar/1000)' ; + public myRestrictions: FileRestrictions = { + allowedExtensions: ['.jpg', '.png', '.jpeg'], + maxFileSize: 2194304 + }; + @ViewChild('messagebox', {static: true}) msgBox: MessageBoxComponent; + @ViewChild('fileSelect', {static: true}) fs: FileSelectComponent; + + constructor(private auth: AuthService, private ps: PeopleService) { } + + ngOnInit(): void { + this.People = this.auth.loggedIn.User; + this.avatarUrl = 'url(' + this.auth.getUrl('avatar/' + this.PeopleId) + ')'; + this.avatarUrl = 'url(' + this.auth.getUrl('avatar/' + this.PeopleId) + ')'; + } + + onDialogClose(status: string): void { + console.log(status); + } + + public onSelectAvatar(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.PeopleId).subscribe( resp => { + this.avatarUrl = 'url(' + str + ' )'; + }, err => { + this.msgBox.Show('Failed to Update Avatar: ' + err.toString()); + }); + this.fs.clearFiles(); + }; + reader.readAsDataURL(file.rawFile); + }else{ + this.msgBox.Show('Only jpg, and png are supported (max 2MB)'); + setTimeout(() => { this.fs.clearFiles(); }, 10); + } + return false; // we only take first file + }); + } + } + + + public save(peopleForm: NgForm): void{ + if (! peopleForm.touched || peopleForm.form.pristine) { + this.msgBox.Show('Nothing has been changed'); + return; + } + this.ps.saveUser(this.People).subscribe( () => { + this.msgBox.Show('Updated successfully '); + if ( this.auth.loggedIn.User.Id === this.People.Id ) { + this.auth.UpdatePeopleInfo(this.People); + } + peopleForm.form.markAsPristine(); + }, err => { + this.msgBox.Show('Failed to Update: ' + err.toString()); + }); + } +} diff --git a/src/app/profile/profile.component.html b/src/app/profile/profile.component.html new file mode 100644 index 0000000..561969d --- /dev/null +++ b/src/app/profile/profile.component.html @@ -0,0 +1,20 @@ + + +
+
+
+
+ +

+ +

+ +

+ +

+ +
+
+
+
+ diff --git a/src/app/profile/profile.component.scss b/src/app/profile/profile.component.scss new file mode 100644 index 0000000..1176235 --- /dev/null +++ b/src/app/profile/profile.component.scss @@ -0,0 +1,25 @@ +div.parent { + display: table; + width: 100%; + height: 100vh; + opacity: 0.95; + background: url('/assets/img/bg-settings.jpg') no-repeat center center fixed; + background-size: cover; +} + + +.settings { + max-width: 800px; + text-align: center; + vertical-align: middle; + padding: 20px; + box-shadow: 0 0 6px black; + border-radius: 5px; + background-color: white; + margin: 10% auto 100px; +} + +div.vertical-spacer { + height:1px; + margin-bottom: 30px; +} diff --git a/src/app/profile/profile.component.spec.ts b/src/app/profile/profile.component.spec.ts new file mode 100644 index 0000000..e88012e --- /dev/null +++ b/src/app/profile/profile.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ProfileComponent } from './profile.component'; + +describe('ProfileComponent', () => { + let component: ProfileComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ ProfileComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ProfileComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/profile/profile.component.ts b/src/app/profile/profile.component.ts new file mode 100644 index 0000000..148d38d --- /dev/null +++ b/src/app/profile/profile.component.ts @@ -0,0 +1,63 @@ +import {Component, Input, OnInit, ViewChild} from '@angular/core'; +import {FormControl, FormGroup} from '@angular/forms'; +import {AuthService} from '../service/auth.service'; +import {PeopleService} from '../service/people.service'; +import {PeopleProfileComponent} from './people-profile/people-profile.component'; +import {BrokerProfileComponent} from './broker-profile/broker-profile.component'; +import {UserProfileComponent} from './user-profile/user-profile.component'; + +@Component({ + selector: 'app-profile', + templateUrl: './profile.component.html', + styleUrls: ['./profile.component.scss'] +}) +export class ProfileComponent implements OnInit { + @Input() PeopleId = ''; + @ViewChild('peopleProfile', {static: true}) pp: PeopleProfileComponent; + @ViewChild('userProfile', {static: true}) up: UserProfileComponent; + @ViewChild('brokerProfile', {static: true}) bp: BrokerProfileComponent; + + public role = 'client'; + + constructor(private auth: AuthService, private ps: PeopleService) { } + + ngOnInit(): void { + this.role = this.auth.loggedIn.role; + this.PeopleId = this.auth.loggedIn.User.Id; + console.log('profile people id', this.PeopleId); + } + + + public showPeople(): boolean { + return true; // always true + } + + public showUser(): boolean { + return this.isUser() || this.isBroker() || this.isAdmin(); + } + + public showBroker(): boolean { + return this.isBroker() && ! this.isAdmin(); + } + + public showAdmin(): boolean { + return this.isAdmin(); + } + + public showPassword(): boolean { + return this.isUser() || this.isBroker() || this.isAdmin(); + } + + public isAdmin(): boolean { + return this.auth.isAdmin(); + } + + public isBroker(): boolean { + return this.auth.isBroker(); + } + + public isUser(): boolean { + return this.auth.isUser(); + } + +} diff --git a/src/app/profile/user-profile/user-profile.component.html b/src/app/profile/user-profile/user-profile.component.html new file mode 100644 index 0000000..25fc365 --- /dev/null +++ b/src/app/profile/user-profile/user-profile.component.html @@ -0,0 +1,33 @@ +
  Login Related
+ +
+ +
+ + + + First name is required + +
+ + + + +
+ +
+
+
+
+ +
+
+
+ + diff --git a/src/app/profile/user-profile/user-profile.component.scss b/src/app/profile/user-profile/user-profile.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/profile/user-profile/user-profile.component.spec.ts b/src/app/profile/user-profile/user-profile.component.spec.ts new file mode 100644 index 0000000..f0c36ed --- /dev/null +++ b/src/app/profile/user-profile/user-profile.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { UserProfileComponent } from './user-profile.component'; + +describe('UserProfileComponent', () => { + let component: UserProfileComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ UserProfileComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(UserProfileComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/profile/user-profile/user-profile.component.ts b/src/app/profile/user-profile/user-profile.component.ts new file mode 100644 index 0000000..ffd0c98 --- /dev/null +++ b/src/app/profile/user-profile/user-profile.component.ts @@ -0,0 +1,50 @@ +import {Component, Input, OnInit, ViewChild} from '@angular/core'; +import {UserExtraModel} from '../../models/user-extra.model'; +import {NgForm} from '@angular/forms'; +import {AuthService} from '../../service/auth.service'; +import {HttpClient} from '@angular/common/http'; +import {MessageBoxComponent} from '../../message-box/message-box.component'; + +@Component({ + selector: 'app-user-profile', + templateUrl: './user-profile.component.html', + styleUrls: ['./user-profile.component.scss'] +}) +export class UserProfileComponent implements OnInit { + @Input() public PeopleId = ''; + @Input() public showAdmin: false; + + public UserExtra: UserExtraModel = UserExtraModel.EmptyNew(); + @ViewChild('messageBox', {static: true}) msgBox: MessageBoxComponent; + + constructor(private auth: AuthService, private http: HttpClient) { } + + ngOnInit(): void { + this.PeopleId = this.auth.loggedIn.User.Id; + this.UserExtra = this.auth.loggedIn.UserExtra; + } + + public save(userForm: NgForm): void { + const expected = userForm.form.get('Login').value; + this.http.post(this.auth.getUrl('user/' + this.PeopleId), this.UserExtra).subscribe( + resp => { + if ( resp === expected ) { + this.msgBox.Show('Successfully Changed'); + }else{ + this.msgBox.Show('Login not Changed: ' + resp ); + } + }, err => { + this.msgBox.Show('Error Occurred' + err.toString()); + } + ); + } + + public currentUserIsAdmin(): boolean { + return this.auth.loggedIn.role === 'admin'; + } + + public canEditUser(): boolean { + return this.UserExtra !== undefined && this.UserExtra.Login !== undefined; + } + +} diff --git a/src/app/service/auth.service.ts b/src/app/service/auth.service.ts index 564b49e..d9e3ae4 100644 --- a/src/app/service/auth.service.ts +++ b/src/app/service/auth.service.ts @@ -1,5 +1,5 @@ -import {EventEmitter, Injectable, OnDestroy, OnInit} from '@angular/core'; -import {HttpClient, HttpEvent, HttpHandler, HttpInterceptor, HttpParams, HttpRequest} from '@angular/common/http'; +import {EventEmitter, Injectable} from '@angular/core'; +import {HttpClient} from '@angular/common/http'; import {ApiV1LoginResponse} from '../models/api-v1-login-response'; import {Router} from '@angular/router'; import {PeopleModel} from '../models/people.model'; @@ -10,8 +10,8 @@ export class AuthService { public apiUrl = 'https://svr2021.lawipac.com:8080/api/v1/'; 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 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 (); @@ -32,11 +32,11 @@ export class AuthService { 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); + if ( sfm.UserExtra !== undefined ) { + this.loggedIn.UserExtra = new UserExtraModel(sfm.UserExtra); } this.loginSuccess.emit(this.loggedIn); @@ -66,30 +66,29 @@ export class AuthService { this.loggedIn.machineId = responseData['Biukop-Mid']; this.loggedIn.sessionExpire = responseData.sessionExpire; this.loggedIn.role = responseData.role; - if ( responseData.user !== undefined) { - this.loggedIn.user = new PeopleModel( - responseData.user.Id, - responseData.user.First, - responseData.user.Last, - responseData.user.Middle, - responseData.user.Title, - responseData.user.Display, - responseData.user.Nick + if ( responseData.User !== undefined) { + this.loggedIn.User = new PeopleModel( + responseData.User.Id, + responseData.User.First, + responseData.User.Last, + responseData.User.Middle, + responseData.User.Title, + responseData.User.Display, + responseData.User.Nick ); - if (responseData.userExtra !== undefined ) { - this.loggedIn.userExtra = new UserExtraModel(responseData.userExtra); + if (responseData.UserExtra !== undefined ) { + this.loggedIn.UserExtra = new UserExtraModel(responseData.UserExtra); } }else{ - this.loggedIn.user = PeopleModel.EmptyNew(); + this.loggedIn.User = PeopleModel.EmptyNew(); } this.saveSessionInfo(); this.loginSuccess.emit(responseData); }, error => { - const fail = ApiV1LoginResponse.EmptyNew(); - this.loggedIn = fail; + this.loggedIn = ApiV1LoginResponse.EmptyNew(); console.log('login error', error); this.loginSuccess.emit(this.loggedIn); } @@ -131,4 +130,23 @@ export class AuthService { // not found if arrive here return s; } + + public UpdatePeopleInfo(people: PeopleModel): void{ + this.loggedIn.User.Display = people.Display; + this.loggedIn.User.First = people.First; + this.loggedIn.User.Last = people.Last; + this.saveSessionInfo(); + } + + public isAdmin(): boolean { + return this.loggedIn.role === 'admin'; + } + + public isBroker(): boolean { + return this.loggedIn.role === 'broker'; + } + + public isUser(): boolean { + return this.loggedIn.login === true; + } } diff --git a/src/app/service/menu.service.ts b/src/app/service/menu.service.ts index c553aeb..f9ba9c7 100644 --- a/src/app/service/menu.service.ts +++ b/src/app/service/menu.service.ts @@ -1,9 +1,17 @@ import { EventEmitter, Injectable } from '@angular/core'; +import {HttpClient} from '@angular/common/http'; +import {AuthService} from './auth.service'; +import {ClonerService} from './clone.service'; +import {Router} from '@angular/router'; @Injectable() export class MenuService { - itemClicked = new EventEmitter (); - + itemClicked = new EventEmitter (); + constructor(auth: AuthService, private router: Router ){ } + // display profile editing based on current user + public showProfile(): void { + this.router.navigate(['/profile']); + } } diff --git a/src/app/settings/settings.component.html b/src/app/settings/settings.component.html index 4ab2a41..0d6af24 100644 --- a/src/app/settings/settings.component.html +++ b/src/app/settings/settings.component.html @@ -1 +1,44 @@ -

settings works!

+
+
+
+
+ Change Admin Password +
+
+ + + + Current password is needed (3-20 chars) + + + + + + New password is needed (3-20 chars) + + + + + + + New password repeat is needed (3-20 chars) + +
+ + +
+
+
+
+
+ + +

{{ Message }}

+ + + +
+ diff --git a/src/app/settings/settings.component.scss b/src/app/settings/settings.component.scss index e69de29..2d86d0f 100644 --- a/src/app/settings/settings.component.scss +++ b/src/app/settings/settings.component.scss @@ -0,0 +1,22 @@ +div.parent { + display: table; + width: 100%; + height: 100vh; + opacity: 0.95; + background: url('/assets/img/bg-settings.jpg') no-repeat center center fixed; + background-size: cover; +} + + +.settings { + margin-left: auto; + margin-right: auto; + margin-top: 10%; + max-width: 600px; + text-align: center; + vertical-align: middle; + padding: 20px; + box-shadow: 0 0 6px black; + border-radius: 5px; + background-color: white; +} diff --git a/src/app/settings/settings.component.ts b/src/app/settings/settings.component.ts index 232b5dd..421f200 100644 --- a/src/app/settings/settings.component.ts +++ b/src/app/settings/settings.component.ts @@ -1,4 +1,7 @@ import { Component, OnInit } from '@angular/core'; +import {AuthService} from '../service/auth.service'; +import {PeopleService} from '../service/people.service'; +import {FormControl, FormGroup} from '@angular/forms'; @Component({ selector: 'app-settings', @@ -6,10 +9,56 @@ import { Component, OnInit } from '@angular/core'; styleUrls: ['./settings.component.scss'] }) export class SettingsComponent implements OnInit { + public changeAdminPassword = false; + public opened = false; // dialog box + public Message = ''; // dialog message - constructor() { } + public ChangeAdminPassForm: FormGroup = new FormGroup({ + OldPassword: new FormControl(), + NewPass: new FormControl(), + NewPass1: new FormControl(), + }); + constructor(private auth: AuthService, private ps: PeopleService) { } ngOnInit(): void { + setTimeout(() => { + this.changeAdminPassword = true; + }, 1000); } + + public hideAdminPass(): void{ + if ( this.changeAdminPassword ) { + this.ChangeAdminPassForm.reset(); + } + } + + public saveAdminPassword(): void{ + this.ps.savePassword('0', this.ChangeAdminPassForm.value).subscribe( + () => { + this.showDialog('Password Changed'); + }, err => { + this.showDialog('Failed to Change Password :' + err.toString()); + } + ); + } + + public adminPasswordEqual(): boolean{ + const v = this.ChangeAdminPassForm.value; + if ( this.ChangeAdminPassForm.valid && v.NewPass === v.NewPass1 && this.ChangeAdminPassForm.touched && v.NewPass1 !== '') { + return true; + }else{ + this.ChangeAdminPassForm.controls['NewPass1'].setErrors({'incorrect': true}); + } + return false; + } + + public showDialog(msg: string): void { + this.Message = msg; + this.opened = true; // open dialog + } + + public close(status): void { + this.opened = false; + } } diff --git a/src/app/top-bar/top-bar.component.html b/src/app/top-bar/top-bar.component.html index 18500b0..eb62058 100644 --- a/src/app/top-bar/top-bar.component.html +++ b/src/app/top-bar/top-bar.component.html @@ -1,7 +1,10 @@ - - {{LoggedInUser.Display}} + + + + {{LoggedInUser.Display}} @@ -32,7 +35,7 @@ - + diff --git a/src/app/top-bar/top-bar.component.ts b/src/app/top-bar/top-bar.component.ts index 8d90dad..e117147 100644 --- a/src/app/top-bar/top-bar.component.ts +++ b/src/app/top-bar/top-bar.component.ts @@ -29,20 +29,20 @@ export class TopBarComponent implements OnInit , OnDestroy { ngOnInit(): void { this.initAndSubLogin(); + console.log(this); } public initAndSubLogin(): void{ this.login = this.authService.loggedIn.login; - this.LoggedInUser = this.authService.loggedIn.user; + this.LoggedInUser = this.authService.loggedIn.User; this.selectMenuShow(this.authService.loggedIn.role); this.loginSub = this.authService.loginSuccess.subscribe( (rsp: ApiV1LoginResponse) => { this.login = rsp.login; - this.LoggedInUser = this.authService.loggedIn.user; + this.LoggedInUser = this.authService.loggedIn.User; this.selectMenuShow(rsp.role); - } ); } @@ -102,7 +102,11 @@ export class TopBarComponent implements OnInit , OnDestroy { } public loggedInUserAvatar(): string { - return this.authService.getUrl('avatar/') + this.authService.loggedIn.user.Id; + return this.authService.getUrl('avatar/') + this.authService.loggedIn.User.Id; } + public profile(): void { + this.menuService.showProfile(); +} + } diff --git a/src/assets/bg.jpg b/src/assets/bg.jpg deleted file mode 100644 index 7efb725..0000000 Binary files a/src/assets/bg.jpg and /dev/null differ diff --git a/src/assets/img/bg-settings.jpg b/src/assets/img/bg-settings.jpg new file mode 100644 index 0000000..e402a9b Binary files /dev/null and b/src/assets/img/bg-settings.jpg differ