|
|
@@ -0,0 +1,167 @@
|
|
|
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core';
|
|
|
+import { PaginationInstance } from 'ngx-pagination';
|
|
|
+import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
|
|
|
+import { map, tap } from 'rxjs/operators';
|
|
|
+
|
|
|
+import { SearchProductsQuery } from '../../../common/generated-types';
|
|
|
+import { SelectionManager } from '../../../common/utilities/selection-manager';
|
|
|
+import { DataService } from '../../../data/providers/data.service';
|
|
|
+import { Dialog } from '../../../providers/modal/modal.service';
|
|
|
+
|
|
|
+export type SearchItem = SearchProductsQuery['search']['items'][number];
|
|
|
+
|
|
|
+@Component({
|
|
|
+ selector: 'vdr-product-multi-selector-dialog',
|
|
|
+ templateUrl: './product-multi-selector-dialog.component.html',
|
|
|
+ styleUrls: ['./product-multi-selector-dialog.component.scss'],
|
|
|
+ changeDetection: ChangeDetectionStrategy.OnPush,
|
|
|
+})
|
|
|
+export class ProductMultiSelectorDialogComponent implements OnInit, Dialog<SearchItem[]> {
|
|
|
+ mode: 'product' | 'variant' = 'product';
|
|
|
+ initialSelectionIds: string[] = [];
|
|
|
+ items$: Observable<SearchItem[]>;
|
|
|
+ facetValues$: Observable<SearchProductsQuery['search']['facetValues']>;
|
|
|
+ searchTerm$ = new BehaviorSubject<string>('');
|
|
|
+ searchFacetValueIds$ = new BehaviorSubject<string[]>([]);
|
|
|
+ paginationConfig: PaginationInstance = {
|
|
|
+ currentPage: 1,
|
|
|
+ itemsPerPage: 25,
|
|
|
+ totalItems: 1,
|
|
|
+ };
|
|
|
+ selectionManager: SelectionManager<SearchItem>;
|
|
|
+
|
|
|
+ resolveWith: (result?: SearchItem[]) => void;
|
|
|
+ private paginationConfig$ = new BehaviorSubject<PaginationInstance>(this.paginationConfig);
|
|
|
+
|
|
|
+ constructor(private dataService: DataService, private changeDetector: ChangeDetectorRef) {}
|
|
|
+
|
|
|
+ ngOnInit(): void {
|
|
|
+ const idFn =
|
|
|
+ this.mode === 'product'
|
|
|
+ ? (a: SearchItem, b: SearchItem) => a.productId === b.productId
|
|
|
+ : (a: SearchItem, b: SearchItem) => a.productVariantId === b.productVariantId;
|
|
|
+ this.selectionManager = new SelectionManager<SearchItem>({
|
|
|
+ multiSelect: true,
|
|
|
+ itemsAreEqual: idFn,
|
|
|
+ additiveMode: true,
|
|
|
+ });
|
|
|
+ const searchQueryResult = this.dataService.product.searchProducts(
|
|
|
+ '',
|
|
|
+ this.paginationConfig.itemsPerPage,
|
|
|
+ 0,
|
|
|
+ );
|
|
|
+ const result$ = combineLatest(
|
|
|
+ this.searchTerm$,
|
|
|
+ this.searchFacetValueIds$,
|
|
|
+ this.paginationConfig$,
|
|
|
+ ).subscribe(([term, facetValueIds, pagination]) => {
|
|
|
+ const take = +pagination.itemsPerPage;
|
|
|
+ const skip = (pagination.currentPage - 1) * take;
|
|
|
+ return searchQueryResult.ref.refetch({
|
|
|
+ input: { skip, take, term, facetValueIds, groupByProduct: this.mode === 'product' },
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ this.items$ = searchQueryResult.stream$.pipe(
|
|
|
+ tap(data => {
|
|
|
+ this.paginationConfig.totalItems = data.search.totalItems;
|
|
|
+ this.selectionManager.setCurrentItems(data.search.items);
|
|
|
+ }),
|
|
|
+ map(data => data.search.items),
|
|
|
+ );
|
|
|
+
|
|
|
+ this.facetValues$ = searchQueryResult.stream$.pipe(map(data => data.search.facetValues));
|
|
|
+
|
|
|
+ if (this.initialSelectionIds.length) {
|
|
|
+ if (this.mode === 'product') {
|
|
|
+ this.dataService.product
|
|
|
+ .getProducts({
|
|
|
+ filter: {
|
|
|
+ id: {
|
|
|
+ in: this.initialSelectionIds,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ })
|
|
|
+ .single$.subscribe(({ products }) => {
|
|
|
+ this.selectionManager.selectMultiple(
|
|
|
+ products.items.map(
|
|
|
+ product =>
|
|
|
+ ({
|
|
|
+ productId: product.id,
|
|
|
+ productName: product.name,
|
|
|
+ } as SearchItem),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ this.changeDetector.markForCheck();
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ this.dataService.product
|
|
|
+ .getProductVariants({
|
|
|
+ filter: {
|
|
|
+ id: {
|
|
|
+ in: this.initialSelectionIds,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ })
|
|
|
+ .single$.subscribe(({ productVariants }) => {
|
|
|
+ this.selectionManager.selectMultiple(
|
|
|
+ productVariants.items.map(
|
|
|
+ variant =>
|
|
|
+ ({
|
|
|
+ productVariantId: variant.id,
|
|
|
+ productVariantName: variant.name,
|
|
|
+ } as SearchItem),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ this.changeDetector.markForCheck();
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ trackByFn(index: number, item: SearchItem) {
|
|
|
+ return item.productId;
|
|
|
+ }
|
|
|
+
|
|
|
+ setSearchTerm(term: string) {
|
|
|
+ this.searchTerm$.next(term);
|
|
|
+ }
|
|
|
+ setFacetValueIds(ids: string[]) {
|
|
|
+ this.searchFacetValueIds$.next(ids);
|
|
|
+ }
|
|
|
+
|
|
|
+ toggleSelection(item: SearchItem, event: MouseEvent) {
|
|
|
+ this.selectionManager.toggleSelection(item, event);
|
|
|
+ }
|
|
|
+
|
|
|
+ clearSelection() {
|
|
|
+ this.selectionManager.selectMultiple([]);
|
|
|
+ }
|
|
|
+
|
|
|
+ isSelected(item: SearchItem) {
|
|
|
+ return this.selectionManager.isSelected(item);
|
|
|
+ }
|
|
|
+
|
|
|
+ entityInfoClick(event: MouseEvent) {
|
|
|
+ event.preventDefault();
|
|
|
+ event.stopPropagation();
|
|
|
+ }
|
|
|
+
|
|
|
+ pageChange(page: number) {
|
|
|
+ this.paginationConfig.currentPage = page;
|
|
|
+ this.paginationConfig$.next(this.paginationConfig);
|
|
|
+ }
|
|
|
+
|
|
|
+ itemsPerPageChange(itemsPerPage: number) {
|
|
|
+ this.paginationConfig.itemsPerPage = itemsPerPage;
|
|
|
+ this.paginationConfig$.next(this.paginationConfig);
|
|
|
+ }
|
|
|
+
|
|
|
+ select() {
|
|
|
+ this.resolveWith(this.selectionManager.selection);
|
|
|
+ }
|
|
|
+
|
|
|
+ cancel() {
|
|
|
+ this.resolveWith();
|
|
|
+ }
|
|
|
+}
|