Merged PR 677: #1812 Filter Lesealter

#1812 Filter Lesealter
This commit is contained in:
Nino Righi
2021-05-20 08:06:14 +00:00
committed by Lorenz Hilpert
parent 5143e13ebe
commit acadada245
15 changed files with 240 additions and 24 deletions

View File

@@ -16,7 +16,7 @@ import {
OrderByDTO,
QueryTokenDTO,
} from '@swagger/cat';
import { Filter, FilterType, SelectFilter, SelectFilterGroup, SelectFilterOption } from '@ui/filter';
import { Filter, FilterType, RangeFilter, RangeFilterOption, SelectFilter, SelectFilterGroup, SelectFilterOption } from '@ui/filter';
import { Observable } from 'rxjs';
import { debounceTime, distinctUntilChanged, exhaustMap, map, switchMap, tap, withLatestFrom } from 'rxjs/operators';
import { ScrollPositionService } from 'apps/ui/common/src/lib/scroll-position/scroll-position.service';
@@ -131,11 +131,6 @@ export class ArticleSearchStore extends ComponentStore<ArticleSearchState> {
tapResponse(
(response: InputGroupDTO[]) => {
const mappedInputGroup = this.mapInputArraysToFilterGroupArrayInsideInputGroup(response);
// TODO: Reading Age
mappedInputGroup[2].input.splice(3, 1);
console.log(mappedInputGroup);
const initialFilter = this.concatNestedArrays(mappedInputGroup.filter((filters) => filters.group === 'filter'));
const initialprimaryFilter = this.concatNestedArrays(
mappedInputGroup.filter((filters) => filters.group === 'main' || filters.group === 'input_selector')
@@ -374,15 +369,28 @@ export class ArticleSearchStore extends ComponentStore<ArticleSearchState> {
return arr;
}
private fromInputDto(input: InputDTO): SelectFilter {
return {
key: input.key,
name: input.label,
max: input.options && input.options.max,
type: this.inputTypeToType(input.type),
target: input.target,
options: input.options && input.options.values.map((v) => this.fromOptionDto(v)),
} as SelectFilter;
private fromInputDto(input: InputDTO): SelectFilter | RangeFilter {
if (this.inputTypeToType(input.type) === 'integer-range') {
return {
key: input.key,
name: input.label,
description: input.description,
type: this.inputTypeToType(input.type),
target: input.target,
options: input.options && input.options.values.map((v) => this.fromOptionDtoRange(v)),
} as RangeFilter;
}
if (this.inputTypeToType(input.type) !== 'integer-range') {
return {
key: input.key,
name: input.label,
max: input.options && input.options.max,
type: this.inputTypeToType(input.type),
target: input.target,
options: input.options && input.options.values.map((v) => this.fromOptionDto(v)),
} as SelectFilter;
}
}
private fromOptionDto(option: OptionDTO): SelectFilterOption {
@@ -396,6 +404,18 @@ export class ArticleSearchStore extends ComponentStore<ArticleSearchState> {
} as SelectFilterOption;
}
private fromOptionDtoRange(option: OptionDTO): RangeFilterOption {
return {
name: option.label,
selected: option.selected || false,
value: '',
id: option.key || option.value,
minValue: option.minValue,
maxValue: option.maxValue,
placeholder: option.placeholder,
} as RangeFilterOption;
}
private inputTypeToType(type: InputType): FilterType {
switch (type) {
case 1:
@@ -413,6 +433,9 @@ export class ArticleSearchStore extends ComponentStore<ArticleSearchState> {
case 32 || 64:
return 'number';
case 4096:
return 'integer-range';
default:
return 'select';
}
@@ -423,7 +446,22 @@ export class ArticleSearchStore extends ComponentStore<ArticleSearchState> {
for (const filter of source) {
const selected = filter.options.filter((o) => o.selected);
if (selected.length > 0) {
dict[filter.key] = selected.map((o) => o.id).join(';');
dict[filter.key] = selected
.map((o: SelectFilterOption | RangeFilterOption) => {
if (filter.key === 'reading-age') {
if (o.id === 'start') {
return `${(o as RangeFilterOption).value}-`;
} else if (o.id === 'stop') {
return `-${(o as RangeFilterOption).value}`;
}
} else {
return o.id;
}
})
.join(';');
}
if (selected.find((o) => o.id === 'start') && selected.find((o) => o.id === 'stop')) {
dict['reading-age'] = dict['reading-age'].replace('-;', '');
}
}
return dict;

View File

@@ -3,8 +3,11 @@ import { InputOptionsDTO } from './input-options-dto';
import { InputType } from './input-type';
export interface InputDTO {
constraint?: string;
description?: string;
key?: string;
label?: string;
maxValue?: string;
minValue?: string;
options?: InputOptionsDTO;
placeholder?: string;
target?: string;

View File

@@ -1,6 +1,7 @@
/* tslint:disable */
import { InputDTO } from './input-dto';
export interface InputGroupDTO {
description?: string;
group?: string;
input?: Array<InputDTO>;
label?: string;

View File

@@ -1,8 +1,12 @@
/* tslint:disable */
export interface OptionDTO {
description?: string;
enabled?: boolean;
key?: string;
label?: string;
maxValue?: string;
minValue?: string;
placeholder?: string;
selected?: boolean;
value?: string;
values?: Array<OptionDTO>;

View File

@@ -24,5 +24,6 @@
[selectionContainer]="selectionContainerRef"
>
</ui-select-filter>
<ui-range-filter *ngSwitchCase="'integer-range'" (category)="setActive($event)" [filter]="active" [module]="module"> </ui-range-filter>
</div>
</div>

View File

@@ -0,0 +1 @@
export * from './range-filter.component';

View File

@@ -0,0 +1,23 @@
<div #selectFilter class="isa-card">
<div class="select-filter-options isa-mt-10">
<p class="range-filter-headline">{{ filter.description }}</p>
<div [formGroup]="formGroup" class="range-input-wrapper">
<input
class="range-filter-input"
uiInput
type="string"
[tabindex]="0"
[formControlName]="'start'"
[placeholder]="filter.options[0].name"
/>
<input
class="range-filter-input"
uiInput
type="string"
[tabindex]="1"
[formControlName]="'stop'"
[placeholder]="filter.options[1].name"
/>
</div>
</div>
</div>

View File

@@ -0,0 +1,22 @@
.select-filter-options {
@apply pr-px-50;
}
.range-filter-headline {
@apply font-semibold text-base;
}
.range-input-wrapper {
@apply flex flex-row justify-between mb-6;
}
.range-filter-input {
@apply pt-px-20 font-bold text-xl mr-8;
border: none;
outline: none;
border-bottom: 2px solid #e1ebf5;
}
.range-filter-input::placeholder {
@apply font-bold text-xl text-cool-grey;
}

View File

@@ -0,0 +1,102 @@
import { Component, ChangeDetectionStrategy, Input, ElementRef, ChangeDetectorRef, OnInit, Output, EventEmitter } from '@angular/core';
import { AbstractControl, FormBuilder, FormGroup, ValidationErrors } from '@angular/forms';
import { RangeFilter, RangeFilterOption, SelectFilter } from '../../../models';
import { FilterGroup } from '../../filter-group';
@Component({
selector: 'ui-range-filter',
templateUrl: 'range-filter.component.html',
styleUrls: ['range-filter.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class UiRangeFilterComponent implements OnInit {
@Output() category = new EventEmitter<SelectFilter | RangeFilter>();
@Input()
filter: RangeFilter;
@Input() selectionContainer: ElementRef;
@Input() module: 'Customer' | 'Branch' = 'Branch';
formGroup: FormGroup;
startValidator = (opt: RangeFilterOption) => (control: AbstractControl): null | ValidationErrors => {
const stopCtrl = control?.parent?.get('stop');
if (control.value !== opt.value) {
this.updateValue(control.value, opt, control, { compareControlValue: stopCtrl.value, target: 'stop' });
}
return null;
};
stopValidator = (opt: RangeFilterOption) => (control: AbstractControl): null | ValidationErrors => {
const startCtrl = control?.parent?.get('start');
if (control.value !== opt.value) {
this.updateValue(control.value, opt, control, { compareControlValue: startCtrl.value, target: 'start' });
}
return null;
};
constructor(protected cdr: ChangeDetectorRef, public filterGroup: FilterGroup, private fb: FormBuilder) {}
ngOnInit() {
this.formGroup = this.fb.group({
start: this.fb.control(this.filter.options[0].value, [this.startValidator(this.filter.options[0])]),
stop: this.fb.control(this.filter.options[1].value, [this.stopValidator(this.filter.options[1])]),
});
this.filterGroup.updateView.subscribe((_) => this.cdr.markForCheck());
}
updateValue(
value: string,
option: RangeFilterOption,
control: AbstractControl,
compareValue: { compareControlValue: string; target: 'start' | 'stop' }
) {
value === '' ? (option.selected = true) : (option.selected = false);
option.value = this.checkValue(value, option, compareValue);
this.updateControl(option.value, control);
this.filterGroup.toggleOption(this.filter, option);
this.preSelectCategory(this.filter);
this.cdr.markForCheck();
}
updateControl(value: string, control: AbstractControl) {
control.setValue(value, { emitEvent: false });
}
checkValue(value: string, option: RangeFilterOption, compareValue: { compareControlValue: string; target: 'start' | 'stop' }): string {
let validatedResult =
Number(value) <= option.maxValue && Number(value) >= option.minValue
? value
.replace(/[^0-9.]/g, '') // Only Numbers
.replace(/^(?:0+(?=[1-9])|0+(?=0$))/gm, '') // No leading Zeros and only one Zero allowed
.replace(/(\..*)\./g, '$1') // No special characters
: Number(value) > option.maxValue
? `${option.maxValue}`
: Number(value) < option.minValue
? `${option.minValue}`
: '';
// Checking if start value is smaller than stop value
if (compareValue.target === 'stop' && compareValue.compareControlValue !== '') {
if (Number(compareValue.compareControlValue) < Number(validatedResult)) {
validatedResult = compareValue.compareControlValue;
}
}
// Checking if start value is smaller than stop value and vice versa
// if (compareValue.target === 'start' && compareValue.compareControlValue !== '') {
// if (Number(compareValue.compareControlValue) > Number(validatedResult)) {
// // validatedResult = compareValue.compareControlValue;
// }
// }
return validatedResult;
}
preSelectCategory(category: SelectFilter | RangeFilter) {
this.category.emit(category);
}
}

View File

@@ -2,13 +2,15 @@ import { NgModule } from '@angular/core';
import { UiFilterGroupComponent } from './components/filter-group';
import { CommonModule } from '@angular/common';
import { UiSelectFilterComponent, UiSelectFilterOptionComponent } from './components/select-filter';
import { FormsModule } from '@angular/forms';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { UiIconModule } from '@ui/icon';
import { UiRangeFilterComponent } from './components/range-filter';
import { UiInputModule } from '@ui/input';
@NgModule({
imports: [CommonModule, UiIconModule, FormsModule],
imports: [CommonModule, UiIconModule, FormsModule, UiInputModule, ReactiveFormsModule],
exports: [UiFilterGroupComponent],
declarations: [UiFilterGroupComponent, UiSelectFilterComponent, UiSelectFilterOptionComponent],
declarations: [UiFilterGroupComponent, UiSelectFilterComponent, UiSelectFilterOptionComponent, UiRangeFilterComponent],
providers: [],
})
export class UiFilterGroupModule {}

View File

@@ -1,5 +1,5 @@
import { EventEmitter } from '@angular/core';
import { Filter, FilterOption } from '../models';
import { Filter, FilterOption, RangeFilter } from '../models';
import { isBoolean } from '@utils/common';
export abstract class FilterGroup {
@@ -25,7 +25,7 @@ export abstract class FilterGroup {
this.updateView.emit();
}
toggleOption(filter: Filter, option: FilterOption) {
toggleOption(filter: Filter | RangeFilter, option: FilterOption) {
const optionRef = this.getOptionRef(filter, option);
if (optionRef) {
optionRef.selected = !optionRef.selected;
@@ -34,11 +34,11 @@ export abstract class FilterGroup {
}
}
getFilterRef(filter: Filter) {
getFilterRef(filter: Filter | RangeFilter) {
return this.value.find((f) => f.key === filter.key);
}
getOptionRef(filter: Filter, option: FilterOption) {
getOptionRef(filter: Filter | RangeFilter, option: FilterOption) {
const filterRef = this.getFilterRef(filter);
if (filterRef) {

View File

@@ -1 +1 @@
export type FilterType = 'select' | 'text' | 'date' | 'number' | 'checkbox';
export type FilterType = 'select' | 'text' | 'date' | 'number' | 'checkbox' | 'integer-range';

View File

@@ -6,3 +6,5 @@ export * from './select-option';
export * from './filter';
export * from './filter-type';
export * from './select-filter-group';
export * from './range-filter';
export * from './range-filter-option';

View File

@@ -0,0 +1,9 @@
import { FilterOptionBase } from './filter-option-base';
export interface RangeFilterOption extends FilterOptionBase {
selected: boolean;
value: string;
minValue?: string | number;
maxValue?: string | number;
placeholder?: string;
}

View File

@@ -0,0 +1,8 @@
import { FilterBase } from './filter-base';
import { RangeFilterOption } from './range-filter-option';
export interface RangeFilter extends FilterBase<RangeFilterOption> {
type: 'integer-range';
target?: 'input' | 'filter';
description?: string;
}