[ADF-2754] People Widget - Refactoring style and logic (#3349)

* observable logic added

* tests added & bug fixed

* onkeyup removed

* isValidUser method removed

* tslint fix

* test added

* comments fixed

* check if input value is string
This commit is contained in:
bbcodrin 2018-05-29 17:50:23 +03:00 committed by Maurizio Vitale
parent eb0f91c5db
commit a91fffff97
4 changed files with 69 additions and 162 deletions

View File

@ -9,13 +9,13 @@
class="adf-input"
type="text"
[id]="field.id"
[formControl] ="searchTerm"
[value]="getDisplayName(field.value)"
(keyup)="onKeyUp($event)"
[disabled]="field.readOnly"
placeholder="{{field.placeholder}}"
[matAutocomplete]="auto">
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="onItemSelect($event.option.value)" [displayWith]="getDisplayName">
<mat-option *ngFor="let user of users; let i = index" [value]="user">
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="onItemSelect($event.option.value)" [displayWith]="getDisplayName">
<mat-option *ngFor="let user of users$ | async; let i = index" [value]="user">
<div class="adf-people-widget-row" id="adf-people-widget-user-{{i}}">
<div [outerHTML]="user | usernameInitials:'adf-people-widget-pic'"></div>
<div *ngIf="user.pictureId" class="adf-people-widget-image-row">

View File

@ -9,22 +9,23 @@
width: 100%;
}
&-people-widget-row {
display: flex;
align-items: center;
}
&-people-widget-pic {
background: mat-color($primary);
display: inline-block;
display: flex;
justify-content: center;
align-items: center;
width: 40px;
height: 40px;
border-radius: 100px;
color: mat-color($foreground, text);
text-align: center;
font-weight: bolder;
font-size: 18px;
text-transform: uppercase;
vertical-align: middle;
}
&-people-widget-row {
padding-bottom: 10px;
}
&-people-widget-image {

View File

@ -112,115 +112,6 @@ describe('PeopleWidgetComponent', () => {
expect(widget.groupId).toBe('<id>');
});
it('should fetch users by search term', () => {
let users: any = [{
id: 'people-id',
firstName: 'John',
lastName: 'Doe'
}, {
id: 'people-id2',
firstName: 'John',
lastName: 'Ping'
}];
spyOn(formService, 'getWorkflowUsers').and.returnValue(
Observable.create(observer => {
observer.next(users);
observer.complete();
})
);
fixture.detectChanges();
let keyboardEvent = new KeyboardEvent('keypress');
let input = widget.input;
input.nativeElement.value = 'John';
widget.onKeyUp(keyboardEvent);
expect(formService.getWorkflowUsers).toHaveBeenCalledWith('John', widget.groupId);
expect(widget.users).toBe(users);
});
it('should fetch users by search term and group id', () => {
let users: any = [{
id: 'people-id',
firstName: 'John',
lastName: 'Doe'
}, {
id: 'people-id2',
firstName: 'John',
lastName: 'Ping'
}];
spyOn(formService, 'getWorkflowUsers').and.returnValue(
Observable.create(observer => {
observer.next(users);
observer.complete();
})
);
fixture.detectChanges();
let keyboardEvent = new KeyboardEvent('keypress');
let input = widget.input;
input.nativeElement.value = 'John';
widget.groupId = '1001';
widget.onKeyUp(keyboardEvent);
expect(formService.getWorkflowUsers).toHaveBeenCalledWith('John', widget.groupId);
expect(widget.users).toBe(users);
});
it('should fetch users and show no popup', () => {
spyOn(formService, 'getWorkflowUsers').and.returnValue(
Observable.create(observer => {
observer.next(null);
observer.complete();
})
);
fixture.detectChanges();
let keyboardEvent = new KeyboardEvent('keypress');
let input = widget.input;
input.nativeElement.value = 'user1';
widget.onKeyUp(keyboardEvent);
expect(formService.getWorkflowUsers).toHaveBeenCalledWith('user1', widget.groupId);
expect(widget.users).toEqual([]);
});
it('should require search term to fetch users', () => {
spyOn(formService, 'getWorkflowUsers').and.stub();
let keyboardEvent = new KeyboardEvent('keypress');
let input = widget.input;
input.nativeElement.value = null;
widget.onKeyUp(keyboardEvent);
expect(formService.getWorkflowUsers).not.toHaveBeenCalled();
});
it('should not fetch users due to constraint violation', () => {
spyOn(formService, 'getWorkflowUsers').and.stub();
let keyboardEvent = new KeyboardEvent('keypress');
(element.querySelector('input') as HTMLInputElement).value = '123';
widget.minTermLength = 4;
widget.onKeyUp(keyboardEvent);
expect(formService.getWorkflowUsers).not.toHaveBeenCalled();
});
it('should reset users when the input field is blank string', () => {
let fakeUser = new UserProcessModel({ id: '1', email: 'ffff@fff' });
widget.users.push(fakeUser);
fixture.detectChanges();
let keyboardEvent = new KeyboardEvent('keypress');
(element.querySelector('input') as HTMLInputElement).value = '';
widget.onKeyUp(keyboardEvent);
expect(widget.users).toEqual([]);
});
describe('when template is ready', () => {
let fakeUserResult = [

View File

@ -19,11 +19,20 @@
import { PeopleProcessService } from '../../../../services/people-process.service';
import { UserProcessModel } from '../../../../models';
import { ENTER, ESCAPE } from '@angular/cdk/keycodes';
import { Component, ElementRef, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
import { FormService } from '../../../services/form.service';
import { GroupModel } from '../core/group.model';
import { baseHost, WidgetComponent } from './../widget.component';
import { FormControl } from '@angular/forms';
import { Observable } from 'rxjs/Observable';
import {
catchError,
distinctUntilChanged,
map,
switchMap,
tap
} from 'rxjs/operators';
import 'rxjs/add/observable/empty';
@Component({
selector: 'people-widget',
@ -37,10 +46,45 @@ export class PeopleWidgetComponent extends WidgetComponent implements OnInit {
@ViewChild('inputValue')
input: ElementRef;
minTermLength: number = 1;
oldValue: string;
users: UserProcessModel[] = [];
groupId: string;
value: any;
searchTerm = new FormControl();
errorMsg = '';
searchTerms$: Observable<string> = this.searchTerm.valueChanges;
users$ = this.searchTerms$.pipe(
tap(() => {
this.errorMsg = '';
}),
distinctUntilChanged(),
switchMap((searchTerm) => {
let userResponse = Observable.empty();
if (typeof searchTerm === 'string') {
userResponse = this.formService.getWorkflowUsers(searchTerm, this.groupId)
.pipe(
catchError(err => {
this.errorMsg = err.message;
return userResponse;
})
);
}
return userResponse;
}),
map((list: UserProcessModel[]) => {
let value = (this.input.nativeElement as HTMLInputElement).value;
if (value) {
this.checkUserAndValidateForm(list, value);
} else {
this.field.value = null;
}
return list;
})
);
constructor(public formService: FormService, public peopleProcessService: PeopleProcessService) {
super(formService);
@ -56,34 +100,12 @@ export class PeopleWidgetComponent extends WidgetComponent implements OnInit {
}
}
onKeyUp(event: KeyboardEvent) {
let value = (this.input.nativeElement as HTMLInputElement).value;
if (value && value.length >= this.minTermLength && this.oldValue !== value) {
if (event.keyCode !== ESCAPE && event.keyCode !== ENTER) {
if (value.length >= this.minTermLength) {
this.oldValue = value;
this.searchUsers(value);
}
}
} else {
this.validateValue(value);
}
}
searchUsers(userName: string) {
this.formService.getWorkflowUsers(userName, this.groupId)
.subscribe((result: UserProcessModel[]) => {
this.users = result || [];
this.validateValue(userName);
});
}
validateValue(userName: string) {
if (this.isValidUser(userName)) {
checkUserAndValidateForm(list, value) {
const isValidUser = this.isValidUser(list, value);
if (isValidUser) {
this.field.validationSummary.message = '';
} else if (!userName) {
this.field.value = null;
this.users = [];
this.field.validate();
this.field.form.validateForm();
} else {
this.field.validationSummary.message = 'FORM.FIELD.VALIDATOR.INVALID_VALUE';
this.field.markAsInvalid();
@ -91,17 +113,10 @@ export class PeopleWidgetComponent extends WidgetComponent implements OnInit {
}
}
isValidUser(value: string): boolean {
let isValid = false;
if (value) {
let resultUser: UserProcessModel = this.users.find((user) => this.getDisplayName(user).toLocaleLowerCase() === value.toLocaleLowerCase());
if (resultUser) {
isValid = true;
}
}
return isValid;
isValidUser(users: UserProcessModel[], name: string) {
return users.find((user) => {
return this.getDisplayName(user).toLocaleLowerCase() === name.toLocaleLowerCase();
});
}
getDisplayName(model: UserProcessModel) {
@ -114,7 +129,7 @@ export class PeopleWidgetComponent extends WidgetComponent implements OnInit {
onItemSelect(item: UserProcessModel) {
if (item) {
this.field.value = item;
this.field.value = `${item.firstName || ''} ${item.lastName || ''}`;
}
}
}