Skip to content

Commit

Permalink
feat(admin-ui): Implement variant channel assignment controls
Browse files Browse the repository at this point in the history
Relates to #519
  • Loading branch information
michaelbromley committed Nov 24, 2020
1 parent 799f306 commit 83a33b5
Show file tree
Hide file tree
Showing 24 changed files with 334 additions and 69 deletions.
30 changes: 15 additions & 15 deletions packages/admin-ui/i18n-coverage.json
Original file line number Diff line number Diff line change
@@ -1,44 +1,44 @@
{
"generatedOn": "2020-11-20T14:39:19.815Z",
"lastCommit": "60fd856bbcf3389d1b488e4f3e51a4eeaca85370",
"generatedOn": "2020-11-24T15:53:35.931Z",
"lastCommit": "799f30643a3e221e453246534d844bf448b046e5",
"translationStatus": {
"cs": {
"tokenCount": 703,
"tokenCount": 708,
"translatedCount": 688,
"percentage": 98
"percentage": 97
},
"de": {
"tokenCount": 703,
"tokenCount": 708,
"translatedCount": 597,
"percentage": 85
"percentage": 84
},
"en": {
"tokenCount": 703,
"translatedCount": 699,
"tokenCount": 708,
"translatedCount": 703,
"percentage": 99
},
"es": {
"tokenCount": 703,
"tokenCount": 708,
"translatedCount": 455,
"percentage": 65
"percentage": 64
},
"pl": {
"tokenCount": 703,
"tokenCount": 708,
"translatedCount": 552,
"percentage": 79
"percentage": 78
},
"pt_BR": {
"tokenCount": 703,
"tokenCount": 708,
"translatedCount": 643,
"percentage": 91
},
"zh_Hans": {
"tokenCount": 703,
"tokenCount": 708,
"translatedCount": 536,
"percentage": 76
},
"zh_Hant": {
"tokenCount": 703,
"tokenCount": 708,
"translatedCount": 536,
"percentage": 76
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
<ng-template vdrDialogTitle>{{ 'catalog.assign-products-to-channel' | translate }}</ng-template>
<ng-template vdrDialogTitle>
<ng-container *ngIf="isProductVariantMode; else productModeTitle">{{
'catalog.assign-variants-to-channel' | translate
}}</ng-container>
<ng-template #productModeTitle>{{ 'catalog.assign-products-to-channel' | translate }}</ng-template>
</ng-template>

<div class="flex">
<clr-input-container>
Expand All @@ -7,6 +12,7 @@
clrInput
[multiple]="false"
[includeDefaultChannel]="false"
[disableChannelIds]="currentChannelIds"
[formControl]="selectedChannelIdControl"
></vdr-channel-assignment-control>
</clr-input-container>
Expand Down Expand Up @@ -47,9 +53,7 @@
<ng-template [ngIf]="selectedChannel" [ngIfElse]="noChannelSelected">
{{ row.pricePreview / 100 | currency: selectedChannel?.currencyCode }}
</ng-template>
<ng-template #noChannelSelected>
-
</ng-template>
<ng-template #noChannelSelected> - </ng-template>
</td>
</tr>
</tbody>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { combineLatest, from, Observable } from 'rxjs';
import { map, startWith, switchMap } from 'rxjs/operators';

import { GetChannels, ProductVariantFragment } from '@vendure/admin-ui/core';
import { NotificationService } from '@vendure/admin-ui/core';
import { DataService } from '@vendure/admin-ui/core';
import { Dialog } from '@vendure/admin-ui/core';
import { combineLatest, from, Observable } from 'rxjs';
import { map, startWith, switchMap } from 'rxjs/operators';

@Component({
selector: 'vdr-assign-products-to-channel-dialog',
Expand All @@ -26,6 +25,12 @@ export class AssignProductsToChannelDialogComponent implements OnInit, Dialog<an

// assigned by ModalService.fromComponent() call
productIds: string[];
productVariantIds: string[] | undefined;
currentChannelIds: string[];

get isProductVariantMode(): boolean {
return this.productVariantIds != null;
}

constructor(private dataService: DataService, private notificationService: NotificationService) {}

Expand Down Expand Up @@ -67,18 +72,33 @@ export class AssignProductsToChannelDialogComponent implements OnInit, Dialog<an
assign() {
const selectedChannel = this.selectedChannel;
if (selectedChannel) {
this.dataService.product
.assignProductsToChannel({
channelId: selectedChannel.id,
productIds: this.productIds,
priceFactor: +this.priceFactorControl.value,
})
.subscribe(() => {
this.notificationService.success(_('catalog.assign-product-to-channel-success'), {
channel: selectedChannel.code,
if (!this.isProductVariantMode) {
this.dataService.product
.assignProductsToChannel({
channelId: selectedChannel.id,
productIds: this.productIds,
priceFactor: +this.priceFactorControl.value,
})
.subscribe(() => {
this.notificationService.success(_('catalog.assign-product-to-channel-success'), {
channel: selectedChannel.code,
});
this.resolveWith(true);
});
this.resolveWith(true);
});
} else if (this.productVariantIds) {
this.dataService.product
.assignVariantsToChannel({
channelId: selectedChannel.id,
productVariantIds: this.productVariantIds,
priceFactor: +this.priceFactorControl.value,
})
.subscribe(() => {
this.notificationService.success(_('catalog.assign-variant-to-channel-success'), {
channel: selectedChannel.code,
});
this.resolveWith(true);
});
}
}
}

Expand All @@ -92,7 +112,12 @@ export class AssignProductsToChannelDialogComponent implements OnInit, Dialog<an
for (let i = 0; i < this.productIds.length && variants.length < take; i++) {
const productVariants = await this.dataService.product
.getProduct(this.productIds[i])
.mapSingle(({ product }) => product && product.variants)
.mapSingle(({ product }) => {
const _variants = product ? product.variants : [];
return _variants.filter(v =>
this.isProductVariantMode ? this.productVariantIds?.includes(v.id) : true,
);
})
.toPromise();
variants.push(...(productVariants || []));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,21 +65,19 @@
[label]="'common.channels' | translate"
*vdrIfDefaultChannelActive
>
<div class="flex">
<div class="product-channels">
<ng-container *ngFor="let channel of productChannels$ | async">
<vdr-chip
*ngIf="!isDefaultChannel(channel.code)"
icon="times-circle"
(iconClick)="removeFromChannel(channel.id)"
>
<vdr-channel-badge
[channelCode]="channel.code"
></vdr-channel-badge>
{{ channel.code | channelCodeToLabel }}
</vdr-chip>
</ng-container>
</div>
<div class="flex channel-assignment">
<ng-container *ngFor="let channel of productChannels$ | async">
<vdr-chip
*ngIf="!isDefaultChannel(channel.code)"
icon="times-circle"
(iconClick)="removeFromChannel(channel.id)"
>
<vdr-channel-badge
[channelCode]="channel.code"
></vdr-channel-badge>
{{ channel.code | channelCodeToLabel }}
</vdr-chip>
</ng-container>
<button class="btn btn-sm" (click)="assignToChannel()">
<clr-icon shape="layers"></clr-icon>
{{ 'catalog.assign-to-channel' | translate }}
Expand Down Expand Up @@ -225,6 +223,8 @@ <h4>{{ 'catalog.product-variants' | translate }}</h4>
[customFields]="customVariantFields"
[customOptionFields]="customOptionFields"
[activeLanguage]="languageCode$ | async"
(assignToChannel)="assignVariantToChannel($event)"
(removeFromChannel)="removeVariantFromChannel($event)"
(assetChange)="variantAssetChange($event)"
(updateProductOption)="updateProductOption($event)"
(selectionChange)="selectedVariantIds = $event"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,7 @@ vdr-action-bar clr-toggle-wrapper {
.edit-variants-btn {
margin-top: 0;
}

.channel-assignment {
flex-wrap: wrap;
}
Original file line number Diff line number Diff line change
Expand Up @@ -204,20 +204,74 @@ export class ProductDetailComponent
}

assignToChannel() {
this.productChannels$
.pipe(
take(1),
switchMap(channels => {
return this.modalService.fromComponent(AssignProductsToChannelDialogComponent, {
size: 'lg',
locals: {
productIds: [this.id],
currentChannelIds: channels.map(c => c.id),
},
});
}),
)
.subscribe();
}

removeFromChannel(channelId: string) {
this.modalService
.dialog({
title: _('catalog.remove-product-from-channel'),
buttons: [
{ type: 'secondary', label: _('common.cancel') },
{ type: 'danger', label: _('catalog.remove-from-channel'), returnValue: true },
],
})
.pipe(
switchMap(response =>
response
? this.dataService.product.removeProductsFromChannel({
channelId,
productIds: [this.id],
})
: EMPTY,
),
)
.subscribe(
() => {
this.notificationService.success(_('catalog.notify-remove-product-from-channel-success'));
},
err => {
this.notificationService.error(_('catalog.notify-remove-product-from-channel-error'));
},
);
}

assignVariantToChannel(variant: ProductWithVariants.Variants) {
return this.modalService
.fromComponent(AssignProductsToChannelDialogComponent, {
size: 'lg',
locals: {
productIds: [this.id],
productVariantIds: [variant.id],
currentChannelIds: variant.channels.map(c => c.id),
},
})
.subscribe();
}

removeFromChannel(channelId: string) {
removeVariantFromChannel({
channelId,
variant,
}: {
channelId: string;
variant: ProductWithVariants.Variants;
}) {
this.modalService
.dialog({
title: _('catalog.remove-product-from-channel'),
title: _('catalog.remove-product-variant-from-channel'),
buttons: [
{ type: 'secondary', label: _('common.cancel') },
{ type: 'danger', label: _('catalog.remove-from-channel'), returnValue: true },
Expand All @@ -226,19 +280,19 @@ export class ProductDetailComponent
.pipe(
switchMap(response =>
response
? this.dataService.product.removeProductsFromChannel({
? this.dataService.product.removeVariantsFromChannel({
channelId,
productIds: [this.id],
productVariantIds: [variant.id],
})
: EMPTY,
),
)
.subscribe(
() => {
this.notificationService.success(_('catalog.notify-remove-product-from-channel-success'));
this.notificationService.success(_('catalog.notify-remove-variant-from-channel-success'));
},
err => {
this.notificationService.error(_('catalog.notify-remove-product-from-channel-error'));
this.notificationService.error(_('catalog.notify-remove-variant-from-channel-error'));
},
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,27 @@
</div>
</div>
</div>
<ng-container *vdrIfMultichannel>
<div class="card-block" *vdrIfDefaultChannelActive>
<div class="flex channel-assignment">
<ng-container *ngFor="let channel of variant.channels">
<vdr-chip
*ngIf="!isDefaultChannel(channel.code)"
icon="times-circle"
[title]="'catalog.remove-from-channel' | translate"
(iconClick)="removeFromChannel.emit({ channelId: channel.id, variant: variant })"
>
<vdr-channel-badge [channelCode]="channel.code"></vdr-channel-badge>
{{ channel.code | channelCodeToLabel }}
</vdr-chip>
</ng-container>
<button class="btn btn-sm" (click)="assignToChannel.emit(variant)">
<clr-icon shape="layers"></clr-icon>
{{ 'catalog.assign-to-channel' | translate }}
</button>
</div>
</div>
</ng-container>
</ng-container>
</div>
<div class="table-footer">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,13 @@
}
}

.channel-assignment {
justify-content: flex-end;
.btn {
margin: 6px 12px 6px 0;
}
}

.out-of-stock-threshold-wrapper {
display: flex;
flex-direction: column;
Expand Down
Loading

0 comments on commit 83a33b5

Please sign in to comment.