Browse Source

feat(dev-server): Add example shared UI extension module

Michael Bromley 6 years ago
parent
commit
3ceac494b0

+ 12 - 1
packages/dev-server/dev-config.ts

@@ -1,5 +1,6 @@
 /* tslint:disable:no-console */
 import { AdminUiPlugin } from '@vendure/admin-ui-plugin';
+import { LanguageCode } from '@vendure/admin-ui/src/app/common/generated-types';
 import { AssetServerPlugin } from '@vendure/asset-server-plugin';
 import { ADMIN_API_PATH, API_PORT, SHOP_API_PATH } from '@vendure/common/lib/shared-constants';
 import {
@@ -35,7 +36,17 @@ export const devConfig: VendureConfig = {
     paymentOptions: {
         paymentMethodHandlers: [examplePaymentHandler],
     },
-    customFields: {},
+    customFields: {
+        Product: [
+            { name: 'length', type: 'int', min: 0, max: 100 },
+            {
+                name: 'offerImageId',
+                label: [{ languageCode: LanguageCode.en, value: 'Offer image' }],
+                type: 'string',
+            },
+        ],
+        ProductVariant: [{ name: 'length', type: 'int', min: 0, max: 100 }],
+    },
     logger: new DefaultLogger({ level: LogLevel.Info }),
     importExportOptions: {
         importAssetsDir: path.join(__dirname, 'import-assets'),

+ 1 - 1
packages/dev-server/ui-plugin/lazy-module/ui-plugin.module.ts

@@ -5,7 +5,7 @@ import { ModalService, SharedModule } from '@vendure/admin-ui/src';
 @Component({
     selector: 'plugin-test-component',
     template: `
-        <p>Test component works!!</p>
+        <p>Test component works!!!</p>
         <button class="btn btn-primary" (click)="handleClick()">Click me!</button>
     `,
 })

+ 0 - 40
packages/dev-server/ui-plugin/module/ui-plugin.module.ts

@@ -1,40 +0,0 @@
-import { Component, NgModule } from '@angular/core';
-import { RouterModule } from '@angular/router';
-import { ModalService, SharedModule } from '@vendure/admin-ui/src';
-
-@Component({
-    selector: 'plugin-test-component',
-    template: `
-        <p>Test component works!!</p>
-        <button class="btn btn-primary" (click)="handleClick()">Click me!</button>
-    `,
-})
-export class TestComponent {
-    constructor(private modalService: ModalService) {}
-
-    handleClick() {
-        this.modalService
-            .dialog({
-                title: 'Did it work?',
-                buttons: [{ label: 'Yes!!!!', returnValue: true, type: 'primary' }],
-            })
-            .subscribe(val => {
-                // tslint:disable-next-line:no-console
-                console.log(val);
-            });
-    }
-}
-
-@NgModule({
-    imports: [
-        SharedModule,
-        RouterModule.forChild([
-            {
-                path: 'test',
-                component: TestComponent,
-            },
-        ]),
-    ],
-    declarations: [TestComponent],
-})
-export class TestModule {}

+ 125 - 4
packages/dev-server/ui-plugin/shared-module/ui-shared-plugin.module.ts

@@ -1,10 +1,113 @@
-import { APP_INITIALIZER, NgModule } from '@angular/core';
-import { NavBuilderService, SharedModule } from '@vendure/admin-ui/src';
-import { interval } from 'rxjs';
-import { map } from 'rxjs/operators';
+import { APP_INITIALIZER, ChangeDetectorRef, Component, NgModule, OnInit } from '@angular/core';
+import { FormControl } from '@angular/forms';
+import {
+    AssetPickerDialogComponent,
+    CustomFieldComponentService,
+    CustomFieldConfig,
+    CustomFieldControl,
+    DataService,
+    ModalService,
+    NavBuilderService,
+    SharedModule,
+} from '@vendure/admin-ui/src';
+import { unique } from '@vendure/common/lib/unique';
+import gql from 'graphql-tag';
+import { Observable, of } from 'rxjs';
+import { startWith, switchMap } from 'rxjs/operators';
+
+@Component({
+    template: `
+        <input
+            type="range"
+            [min]="customFieldConfig.intMin"
+            [max]="customFieldConfig.intMax"
+            [formControl]="formControl"
+        />
+        {{ formControl.value }}
+    `,
+})
+export class SliderControl implements CustomFieldControl {
+    customFieldConfig: CustomFieldConfig;
+    formControl: FormControl;
+}
+
+@Component({
+    template: `
+        <div class="featured-asset">
+            <img
+                *ngIf="currentAsset$ | async as asset; else placeholder"
+                [src]="asset!.preview + '?preset=thumb'"
+            />
+            <ng-template #placeholder>
+                <div class="placeholder">
+                    <clr-icon shape="image" size="128"></clr-icon>
+                    <div>{{ 'catalog.no-featured-asset' | translate }}</div>
+                </div>
+            </ng-template>
+        </div>
+        <button class="btn" (click)="selectAssets()">
+            <clr-icon shape="attachment"></clr-icon>
+            {{ 'catalog.add-asset' | translate }}
+        </button>
+    `,
+})
+export class AssetPickerControl implements CustomFieldControl, OnInit {
+    customFieldConfig: CustomFieldConfig;
+    formControl: FormControl;
+    currentAsset$: Observable<any | null>;
+
+    constructor(
+        private changeDetectorRef: ChangeDetectorRef,
+        private modalService: ModalService,
+        private dataService: DataService,
+    ) {}
+
+    ngOnInit(): void {
+        this.currentAsset$ = this.formControl.valueChanges.pipe(
+            startWith(this.formControl.value),
+            switchMap(assetId => {
+                if (!assetId) {
+                    return of(null);
+                }
+                return this.dataService
+                    .query(
+                        gql`
+                            query($id: ID!) {
+                                asset(id: $id) {
+                                    id
+                                    name
+                                    preview
+                                    width
+                                    height
+                                }
+                            }
+                        `,
+                        { id: assetId },
+                    )
+                    .mapStream((data: any) => data.asset);
+            }),
+        );
+    }
+
+    selectAssets() {
+        this.modalService
+            .fromComponent(AssetPickerDialogComponent, {
+                size: 'xl',
+            })
+            .subscribe((result: any) => {
+                if (result && result.length) {
+                    this.formControl.setValue(result[0].id);
+                    this.formControl.markAsDirty();
+                    // this.changeDetectorRef.markForCheck();
+                }
+            });
+    }
+}
 
 @NgModule({
     imports: [SharedModule],
+    declarations: [SliderControl, AssetPickerControl],
+    entryComponents: [SliderControl, AssetPickerControl],
     providers: [
         {
             provide: APP_INITIALIZER,
@@ -12,10 +115,28 @@ import { map } from 'rxjs/operators';
             useFactory: addNavItems,
             deps: [NavBuilderService],
         },
+        {
+            provide: APP_INITIALIZER,
+            multi: true,
+            useFactory: registerCustomFieldComponents,
+            deps: [CustomFieldComponentService],
+        },
     ],
 })
 export class TestSharedModule {}
 
+export function registerCustomFieldComponents(customFieldComponentService: CustomFieldComponentService) {
+    return () => {
+        customFieldComponentService.registerCustomFieldComponent('Product', 'length', SliderControl);
+        customFieldComponentService.registerCustomFieldComponent('ProductVariant', 'length', SliderControl);
+        customFieldComponentService.registerCustomFieldComponent(
+            'Product',
+            'offerImageId',
+            AssetPickerControl,
+        );
+    };
+}
+
 export function addNavItems(navBuilder: NavBuilderService) {
     return () => {
         navBuilder.addNavMenuSection(