Modify member name checking

This commit is contained in:
Steven Zou 2017-05-16 18:01:54 -07:00
parent cf65c39cef
commit 26d20bd9aa
3 changed files with 162 additions and 94 deletions

View File

@ -72,6 +72,10 @@ export class GlobalSearchComponent implements OnInit, OnDestroy {
if (this.searchSub) { if (this.searchSub) {
this.searchSub.unsubscribe(); this.searchSub.unsubscribe();
} }
if (this.closeSub) {
this.closeSub.unsubscribe();
}
} }
//Handle the term inputting event //Handle the term inputting event

View File

@ -1,41 +1,44 @@
<clr-modal [(clrModalOpen)]="addMemberOpened" [clrModalStaticBackdrop]="staticBackdrop" [clrModalClosable]="closable"> <clr-modal [(clrModalOpen)]="addMemberOpened" [clrModalStaticBackdrop]="staticBackdrop" [clrModalClosable]="closable">
<h3 class="modal-title">{{'MEMBER.NEW_MEMBER' | translate}}</h3> <h3 class="modal-title">{{'MEMBER.NEW_MEMBER' | translate}}</h3>
<inline-alert class="modal-title" (confirmEvt)="confirmCancel($event)"></inline-alert> <inline-alert class="modal-title" (confirmEvt)="confirmCancel($event)"></inline-alert>
<div class="modal-body"> <div class="modal-body">
<form #memberForm="ngForm"> <form #memberForm="ngForm">
<section class="form-block"> <section class="form-block">
<div class="form-group"> <div class="form-group">
<label for="member_name" class="col-md-4 form-group-label-override">{{'MEMBER.NAME' | translate}}</label> <label for="member_name" class="col-md-4 form-group-label-override required">{{'MEMBER.NAME' | translate}}</label>
<label for="member_name" aria-haspopup="true" role="tooltip" [class.invalid]="memberName.invalid && (memberName.dirty || memberName.touched)" [class.valid]="memberName.valid" class="tooltip tooltip-validation tooltip-sm tooltip-bottom-left"> <label for="member_name" aria-haspopup="true" role="tooltip" [class.invalid]="!isMemberNameValid" class="tooltip tooltip-validation tooltip-md tooltip-bottom-left">
<input type="text" id="member_name" [(ngModel)]="member.username" name="name" size="20" #memberName="ngModel" required targetExists="MEMBER_NAME" [projectId]="projectId"> <input type="text" id="member_name" [(ngModel)]="member.username"
<span class="tooltip-content" *ngIf="memberName.errors && memberName.errors.required && (memberName.dirty || memberName.touched)"> name="member_name"
{{ 'MEMBER.USERNAME_IS_REQUIRED' | translate }} size="20"
</span> #memberName="ngModel"
<span class="tooltip-content" *ngIf="memberName.errors && memberName.errors.targetExists && (memberName.dirty || memberName.touched)"> required
{{ 'MEMBER.USERNAME_ALREADY_EXISTS' | translate }} (keyup)='handleValidation()'>
<span class="tooltip-content">
{{ memberTooltip | translate }}
</span> </span>
</label> </label>
</div> <span class="spinner spinner-inline" [hidden]="!checkOnGoing"></span>
<div class="form-group"> </div>
<label class="col-md-4 form-group-label-override">{{'MEMBER.ROLE' | translate}}</label> <div class="form-group">
<div class="radio"> <label class="col-md-4 form-group-label-override">{{'MEMBER.ROLE' | translate}}</label>
<input type="radio" name="roleRadios" id="checkrads_project_admin" [value]="1" [(ngModel)]="member.role_id"> <div class="radio">
<label for="checkrads_project_admin">{{'MEMBER.PROJECT_ADMIN' | translate}}</label> <input type="radio" name="member_role" id="checkrads_project_admin" [value]="1" [(ngModel)]="member.role_id">
</div> <label for="checkrads_project_admin">{{'MEMBER.PROJECT_ADMIN' | translate}}</label>
<div class="radio"> </div>
<input type="radio" name="roleRadios" id="checkrads_developer" [value]="2" [(ngModel)]="member.role_id"> <div class="radio">
<label for="checkrads_developer">{{'MEMBER.DEVELOPER' | translate}}</label> <input type="radio" name="member_role" id="checkrads_developer" [value]="2" [(ngModel)]="member.role_id">
</div> <label for="checkrads_developer">{{'MEMBER.DEVELOPER' | translate}}</label>
<div class="radio"> </div>
<input type="radio" name="roleRadios" id="checkrads_guest" [value]="3" [(ngModel)]="member.role_id"> <div class="radio">
<label for="checkrads_guest">{{'MEMBER.GUEST' | translate}}</label> <input type="radio" name="member_role" id="checkrads_guest" [value]="3" [(ngModel)]="member.role_id">
</div> <label for="checkrads_guest">{{'MEMBER.GUEST' | translate}}</label>
</div> </div>
</section> </div>
</form> </section>
</div> </form>
<div class="modal-footer"> </div>
<button type="button" class="btn btn-outline" (click)="onCancel()">{{'BUTTON.CANCEL' | translate}}</button> <div class="modal-footer">
<button type="button" class="btn btn-primary" [disabled]="memberForm.form.invalid" (click)="onSubmit()">{{'BUTTON.OK' | translate}}</button> <button type="button" class="btn btn-outline" (click)="onCancel()">{{'BUTTON.CANCEL' | translate}}</button>
</div> <button type="button" class="btn btn-primary" [disabled]="!isValid" (click)="onSubmit()">{{'BUTTON.OK' | translate}}</button>
</clr-modal> </div>
</clr-modal>

View File

@ -11,10 +11,19 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { Component, Input, EventEmitter, Output, ViewChild, AfterViewChecked } from '@angular/core'; import {
Component,
Input,
EventEmitter,
Output,
ViewChild,
AfterViewChecked,
OnInit,
OnDestroy
} from '@angular/core';
import { Response } from '@angular/http'; import { Response } from '@angular/http';
import { NgForm } from '@angular/forms'; import { NgForm } from '@angular/forms';
import { MemberService } from '../member.service'; import { MemberService } from '../member.service';
import { MessageHandlerService } from '../../../shared/message-handler/message-handler.service'; import { MessageHandlerService } from '../../../shared/message-handler/message-handler.service';
@ -24,18 +33,21 @@ import { TranslateService } from '@ngx-translate/core';
import { Member } from '../member'; import { Member } from '../member';
import { Subject } from 'rxjs/Subject';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
@Component({ @Component({
selector: 'add-member', selector: 'add-member',
templateUrl: 'add-member.component.html', templateUrl: 'add-member.component.html',
styleUrls: [ 'add-member.component.css' ] styleUrls: ['add-member.component.css']
}) })
export class AddMemberComponent implements AfterViewChecked { export class AddMemberComponent implements AfterViewChecked, OnInit, OnDestroy {
member: Member = new Member(); member: Member = new Member();
initVal: Member = new Member();
addMemberOpened: boolean; addMemberOpened: boolean;
memberForm: NgForm; memberForm: NgForm;
staticBackdrop: boolean = true; staticBackdrop: boolean = true;
@ -52,49 +64,87 @@ export class AddMemberComponent implements AfterViewChecked {
@Input() projectId: number; @Input() projectId: number;
@Output() added = new EventEmitter<boolean>(); @Output() added = new EventEmitter<boolean>();
constructor(private memberService: MemberService, isMemberNameValid: boolean = true;
private messageHandlerService: MessageHandlerService, memberTooltip: string = 'MEMBER.USERNAME_IS_REQUIRED';
private translateService: TranslateService) {} nameChecker: Subject<string> = new Subject<string>();
checkOnGoing: boolean = false;
constructor(private memberService: MemberService,
private messageHandlerService: MessageHandlerService,
private translateService: TranslateService) { }
ngOnInit(): void {
this.nameChecker
.debounceTime(500)
.distinctUntilChanged()
.subscribe((name: string) => {
let cont = this.currentForm.controls['member_name'];
if (cont) {
this.isMemberNameValid = cont.valid;
if (cont.valid) {
this.checkOnGoing = true;
this.memberService
.listMembers(this.projectId, cont.value).toPromise()
.then((members: Member[]) => {
if (members.filter(m => { return m.username === cont.value }).length > 0) {
this.isMemberNameValid = false;
this.memberTooltip = 'MEMBER.USERNAME_ALREADY_EXISTS';
}
this.checkOnGoing = false;
})
.catch(error => {
this.checkOnGoing = false;
});
} else {
this.memberTooltip = 'MEMBER.USERNAME_IS_REQUIRED';
}
}
});
}
ngOnDestroy(): void {
this.nameChecker.unsubscribe();
}
onSubmit(): void { onSubmit(): void {
if(!this.member.username || this.member.username.length === 0) { return; } if (!this.member.username || this.member.username.length === 0) { return; }
this.memberService this.memberService
.addMember(this.projectId, this.member.username, +this.member.role_id) .addMember(this.projectId, this.member.username, +this.member.role_id)
.subscribe( .subscribe(
response=>{ response => {
this.messageHandlerService.showSuccess('MEMBER.ADDED_SUCCESS'); this.messageHandlerService.showSuccess('MEMBER.ADDED_SUCCESS');
this.added.emit(true); this.added.emit(true);
this.addMemberOpened = false; this.addMemberOpened = false;
}, },
error=>{ error => {
if (error instanceof Response) { if (error instanceof Response) {
let errorMessageKey: string; let errorMessageKey: string;
switch(error.status){ switch (error.status) {
case 404: case 404:
errorMessageKey = 'MEMBER.USERNAME_DOES_NOT_EXISTS'; errorMessageKey = 'MEMBER.USERNAME_DOES_NOT_EXISTS';
break; break;
case 409: case 409:
errorMessageKey = 'MEMBER.USERNAME_ALREADY_EXISTS'; errorMessageKey = 'MEMBER.USERNAME_ALREADY_EXISTS';
break; break;
default: default:
errorMessageKey = 'MEMBER.UNKNOWN_ERROR'; errorMessageKey = 'MEMBER.UNKNOWN_ERROR';
}
if(this.messageHandlerService.isAppLevel(error)) {
this.messageHandlerService.handleError(error);
this.addMemberOpened = false;
} else {
this.translateService
.get(errorMessageKey)
.subscribe(errorMessage=>this.inlineAlert.showInlineError(errorMessage));
}
}
} }
); if (this.messageHandlerService.isAppLevel(error)) {
this.messageHandlerService.handleError(error);
this.addMemberOpened = false;
} else {
this.translateService
.get(errorMessageKey)
.subscribe(errorMessage => this.inlineAlert.showInlineError(errorMessage));
}
}
}
);
} }
onCancel() { onCancel() {
if(this.hasChanged) { if (this.hasChanged) {
this.inlineAlert.showInlineConfirmation({message: 'ALERT.FORM_CHANGE_CONFIRMATION'}); this.inlineAlert.showInlineConfirmation({ message: 'ALERT.FORM_CHANGE_CONFIRMATION' });
} else { } else {
this.addMemberOpened = false; this.addMemberOpened = false;
this.memberForm.reset(); this.memberForm.reset();
@ -102,19 +152,17 @@ export class AddMemberComponent implements AfterViewChecked {
} }
ngAfterViewChecked(): void { ngAfterViewChecked(): void {
this.memberForm = this.currentForm; if (this.memberForm !== this.currentForm) {
if(this.memberForm) { this.memberForm = this.currentForm;
this.memberForm.valueChanges.subscribe(data=>{ }
for(let i in data) { if (this.memberForm) {
let origin = this.initVal[i]; this.memberForm.valueChanges.subscribe(data => {
let current = data[i]; let memberName = data['member_name'];
if(current && current !== origin) { if (memberName && memberName !== '') {
this.hasChanged = true; this.hasChanged = true;
break; this.inlineAlert.close();
} else { } else {
this.hasChanged = false; this.hasChanged = false;
this.inlineAlert.close();
}
} }
}); });
} }
@ -132,6 +180,19 @@ export class AddMemberComponent implements AfterViewChecked {
this.addMemberOpened = true; this.addMemberOpened = true;
this.hasChanged = false; this.hasChanged = false;
this.member.role_id = 1; this.member.role_id = 1;
this.member.username = '';
this.isMemberNameValid = true;
this.memberTooltip = 'MEMBER.USERNAME_IS_REQUIRED';
} }
handleValidation(): void {
let cont = this.currentForm.controls['member_name'];
if (cont) {
this.nameChecker.next(cont.value);
}
}
public get isValid(): boolean {
return this.currentForm && this.currentForm.valid && this.isMemberNameValid;
}
} }