Просмотр исходного кода

feat(admin-ui): Implement modifying a product's assets

Michael Bromley 7 лет назад
Родитель
Сommit
b85b5a03b6

+ 2 - 0
admin-ui/src/app/catalog/components/asset-gallery/asset-gallery.component.scss

@@ -9,10 +9,12 @@
     flex: 1;
     display: grid;
     grid-template-columns: repeat(auto-fill, 150px);
+    grid-template-rows: repeat(auto-fill, 180px);
     grid-gap: 10px 20px;
     overflow-y: auto;
     padding-left: 12px;
     padding-top: 12px;
+    padding-bottom: 12px;
 
     .card:hover {
         box-shadow: 0 0.125rem 0 0 $color-brand;

+ 11 - 1
admin-ui/src/app/catalog/components/product-assets/product-assets.component.ts

@@ -25,7 +25,7 @@ import { AssetPickerDialogComponent } from '../asset-picker-dialog/asset-picker-
 export class ProductAssetsComponent {
     @Input() assets: Asset[] = [];
     @Input() featuredAsset: Asset | undefined;
-    @Output() change = new EventEmitter<{ assetIds: string[]; featuredAssetId: string }>();
+    @Output() change = new EventEmitter<{ assetIds: string[]; featuredAssetId: string | undefined }>();
 
     constructor(private modalService: ModalService, private changeDetector: ChangeDetectorRef) {}
 
@@ -45,6 +45,7 @@ export class ProductAssetsComponent {
                     if (!this.featuredAsset) {
                         this.featuredAsset = result[0];
                     }
+                    this.emitChangeEvent(this.assets, this.featuredAsset);
                     this.changeDetector.markForCheck();
                 }
             });
@@ -52,6 +53,7 @@ export class ProductAssetsComponent {
 
     setAsFeatured(asset: Asset) {
         this.featuredAsset = asset;
+        this.emitChangeEvent(this.assets, asset);
     }
 
     isFeatured(asset: Asset): boolean {
@@ -63,5 +65,13 @@ export class ProductAssetsComponent {
         if (this.featuredAsset && this.featuredAsset.id === asset.id) {
             this.featuredAsset = this.assets.length > 0 ? this.assets[0] : undefined;
         }
+        this.emitChangeEvent(this.assets, this.featuredAsset);
+    }
+
+    private emitChangeEvent(assets: Asset[], featuredAsset: Asset | undefined) {
+        this.change.emit({
+            assetIds: assets.map(a => a.id),
+            featuredAssetId: featuredAsset && featuredAsset.id,
+        });
     }
 }

+ 3 - 2
admin-ui/src/app/catalog/components/product-detail/product-detail.component.html

@@ -14,7 +14,7 @@
         <ng-template #updateButton>
             <button class="btn btn-primary"
                     (click)="save()"
-                    [disabled]="productForm.invalid || productForm.pristine">{{ 'common.update' | translate }}</button>
+                    [disabled]="(productForm.invalid || productForm.pristine) && !assetsChanged()">{{ 'common.update' | translate }}</button>
         </ng-template>
     </vdr-ab-right>
 </vdr-action-bar>
@@ -47,7 +47,8 @@
         </div>
         <div class="clr-col-md-auto">
             <vdr-product-assets [assets]="product.assets"
-                                [featuredAsset]="product.featuredAsset"></vdr-product-assets>
+                                [featuredAsset]="product.featuredAsset"
+                                (change)="assetChanges = $event"></vdr-product-assets>
         </div>
     </div>
 

+ 20 - 6
admin-ui/src/app/catalog/components/product-detail/product-detail.component.ts

@@ -36,6 +36,7 @@ export class ProductDetailComponent extends BaseDetailComponent<ProductWithVaria
     customFields: CustomFieldConfig[];
     customVariantFields: CustomFieldConfig[];
     productForm: FormGroup;
+    assetChanges: { assetIds?: string[]; featuredAssetId?: string } = {};
 
     constructor(
         route: ActivatedRoute,
@@ -79,6 +80,10 @@ export class ProductDetailComponent extends BaseDetailComponent<ProductWithVaria
         return !!this.productForm.get(['product', 'customFields', name]);
     }
 
+    assetsChanged(): boolean {
+        return !!Object.values(this.assetChanges).length;
+    }
+
     /**
      * If creating a new product, automatically generate the slug based on the product name.
      */
@@ -137,6 +142,7 @@ export class ProductDetailComponent extends BaseDetailComponent<ProductWithVaria
                     this.notificationService.success(_('common.notify-create-success'), {
                         entity: 'Product',
                     });
+                    this.assetChanges = {};
                     this.productForm.markAsPristine();
                     this.router.navigate(['../', data.createProduct.id], { relativeTo: this.route });
                 },
@@ -157,7 +163,7 @@ export class ProductDetailComponent extends BaseDetailComponent<ProductWithVaria
                     const productGroup = this.productForm.get('product');
                     const updateOperations: Array<Observable<any>> = [];
 
-                    if (productGroup && productGroup.dirty) {
+                    if ((productGroup && productGroup.dirty) || this.assetsChanged()) {
                         const newProduct = this.getUpdatedProduct(
                             product,
                             productGroup as FormGroup,
@@ -183,6 +189,7 @@ export class ProductDetailComponent extends BaseDetailComponent<ProductWithVaria
             .subscribe(
                 () => {
                     this.productForm.markAsPristine();
+                    this.assetChanges = {};
                     this.notificationService.success(_('common.notify-update-success'), {
                         entity: 'Product',
                     });
@@ -255,12 +262,19 @@ export class ProductDetailComponent extends BaseDetailComponent<ProductWithVaria
         productFormGroup: FormGroup,
         languageCode: LanguageCode,
     ): UpdateProductInput | CreateProductInput {
-        return createUpdatedTranslatable(product, productFormGroup.value, this.customFields, languageCode, {
+        const updatedProduct = createUpdatedTranslatable(
+            product,
+            productFormGroup.value,
+            this.customFields,
             languageCode,
-            name: product.name || '',
-            slug: product.slug || '',
-            description: product.description || '',
-        });
+            {
+                languageCode,
+                name: product.name || '',
+                slug: product.slug || '',
+                description: product.description || '',
+            },
+        );
+        return { ...updatedProduct, ...this.assetChanges } as UpdateProductInput | CreateProductInput;
     }
 
     /**

+ 2 - 2
admin-ui/src/app/data/providers/product-data.service.ts

@@ -79,7 +79,7 @@ export class ProductDataService {
 
     createProduct(product: CreateProductInput): Observable<CreateProduct> {
         const input: CreateProductVariables = {
-            input: pick(product, ['translations', 'customFields']),
+            input: pick(product, ['translations', 'customFields', 'assetIds', 'featuredAssetId']),
         };
         return this.baseDataService.mutate<CreateProduct, CreateProductVariables>(
             addCustomFields(CREATE_PRODUCT),
@@ -89,7 +89,7 @@ export class ProductDataService {
 
     updateProduct(product: UpdateProductInput): Observable<UpdateProduct> {
         const input: UpdateProductVariables = {
-            input: pick(product, ['id', 'translations', 'customFields']),
+            input: pick(product, ['id', 'translations', 'customFields', 'assetIds', 'featuredAssetId']),
         };
         return this.baseDataService.mutate<UpdateProduct, UpdateProductVariables>(
             addCustomFields(UPDATE_PRODUCT),