Parcourir la source

refactor(admin-ui): Extract CollectionContentsComponent

Michael Bromley il y a 6 ans
Parent
commit
0db7890f0a

+ 2 - 0
admin-ui/src/app/catalog/catalog.module.ts

@@ -10,6 +10,7 @@ import { AssetFileInputComponent } from './components/asset-file-input/asset-fil
 import { AssetGalleryComponent } from './components/asset-gallery/asset-gallery.component';
 import { AssetListComponent } from './components/asset-list/asset-list.component';
 import { AssetPickerDialogComponent } from './components/asset-picker-dialog/asset-picker-dialog.component';
+import { CollectionContentsComponent } from './components/collection-contents/collection-contents.component';
 import { CollectionDetailComponent } from './components/collection-detail/collection-detail.component';
 import { CollectionListComponent } from './components/collection-list/collection-list.component';
 import { CollectionTreeNodeComponent } from './components/collection-tree/collection-tree-node.component';
@@ -57,6 +58,7 @@ import { ProductResolver } from './providers/routing/product-resolver';
         CollectionDetailComponent,
         CollectionTreeComponent,
         CollectionTreeNodeComponent,
+        CollectionContentsComponent,
     ],
     entryComponents: [
         AssetPickerDialogComponent,

+ 32 - 0
admin-ui/src/app/catalog/components/collection-contents/collection-contents.component.html

@@ -0,0 +1,32 @@
+<div class="contents-header">
+    <div class="header-title-row">
+        <ng-container
+            *ngTemplateOutlet="headerTemplate; context: { $implicit: contentsTotalItems$ | async }"
+        ></ng-container>
+    </div>
+    <input
+        type="text"
+        [placeholder]="'catalog.filter-by-name' | translate"
+        class="clr-input"
+        [formControl]="filterTermControl"
+    />
+</div>
+<vdr-data-table
+    [items]="contents$ | async"
+    [itemsPerPage]="contentsItemsPerPage$ | async"
+    [totalItems]="contentsTotalItems$ | async"
+    [currentPage]="contentsCurrentPage$ | async"
+    (pageChange)="setContentsPageNumber($event)"
+    (itemsPerPageChange)="setContentsItemsPerPage($event)"
+>
+    <ng-template let-variant="item">
+        <td class="left align-middle">{{ variant.name }}</td>
+        <td class="right align-middle">
+            <vdr-table-row-action
+                iconShape="edit"
+                [label]="'common.edit' | translate"
+                [linkTo]="['../products', variant.productId, { tab: 'variants' }]"
+            ></vdr-table-row-action>
+        </td>
+    </ng-template>
+</vdr-data-table>

+ 26 - 0
admin-ui/src/app/catalog/components/collection-contents/collection-contents.component.scss

@@ -0,0 +1,26 @@
+@import "variables";
+
+.contents-header {
+    background-color: $color-grey-1;
+    position: sticky;
+    top: 0;
+    padding: 6px;
+    z-index: 1;
+    border-bottom: 1px solid $color-grey-3;
+
+    .header-title-row {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+    }
+
+    .clr-input {
+        width: 100%;
+    }
+}
+
+:host {
+    ::ng-deep table {
+        margin-top: -1px;
+    }
+}

+ 120 - 0
admin-ui/src/app/catalog/components/collection-contents/collection-contents.component.ts

@@ -0,0 +1,120 @@
+import {
+    ChangeDetectionStrategy,
+    Component,
+    ContentChild,
+    Input,
+    OnChanges,
+    OnDestroy,
+    OnInit,
+    SimpleChanges,
+    TemplateRef,
+} from '@angular/core';
+import { FormControl } from '@angular/forms';
+import { ActivatedRoute, Router } from '@angular/router';
+import { BehaviorSubject, combineLatest, Observable, of, Subject } from 'rxjs';
+import {
+    debounceTime,
+    distinctUntilChanged,
+    map,
+    startWith,
+    switchMap,
+    takeUntil,
+    tap,
+} from 'rxjs/operators';
+import { GetCollectionContents } from 'shared/generated-types';
+
+import { DataService } from '../../../data/providers/data.service';
+
+@Component({
+    selector: 'vdr-collection-contents',
+    templateUrl: './collection-contents.component.html',
+    styleUrls: ['./collection-contents.component.scss'],
+    changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class CollectionContentsComponent implements OnInit, OnChanges, OnDestroy {
+    @Input() collectionId: string;
+    @ContentChild(TemplateRef) headerTemplate: TemplateRef<any>;
+
+    contents$: Observable<GetCollectionContents.Items[]>;
+    contentsTotalItems$: Observable<number>;
+    contentsItemsPerPage$: Observable<number>;
+    contentsCurrentPage$: Observable<number>;
+    filterTermControl = new FormControl('');
+    private collectionIdChange$ = new BehaviorSubject<string>('');
+    private destroy$ = new Subject<void>();
+
+    constructor(private route: ActivatedRoute, private router: Router, private dataService: DataService) {}
+
+    ngOnInit() {
+        this.contentsCurrentPage$ = this.route.paramMap.pipe(
+            map(qpm => qpm.get('contentsPage')),
+            map(page => (!page ? 1 : +page)),
+            startWith(1),
+            distinctUntilChanged(),
+        );
+
+        this.contentsItemsPerPage$ = this.route.paramMap.pipe(
+            map(qpm => qpm.get('contentsPerPage')),
+            map(perPage => (!perPage ? 10 : +perPage)),
+            startWith(10),
+            distinctUntilChanged(),
+        );
+
+        const filterTerm$ = this.filterTermControl.valueChanges.pipe(
+            debounceTime(250),
+            tap(() => this.setContentsPageNumber(1)),
+            startWith(''),
+        );
+
+        const collection$ = combineLatest(
+            this.collectionIdChange$,
+            this.contentsCurrentPage$,
+            this.contentsItemsPerPage$,
+            filterTerm$,
+        ).pipe(
+            takeUntil(this.destroy$),
+            switchMap(([id, currentPage, itemsPerPage, filterTerm]) => {
+                const take = itemsPerPage;
+                const skip = (currentPage - 1) * itemsPerPage;
+                if (id) {
+                    return this.dataService.collection
+                        .getCollectionContents(id, take, skip, filterTerm)
+                        .mapSingle(data => data.collection);
+                } else {
+                    return of(null);
+                }
+            }),
+        );
+
+        this.contents$ = collection$.pipe(map(result => (result ? result.productVariants.items : [])));
+        this.contentsTotalItems$ = collection$.pipe(
+            map(result => (result ? result.productVariants.totalItems : 0)),
+        );
+    }
+
+    ngOnChanges(changes: SimpleChanges): void {
+        if ('collectionId' in changes) {
+            this.collectionIdChange$.next(changes.collectionId.currentValue);
+        }
+    }
+
+    ngOnDestroy() {
+        this.destroy$.next();
+        this.destroy$.complete();
+    }
+
+    setContentsPageNumber(page: number) {
+        this.setParam('contentsPage', page);
+    }
+
+    setContentsItemsPerPage(perPage: number) {
+        this.setParam('contentsPerPage', perPage);
+    }
+
+    private setParam(key: string, value: any) {
+        this.router.navigate(['./', { ...this.route.snapshot.params, [key]: value }], {
+            relativeTo: this.route,
+            queryParamsHandling: 'merge',
+        });
+    }
+}

+ 4 - 29
admin-ui/src/app/catalog/components/collection-list/collection-list.component.html

@@ -14,42 +14,17 @@
     ></vdr-collection-tree>
 
     <div class="collection-contents" [class.expanded]="activeCollectionId$ | async">
-        <div class="contents-header">
-            <div class="header-title-row">
+        <vdr-collection-contents [collectionId]="activeCollectionId$ | async">
+            <ng-template let-count>
                 <div class="collection-title">
                     {{ activeCollectionTitle$ | async }} ({{
-                        'common.results-count' | translate: { count: contentsTotalItems$ | async }
+                        'common.results-count' | translate: { count: count }
                     }})
                 </div>
                 <button type="button" class="close-button" (click)="closeContents()">
                     <clr-icon shape="close"></clr-icon>
                 </button>
-            </div>
-            <input
-                type="text"
-                [placeholder]="'catalog.filter-by-name' | translate"
-                class="clr-input"
-                [formControl]="filterTermControl"
-            />
-        </div>
-        <vdr-data-table
-            [items]="contents$ | async"
-            [itemsPerPage]="contentsItemsPerPage$ | async"
-            [totalItems]="contentsTotalItems$ | async"
-            [currentPage]="contentsCurrentPage$ | async"
-            (pageChange)="setContentsPageNumber($event)"
-            (itemsPerPageChange)="setContentsItemsPerPage($event)"
-        >
-            <ng-template let-variant="item">
-                <td class="left align-middle">{{ variant.name }}</td>
-                <td class="right align-middle">
-                    <vdr-table-row-action
-                        iconShape="edit"
-                        [label]="'common.edit' | translate"
-                        [linkTo]="['../products', variant.productId, { tab: 'variants' }]"
-                    ></vdr-table-row-action>
-                </td>
             </ng-template>
-        </vdr-data-table>
+        </vdr-collection-contents>
     </div>
 </div>

+ 5 - 27
admin-ui/src/app/catalog/components/collection-list/collection-list.component.scss

@@ -30,33 +30,11 @@
             padding-left: 12px;
         }
 
-        .contents-header {
-            background-color: $color-grey-1;
-            position: sticky;
-            top: 0;
-            padding: 6px;
-            z-index: 1;
-            border-bottom: 1px solid $color-grey-3;
-
-            .header-title-row {
-                display: flex;
-                justify-content: space-between;
-                align-items: center;
-            }
-
-            .close-button {
-                margin: 0;
-                background: none;
-                border: none;
-                cursor: pointer;
-            }
-
-            .clr-input {
-                width: 100%;
-            }
-        }
-        ::ng-deep table {
-            margin-top: -1px;
+        .close-button {
+            margin: 0;
+            background: none;
+            border: none;
+            cursor: pointer;
         }
     }
 }

+ 11 - 72
admin-ui/src/app/catalog/components/collection-list/collection-list.component.ts

@@ -1,17 +1,8 @@
 import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
-import { FormControl } from '@angular/forms';
 import { ActivatedRoute, Router } from '@angular/router';
-import { combineLatest, Observable, of } from 'rxjs';
-import {
-    debounceTime,
-    distinctUntilChanged,
-    map,
-    startWith,
-    switchMap,
-    takeUntil,
-    tap,
-} from 'rxjs/operators';
-import { GetCollectionContents, GetCollectionList } from 'shared/generated-types';
+import { combineLatest, Observable } from 'rxjs';
+import { distinctUntilChanged, map } from 'rxjs/operators';
+import { GetCollectionList } from 'shared/generated-types';
 
 import { BaseListComponent } from '../../../common/base-list.component';
 import { _ } from '../../../core/providers/i18n/mark-for-extraction';
@@ -28,13 +19,8 @@ import { RearrangeEvent } from '../collection-tree/collection-tree.component';
 export class CollectionListComponent
     extends BaseListComponent<GetCollectionList.Query, GetCollectionList.Items>
     implements OnInit {
-    contents$: Observable<GetCollectionContents.Items[]>;
-    contentsTotalItems$: Observable<number>;
-    contentsItemsPerPage$: Observable<number>;
-    contentsCurrentPage$: Observable<number>;
     activeCollectionId$: Observable<string | null>;
     activeCollectionTitle$: Observable<string>;
-    filterTermControl = new FormControl('');
 
     constructor(
         private dataService: DataService,
@@ -56,50 +42,16 @@ export class CollectionListComponent
             map(pm => pm.get('contents')),
             distinctUntilChanged(),
         );
-        this.contentsCurrentPage$ = this.route.paramMap.pipe(
-            map(qpm => qpm.get('contentsPage')),
-            map(page => (!page ? 1 : +page)),
-            startWith(1),
-            distinctUntilChanged(),
-        );
-        this.contentsItemsPerPage$ = this.route.paramMap.pipe(
-            map(qpm => qpm.get('contentsPerPage')),
-            map(perPage => (!perPage ? 10 : +perPage)),
-            startWith(10),
-            distinctUntilChanged(),
-        );
 
-        const filterTerm$ = this.filterTermControl.valueChanges.pipe(
-            debounceTime(250),
-            tap(() => this.setContentsPageNumber(1)),
-            startWith(''),
-        );
-
-        const collection$ = combineLatest(
-            this.activeCollectionId$,
-            this.contentsCurrentPage$,
-            this.contentsItemsPerPage$,
-            filterTerm$,
-        ).pipe(
-            takeUntil(this.destroy$),
-            switchMap(([id, currentPage, itemsPerPage, filterTerm]) => {
+        this.activeCollectionTitle$ = combineLatest(this.activeCollectionId$, this.items$).pipe(
+            map(([id, collections]) => {
                 if (id) {
-                    const take = itemsPerPage;
-                    const skip = (currentPage - 1) * itemsPerPage;
-                    return this.dataService.collection
-                        .getCollectionContents(id, take, skip, filterTerm)
-                        .mapSingle(data => data.collection);
-                } else {
-                    return of(null);
+                    const match = collections.find(c => c.id === id);
+                    return match ? match.name : '';
                 }
+                return '';
             }),
         );
-
-        this.contents$ = collection$.pipe(map(result => (result ? result.productVariants.items : [])));
-        this.contentsTotalItems$ = collection$.pipe(
-            map(result => (result ? result.productVariants.totalItems : 0)),
-        );
-        this.activeCollectionTitle$ = collection$.pipe(map(result => (result ? result.name : '')));
     }
 
     onRearrange(event: RearrangeEvent) {
@@ -114,22 +66,9 @@ export class CollectionListComponent
         });
     }
 
-    setContentsPageNumber(page: number) {
-        this.setParam('contentsPage', page);
-    }
-
-    setContentsItemsPerPage(perPage: number) {
-        this.setParam('contentsPerPage', perPage);
-    }
-
     closeContents() {
-        this.setParam('contents', null);
-    }
-
-    private setParam(key: string, value: any) {
-        this.router.navigate(['./', { ...this.route.snapshot.params, [key]: value }], {
-            relativeTo: this.route,
-            queryParamsHandling: 'merge',
-        });
+        const params = { ...this.route.snapshot.params };
+        delete params.contents;
+        this.router.navigate(['./', params], { relativeTo: this.route });
     }
 }