@useinsider/guido 2.1.0-beta.42f5dfa → 2.1.0-beta.486ee9c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -0
- package/dist/@types/config/schemas.js +70 -65
- package/dist/components/Guido.vue.js +1 -1
- package/dist/components/Guido.vue2.js +69 -58
- package/dist/components/organisms/base/Toaster.vue.js +4 -4
- package/dist/components/organisms/base/Toaster.vue2.js +12 -9
- package/dist/components/organisms/email-preview/desktop-preview/EmailSizeIndicator.vue.js +5 -5
- package/dist/components/organisms/email-preview/desktop-preview/EmailSizeIndicator.vue2.js +2 -2
- package/dist/components/organisms/extensions/recommendation/FilterItem.vue.js +11 -13
- package/dist/components/organisms/extensions/recommendation/FilterItem.vue2.js +54 -23
- package/dist/components/organisms/extensions/recommendation/FilterSelectionDrawer.vue.js +7 -5
- package/dist/components/organisms/extensions/recommendation/FilterSelectionDrawer.vue2.js +34 -21
- package/dist/components/organisms/extensions/recommendation/Filters.vue.js +11 -11
- package/dist/components/organisms/extensions/recommendation/Filters.vue2.js +48 -36
- package/dist/components/organisms/extensions/recommendation/LogicAdapter.vue2.js +11 -9
- package/dist/components/organisms/header/HeaderWrapper.vue.js +9 -9
- package/dist/components/organisms/unsubscribe/UnsubscribePageSelection.vue.js +1 -1
- package/dist/components/organisms/unsubscribe/UnsubscribePageSelection.vue2.js +19 -19
- package/dist/composables/useBlocksConfig.js +26 -16
- package/dist/composables/useHtmlValidator.js +107 -119
- package/dist/composables/useRecommendation.js +9 -9
- package/dist/composables/useStripo.js +25 -23
- package/dist/composables/useVersionHistoryApi.js +1 -1
- package/dist/config/compiler/utils/recommendationCompilerUtils.js +28 -23
- package/dist/config/i18n/en/index.js +11 -0
- package/dist/config/i18n/en/labels.json.js +7 -0
- package/dist/config/i18n/en/toasters.json.js +56 -0
- package/dist/config/i18n/en/tooltips.json.js +82 -0
- package/dist/config/i18n/index.js +7 -0
- package/dist/config/migrator/itemsBlockMigrator.js +127 -122
- package/dist/config/migrator/recommendationMigrator.js +1 -1
- package/dist/enums/defaults.js +8 -4
- package/dist/extensions/Blocks/Recommendation/block.js +26 -23
- package/dist/extensions/Blocks/Recommendation/constants/defaultConfig.js +37 -33
- package/dist/extensions/Blocks/Recommendation/constants/layout.js +16 -12
- package/dist/extensions/Blocks/Recommendation/constants/selectors.js +15 -11
- package/dist/extensions/Blocks/Recommendation/controls/button/index.js +9 -9
- package/dist/extensions/Blocks/Recommendation/controls/image/index.js +1 -1
- package/dist/extensions/Blocks/Recommendation/controls/layout/index.js +41 -29
- package/dist/extensions/Blocks/Recommendation/controls/main/algorithm.js +16 -16
- package/dist/extensions/Blocks/Recommendation/controls/main/currency.js +30 -32
- package/dist/extensions/Blocks/Recommendation/controls/main/index.js +217 -94
- package/dist/extensions/Blocks/Recommendation/controls/main/locale.js +9 -9
- package/dist/extensions/Blocks/Recommendation/controls/main/productLayout.js +97 -39
- package/dist/extensions/Blocks/Recommendation/controls/main/shuffle.js +16 -16
- package/dist/extensions/Blocks/Recommendation/controls/main/utils.js +304 -209
- package/dist/extensions/Blocks/Recommendation/controls/mobileLayout/cssRules.js +21 -0
- package/dist/extensions/Blocks/Recommendation/controls/name/index.js +10 -10
- package/dist/extensions/Blocks/Recommendation/controls/name/textTrim.js +5 -5
- package/dist/extensions/Blocks/Recommendation/controls/oldPrice/index.js +14 -14
- package/dist/extensions/Blocks/Recommendation/controls/omnibusDiscount/index.js +9 -9
- package/dist/extensions/Blocks/Recommendation/controls/omnibusDiscount/textAfter.js +3 -3
- package/dist/extensions/Blocks/Recommendation/controls/omnibusDiscount/textBefore.js +1 -1
- package/dist/extensions/Blocks/Recommendation/controls/omnibusPrice/index.js +9 -9
- package/dist/extensions/Blocks/Recommendation/controls/omnibusPrice/textAfter.js +3 -3
- package/dist/extensions/Blocks/Recommendation/controls/omnibusPrice/textBefore.js +13 -13
- package/dist/extensions/Blocks/Recommendation/controls/price/index.js +3 -3
- package/dist/extensions/Blocks/Recommendation/controls/spacing/index.js +223 -99
- package/dist/extensions/Blocks/Recommendation/store/recommendation.js +237 -140
- package/dist/extensions/Blocks/Recommendation/templates/grid/elementRenderer.js +27 -32
- package/dist/extensions/Blocks/Recommendation/templates/grid/migration.js +1 -1
- package/dist/extensions/Blocks/Recommendation/templates/grid/template.js +27 -30
- package/dist/extensions/Blocks/Recommendation/templates/list/elementRenderer.js +22 -27
- package/dist/extensions/Blocks/Recommendation/templates/utils.js +50 -38
- package/dist/extensions/Blocks/Recommendation/utils/filterUtil.js +8 -8
- package/dist/extensions/Blocks/Recommendation/validation/filterSchema.js +29 -0
- package/dist/extensions/Blocks/Unsubscribe/block.js +29 -29
- package/dist/extensions/Blocks/Unsubscribe/control.js +12 -9
- package/dist/extensions/Blocks/Unsubscribe/elements/preview.js +13 -11
- package/dist/extensions/Blocks/Unsubscribe/styles.css.js +31 -1
- package/dist/extensions/ModulesTabIcons/extension.js +17 -0
- package/dist/guido.css +1 -1
- package/dist/node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js +257 -187
- package/dist/services/recommendationApi.js +11 -9
- package/dist/services/stripoApi.js +20 -17
- package/dist/src/@types/config/schemas.d.ts +8 -0
- package/dist/src/components/organisms/extensions/recommendation/FilterItem.vue.d.ts +1 -0
- package/dist/src/components/organisms/extensions/recommendation/Filters.vue.d.ts +17 -1
- package/dist/src/composables/useConfig.d.ts +4 -0
- package/dist/src/config/i18n/en/index.d.ts +1 -0
- package/dist/src/config/i18n/index.d.ts +16 -0
- package/dist/src/enums/defaults.d.ts +4 -0
- package/dist/src/extensions/Blocks/Recommendation/constants/defaultConfig.d.ts +6 -0
- package/dist/src/extensions/Blocks/Recommendation/constants/index.d.ts +3 -3
- package/dist/src/extensions/Blocks/Recommendation/constants/layout.d.ts +12 -2
- package/dist/src/extensions/Blocks/Recommendation/constants/selectors.d.ts +12 -1
- package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +50 -11
- package/dist/src/extensions/Blocks/Recommendation/controls/main/productLayout.d.ts +22 -4
- package/dist/src/extensions/Blocks/Recommendation/controls/main/utils.d.ts +36 -16
- package/dist/src/extensions/Blocks/Recommendation/controls/mobileLayout/cssRules.d.ts +29 -0
- package/dist/src/extensions/Blocks/Recommendation/controls/spacing/index.d.ts +50 -17
- package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +26 -2
- package/dist/src/extensions/Blocks/Recommendation/templates/grid/migration.d.ts +1 -1
- package/dist/src/extensions/Blocks/Recommendation/templates/grid/template.d.ts +1 -1
- package/dist/src/extensions/Blocks/Recommendation/templates/index.d.ts +4 -0
- package/dist/src/extensions/Blocks/Recommendation/templates/list/migration.d.ts +1 -1
- package/dist/src/extensions/Blocks/Recommendation/templates/utils.d.ts +12 -3
- package/dist/src/extensions/Blocks/Recommendation/types/nodeConfig.d.ts +14 -0
- package/dist/src/extensions/Blocks/Recommendation/validation/filterSchema.d.ts +15 -0
- package/dist/src/extensions/Blocks/Unsubscribe/control.d.ts +1 -0
- package/dist/src/extensions/ModulesTabIcons/extension.d.ts +2 -0
- package/dist/src/stores/config.d.ts +36 -0
- package/dist/static/styles/components/notification.css.js +19 -0
- package/dist/static/styles/components/tools.css.js +6 -2
- package/dist/static/styles/components/version-history.css.js +10 -2
- package/dist/static/styles/components/wide-panel.css.js +18 -2
- package/dist/static/styles/customEditorStyle.css.js +59 -31
- package/dist/static/styles/variables.css.js +2 -0
- package/dist/static/templates/empty/index.html.js +74 -0
- package/dist/static/templates/empty/style.css.js +779 -0
- package/dist/stores/unsubscribe.js +37 -34
- package/package.json +2 -2
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var i = (
|
|
4
|
-
import { CommonControl as
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
-
|
|
1
|
+
var g = Object.defineProperty;
|
|
2
|
+
var C = (d, c, t) => c in d ? g(d, c, { enumerable: !0, configurable: !0, writable: !0, value: t }) : d[c] = t;
|
|
3
|
+
var i = (d, c, t) => C(d, typeof c != "symbol" ? c + "" : c, t);
|
|
4
|
+
import { CommonControl as p } from "../../../common-control.js";
|
|
5
|
+
import { DEFAULT_NODE_CONFIG as a } from "../../constants/defaultConfig.js";
|
|
6
|
+
import { RecommendationConfigService as m } from "../../services/configService.js";
|
|
7
|
+
import { useRecommendationExtensionStore as y } from "../../store/recommendation.js";
|
|
8
|
+
import { AlgorithmControl as R } from "./algorithm.js";
|
|
9
|
+
import { ALGORITHM_CONTROL_ID as H } from "./algorithm.js";
|
|
10
|
+
import { CurrencyControl as N } from "./currency.js";
|
|
11
|
+
import { CURRENCY_CONTROL_ID as K } from "./currency.js";
|
|
12
|
+
import { FiltersControl as b } from "./filters.js";
|
|
13
|
+
import { FILTERS_CONTROL_ID as J } from "./filters.js";
|
|
14
|
+
import { LocaleControl as _ } from "./locale.js";
|
|
15
|
+
import { LOCALE_CONTROL_ID as X } from "./locale.js";
|
|
16
|
+
import { ProductLayoutControl as I } from "./productLayout.js";
|
|
17
|
+
import { PRODUCT_LAYOUT_CONTROL_ID as tt } from "./productLayout.js";
|
|
18
|
+
import { ShuffleControl as S } from "./shuffle.js";
|
|
19
|
+
import { SHUFFLE_CONTROL_ID as ot } from "./shuffle.js";
|
|
20
|
+
import { getBlockElement as P, updateProductContentInPlace as T, regenerateProductRowsWithStyles as L } from "./utils.js";
|
|
21
|
+
import { adjustProductsToSize as nt, formatProductPrice as st, getCardComposition as it, getCurrentLayout as at, reapplySpacing as ct, regenerateMobileProductRows as lt, regenerateProductRows as ut, setCurrencyAttributes as dt, updatePricesInPlace as mt, updateSingleProductContent as ht } from "./utils.js";
|
|
22
|
+
import { useDebounceFn as h } from "../../../../../node_modules/@vueuse/shared/index.js";
|
|
23
|
+
const k = "recommendation-id", D = "ui-elements-recommendation-block";
|
|
24
|
+
class W extends p {
|
|
23
25
|
constructor() {
|
|
24
26
|
super(...arguments);
|
|
25
|
-
i(this, "store",
|
|
27
|
+
i(this, "store", y());
|
|
26
28
|
i(this, "storeUnsubscription", () => {
|
|
27
29
|
});
|
|
28
|
-
// Track if initial data has been fetched per block ID to avoid redundant API calls
|
|
29
|
-
i(this, "initializedBlocks", /* @__PURE__ */ new Map());
|
|
30
30
|
// Sub-control instances for lifecycle management
|
|
31
31
|
i(this, "algorithmControl", null);
|
|
32
32
|
i(this, "localeControl", null);
|
|
@@ -37,30 +37,41 @@ class x extends h {
|
|
|
37
37
|
/**
|
|
38
38
|
* Debounced product fetch to prevent rapid API calls during config changes
|
|
39
39
|
*/
|
|
40
|
-
i(this, "_debouncedFetchProducts",
|
|
40
|
+
i(this, "_debouncedFetchProducts", h(() => {
|
|
41
41
|
this.store.fetchRecommendationProducts();
|
|
42
42
|
}, 500));
|
|
43
43
|
/**
|
|
44
|
-
* Debounced
|
|
45
|
-
*
|
|
44
|
+
* Debounced content update when products arrive from API.
|
|
45
|
+
*
|
|
46
|
+
* Tries in-place update first (preserves user-applied styles) — this succeeds
|
|
47
|
+
* when the product count matches the DOM (algorithm/locale/currency changes).
|
|
48
|
+
*
|
|
49
|
+
* Falls back to full regeneration when product count differs from DOM — this
|
|
50
|
+
* happens after "Number of Products" changes where the DOM still has the old
|
|
51
|
+
* count. The store pads products to the configured size, so in-place only
|
|
52
|
+
* fails when the size actually changed.
|
|
46
53
|
*/
|
|
47
|
-
i(this, "_debouncedRegenerateWithProducts",
|
|
54
|
+
i(this, "_debouncedRegenerateWithProducts", h(() => {
|
|
48
55
|
const t = this.store.recommendationProducts;
|
|
49
56
|
if (!this.currentNode || !this.api)
|
|
50
57
|
return;
|
|
51
58
|
const e = this.api.getDocumentModifier();
|
|
52
|
-
|
|
59
|
+
T({
|
|
53
60
|
currentNode: this.currentNode,
|
|
54
61
|
documentModifier: e,
|
|
55
62
|
products: t
|
|
56
|
-
}) ||
|
|
63
|
+
}) || L({
|
|
64
|
+
currentNode: this.currentNode,
|
|
65
|
+
documentModifier: e,
|
|
66
|
+
products: t
|
|
67
|
+
});
|
|
57
68
|
}, 100));
|
|
58
69
|
}
|
|
59
70
|
getId() {
|
|
60
|
-
return
|
|
71
|
+
return D;
|
|
61
72
|
}
|
|
62
73
|
getTemplate() {
|
|
63
|
-
return this.algorithmControl = new
|
|
74
|
+
return this.algorithmControl = new R(), this.localeControl = new _(), this.currencyControl = new N(), this.productLayoutControl = new I(), this.filtersControl = new b(), this.shuffleControl = new S(), `
|
|
64
75
|
<div class="recommendation-controls-container">
|
|
65
76
|
${this.algorithmControl.getTemplate()}
|
|
66
77
|
${this.localeControl.getTemplate()}
|
|
@@ -72,41 +83,28 @@ class x extends h {
|
|
|
72
83
|
`;
|
|
73
84
|
}
|
|
74
85
|
async onRender() {
|
|
86
|
+
var e;
|
|
75
87
|
const t = this._getRecommendationIdFromNode(this.currentNode) ?? this.store.currentRecommendationId;
|
|
76
|
-
if (t !== null && this.store.setCurrentBlock(t), this._listenStateUpdates(), t !== null && this.
|
|
88
|
+
if (t !== null && this.store.setCurrentBlock(t), this._listenStateUpdates(), t !== null && ((e = this.store.blockStates[t]) != null && e.isInitialized)) {
|
|
77
89
|
this._initializeSubControls();
|
|
78
90
|
return;
|
|
79
91
|
}
|
|
80
92
|
await this._fetchBlockData(t), this._initializeSubControls();
|
|
81
93
|
}
|
|
82
|
-
/**
|
|
83
|
-
* Immediately regenerate products with styles (no debounce)
|
|
84
|
-
* Used for initial load after fetch completes
|
|
85
|
-
*/
|
|
86
|
-
_regenerateWithProducts(t) {
|
|
87
|
-
if (!this.currentNode || !this.api) {
|
|
88
|
-
console.warn("[Recommendation] Cannot regenerate - missing currentNode or api");
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
P({
|
|
92
|
-
currentNode: this.currentNode,
|
|
93
|
-
documentModifier: this.api.getDocumentModifier(),
|
|
94
|
-
products: t
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
94
|
onTemplateNodeUpdated(t) {
|
|
95
|
+
var r;
|
|
98
96
|
super.onTemplateNodeUpdated(t);
|
|
99
97
|
const e = this._getRecommendationIdFromNode(t);
|
|
100
|
-
e !== null && e !== this.store.currentRecommendationId && this.store.setCurrentBlock(e), e !== null && !this.
|
|
98
|
+
e !== null && e !== this.store.currentRecommendationId && this.store.setCurrentBlock(e), this._syncNodeConfigToStore(), e !== null && !((r = this.store.blockStates[e]) != null && r.isInitialized) && this._fetchBlockData(e), [
|
|
101
99
|
this.algorithmControl,
|
|
102
100
|
this.localeControl,
|
|
103
101
|
this.currencyControl,
|
|
104
102
|
this.productLayoutControl,
|
|
105
103
|
this.filtersControl,
|
|
106
104
|
this.shuffleControl
|
|
107
|
-
].forEach((
|
|
105
|
+
].forEach((n) => {
|
|
108
106
|
var s;
|
|
109
|
-
|
|
107
|
+
n != null && n.api && (n.currentNode = t, (s = n.onTemplateNodeUpdated) == null || s.call(n, t));
|
|
110
108
|
});
|
|
111
109
|
}
|
|
112
110
|
onDestroy() {
|
|
@@ -140,31 +138,128 @@ class x extends h {
|
|
|
140
138
|
});
|
|
141
139
|
}
|
|
142
140
|
/**
|
|
143
|
-
*
|
|
141
|
+
* Syncs persisted node config into the Pinia store's block state.
|
|
142
|
+
*
|
|
143
|
+
* setCurrentBlock() creates a default entry (USD, en_US, mostPopular).
|
|
144
|
+
* For saved templates, the real config lives in the node (e.g., TRY, tr_TR).
|
|
145
|
+
* This method reads it and patches the store so fetchRecommendationProducts()
|
|
146
|
+
* uses the correct values.
|
|
147
|
+
*
|
|
148
|
+
* Uses triggerRefetch: false because the fetch hasn't happened yet —
|
|
149
|
+
* values are being prepared for the upcoming initial fetch.
|
|
150
|
+
*/
|
|
151
|
+
_syncNodeConfigToStore() {
|
|
152
|
+
var r;
|
|
153
|
+
const t = m.getConfig(this.currentNode), e = this.store.currentRecommendationId, o = e !== null && ((r = this.store.blockStates[e]) == null ? void 0 : r.isInitialized);
|
|
154
|
+
this.store.patchCurrentBlockConfig({
|
|
155
|
+
strategy: t.strategy,
|
|
156
|
+
language: t.language,
|
|
157
|
+
size: t.size,
|
|
158
|
+
productIds: t.productIds,
|
|
159
|
+
// Only sync filters from node config during initial load.
|
|
160
|
+
// After initialization, the Pinia store is the source of truth
|
|
161
|
+
// for filters (edited via the filter drawer).
|
|
162
|
+
...o ? {} : { filters: t.filters },
|
|
163
|
+
shuffleProducts: t.shuffleProducts,
|
|
164
|
+
currencySettings: {
|
|
165
|
+
name: t.currency.code,
|
|
166
|
+
value: t.currency.code,
|
|
167
|
+
symbol: t.currency.symbol,
|
|
168
|
+
alignment: t.currency.alignment === "before" ? "0" : "1",
|
|
169
|
+
decimalCount: t.currency.decimalCount.toString(),
|
|
170
|
+
decimalSeparator: t.currency.decimalSeparator,
|
|
171
|
+
thousandSeparator: t.currency.thousandSeparator
|
|
172
|
+
}
|
|
173
|
+
}, { triggerRefetch: !1 });
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Fetches initial data for a block in three phases:
|
|
177
|
+
* 1. Shared reference data (algorithms, currencies, filters) — parallel
|
|
178
|
+
* 2. Smart defaults for new blocks (currency, algorithm) — sequential
|
|
179
|
+
* 3. Product data with correct defaults — sequential
|
|
180
|
+
*
|
|
144
181
|
* Shared by onRender() and onTemplateNodeUpdated() to avoid duplication.
|
|
145
182
|
* Marks the block as initialized to prevent redundant fetches on re-selection.
|
|
146
183
|
*/
|
|
147
184
|
async _fetchBlockData(t) {
|
|
148
|
-
t !== null && this.
|
|
149
|
-
this.store.fetchRecommendationFilters(),
|
|
185
|
+
t !== null && this.store.markBlockInitialized(t), (await Promise.allSettled([
|
|
150
186
|
this.store.fetchRecommendationCreateData(),
|
|
151
|
-
this.store.
|
|
187
|
+
this.store.fetchRecommendationFilters()
|
|
152
188
|
])).forEach((o, r) => {
|
|
153
|
-
o.status === "rejected" && console.warn(`Recommendation block: ${[
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
189
|
+
o.status === "rejected" && console.warn(`Recommendation block: ${["fetchRecommendationCreateData", "fetchRecommendationFilters"][r]} failed`, o.reason);
|
|
190
|
+
}), this._applySmartDefaults();
|
|
191
|
+
try {
|
|
192
|
+
await this.store.fetchRecommendationProducts();
|
|
193
|
+
} catch (o) {
|
|
194
|
+
console.warn("Recommendation block: fetchRecommendationProducts failed", o);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Applies smart defaults for newly dropped blocks.
|
|
199
|
+
*
|
|
200
|
+
* For new blocks (config still matches hardcoded defaults), validates that
|
|
201
|
+
* the default currency and algorithm are available from the API response.
|
|
202
|
+
* If not, falls back to the first available option.
|
|
203
|
+
*
|
|
204
|
+
* Saved templates with user-customized config are left unchanged because
|
|
205
|
+
* their values won't match the hardcoded defaults.
|
|
206
|
+
*/
|
|
207
|
+
_applySmartDefaults() {
|
|
208
|
+
if (!this.currentNode || !this.api)
|
|
209
|
+
return;
|
|
210
|
+
const t = m.getConfig(this.currentNode), e = {};
|
|
211
|
+
let o = null, r = null, n = null;
|
|
212
|
+
if (t.currency.code === a.currency.code) {
|
|
213
|
+
const { currencyList: s } = this.store;
|
|
214
|
+
s.length > 0 && (s.some(
|
|
215
|
+
(u) => u.value === `price.${a.currency.code}`
|
|
216
|
+
) || (o = s[0].value.replace("price.", ""), e.currency = {
|
|
217
|
+
...a.currency,
|
|
218
|
+
code: o,
|
|
219
|
+
symbol: o
|
|
220
|
+
}));
|
|
221
|
+
}
|
|
222
|
+
if (t.strategy === a.strategy) {
|
|
223
|
+
const s = this.store.getActivePredictiveAlgorithms;
|
|
224
|
+
s.length > 0 && (s.some(
|
|
225
|
+
(u) => u.value === a.strategy
|
|
226
|
+
) || (r = s[0].value, e.strategy = r));
|
|
227
|
+
}
|
|
228
|
+
if (t.language === a.language) {
|
|
229
|
+
const s = this.store.getLanguages;
|
|
230
|
+
s.length > 0 && (s.some(
|
|
231
|
+
(u) => u.value === a.language
|
|
232
|
+
) || (n = s[0].value, e.language = n));
|
|
233
|
+
}
|
|
234
|
+
!o && !r && !n || (m.updateConfig(
|
|
235
|
+
this.api,
|
|
236
|
+
this.currentNode,
|
|
237
|
+
e,
|
|
238
|
+
"Applied smart defaults"
|
|
239
|
+
), this.store.patchCurrentBlockConfig({
|
|
240
|
+
...o ? {
|
|
241
|
+
currencySettings: {
|
|
242
|
+
name: o,
|
|
243
|
+
value: o,
|
|
244
|
+
symbol: o,
|
|
245
|
+
alignment: a.currency.alignment === "before" ? "0" : "1",
|
|
246
|
+
decimalCount: a.currency.decimalCount.toString(),
|
|
247
|
+
decimalSeparator: a.currency.decimalSeparator,
|
|
248
|
+
thousandSeparator: a.currency.thousandSeparator
|
|
249
|
+
}
|
|
250
|
+
} : {},
|
|
251
|
+
...r ? { strategy: r } : {},
|
|
252
|
+
...n ? { language: n } : {}
|
|
253
|
+
}, { triggerRefetch: !1 }));
|
|
159
254
|
}
|
|
160
255
|
/**
|
|
161
256
|
* Reads the recommendation-id attribute from the block element within the node
|
|
162
257
|
*/
|
|
163
258
|
_getRecommendationIdFromNode(t) {
|
|
164
|
-
const e =
|
|
259
|
+
const e = P(t);
|
|
165
260
|
if (!e || !("getAttribute" in e))
|
|
166
261
|
return null;
|
|
167
|
-
const o = e.getAttribute(
|
|
262
|
+
const o = e.getAttribute(k);
|
|
168
263
|
if (!o)
|
|
169
264
|
return null;
|
|
170
265
|
const r = parseInt(o);
|
|
@@ -176,42 +271,70 @@ class x extends h {
|
|
|
176
271
|
* Uses configVersion counter (incremented only by patchCurrentBlockConfig)
|
|
177
272
|
* to distinguish user-initiated config changes from internal mutations
|
|
178
273
|
* (e.g., fetchRecommendationCreateData setting preferred currency).
|
|
274
|
+
*
|
|
275
|
+
* Tracks currentRecommendationId to detect block switches. When the user
|
|
276
|
+
* selects a different recommendation block, the proxy getters (e.g.,
|
|
277
|
+
* recommendationProducts) return the new block's data — a different array
|
|
278
|
+
* reference that would be falsely detected as "new products arrived".
|
|
279
|
+
* We skip that tick and update tracking references instead.
|
|
179
280
|
*/
|
|
180
281
|
_listenStateUpdates() {
|
|
181
282
|
const { store: t } = this;
|
|
182
|
-
let e = t.recommendationProducts, o = t.$state.configVersion;
|
|
283
|
+
let e = t.recommendationProducts, o = t.$state.configVersion, r = t.currentRecommendationId;
|
|
183
284
|
this.storeUnsubscription = t.$subscribe(() => {
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
285
|
+
const n = t.currentRecommendationId;
|
|
286
|
+
if (n !== r) {
|
|
287
|
+
r = n, e = t.recommendationProducts, o = t.$state.configVersion;
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
const s = t.$state.configVersion;
|
|
291
|
+
s !== o && (o = s, this._persistFiltersToNodeConfig(), this._debouncedFetchProducts());
|
|
292
|
+
const l = t.recommendationProducts, u = l !== e, f = Array.isArray(l) && l.length > 0;
|
|
293
|
+
u && f && (e = l, this._debouncedRegenerateWithProducts());
|
|
188
294
|
});
|
|
189
295
|
}
|
|
296
|
+
/**
|
|
297
|
+
* Persists the current filter state from Pinia store to the Stripo node config.
|
|
298
|
+
* This ensures filters survive template save/reload cycles.
|
|
299
|
+
*/
|
|
300
|
+
_persistFiltersToNodeConfig() {
|
|
301
|
+
if (!this.currentNode || !this.api)
|
|
302
|
+
return;
|
|
303
|
+
const { filters: t } = this.store.recommendationConfigs;
|
|
304
|
+
m.updateConfig(
|
|
305
|
+
this.api,
|
|
306
|
+
this.currentNode,
|
|
307
|
+
{ filters: t },
|
|
308
|
+
"Update recommendation filters"
|
|
309
|
+
);
|
|
310
|
+
}
|
|
190
311
|
}
|
|
191
312
|
export {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
313
|
+
H as ALGORITHM_CONTROL_ID,
|
|
314
|
+
R as AlgorithmControl,
|
|
315
|
+
D as CONTROL_BLOCK_ID,
|
|
316
|
+
K as CURRENCY_CONTROL_ID,
|
|
317
|
+
N as CurrencyControl,
|
|
318
|
+
J as FILTERS_CONTROL_ID,
|
|
319
|
+
b as FiltersControl,
|
|
320
|
+
X as LOCALE_CONTROL_ID,
|
|
321
|
+
_ as LocaleControl,
|
|
322
|
+
tt as PRODUCT_LAYOUT_CONTROL_ID,
|
|
323
|
+
I as ProductLayoutControl,
|
|
324
|
+
W as RecommendationBlockControl,
|
|
325
|
+
ot as SHUFFLE_CONTROL_ID,
|
|
326
|
+
S as ShuffleControl,
|
|
327
|
+
nt as adjustProductsToSize,
|
|
328
|
+
st as formatProductPrice,
|
|
329
|
+
P as getBlockElement,
|
|
330
|
+
it as getCardComposition,
|
|
331
|
+
at as getCurrentLayout,
|
|
332
|
+
ct as reapplySpacing,
|
|
333
|
+
lt as regenerateMobileProductRows,
|
|
334
|
+
ut as regenerateProductRows,
|
|
335
|
+
L as regenerateProductRowsWithStyles,
|
|
336
|
+
dt as setCurrencyAttributes,
|
|
337
|
+
mt as updatePricesInPlace,
|
|
338
|
+
T as updateProductContentInPlace,
|
|
339
|
+
ht as updateSingleProductContent
|
|
217
340
|
};
|
|
@@ -2,20 +2,20 @@ var s = Object.defineProperty;
|
|
|
2
2
|
var r = (o, t, e) => t in o ? s(o, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : o[t] = e;
|
|
3
3
|
var a = (o, t, e) => r(o, typeof t != "symbol" ? t + "" : t, e);
|
|
4
4
|
import { UEAttr as l } from "../../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
5
|
-
import { CommonControl as
|
|
5
|
+
import { CommonControl as c } from "../../../common-control.js";
|
|
6
6
|
import { RecommendationConfigService as i } from "../../services/configService.js";
|
|
7
|
-
import { useRecommendationExtensionStore as
|
|
8
|
-
const
|
|
7
|
+
import { useRecommendationExtensionStore as g } from "../../store/recommendation.js";
|
|
8
|
+
const m = "recommendation-locale-control", n = {
|
|
9
9
|
LOCALE: "language"
|
|
10
10
|
};
|
|
11
|
-
class
|
|
11
|
+
class E extends c {
|
|
12
12
|
constructor() {
|
|
13
13
|
super(...arguments);
|
|
14
14
|
// Store is used ONLY for API-fetched data (language options), not for config
|
|
15
|
-
a(this, "store",
|
|
15
|
+
a(this, "store", g());
|
|
16
16
|
}
|
|
17
17
|
getId() {
|
|
18
|
-
return
|
|
18
|
+
return m;
|
|
19
19
|
}
|
|
20
20
|
getTemplate() {
|
|
21
21
|
return `
|
|
@@ -51,7 +51,7 @@ class C extends m {
|
|
|
51
51
|
);
|
|
52
52
|
}
|
|
53
53
|
_onLocaleChange(e) {
|
|
54
|
-
this.currentNode
|
|
54
|
+
!this.currentNode || i.getConfig(this.currentNode).language === e || (i.updateConfig(
|
|
55
55
|
this.api,
|
|
56
56
|
this.currentNode,
|
|
57
57
|
{ language: e },
|
|
@@ -65,6 +65,6 @@ class C extends m {
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
export {
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
m as LOCALE_CONTROL_ID,
|
|
69
|
+
E as LocaleControl
|
|
70
70
|
};
|
|
@@ -1,45 +1,60 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
1
|
+
var u = Object.defineProperty;
|
|
2
|
+
var _ = (n, r, t) => r in n ? u(n, r, { enumerable: !0, configurable: !0, writable: !0, value: t }) : n[r] = t;
|
|
3
|
+
var a = (n, r, t) => _(n, typeof r != "symbol" ? r + "" : r, t);
|
|
4
|
+
import { EditorStatePropertyType as c, PreviewDeviceMode as C } from "../../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
5
|
+
import { CommonControl as R } from "../../../common-control.js";
|
|
6
|
+
import { MAX_PRODUCT_COUNT as h, MAX_PRODUCTS_PER_ROW as p, MAX_MOBILE_PRODUCTS_PER_ROW as g, DEFAULT_COLUMN_SPACING as m, DEFAULT_MOBILE_COLUMN_SPACING as O } from "../../constants/layout.js";
|
|
7
|
+
import { RecommendationConfigService as i } from "../../services/configService.js";
|
|
8
|
+
import { useRecommendationExtensionStore as l } from "../../store/recommendation.js";
|
|
9
|
+
import { ensureMobileCssRulesExist as I } from "../mobileLayout/cssRules.js";
|
|
10
|
+
import { getCurrentLayout as N, regenerateMobileProductRows as f, adjustProductsToSize as b, regenerateProductRowsWithStyles as P } from "./utils.js";
|
|
11
|
+
import { useDebounceFn as L } from "../../../../../node_modules/@vueuse/shared/index.js";
|
|
12
|
+
const M = "recommendation-product-layout-control", e = {
|
|
11
13
|
PRODUCT_COUNT: "size",
|
|
12
14
|
PRODUCT_IN_ROW: "cardsInRow",
|
|
13
|
-
PRODUCT_IN_ROW_LABEL: "cardsInRowLabel"
|
|
15
|
+
PRODUCT_IN_ROW_LABEL: "cardsInRowLabel",
|
|
16
|
+
MOBILE_CARDS_IN_ROW: "mobileCardsInRow",
|
|
17
|
+
MOBILE_CARDS_IN_ROW_LABEL: "mobileCardsInRowLabel"
|
|
14
18
|
};
|
|
15
|
-
class
|
|
19
|
+
class V extends R {
|
|
16
20
|
constructor() {
|
|
17
21
|
super(...arguments);
|
|
18
22
|
// Store is used for backward compatibility with product fetching and regeneration
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
a(this, "store", l());
|
|
24
|
+
a(this, "storeUnsubscription", () => {
|
|
21
25
|
});
|
|
22
|
-
|
|
26
|
+
a(this, "_debouncedRegenerateProductRows", L(() => {
|
|
23
27
|
this._regenerateProductRows();
|
|
24
28
|
}, 500));
|
|
25
29
|
}
|
|
26
30
|
getId() {
|
|
27
|
-
return
|
|
31
|
+
return M;
|
|
28
32
|
}
|
|
29
33
|
getTemplate() {
|
|
30
34
|
return `
|
|
31
35
|
<div class="product-layout-control-container">
|
|
32
36
|
${this._GuTwoColumns([
|
|
33
37
|
this._GuLabel({ text: "Number of Products" }),
|
|
34
|
-
this._GuCounter({ name:
|
|
35
|
-
this._GuLabel({
|
|
36
|
-
|
|
38
|
+
this._GuCounter({ name: e.PRODUCT_COUNT, maxValue: h }),
|
|
39
|
+
this._GuLabel({
|
|
40
|
+
text: "Products in One Row on Desktop",
|
|
41
|
+
name: e.PRODUCT_IN_ROW_LABEL
|
|
42
|
+
}),
|
|
43
|
+
this._GuCounter({ name: e.PRODUCT_IN_ROW, maxValue: p }),
|
|
44
|
+
this._GuLabel({
|
|
45
|
+
text: "Products in One Row on Mobile",
|
|
46
|
+
name: e.MOBILE_CARDS_IN_ROW_LABEL
|
|
47
|
+
}),
|
|
48
|
+
this._GuCounter({
|
|
49
|
+
name: e.MOBILE_CARDS_IN_ROW,
|
|
50
|
+
maxValue: g
|
|
51
|
+
})
|
|
37
52
|
])}
|
|
38
53
|
</div>
|
|
39
54
|
`;
|
|
40
55
|
}
|
|
41
56
|
onRender() {
|
|
42
|
-
this._setFormValues(), this._updateProductsInRowVisibility(), this._listenToFormUpdates(), this._listenStateUpdates();
|
|
57
|
+
this._setFormValues(), this._updateProductsInRowVisibility(), this._listenToFormUpdates(), this._listenStateUpdates(), this._subscribeToEditorModeChanges();
|
|
43
58
|
}
|
|
44
59
|
onTemplateNodeUpdated(t) {
|
|
45
60
|
super.onTemplateNodeUpdated(t), this._setFormValues(), this._updateProductsInRowVisibility();
|
|
@@ -48,48 +63,91 @@ class I extends c {
|
|
|
48
63
|
this.storeUnsubscription();
|
|
49
64
|
}
|
|
50
65
|
_setFormValues() {
|
|
51
|
-
const t =
|
|
66
|
+
const t = i.getConfig(this.currentNode);
|
|
52
67
|
this.api.updateValues({
|
|
53
|
-
[
|
|
54
|
-
[
|
|
68
|
+
[e.PRODUCT_COUNT]: t.size,
|
|
69
|
+
[e.PRODUCT_IN_ROW]: t.cardsInRow,
|
|
70
|
+
[e.MOBILE_CARDS_IN_ROW]: t.mobileCardsInRow
|
|
55
71
|
});
|
|
56
72
|
}
|
|
57
73
|
/**
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
|
|
74
|
+
* Checks if the editor is currently in mobile preview mode
|
|
75
|
+
* using Stripo's EditorStatePropertyType API.
|
|
76
|
+
*/
|
|
77
|
+
_isMobileMode() {
|
|
78
|
+
return this.api.getEditorState()[c.previewDeviceMode] === C.MOBILE;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Updates counter visibility based on layout orientation and editor mode.
|
|
82
|
+
* - List layout: hide both counters (products always full-width)
|
|
83
|
+
* - Grid + desktop mode: show desktop counter, hide mobile counter
|
|
84
|
+
* - Grid + mobile mode: show mobile counter, hide desktop counter
|
|
61
85
|
*/
|
|
62
86
|
_updateProductsInRowVisibility() {
|
|
63
|
-
const
|
|
64
|
-
this.api.setVisibility(
|
|
87
|
+
const o = (i.getConfig(this.currentNode).layout || N(this.currentNode)) === "grid", d = this._isMobileMode();
|
|
88
|
+
this.api.setVisibility(e.PRODUCT_IN_ROW, o && !d), this.api.setVisibility(e.PRODUCT_IN_ROW_LABEL, o && !d), this.api.setVisibility(e.MOBILE_CARDS_IN_ROW, o && d), this.api.setVisibility(e.MOBILE_CARDS_IN_ROW_LABEL, o && d);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Subscribes to editor preview mode changes via Stripo API.
|
|
92
|
+
* When the user switches between desktop/mobile preview, toggles
|
|
93
|
+
* which "Products in One Row" counter is visible.
|
|
94
|
+
*/
|
|
95
|
+
_subscribeToEditorModeChanges() {
|
|
96
|
+
this.api.onEditorStatePropUpdated(
|
|
97
|
+
c.previewDeviceMode,
|
|
98
|
+
() => {
|
|
99
|
+
this._updateProductsInRowVisibility();
|
|
100
|
+
}
|
|
101
|
+
);
|
|
65
102
|
}
|
|
66
103
|
_onProductCountChange(t) {
|
|
67
|
-
this.currentNode
|
|
104
|
+
!this.currentNode || i.getConfig(this.currentNode).size === t || (i.updateConfig(
|
|
68
105
|
this.api,
|
|
69
106
|
this.currentNode,
|
|
70
107
|
{ size: t },
|
|
71
108
|
`Changed product count to ${t}`
|
|
72
|
-
), this.store.patchCurrentBlockConfig({ size: t })
|
|
109
|
+
), this.store.patchCurrentBlockConfig({ size: t }));
|
|
73
110
|
}
|
|
74
111
|
_onProductsInRowChange(t) {
|
|
75
|
-
this.currentNode
|
|
112
|
+
if (!this.currentNode || i.getConfig(this.currentNode).cardsInRow === t)
|
|
113
|
+
return;
|
|
114
|
+
const o = t === 1 ? 0 : m;
|
|
115
|
+
i.updateConfig(
|
|
76
116
|
this.api,
|
|
77
117
|
this.currentNode,
|
|
78
|
-
{ cardsInRow: t },
|
|
118
|
+
{ cardsInRow: t, columnSpacing: o },
|
|
79
119
|
`Changed products per row to ${t}`
|
|
80
|
-
), this.store.patchCurrentBlockConfig({ cardsInRow: t }), this._debouncedRegenerateProductRows()
|
|
120
|
+
), this.store.patchCurrentBlockConfig({ cardsInRow: t }, { triggerRefetch: !1 }), this._debouncedRegenerateProductRows();
|
|
81
121
|
}
|
|
82
|
-
|
|
83
|
-
|
|
122
|
+
_onMobileCardsInRowChange(t) {
|
|
123
|
+
if (!this.currentNode || i.getConfig(this.currentNode).mobileCardsInRow === t)
|
|
124
|
+
return;
|
|
125
|
+
const o = t === 1 ? 0 : O;
|
|
126
|
+
i.updateConfig(
|
|
127
|
+
this.api,
|
|
128
|
+
this.currentNode,
|
|
129
|
+
{ mobileCardsInRow: t, mobileColumnSpacing: o },
|
|
130
|
+
`Changed mobile products per row to ${t}`
|
|
131
|
+
), I(this.api), f({
|
|
84
132
|
currentNode: this.currentNode,
|
|
85
133
|
documentModifier: this.api.getDocumentModifier()
|
|
86
134
|
});
|
|
87
135
|
}
|
|
136
|
+
_regenerateProductRows() {
|
|
137
|
+
const t = i.getConfig(this.currentNode), s = parseInt(t.size) || 6, o = b(this.store.recommendationProducts, s);
|
|
138
|
+
P({
|
|
139
|
+
currentNode: this.currentNode,
|
|
140
|
+
documentModifier: this.api.getDocumentModifier(),
|
|
141
|
+
products: o
|
|
142
|
+
});
|
|
143
|
+
}
|
|
88
144
|
_listenToFormUpdates() {
|
|
89
|
-
this.api.onValueChanged(
|
|
145
|
+
this.api.onValueChanged(e.PRODUCT_COUNT, (t) => {
|
|
90
146
|
this._onProductCountChange(t.toString());
|
|
91
|
-
}), this.api.onValueChanged(
|
|
147
|
+
}), this.api.onValueChanged(e.PRODUCT_IN_ROW, (t) => {
|
|
92
148
|
this._onProductsInRowChange(Number(t));
|
|
149
|
+
}), this.api.onValueChanged(e.MOBILE_CARDS_IN_ROW, (t) => {
|
|
150
|
+
this._onMobileCardsInRowChange(Number(t));
|
|
93
151
|
});
|
|
94
152
|
}
|
|
95
153
|
/**
|
|
@@ -105,6 +163,6 @@ class I extends c {
|
|
|
105
163
|
}
|
|
106
164
|
}
|
|
107
165
|
export {
|
|
108
|
-
|
|
109
|
-
|
|
166
|
+
M as PRODUCT_LAYOUT_CONTROL_ID,
|
|
167
|
+
V as ProductLayoutControl
|
|
110
168
|
};
|