Merge pull request #1408 from vmware/feature/account-settings

Complete account settings component
This commit is contained in:
Steven Zou 2017-02-21 20:05:51 +08:00 committed by GitHub
commit d000fe2914
6 changed files with 187 additions and 21 deletions

View File

@ -1,32 +1,49 @@
<clr-modal [(clrModalOpen)]="opened" [clrModalStaticBackdrop]="staticBackdrop" [clrModalSize]="'lg'">
<h3 class="modal-title">Accout Settings</h3>
<div class="modal-body">
<form>
<form #accountSettingsFrom="ngForm" class="form">
<section class="form-block">
<div class="form-group">
<label for="account_settings_username" class="col-md-4">Username</label>
<input type="text" class="col-md-8" id="account_settings_username" size="20">
<input type="text" name="account_settings_username" [(ngModel)]="account.username" disabled id="account_settings_username" size="51">
</div>
<div class="form-group">
<label for="account_settings_email" class="col-md-4">Email</label>
<input type="text" class="col-md-8" id="account_settings_email" size="20">
<label for="account_settings_email" class="col-md-4 required">Email</label>
<label for="account_settings_email" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-bottom-right" [class.invalid]="eamilInput.invalid && (eamilInput.dirty || eamilInput.touched)">
<input name="account_settings_email" type="text" #eamilInput="ngModel" [(ngModel)]="account.email"
required
pattern='^[a-zA-Z0-9.!#$%&*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$' id="account_settings_email" size="48">
<span class="tooltip-content">
Email should be a valid email address like name@example.com
</span>
</label>
</div>
<div class="form-group">
<label for="account_settings_full_name" class="col-md-4">Full name</label>
<input type="text" class="col-md-8" id="account_settings_full_name" size="20">
<label for="account_settings_full_name" class="col-md-4 required">Full name</label>
<label for="account_settings_email" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-bottom-right" [class.invalid]="fullNameInput.invalid && (fullNameInput.dirty || fullNameInput.touched)">
<input type="text" name="account_settings_full_name" #fullNameInput="ngModel" [(ngModel)]="account.realname" required maxLength="20" maxLengthExt="20" id="account_settings_full_name" size="48">
<span class="tooltip-content">
Max length of full name is 20
</span>
</label>
</div>
<div class="form-group">
<label for="account_settings_comments" class="col-md-4">Comments</label>
<input type="text" class="col-md-8" id="account_settings_comments" size="20">
</div>
<div class="form-group">
<button type="button" class="col-md-4" class="btn btn-outline">Change Password</button>
<input type="text" name="account_settings_comments" [(ngModel)]="account.comment" id="account_settings_comments" size="51">
</div>
</section>
</form>
<clr-alert [clrAlertType]="'alert-danger'" [clrAlertClosable]="true" [hidden]='errorMessage === ""'>
<div class="alert-item">
<span class="alert-text">
This alert indicates success.
</span>
</div>
</clr-alert>
</div>
<div class="modal-footer">
<span class="spinner spinner-inline" style="top:8px;" [hidden]="showProgress === false"></span>
<button type="button" class="btn btn-outline" (click)="close()">Cancel</button>
<button type="button" class="btn btn-primary" (click)="submit()">Ok</button>
<button type="button" class="btn btn-primary" [disabled]="!isValid || showProgress" (click)="submit()">Ok</button>
</div>
</clr-modal>

View File

@ -1,15 +1,63 @@
import { Component } from '@angular/core';
import { Component, OnInit, ViewChild, AfterViewChecked } from '@angular/core';
import { NgForm } from '@angular/forms';
import { SessionUser } from '../../shared/session-user';
import { SessionService } from '../../shared/session.service';
@Component({
selector: "account-settings-modal",
templateUrl: "account-settings-modal.component.html"
})
export class AccountSettingsModalComponent{
opened:boolean = false;
export class AccountSettingsModalComponent implements OnInit, AfterViewChecked {
opened: boolean = false;
staticBackdrop: boolean = true;
account: SessionUser;
error: any;
private isOnCalling: boolean = false;
private formValueChanged: boolean = false;
accountFormRef: NgForm;
@ViewChild("accountSettingsFrom") accountForm: NgForm;
constructor(private session: SessionService) { }
ngOnInit(): void {
//Value copy
this.account = Object.assign({}, this.session.getCurrentUser());
}
public get isValid(): boolean {
return this.accountForm && this.accountForm.valid;
}
public get showProgress(): boolean {
return this.isOnCalling;
}
public get errorMessage(): string {
return this.error ? (this.error.message ? this.error.message : this.error) : "";
}
ngAfterViewChecked(): void {
if (this.accountFormRef != this.accountForm) {
this.accountFormRef = this.accountForm;
if (this.accountFormRef) {
this.accountFormRef.valueChanges.subscribe(data => {
if (this.error) {
this.error = null;
}
this.formValueChanged = true;
});
}
}
}
open() {
this.account = Object.assign({}, this.session.getCurrentUser());
this.formValueChanged = false;
this.opened = true;
}
@ -18,8 +66,27 @@ export class AccountSettingsModalComponent{
}
submit() {
console.info("ok here!");
this.close();
if (!this.isValid || this.isOnCalling) {
return;
}
//Double confirm session is valid
let cUser = this.session.getCurrentUser();
if (!cUser) {
return;
}
this.isOnCalling = true;
this.session.updateAccountSettings(this.account)
.then(() => {
this.isOnCalling = false;
this.close();
})
.catch(error => {
this.isOnCalling = false;
this.error = error
});
}
}

View File

@ -0,0 +1,51 @@
import { Directive, OnChanges, Input, SimpleChanges } from '@angular/core';
import { ValidatorFn, AbstractControl, Validator, NG_VALIDATORS, Validators } from '@angular/forms';
export const assiiChars = /[\u4e00-\u9fa5]/;
export function maxLengthExtValidator(length: number): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } => {
const value: string = control.value
if (!value || value.trim() === "") {
return { 'maxLengthExt': 0 };
}
const regExp = new RegExp(assiiChars, 'i');
let count = 0;
let len = value.length;
for (var i = 0; i < len; i++) {
if (regExp.test(value[i])) {
count += 2;
} else {
count++;
}
}
return count > length ? { 'maxLengthExt': count } : null;
}
}
@Directive({
selector: '[maxLengthExt]',
providers: [{ provide: NG_VALIDATORS, useExisting: MaxLengthExtValidatorDirective, multi: true }]
})
export class MaxLengthExtValidatorDirective implements Validator, OnChanges {
@Input() maxLengthExt: number;
private valFn = Validators.nullValidator;
ngOnChanges(changes: SimpleChanges): void {
const change = changes['maxLengthExt'];
if (change) {
const val: number = change.currentValue;
this.valFn = maxLengthExtValidator(val);
} else {
this.valFn = Validators.nullValidator;
}
console.info(changes, this.maxLengthExt);
}
validate(control: AbstractControl): { [key: string]: any } {
return this.valFn(control);
}
}

View File

@ -3,7 +3,9 @@ export class SessionUser {
user_id: number;
username: string;
email: string;
role_name: string;
role_id: number;
has_admin_role: number;
realname: string;
role_name?: string;
role_id?: number;
has_admin_role?: number;
comment: string;
}

View File

@ -6,6 +6,7 @@ import { SessionUser } from './session-user';
const currentUserEndpint = "/api/users/current";
const signOffEndpoint = "/log_out";
const accountEndpoint = "/api/users/:id";
/**
* Define related methods to handle account and session corresponding things
*
@ -62,4 +63,29 @@ export class SessionService {
return Promise.reject(error);
})
}
/**
*
* Update accpunt settings
*
* @param {SessionUser} account
* @returns {Promise<any>}
*
* @memberOf SessionService
*/
updateAccountSettings(account: SessionUser): Promise<any>{
if(!account){
return Promise.reject("Invalid account settings");
}
console.info(account);
let putUrl = accountEndpoint.replace(":id", account.user_id+"");
return this.http.put(putUrl, JSON.stringify(account), { headers: this.headers }).toPromise()
.then(() => {
//Retrieve current session user
return this.retrieveUser();
})
.catch(error => {
return Promise.reject(error);
})
}
}

View File

@ -5,6 +5,7 @@ import { AccountModule } from '../account/account.module';
import { SessionService } from '../shared/session.service';
import { MessageComponent } from '../global-message/message.component';
import { MessageService } from '../global-message/message.service';
import { MaxLengthExtValidatorDirective } from './max-length-ext.directive';
@NgModule({
imports: [
@ -12,12 +13,14 @@ import { MessageService } from '../global-message/message.service';
AccountModule
],
declarations: [
MessageComponent
MessageComponent,
MaxLengthExtValidatorDirective
],
exports: [
CoreModule,
AccountModule,
MessageComponent
MessageComponent,
MaxLengthExtValidatorDirective
],
providers: [SessionService, MessageService]
})