diff --git a/src/lib/filtering/filter.service.ts b/src/lib/filtering/filter.service.ts index abcf49b..a5d49c8 100644 --- a/src/lib/filtering/filter.service.ts +++ b/src/lib/filtering/filter.service.ts @@ -7,11 +7,13 @@ import { INestedFilter } from './models/nested-filter.model'; import { get, shareDistinctLast, shareLast } from '../utils'; import { NestedFilter } from './models/nested-filter'; import { Filter } from './models/filter'; +import { IFilter } from './models/filter.model'; @Injectable() export class FilterService { readonly showResetFilters$: Observable; readonly filterGroups$: Observable; + readonly #singleFilters = new Map>(); private readonly _filterGroups$ = new BehaviorSubject([]); private readonly _refresh$ = new Subject(); @@ -29,6 +31,10 @@ export class FilterService { return toFlatFilters(this.filterGroups, filters => filters.filter(f => f.checked)); } + get singleFilters() { + return Array.from(this.#singleFilters.values()); + } + private get _showResetFilters$(): Observable { return this.filterGroups$.pipe( map(value => toFlatFilters(value)), @@ -92,6 +98,23 @@ export class FilterService { ); } + addSingleFilter(filter: IFilter) { + if (!this.#singleFilters.has(filter.id)) { + return this.#singleFilters.set(filter.id, new BehaviorSubject(filter)); + } + + return this.#singleFilters.get(filter.id)?.next(filter); + } + + getSingleFilter(filterId: string) { + if (!this.#singleFilters.has(filterId)) { + this.#singleFilters.set(filterId, new BehaviorSubject(undefined)); + } + + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return this.#singleFilters.get(filterId)!.asObservable(); + } + getGroup(slug: string): IFilterGroup | undefined { return this.filterGroups.find(group => group.slug === slug); } @@ -131,6 +154,30 @@ export class FilterService { }); }); + this.resetSingleFilters(); + this.refresh(); } + + resetSingleFilters() { + this.#singleFilters.forEach(filter$ => { + const filter = filter$.value; + if (filter) { + filter$.next({ ...filter$.value, checked: !filter$.value?.checked }); + } + }); + } + + toggleSingleFilter(filterId: string) { + const filter$ = this.#singleFilters.get(filterId); + if (!filter$) { + return; + } + + const filter = filter$.value; + if (filter) { + filter.checked = !filter.checked; + this.addSingleFilter(filter); + } + } } diff --git a/src/lib/filtering/filters.module.ts b/src/lib/filtering/filters.module.ts index 21b9f2f..aa445f8 100644 --- a/src/lib/filtering/filters.module.ts +++ b/src/lib/filtering/filters.module.ts @@ -9,10 +9,11 @@ import { QuickFiltersComponent } from './quick-filters/quick-filters.component'; import { IqserIconsModule } from '../icons'; import { IqserInputsModule } from '../inputs'; import { IqserHelpModeModule } from '../help-mode'; +import { SingleFilterComponent } from './single-filter/single-filter.component'; const matModules = [MatCheckboxModule, MatMenuModule]; const modules = [TranslateModule, IqserButtonsModule, IqserIconsModule, IqserInputsModule, IqserHelpModeModule]; -const components = [QuickFiltersComponent, PopupFilterComponent]; +const components = [QuickFiltersComponent, PopupFilterComponent, SingleFilterComponent]; @NgModule({ declarations: [...components], diff --git a/src/lib/filtering/single-filter/single-filter.component.html b/src/lib/filtering/single-filter/single-filter.component.html new file mode 100644 index 0000000..2c5a415 --- /dev/null +++ b/src/lib/filtering/single-filter/single-filter.component.html @@ -0,0 +1,3 @@ + + {{ filter.label }} + diff --git a/src/lib/filtering/single-filter/single-filter.component.scss b/src/lib/filtering/single-filter/single-filter.component.scss new file mode 100644 index 0000000..af9398b --- /dev/null +++ b/src/lib/filtering/single-filter/single-filter.component.scss @@ -0,0 +1,8 @@ +::ng-deep .filter-menu-checkbox { + width: 100%; + + label { + width: 100%; + height: 100%; + } +} diff --git a/src/lib/filtering/single-filter/single-filter.component.ts b/src/lib/filtering/single-filter/single-filter.component.ts new file mode 100644 index 0000000..c11ae07 --- /dev/null +++ b/src/lib/filtering/single-filter/single-filter.component.ts @@ -0,0 +1,19 @@ +import { Component, Input } from '@angular/core'; +import { FilterService } from '../filter.service'; +import { IFilter } from '../models/filter.model'; + +@Component({ + selector: 'iqser-single-filter', + templateUrl: './single-filter.component.html', + styleUrls: ['./single-filter.component.scss'], +}) +export class SingleFilterComponent { + @Input() filter!: IFilter; + + constructor(readonly filterService: FilterService) {} + + checkboxClicked($event: MouseEvent) { + $event.preventDefault(); + this.filterService.toggleSingleFilter(this.filter.id); + } +} diff --git a/src/lib/listing/page-header/page-header.component.html b/src/lib/listing/page-header/page-header.component.html index e23b73c..70e1fc0 100644 --- a/src/lib/listing/page-header/page-header.component.html +++ b/src/lib/listing/page-header/page-header.component.html @@ -7,7 +7,15 @@ - + + + + + @@ -15,9 +23,9 @@
@@ -30,9 +38,9 @@ *ngIf="!config.hide" [icon]="config.icon" [id]="config.label.replace('.', '-')" + [iqserHelpMode]="config.helpModeKey" [label]="config.label | translate" [type]="config.type" - [iqserHelpMode]="config.helpModeKey" > @@ -43,9 +51,9 @@ *ngIf="!config.hide" [disabled]="config.disabled$ && (config.disabled$ | async)" [icon]="config.icon" + [iqserHelpMode]="config.helpModeKey" [tooltip]="config.label" tooltipPosition="below" - [iqserHelpMode]="config.helpModeKey" > @@ -58,8 +66,8 @@ [class.ml-6]="actionConfigs" [tooltip]="'common.close' | translate" icon="iqser:close" - tooltipPosition="below" iqserHelpMode="edit_dossier_in_dossier" + tooltipPosition="below" > diff --git a/src/lib/listing/page-header/page-header.component.ts b/src/lib/listing/page-header/page-header.component.ts index 5494a04..d05f148 100644 --- a/src/lib/listing/page-header/page-header.component.ts +++ b/src/lib/listing/page-header/page-header.component.ts @@ -45,6 +45,14 @@ export class PageHeaderComponent { ); } + get filterHelpModeKey() { + return this.helpModeKey ? `filter_${this.helpModeKey}_list` : ''; + } + + get resetFiltersHelpModeKey() { + return this.helpModeKey === 'dossier' ? 'reset_filters' : 'delete_document_filter'; + } + resetFilters(): void { this.filterService.reset(); this.searchService.reset(); @@ -53,12 +61,4 @@ export class PageHeaderComponent { trackByLabel(index: number, item: K): string | undefined { return item.label; } - - get filterHelpModeKey() { - return !!this.helpModeKey ? `filter_${this.helpModeKey}_list` : ''; - } - - get resetFiltersHelpModeKey() { - return this.helpModeKey === 'dossier' ? 'reset_filters' : `delete_document_filter`; - } } diff --git a/src/lib/utils/functions.ts b/src/lib/utils/functions.ts index 609e932..3791217 100644 --- a/src/lib/utils/functions.ts +++ b/src/lib/utils/functions.ts @@ -68,3 +68,19 @@ export function hasFormChanged(form: FormGroup, initialFormValue): boolean { } return false; } + +const HOURS_IN_A_DAY = 24; +const MINUTES_IN_AN_HOUR = 60; + +export function getLeftDateTime(ISOString: string) { + const date = moment(ISOString); + const now = new Date(Date.now()); + + const daysLeft = date.diff(now, 'days'); + const hoursFromNow = date.diff(now, 'hours'); + const hoursLeft = hoursFromNow - HOURS_IN_A_DAY * daysLeft; + const minutesFromNow = date.diff(now, 'minutes'); + const minutesLeft = minutesFromNow - HOURS_IN_A_DAY * MINUTES_IN_AN_HOUR * daysLeft; + + return { daysLeft, hoursLeft, minutesLeft }; +}