Browse Source

feat(admin-ui): Enable adding options to single-variant Products

Relates to #162
Michael Bromley 6 years ago
parent
commit
73031714ac

+ 1 - 1
packages/admin-ui/src/app/catalog/components/product-detail/product-detail.component.ts

@@ -280,7 +280,7 @@ export class ProductDetailComponent extends BaseDetailComponent<ProductWithVaria
                         productGroup as FormGroup,
                         languageCode,
                     ) as CreateProductInput;
-                    return this.productDetailService.createProduct(
+                    return this.productDetailService.createProductWithVariants(
                         newProduct,
                         this.createVariantsConfig,
                         languageCode,

+ 4 - 4
packages/admin-ui/src/app/catalog/components/product-variants-editor/product-variants-editor.component.html

@@ -17,7 +17,7 @@
             clrInput
             [(ngModel)]="group.name"
             name="name"
-            readonly
+            [readonly]="!group.isNew"
         />
     </div>
     <div class="values">
@@ -31,7 +31,7 @@
         ></vdr-option-value-input>
     </div>
 </div>
-<button class="btn btn-primary-outline btn-sm" (click)="addOption()">
+<button class="btn btn-primary-outline btn-sm" (click)="addOption()" *ngIf="product.variants.length === 1">
     <clr-icon shape="plus"></clr-icon>
     {{ 'catalog.add-option' | translate }}
 </button>
@@ -49,7 +49,7 @@
         </tr>
         </thead>
         <tr
-            *ngFor="let variant of variants; trackBy: trackByFn"
+            *ngFor="let variant of variants"
             [class.disabled]="!variantFormValues[variant.id].enabled || variantFormValues[variant.id].existing"
         >
             <td>
@@ -59,7 +59,7 @@
                     [(ngModel)]="variantFormValues[variant.id].enabled"
                     name="enabled"
                     clrCheckbox
-                    (ngModelChange)="onFormChanged(variantFormValues[variant.id])"
+                    (ngModelChange)="formValueChanged = true"
                 />
             </td>
             <td>

+ 26 - 3
packages/admin-ui/src/app/catalog/components/product-variants-editor/product-variants-editor.component.ts

@@ -59,9 +59,9 @@ export class ProductVariantsEditorComponent implements OnInit, DeactivateAware {
         }>;
     }>;
     variantFormValues: { [id: string]: VariantInfo } = {};
+    product: GetProductVariantOptions.Product;
     private currencyCode: CurrencyCode;
     private languageCode: LanguageCode;
-    private product: GetProductVariantOptions.Product;
 
     constructor(
         private route: ActivatedRoute,
@@ -195,9 +195,11 @@ export class ProductVariantsEditorComponent implements OnInit, DeactivateAware {
                 values: [],
             }));
 
-        this.productDetailService
-            .createProductOptionGroups(newOptionGroups, this.languageCode)
+        this.confirmDeletionOfDefault()
             .pipe(
+                mergeMap(() =>
+                    this.productDetailService.createProductOptionGroups(newOptionGroups, this.languageCode),
+                ),
                 mergeMap(createdOptionGroups => this.addOptionGroupsToProduct(createdOptionGroups)),
                 mergeMap(createdOptionGroups => this.addNewOptionsToGroups(createdOptionGroups)),
                 mergeMap(groupsIds => this.fetchOptionGroups(groupsIds)),
@@ -216,6 +218,27 @@ export class ProductVariantsEditorComponent implements OnInit, DeactivateAware {
             });
     }
 
+    private confirmDeletionOfDefault(): Observable<boolean> {
+        if (this.product.variants.length === 1) {
+            return this.modalService
+                .dialog({
+                    title: _('catalog.confirm-adding-options-delete-default-title'),
+                    body: _('catalog.confirm-adding-options-delete-default-body'),
+                    buttons: [
+                        { type: 'seconday', label: _('common.cancel') },
+                        { type: 'danger', label: _('catalog.delete-default-variant'), returnValue: true },
+                    ],
+                })
+                .pipe(
+                    mergeMap(res => {
+                        return res === true ? of(true) : EMPTY;
+                    }),
+                );
+        } else {
+            return of(true);
+        }
+    }
+
     private addOptionGroupsToProduct(
         createdOptionGroups: CreateProductOptionGroup.CreateProductOptionGroup[],
     ): Observable<CreateProductOptionGroup.CreateProductOptionGroup[]> {

+ 22 - 18
packages/admin-ui/src/app/catalog/providers/product-detail.service.ts

@@ -53,32 +53,17 @@ export class ProductDetailService {
             .pipe(shareReplay(1));
     }
 
-    createProduct(
+    createProductWithVariants(
         input: CreateProductInput,
         createVariantsConfig: CreateProductVariantsConfig,
         languageCode: LanguageCode,
     ) {
         const createProduct$ = this.dataService.product.createProduct(input);
-
         const nonEmptyOptionGroups = createVariantsConfig.groups.filter(g => 0 < g.values.length);
-        const createOptionGroups$ = nonEmptyOptionGroups.length
-            ? forkJoin(
-                  createVariantsConfig.groups.map(c => {
-                      return this.dataService.product.createProductOptionGroups({
-                          code: normalizeString(c.name, '-'),
-                          translations: [{ languageCode, name: c.name }],
-                          options: c.values.map(v => ({
-                              code: normalizeString(v, '-'),
-                              translations: [{ languageCode, name: v }],
-                          })),
-                      });
-                  }),
-              )
-            : of([]);
+        const createOptionGroups$ = this.createProductOptionGroups(nonEmptyOptionGroups, languageCode);
 
         return forkJoin(createProduct$, createOptionGroups$).pipe(
-            mergeMap(([{ createProduct }, createOptionGroups]) => {
-                const optionGroups = createOptionGroups.map(g => g.createProductOptionGroup);
+            mergeMap(([{ createProduct }, optionGroups]) => {
                 const addOptionsToProduct$ = optionGroups.length
                     ? forkJoin(
                           optionGroups.map(optionGroup => {
@@ -119,6 +104,25 @@ export class ProductDetailService {
         );
     }
 
+    createProductOptionGroups(groups: Array<{ name: string; values: string[] }>, languageCode: LanguageCode) {
+        return groups.length
+            ? forkJoin(
+                  groups.map(c => {
+                      return this.dataService.product
+                          .createProductOptionGroups({
+                              code: normalizeString(c.name, '-'),
+                              translations: [{ languageCode, name: c.name }],
+                              options: c.values.map(v => ({
+                                  code: normalizeString(v, '-'),
+                                  translations: [{ languageCode, name: v }],
+                              })),
+                          })
+                          .pipe(map(data => data.createProductOptionGroup));
+                  }),
+              )
+            : of([]);
+    }
+
     createProductVariants(
         product: { name: string; id: string },
         variantData: Array<{ price: number; sku: string; stock: number; optionIds: string[] }>,

+ 4 - 0
packages/admin-ui/src/i18n-messages/en.json

@@ -30,6 +30,8 @@
     "add-option": "Add option",
     "assets-selected-count": "{ count } assets selected",
     "collection-contents": "Collection contents",
+    "confirm-adding-options-delete-default-body": "Adding options to this product will cause the existing default variant to be deleted. Do you wish to proceed?",
+    "confirm-adding-options-delete-default-title": "Delete default variant?",
     "confirm-delete-collection": "Delete collection?",
     "confirm-delete-country": "Delete country?",
     "confirm-delete-facet": "Delete facet?",
@@ -41,6 +43,8 @@
     "create-new-facet": "Create new facet",
     "create-new-product": "New product",
     "created-new-variants-success": "Successfully created {count} new {count, plural, one {variant} other {variants}}",
+    "default-variant": "Default variant",
+    "delete-default-variant": "Delete default variant",
     "display-variant-cards": "View details",
     "display-variant-table": "View as table",
     "drop-files-to-upload": "Drop files to upload",