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) {
this.searchSub.unsubscribe();
}
if (this.closeSub) {
this.closeSub.unsubscribe();
}
}
//Handle the term inputting event

View File

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

View File

@ -11,10 +11,19 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// 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 { NgForm } from '@angular/forms';
import { MemberService } from '../member.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 { Subject } from 'rxjs/Subject';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
@Component({
selector: 'add-member',
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();
initVal: Member = new Member();
addMemberOpened: boolean;
memberForm: NgForm;
staticBackdrop: boolean = true;
@ -52,49 +64,87 @@ export class AddMemberComponent implements AfterViewChecked {
@Input() projectId: number;
@Output() added = new EventEmitter<boolean>();
constructor(private memberService: MemberService,
private messageHandlerService: MessageHandlerService,
private translateService: TranslateService) {}
isMemberNameValid: boolean = true;
memberTooltip: string = 'MEMBER.USERNAME_IS_REQUIRED';
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 {
if(!this.member.username || this.member.username.length === 0) { return; }
if (!this.member.username || this.member.username.length === 0) { return; }
this.memberService
.addMember(this.projectId, this.member.username, +this.member.role_id)
.subscribe(
response=>{
this.messageHandlerService.showSuccess('MEMBER.ADDED_SUCCESS');
this.added.emit(true);
this.addMemberOpened = false;
},
error=>{
if (error instanceof Response) {
let errorMessageKey: string;
switch(error.status){
case 404:
errorMessageKey = 'MEMBER.USERNAME_DOES_NOT_EXISTS';
break;
case 409:
errorMessageKey = 'MEMBER.USERNAME_ALREADY_EXISTS';
break;
default:
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));
}
}
.addMember(this.projectId, this.member.username, +this.member.role_id)
.subscribe(
response => {
this.messageHandlerService.showSuccess('MEMBER.ADDED_SUCCESS');
this.added.emit(true);
this.addMemberOpened = false;
},
error => {
if (error instanceof Response) {
let errorMessageKey: string;
switch (error.status) {
case 404:
errorMessageKey = 'MEMBER.USERNAME_DOES_NOT_EXISTS';
break;
case 409:
errorMessageKey = 'MEMBER.USERNAME_ALREADY_EXISTS';
break;
default:
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));
}
}
}
);
}
onCancel() {
if(this.hasChanged) {
this.inlineAlert.showInlineConfirmation({message: 'ALERT.FORM_CHANGE_CONFIRMATION'});
if (this.hasChanged) {
this.inlineAlert.showInlineConfirmation({ message: 'ALERT.FORM_CHANGE_CONFIRMATION' });
} else {
this.addMemberOpened = false;
this.memberForm.reset();
@ -102,19 +152,17 @@ export class AddMemberComponent implements AfterViewChecked {
}
ngAfterViewChecked(): void {
this.memberForm = this.currentForm;
if(this.memberForm) {
this.memberForm.valueChanges.subscribe(data=>{
for(let i in data) {
let origin = this.initVal[i];
let current = data[i];
if(current && current !== origin) {
this.hasChanged = true;
break;
} else {
this.hasChanged = false;
this.inlineAlert.close();
}
if (this.memberForm !== this.currentForm) {
this.memberForm = this.currentForm;
}
if (this.memberForm) {
this.memberForm.valueChanges.subscribe(data => {
let memberName = data['member_name'];
if (memberName && memberName !== '') {
this.hasChanged = true;
this.inlineAlert.close();
} else {
this.hasChanged = false;
}
});
}
@ -132,6 +180,19 @@ export class AddMemberComponent implements AfterViewChecked {
this.addMemberOpened = true;
this.hasChanged = false;
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;
}
}