From 8efde6d9bb6a7965ac4923f4d961cd8d51d47584 Mon Sep 17 00:00:00 2001 From: Hoang Date: Sun, 6 Oct 2024 02:03:45 -0700 Subject: [PATCH] fix(platform): cache user selection and fix cancel functionality --- .../approval-flow-add-node.component.ts | 4 +- .../approval-flow-user-list.component.html | 8 ++- .../approval-flow-user-list.component.spec.ts | 4 +- .../approval-flow-user-list.component.ts | 70 +++++++++++++++---- libs/platform/list/list.component.ts | 17 ++++- 5 files changed, 81 insertions(+), 22 deletions(-) diff --git a/libs/platform/approval-flow/approval-flow-add-node/approval-flow-add-node.component.ts b/libs/platform/approval-flow/approval-flow-add-node/approval-flow-add-node.component.ts index 7cdbcd3f48c..60052d960cd 100644 --- a/libs/platform/approval-flow/approval-flow-add-node/approval-flow-add-node.component.ts +++ b/libs/platform/approval-flow/approval-flow-add-node/approval-flow-add-node.component.ts @@ -290,9 +290,7 @@ export class ApprovalFlowAddNodeComponent implements OnInit, OnDestroy { /** @hidden */ _exitSelectMode(): void { - if (this._selectedApprovers.length && !this._data.node?.approvers.length) { - this._selectedApprovers = []; - } + this._selectedApprovers = this._data.node?.approvers?.length ? [...this._data.node.approvers] : []; if (!this._data.isEdit && !this._data.node?.approvalTeamId) { this.viewService.resetTeam(); diff --git a/libs/platform/approval-flow/approval-flow-user-list/approval-flow-user-list.component.html b/libs/platform/approval-flow/approval-flow-user-list/approval-flow-user-list.component.html index d56f0b6e45d..3d2a4242e79 100644 --- a/libs/platform/approval-flow/approval-flow-user-list/approval-flow-user-list.component.html +++ b/libs/platform/approval-flow/approval-flow-user-list/approval-flow-user-list.component.html @@ -1,10 +1,11 @@ -@if (_selectedItems.length) { +@if (_allSelectedUsers.length) {
- @if (_selectedItems.length === 1) { + @if (_allSelectedUsers.length === 1) { {{ 'platformApprovalFlow.userListSelectedItemsCountSingular' | fdTranslate }} } @else { {{ - 'platformApprovalFlow.userListSelectedItemsCountPlural' | fdTranslate: { count: _selectedItems.length } + 'platformApprovalFlow.userListSelectedItemsCountPlural' + | fdTranslate: { count: _allSelectedUsers.length } }} }
@@ -21,6 +22,7 @@ @for (_user of _displayUsers; track _trackByFn($index, _user)) { { it('should show team details', () => { const selectionEvent: SelectionChangeEvent = { selectedItems: [], + added: {} as BaseListItem, + removed: {} as BaseListItem, index: 0 }; diff --git a/libs/platform/approval-flow/approval-flow-user-list/approval-flow-user-list.component.ts b/libs/platform/approval-flow/approval-flow-user-list/approval-flow-user-list.component.ts index b1414f020de..25876432af0 100644 --- a/libs/platform/approval-flow/approval-flow-user-list/approval-flow-user-list.component.ts +++ b/libs/platform/approval-flow/approval-flow-user-list/approval-flow-user-list.component.ts @@ -3,7 +3,9 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, + DestroyRef, EventEmitter, + inject, Input, OnChanges, OnDestroy, @@ -15,6 +17,7 @@ import { ViewEncapsulation } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { FormsModule } from '@angular/forms'; import { FdTranslatePipe } from '@fundamental-ngx/i18n'; import { @@ -88,27 +91,31 @@ export class ApprovalFlowUserListComponent implements AfterViewInit, OnChanges, /** @hidden */ _displayUsers: ApprovalUser[] = []; + /** @hidden */ + _allSelectedUsers: ApprovalUser[] = []; + /** @hidden */ private _intervalID?: number; + /** @hidden */ + private _destroyed$ = inject(DestroyRef); + + /** @hidden */ + private _dontCallSelection = false; + /** @hidden */ constructor(private _cdr: ChangeDetectorRef) {} /** @hidden */ ngAfterViewInit(): void { if (this.selectedUsers.length) { - const selectedApproversNames = this.selectedUsers.map((approver) => approver.name); - - this._selectedItems = this.listItems.filter( - (item) => !!item.avatar?.ariaLabel && selectedApproversNames.includes(item.avatar.ariaLabel) - ); - - this._selectedItems.forEach((item) => { - item._selected = true; - this.list._selectItem(item); - }); + this._selectItems(this.selectedUsers); + this._allSelectedUsers = [...this.selectedUsers]; + this._cdr.markForCheck(); + } - this._cdr.detectChanges(); + if (this.isSelectable) { + this._listenToListItemChange(); } } @@ -126,15 +133,28 @@ export class ApprovalFlowUserListComponent implements AfterViewInit, OnChanges, /** @hidden */ _onSelect(event: SelectionChangeEvent): void { - this._selectedItems = event.selectedItems; + if (!this._dontCallSelection) { + this._selectedItems = event.selectedItems; + + if (event.removed) { + this._allSelectedUsers = this._allSelectedUsers.filter( + (user) => `${this._idPrefix + user.id}` !== event.removed!.id + ); + } - this.onSelectionChange.emit(this._getUsersFromSelectedItems(event.selectedItems)); + if (event.added) { + this._allSelectedUsers.push(...this._getUsersFromSelectedItems([event.added])); + } + + this.onSelectionChange.emit(this._allSelectedUsers); + this._cdr.detectChanges(); + } } /** @hidden */ private _getUsersFromSelectedItems(items: BaseListItem[]): ApprovalUser[] { return items - .map((item) => this.users.find((user) => `${this._idPrefix + user.id}` === item.itemEl.nativeElement.id)) + .map((item) => this.users.find((user) => `${this._idPrefix + user.id}` === item.id)) .filter((u): u is ApprovalUser => !!u); } @@ -184,4 +204,26 @@ export class ApprovalFlowUserListComponent implements AfterViewInit, OnChanges, clearInterval(this._intervalID); } } + + /** @hidden */ + private _listenToListItemChange(): void { + this.listItems.changes.pipe(takeUntilDestroyed(this._destroyed$)).subscribe(() => { + this._selectItems(this._allSelectedUsers); + this._cdr.detectChanges(); + }); + } + + /** @hidden */ + private _selectItems(users: ApprovalUser[]): void { + this._dontCallSelection = true; + const allSelectedUserNames = users.map((user) => this._idPrefix + user.id); + const currentSelectedList = this.listItems.filter((item) => allSelectedUserNames.includes(item.id)); + this.list._clearSelection(); + this._selectedItems = [...currentSelectedList]; + this._selectedItems.forEach((item) => { + item._selected = true; + this.list._selectItem(item); + }); + this._dontCallSelection = false; + } } diff --git a/libs/platform/list/list.component.ts b/libs/platform/list/list.component.ts index ae5701f7750..af09871b232 100644 --- a/libs/platform/list/list.component.ts +++ b/libs/platform/list/list.component.ts @@ -69,6 +69,10 @@ export class SelectionChangeEvent { selectedItems: BaseListItem[]; /** Index */ index: number; + /** Selected item */ + added?: BaseListItem; + /** Deselected item */ + removed?: BaseListItem; } let nextListId = 0; @@ -513,10 +517,16 @@ export class ListComponent this._selectionModel = new SelectionModel(this._multiSelect, this.selectedItems); - this._selectionModel.changed.pipe(takeUntilDestroyed(this._destroyed)).subscribe(() => { + this._selectionModel.changed.pipe(takeUntilDestroyed(this._destroyed)).subscribe((selection) => { this.selectedItems = this._selectionModel.selected; const event = new SelectionChangeEvent(); event.selectedItems = this.selectedItems; + if (selection.added?.length) { + event.added = selection.added[0]; + } + if (selection.removed?.length) { + event.removed = selection.removed[0]; + } this.stateChanges.next(event); this.selectedItemChange.emit(event); }); @@ -664,6 +674,11 @@ export class ListComponent this.stateChanges.next(item); } + /** @hidden */ + _clearSelection(): void { + this._selectionModel.clear(); + } + /** @hidden */ private _setItems(): void { if (this._dsItems.length !== null && this.itemSize !== 0) {