Skip to content

Commit 9cf6fbf

Browse files
committed
V14: Integrations (Shopify)
- Update product list
1 parent 536461a commit 9cf6fbf

File tree

9 files changed

+225
-83
lines changed

9 files changed

+225
-83
lines changed

src/Umbraco.Cms.Integrations.Commerce.Shopify/Client/src/config/amount/amount-property-editor.element.ts

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,56 @@
11
import { UmbElementMixin } from "@umbraco-cms/backoffice/element-api";
2+
import { UmbPropertyEditorUiElement } from "@umbraco-cms/backoffice/extension-registry";
23
import { LitElement, customElement, html, property } from "@umbraco-cms/backoffice/external/lit";
3-
import { SHOPIFY_CONTEXT_TOKEN } from "../../context/shopify.context";
4+
import { UmbLitElement } from "@umbraco-cms/backoffice/lit-element";
5+
import { UmbPropertyValueChangeEvent } from '@umbraco-cms/backoffice/property-editor';
6+
import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
47

58
const elementName = "shopify-amount";
69

710
@customElement(elementName)
8-
export class ShopifyAmountElement extends UmbElementMixin(LitElement){
9-
#shopifyContext!: typeof SHOPIFY_CONTEXT_TOKEN.TYPE;
10-
@property()
11-
minValue: number = 0;
12-
maxValue: number = 0;
11+
export class ShopifyAmountElement extends UmbLitElement implements UmbPropertyEditorUiElement{
12+
@property({ type: Number })
13+
min?: number;
1314

14-
render() {
15+
@property({ type: Number })
16+
max?: number;
17+
18+
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
19+
if (!config) return;
20+
21+
this.min = this.#parseInt(config.getValueByAlias('amountMin'));
22+
this.max = this.#parseInt(config.getValueByAlias('amountMax'));
23+
}
24+
25+
#parseInt(input: unknown): number | undefined {
26+
const num = Number(input);
27+
return Number.isNaN(num) ? undefined : num;
28+
}
29+
30+
#onMinInput(e: InputEvent & { target: HTMLInputElement }) {
31+
this.min = this.#parseInt(e.target.value);
32+
this.dispatchEvent(new UmbPropertyValueChangeEvent());
33+
}
34+
35+
#onMaxInput(e: InputEvent & { target: HTMLInputElement }) {
36+
this.max = this.#parseInt(e.target.value);
37+
this.dispatchEvent(new UmbPropertyValueChangeEvent());
38+
}
39+
40+
override render() {
1541
return html`
1642
<div>
17-
<uui-input .value=${this.minValue}></uui-input>
43+
<uui-input
44+
type="number"
45+
.value=${this.min}
46+
@input=${this.#onMinInput}></uui-input>
47+
</uui-input>
1848
<span>-</span>
19-
<uui-input placeholder="" .value=${this.maxValue}></uui-input>
49+
<uui-input
50+
type="number"
51+
.value=${this.max}
52+
@input=${this.#onMaxInput}></uui-input>
53+
</uui-input>
2054
</div>
2155
`;
2256
}

src/Umbraco.Cms.Integrations.Commerce.Shopify/Client/src/context/shopify.context.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ import { UmbContextToken } from "@umbraco-cms/backoffice/context-api";
33
import type { UmbControllerHost } from "@umbraco-cms/backoffice/controller-api";
44
import { ShopifyRepository } from "../repository/shopify.repository";
55
import { type OAuthRequestDtoModel } from "@umbraco-integrations/shopify/generated";
6+
import { UmbObjectState } from "@umbraco-cms/backoffice/observable-api";
67

78
export class ShopifyContext extends UmbControllerBase{
89
#repository: ShopifyRepository;
10+
#data = new UmbObjectState<string | undefined>(undefined);
911

1012
constructor(host: UmbControllerHost){
1113
super(host);
@@ -49,6 +51,10 @@ export class ShopifyContext extends UmbControllerBase{
4951
async refreshAccessToken(){
5052
return await this.#repository.refreshAccessToken();
5153
}
54+
55+
getData() {
56+
return this.#data.getValue();
57+
}
5258
}
5359

5460
export default ShopifyContext;
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
export const SHOPIFY_COLLECTION_TYPE = 'ShopifyProducts';
2-
export const SHOPIFY_VARIANTS_COLLECTION_TYPE = 'ShopifyProductVariants';
32

43
export type ShopifyCollectionEntityType = typeof SHOPIFY_COLLECTION_TYPE;
5-
export type ShopifyVariantsCollectionEntityType = typeof SHOPIFY_VARIANTS_COLLECTION_TYPE;

src/Umbraco.Cms.Integrations.Commerce.Shopify/Client/src/modal/shopify-products-modal.element.ts

Lines changed: 106 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { UmbModalBaseElement } from "@umbraco-cms/backoffice/modal";
22
import { SHOPIFY_CONTEXT_TOKEN } from "../context/shopify.context.js";
33
import { UMB_NOTIFICATION_CONTEXT } from "@umbraco-cms/backoffice/notification";
4-
import { html, css, state, customElement } from "@umbraco-cms/backoffice/external/lit";
4+
import { html, state, customElement, css } from "@umbraco-cms/backoffice/external/lit";
55
import type { ProductDtoModel } from "../../generated";
66
import type { ShopifyProductPickerModalData, ShopifyProductPickerModalValue } from "./shopify.modal-token.js";
77
import type { ShopifyServiceStatus } from "../models/shopify-service.model.js";
8-
import type { UmbTableColumn, UmbTableConfig, UmbTableItem, UmbTableSelectedEvent, UmbTableElement, UmbTableDeselectedEvent } from '@umbraco-cms/backoffice/components';
9-
import type {ShopifyCollectionModel} from "../types/types.js";
8+
import type { UmbTableColumn, UmbTableConfig, UmbTableItem, UmbTableSelectedEvent, UmbTableElement, UmbTableDeselectedEvent, UmbTableItemData } from '@umbraco-cms/backoffice/components';
9+
import type { ShopifyCollectionModel } from "../types/types.js";
1010
import type { UmbDefaultCollectionContext } from '@umbraco-cms/backoffice/collection';
1111
import { UMB_COLLECTION_CONTEXT } from '@umbraco-cms/backoffice/collection';
1212

@@ -16,15 +16,35 @@ const elementName = "shopify-products-modal";
1616
export default class ShopifyProductsModalElement extends UmbModalBaseElement<ShopifyProductPickerModalData, ShopifyProductPickerModalValue>{
1717
#shopifyContext!: typeof SHOPIFY_CONTEXT_TOKEN.TYPE;
1818
#collectionContext!: UmbDefaultCollectionContext<ShopifyCollectionModel>;
19-
19+
_modalSelectedProducts: Array<ProductDtoModel> = [];
20+
_numberOfSelection: number = 0;
21+
_selectionIdList: Array<string | null> = [];
22+
2023
@state()
21-
private _selection: Array<string> = [];
24+
private _selection: Array<string | null> = [];
2225

2326
@state()
2427
private _tableConfig: UmbTableConfig = {
2528
allowSelection: true,
2629
};
2730

31+
@state()
32+
private _tableItems: Array<UmbTableItem> = [];
33+
34+
@state()
35+
private _serviceStatus: ShopifyServiceStatus = {
36+
isValid: false,
37+
type: "",
38+
description: "",
39+
useOAuth: false
40+
};
41+
42+
@state()
43+
private _loading = false;
44+
45+
@state()
46+
private _products: Array<ProductDtoModel> = [];
47+
2848
@state()
2949
private _tableColumns: Array<UmbTableColumn> = [
3050
{
@@ -61,23 +81,6 @@ export default class ShopifyProductsModalElement extends UmbModalBaseElement<Sho
6181
},
6282
];
6383

64-
@state()
65-
private _tableItems: Array<UmbTableItem> = [];
66-
67-
@state()
68-
private _serviceStatus: ShopifyServiceStatus = {
69-
isValid: false,
70-
type: "",
71-
description: "",
72-
useOAuth: false
73-
};
74-
75-
@state()
76-
private _loading = false;
77-
78-
@state()
79-
private _products: Array<ProductDtoModel> = [];
80-
8184
constructor() {
8285
super();
8386

@@ -87,7 +90,14 @@ export default class ShopifyProductsModalElement extends UmbModalBaseElement<Sho
8790

8891
this.consumeContext(UMB_COLLECTION_CONTEXT, (instance) => {
8992
this.#collectionContext = instance;
93+
this.observe(
94+
this.#collectionContext.selection.selection,
95+
(selection) => (this._selection = selection),
96+
'umbCollectionSelectionObserver',
97+
);
9098
});
99+
100+
91101
}
92102

93103
async connectedCallback() {
@@ -124,21 +134,61 @@ export default class ShopifyProductsModalElement extends UmbModalBaseElement<Sho
124134
}
125135

126136
this.#createTableItems(this._products);
137+
this._selection = this.data!.selectedItemIdList;
127138
}
128139

129140
#onSelected(event: UmbTableSelectedEvent) {
130-
event.stopPropagation();
131-
const table = event.target as UmbTableElement;
132-
const selection = table.selection;
133-
this.#collectionContext?.selection.setSelection(selection);
141+
this.#onEventRun(event);
134142
}
135143

136144
#onDeselected(event: UmbTableDeselectedEvent) {
137-
event.stopPropagation();
145+
this.#onEventRun(event);
146+
}
147+
148+
#onEventRun(event: UmbTableSelectedEvent | UmbTableDeselectedEvent){
149+
event.stopPropagation();
138150
const table = event.target as UmbTableElement;
139151
const selection = table.selection;
152+
const items = table.items;
140153
this.#collectionContext?.selection.setSelection(selection);
141-
}
154+
155+
this.#getSelectedProduct(selection, items);
156+
this._numberOfSelection = selection.length;
157+
}
158+
159+
#getSelectedProduct(selectedRows: Array<string>, allRows: Array<UmbTableItem>){
160+
let lst: Array<UmbTableItem[]> = [];
161+
selectedRows.forEach(selectedRow => {
162+
const selectedProduct = allRows.filter(r => r.id == selectedRow);
163+
lst.push(selectedProduct);
164+
});
165+
166+
let lstData = lst.map(l => l[0].data);
167+
let lstId = lst.map(l => l[0].id);
168+
this._modalSelectedProducts = this.#mapToDto(lstData, lstId);
169+
}
170+
171+
#mapToDto(lstData: UmbTableItemData[][], lstId: string[]){
172+
let productList: Array<ProductDtoModel> = [];
173+
for(let i = 0; i < lstData.length; i++){
174+
let dto: ProductDtoModel = {
175+
title: lstData[i].find(x => x.columnAlias == "productName")?.value,
176+
vendor: lstData[i].find(x => x.columnAlias == "vendor")?.value,
177+
id: Number(lstId[i]),
178+
body: "",
179+
status: lstData[i].find(x => x.columnAlias == "status")?.value,
180+
tags: lstData[i].find(x => x.columnAlias == "tags")?.value,
181+
variants: [],
182+
image: {
183+
src: ""
184+
}
185+
}
186+
187+
productList.push(dto);
188+
}
189+
190+
return productList;
191+
}
142192

143193
private async _showError(message: string) {
144194
const notificationContext = await this.getContext(UMB_NOTIFICATION_CONTEXT);
@@ -185,10 +235,23 @@ export default class ShopifyProductsModalElement extends UmbModalBaseElement<Sho
185235
});
186236
}
187237

238+
_onSubmit() {
239+
if(this._numberOfSelection > 2){
240+
this._showError("Cannot select more than 2 products."!);
241+
}else{
242+
if(this._modalSelectedProducts.length == 0){
243+
this._rejectModal();
244+
}
245+
246+
this.value = {productList: this._modalSelectedProducts};
247+
this._submitModal();
248+
}
249+
}
250+
188251
render() {
189252
return html`
190253
<umb-body-layout>
191-
<uui-box headline="Shopify Products">
254+
<uui-box headline=${this.data!.headline}>
192255
${this._loading ? html`<div class="center"><uui-loader></uui-loader></div>` : ""}
193256
<umb-table
194257
.config=${this._tableConfig}
@@ -199,11 +262,23 @@ export default class ShopifyProductsModalElement extends UmbModalBaseElement<Sho
199262
@deselected="${this.#onDeselected}"></umb-table>
200263
201264
</uui-box>
202-
<span>Add up to x items(s)</span>
203265
204-
<uui-button slot="actions" label="Submit" @click=${this._submitModal}></uui-button>
266+
<div class="maximum-selection">
267+
<span>
268+
Add up to 2 items(s)
269+
</span>
270+
</div>
271+
272+
<uui-button look="primary" slot="actions" label="Submit" @click=${this._onSubmit}></uui-button>
205273
<uui-button slot="actions" label="Close" @click=${this._rejectModal}></uui-button>
206274
</umb-body-layout>
207275
`;
208276
}
277+
278+
static styles = [css`
279+
.maximum-selection{
280+
margin-top: 10px;
281+
font-weight: bold;
282+
}
283+
`];
209284
}

src/Umbraco.Cms.Integrations.Commerce.Shopify/Client/src/modal/shopify.modal-token.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1+
import { UmbTableItem } from "@umbraco-cms/backoffice/components";
12
import { UmbModalToken } from "@umbraco-cms/backoffice/modal";
3+
import { UmbSelectionManager } from "@umbraco-cms/backoffice/utils";
24
import type { ProductDtoModel } from "@umbraco-integrations/shopify/generated";
35

46
export type ShopifyProductPickerModalData = {
57
headline: string;
8+
selectedItemIdList: Array<string | null>;
69
}
710

811
export type ShopifyProductPickerModalValue = {
9-
products: Array<ProductDtoModel>;
12+
productList: Array<ProductDtoModel>;
1013
}
1114

1215
export const SHOPIFY_MODAL_TOKEN = new UmbModalToken<ShopifyProductPickerModalData, ShopifyProductPickerModalValue>("Shopify.Modal", {

src/Umbraco.Cms.Integrations.Commerce.Shopify/Client/src/property-editor/manifests.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ export const propertyEditorUiManifest : ManifestPropertyEditorUi = {
66
type: "propertyEditorUi",
77
alias: "Shopify.PropertyEditorUi.ProductPicker",
88
name: "Shopify Product Picker Property Editor UI",
9-
js: () => import("./shopify-product-picker-property-editor.element.js"),
10-
elementName: "shopify-product-picker",
9+
element: () => import("./shopify-product-picker-property-editor.element.js"),
1110
meta: {
1211
label: "Shopify Product Picker",
1312
icon: "icon-shopping-basket-alt",
@@ -26,6 +25,15 @@ export const propertyEditorUiManifest : ManifestPropertyEditorUi = {
2625
label: 'Amount',
2726
description: 'Set a required range of items selected.',
2827
propertyEditorUiAlias: 'Shopify.PropertyEditorUi.Amount',
28+
config: [
29+
{
30+
alias: 'amountMin',
31+
value: 0,
32+
},{
33+
alias: 'amountMax',
34+
value: 2,
35+
}
36+
],
2937
}
3038
]
3139
}

0 commit comments

Comments
 (0)