@useinsider/guido 2.0.0-beta.1c331b8 → 2.0.0-beta.1f72712
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/dist/extensions/Blocks/Recommendation/block.js +40 -6
- package/dist/extensions/Blocks/Recommendation/constants/defaultConfig.js +64 -0
- package/dist/extensions/Blocks/Recommendation/constants/layout.js +9 -4
- package/dist/extensions/Blocks/Recommendation/constants/selectors.js +17 -9
- package/dist/extensions/Blocks/Recommendation/controls/cardComposition/index.js +48 -54
- package/dist/extensions/Blocks/Recommendation/controls/layout/index.js +42 -36
- package/dist/extensions/Blocks/Recommendation/controls/main/algorithm.js +51 -27
- package/dist/extensions/Blocks/Recommendation/controls/main/currency.js +146 -73
- package/dist/extensions/Blocks/Recommendation/controls/main/index.js +49 -35
- package/dist/extensions/Blocks/Recommendation/controls/main/locale.js +23 -13
- package/dist/extensions/Blocks/Recommendation/controls/main/productLayout.js +41 -41
- package/dist/extensions/Blocks/Recommendation/controls/main/shuffle.js +27 -16
- package/dist/extensions/Blocks/Recommendation/controls/main/utils.js +79 -67
- package/dist/extensions/Blocks/Recommendation/controls/omnibusDiscount/textAfter.js +1 -1
- package/dist/extensions/Blocks/Recommendation/controls/omnibusDiscount/textBefore.js +3 -3
- package/dist/extensions/Blocks/Recommendation/controls/spacing/index.js +85 -79
- package/dist/extensions/Blocks/Recommendation/recommendation.css.js +8 -4
- package/dist/extensions/Blocks/Recommendation/services/configService.js +239 -0
- package/dist/extensions/Blocks/Recommendation/store/recommendation.js +30 -28
- package/dist/extensions/Blocks/Recommendation/templates/horizontal/elementRenderer.js +49 -25
- package/dist/extensions/Blocks/Recommendation/templates/horizontal/template.js +18 -19
- package/dist/extensions/Blocks/Recommendation/templates/utils.js +44 -101
- package/dist/extensions/Blocks/Recommendation/templates/vertical/elementRenderer.js +60 -35
- package/dist/extensions/Blocks/Recommendation/types/nodeConfig.js +6 -0
- package/dist/extensions/Blocks/Recommendation/utils/priceFormatter.js +29 -0
- package/dist/extensions/Blocks/Recommendation/utils/tagName.js +46 -0
- package/dist/extensions/Blocks/common-control.js +1 -1
- package/dist/node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js +214 -157
- package/dist/src/components/wrappers/WpDrawer.vue.d.ts +1 -1
- package/dist/src/extensions/Blocks/Recommendation/block.d.ts +34 -0
- package/dist/src/extensions/Blocks/Recommendation/constants/defaultConfig.d.ts +49 -0
- package/dist/src/extensions/Blocks/Recommendation/constants/index.d.ts +3 -2
- package/dist/src/extensions/Blocks/Recommendation/constants/layout.d.ts +10 -0
- package/dist/src/extensions/Blocks/Recommendation/constants/selectors.d.ts +12 -0
- package/dist/src/extensions/Blocks/Recommendation/controls/layout/index.d.ts +3 -1
- package/dist/src/extensions/Blocks/Recommendation/controls/main/algorithm.d.ts +13 -1
- package/dist/src/extensions/Blocks/Recommendation/controls/main/currency.d.ts +30 -1
- package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +19 -0
- package/dist/src/extensions/Blocks/Recommendation/controls/main/locale.d.ts +9 -0
- package/dist/src/extensions/Blocks/Recommendation/controls/main/productLayout.d.ts +4 -2
- package/dist/src/extensions/Blocks/Recommendation/controls/main/shuffle.d.ts +8 -0
- package/dist/src/extensions/Blocks/Recommendation/controls/main/utils.d.ts +19 -0
- package/dist/src/extensions/Blocks/Recommendation/controls/spacing/index.d.ts +13 -2
- package/dist/src/extensions/Blocks/Recommendation/services/configService.d.ts +151 -0
- package/dist/src/extensions/Blocks/Recommendation/services/index.d.ts +6 -0
- package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +1 -0
- package/dist/src/extensions/Blocks/Recommendation/types/index.d.ts +7 -0
- package/dist/src/extensions/Blocks/Recommendation/types/nodeConfig.d.ts +154 -0
- package/dist/src/extensions/Blocks/Recommendation/utils/priceFormatter.d.ts +33 -0
- package/dist/src/extensions/Blocks/Recommendation/utils/stylePreserver.d.ts +113 -0
- package/dist/src/extensions/Blocks/Recommendation/utils/tagName.d.ts +77 -0
- package/package.json +1 -1
|
@@ -1,61 +1,50 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var p = (
|
|
4
|
-
import { ModificationDescription as
|
|
5
|
-
import { CommonControl as
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
1
|
+
var G = Object.defineProperty;
|
|
2
|
+
var I = (o, n, t) => n in o ? G(o, n, { enumerable: !0, configurable: !0, writable: !0, value: t }) : o[n] = t;
|
|
3
|
+
var p = (o, n, t) => I(o, typeof n != "symbol" ? n + "" : n, t);
|
|
4
|
+
import { ModificationDescription as g } from "../../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
5
|
+
import { CommonControl as L } from "../../../common-control.js";
|
|
6
|
+
import { SPACING_STEP as b, MAX_SPACING as y, MIN_SPACING as A, DEFAULT_COLUMN_SPACING as s, DEFAULT_ROW_SPACING as m } from "../../constants/layout.js";
|
|
7
|
+
import { RecommendationConfigService as d } from "../../services/configService.js";
|
|
8
|
+
import { useRecommendationExtensionStore as w } from "../../store/recommendation.js";
|
|
9
|
+
import { safeGetStyle as S, safeGetParent as V } from "../../utils/tagName.js";
|
|
10
|
+
import { getCurrentLayout as C } from "../main/utils.js";
|
|
11
|
+
import { useDebounceFn as O } from "../../../../../node_modules/@vueuse/shared/index.js";
|
|
12
|
+
const R = "recommendation-spacing-control", a = {
|
|
10
13
|
COLUMN_SPACING: "columnSpacing",
|
|
11
14
|
COLUMN_SPACING_LABEL: "columnSpacingLabel",
|
|
12
15
|
ROW_SPACING: "rowSpacing"
|
|
13
|
-
},
|
|
16
|
+
}, P = {
|
|
14
17
|
COLUMN_SPACING: "data-column-spacing",
|
|
15
18
|
ROW_SPACING: "data-row-spacing"
|
|
16
|
-
}, s = {
|
|
17
|
-
COLUMN_SPACING: 10,
|
|
18
|
-
// 5px on each side = 10px total
|
|
19
|
-
ROW_SPACING: 20
|
|
20
|
-
}, u = {
|
|
21
|
-
MIN_SPACING: 0,
|
|
22
|
-
MAX_SPACING: 50,
|
|
23
|
-
STEP: 5
|
|
24
19
|
};
|
|
25
|
-
function
|
|
26
|
-
|
|
20
|
+
function N(o, n) {
|
|
21
|
+
if (!o)
|
|
22
|
+
return n;
|
|
23
|
+
const t = parseFloat(o);
|
|
24
|
+
return Number.isNaN(t) ? n : t;
|
|
27
25
|
}
|
|
28
|
-
|
|
29
|
-
return !n || !("parent" in n) || typeof n.parent != "function" ? null : n.parent();
|
|
30
|
-
}
|
|
31
|
-
function m(n, i) {
|
|
32
|
-
if (!n)
|
|
33
|
-
return i;
|
|
34
|
-
const t = parseFloat(n);
|
|
35
|
-
return Number.isNaN(t) ? i : t;
|
|
36
|
-
}
|
|
37
|
-
class E extends b {
|
|
26
|
+
class $ extends L {
|
|
38
27
|
constructor() {
|
|
39
28
|
super(...arguments);
|
|
40
|
-
p(this, "store",
|
|
29
|
+
p(this, "store", w());
|
|
41
30
|
p(this, "unsubscribeOrientation", null);
|
|
42
31
|
/**
|
|
43
32
|
* Debounced version of _onColumnSpacingChange
|
|
44
33
|
* Prevents excessive DOM updates when user rapidly adjusts the counter
|
|
45
34
|
*/
|
|
46
|
-
p(this, "_debouncedOnColumnSpacingChange",
|
|
35
|
+
p(this, "_debouncedOnColumnSpacingChange", O((t) => {
|
|
47
36
|
this._onColumnSpacingChange(t);
|
|
48
37
|
}, 300));
|
|
49
38
|
/**
|
|
50
39
|
* Debounced version of _onRowSpacingChange
|
|
51
40
|
* Prevents excessive DOM updates when user rapidly adjusts the counter
|
|
52
41
|
*/
|
|
53
|
-
p(this, "_debouncedOnRowSpacingChange",
|
|
42
|
+
p(this, "_debouncedOnRowSpacingChange", O((t) => {
|
|
54
43
|
this._onRowSpacingChange(t);
|
|
55
44
|
}, 300));
|
|
56
45
|
}
|
|
57
46
|
getId() {
|
|
58
|
-
return
|
|
47
|
+
return R;
|
|
59
48
|
}
|
|
60
49
|
getTemplate() {
|
|
61
50
|
return `
|
|
@@ -64,16 +53,16 @@ class E extends b {
|
|
|
64
53
|
this._GuLabel({ text: "Column Spacing (px)", name: a.COLUMN_SPACING_LABEL }),
|
|
65
54
|
this._GuCounter({
|
|
66
55
|
name: a.COLUMN_SPACING,
|
|
67
|
-
minValue:
|
|
68
|
-
maxValue:
|
|
69
|
-
step:
|
|
56
|
+
minValue: A,
|
|
57
|
+
maxValue: y,
|
|
58
|
+
step: b
|
|
70
59
|
}),
|
|
71
60
|
this._GuLabel({ text: "Row Spacing (px)" }),
|
|
72
61
|
this._GuCounter({
|
|
73
62
|
name: a.ROW_SPACING,
|
|
74
|
-
minValue:
|
|
75
|
-
maxValue:
|
|
76
|
-
step:
|
|
63
|
+
minValue: A,
|
|
64
|
+
maxValue: y,
|
|
65
|
+
step: b
|
|
77
66
|
})
|
|
78
67
|
])}
|
|
79
68
|
</div>
|
|
@@ -85,23 +74,30 @@ class E extends b {
|
|
|
85
74
|
onTemplateNodeUpdated(t) {
|
|
86
75
|
super.onTemplateNodeUpdated(t), this._setFormValues(), this._updateColumnSpacingVisibility();
|
|
87
76
|
}
|
|
77
|
+
onDestroy() {
|
|
78
|
+
this.unsubscribeOrientation && (this.unsubscribeOrientation(), this.unsubscribeOrientation = null);
|
|
79
|
+
}
|
|
88
80
|
/**
|
|
89
81
|
* Updates column spacing visibility based on layout orientation
|
|
90
82
|
* Column spacing is hidden for horizontal layout (products are stacked vertically)
|
|
91
|
-
* Reads from
|
|
83
|
+
* Reads from node config first, falls back to store then DOM
|
|
92
84
|
*/
|
|
93
85
|
_updateColumnSpacingVisibility() {
|
|
94
|
-
|
|
95
|
-
|
|
86
|
+
if (!this.api)
|
|
87
|
+
return;
|
|
88
|
+
const t = d.getConfig(this.currentNode), e = this.store.recommendationConfigs.orientation, i = (t.layout || e || C(this.currentNode)) === "vertical";
|
|
89
|
+
this.api.setVisibility(a.COLUMN_SPACING, i), this.api.setVisibility(a.COLUMN_SPACING_LABEL, i);
|
|
96
90
|
}
|
|
97
91
|
/**
|
|
98
|
-
* Reads spacing values from
|
|
92
|
+
* Reads spacing values from node config first, falls back to DOM styles
|
|
99
93
|
*/
|
|
100
94
|
_setFormValues() {
|
|
101
|
-
|
|
95
|
+
if (!this.api)
|
|
96
|
+
return;
|
|
97
|
+
const t = d.getConfig(this.currentNode), e = t.columnSpacing !== s ? t.columnSpacing : this._getStoredColumnSpacing(), r = t.rowSpacing !== m ? t.rowSpacing : this._getStoredRowSpacing();
|
|
102
98
|
this.api.updateValues({
|
|
103
|
-
[a.COLUMN_SPACING]:
|
|
104
|
-
[a.ROW_SPACING]:
|
|
99
|
+
[a.COLUMN_SPACING]: e,
|
|
100
|
+
[a.ROW_SPACING]: r
|
|
105
101
|
});
|
|
106
102
|
}
|
|
107
103
|
/**
|
|
@@ -112,28 +108,28 @@ class E extends b {
|
|
|
112
108
|
*/
|
|
113
109
|
_getStoredColumnSpacing() {
|
|
114
110
|
if (!this.currentNode)
|
|
115
|
-
return s
|
|
116
|
-
if (
|
|
117
|
-
const
|
|
118
|
-
if (!
|
|
119
|
-
return s
|
|
120
|
-
const
|
|
121
|
-
return
|
|
111
|
+
return s;
|
|
112
|
+
if (C(this.currentNode) === "vertical") {
|
|
113
|
+
const l = this.currentNode.querySelector(".recommendation-attribute-row"), c = l == null ? void 0 : l.querySelector("td"), f = S(c, "padding");
|
|
114
|
+
if (!f)
|
|
115
|
+
return s;
|
|
116
|
+
const _ = f.trim().split(/\s+/);
|
|
117
|
+
return _.length < 2 ? s : N(_[1], s / 2) * 2;
|
|
122
118
|
}
|
|
123
|
-
const e = this.currentNode.querySelector(".product-card-wrapper"), r =
|
|
124
|
-
if (!
|
|
125
|
-
return s
|
|
126
|
-
const
|
|
127
|
-
return
|
|
119
|
+
const e = this.currentNode.querySelector(".product-card-wrapper"), r = V(e), i = S(r, "padding");
|
|
120
|
+
if (!i)
|
|
121
|
+
return s;
|
|
122
|
+
const u = i.trim().split(/\s+/);
|
|
123
|
+
return u.length < 2 ? s : N(u[1], s / 2) * 2;
|
|
128
124
|
}
|
|
129
125
|
/**
|
|
130
126
|
* Gets stored row spacing from the first spacer element's height style
|
|
131
127
|
*/
|
|
132
128
|
_getStoredRowSpacing() {
|
|
133
129
|
if (!this.currentNode)
|
|
134
|
-
return
|
|
135
|
-
const t = this.currentNode.querySelector(".spacer"), e =
|
|
136
|
-
return
|
|
130
|
+
return m;
|
|
131
|
+
const t = this.currentNode.querySelector(".spacer"), e = S(t, "height");
|
|
132
|
+
return N(e, m);
|
|
137
133
|
}
|
|
138
134
|
/**
|
|
139
135
|
* Handles column spacing changes.
|
|
@@ -143,17 +139,22 @@ class E extends b {
|
|
|
143
139
|
_onColumnSpacingChange(t) {
|
|
144
140
|
if (!this.currentNode)
|
|
145
141
|
return;
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
142
|
+
d.updateConfig(
|
|
143
|
+
this.api,
|
|
144
|
+
this.currentNode,
|
|
145
|
+
{ columnSpacing: t },
|
|
146
|
+
`Changed column spacing to ${t}px`
|
|
147
|
+
), this._storeColumnSpacing(t);
|
|
148
|
+
const r = d.getConfig(this.currentNode).layout || C(this.currentNode), i = this.api.getDocumentModifier(), h = `0 ${t / 2}px`;
|
|
149
|
+
r === "vertical" ? Array.from(
|
|
149
150
|
this.currentNode.querySelectorAll(".attribute-cell")
|
|
150
|
-
).forEach((
|
|
151
|
-
|
|
151
|
+
).forEach((c) => {
|
|
152
|
+
i.modifyHtml(c).setStyle("padding", h);
|
|
152
153
|
}) : Array.from(
|
|
153
154
|
this.currentNode.querySelectorAll(".product-card-wrapper")
|
|
154
|
-
).forEach((
|
|
155
|
-
"parent" in
|
|
156
|
-
}),
|
|
155
|
+
).forEach((c) => {
|
|
156
|
+
"parent" in c && c.parent() && i.modifyHtml(c.parent()).setStyle("padding", h);
|
|
157
|
+
}), i.apply(new g(`Update column spacing to ${t}px`));
|
|
157
158
|
}
|
|
158
159
|
/**
|
|
159
160
|
* Handles row spacing changes
|
|
@@ -162,16 +163,21 @@ class E extends b {
|
|
|
162
163
|
_onRowSpacingChange(t) {
|
|
163
164
|
if (!this.currentNode)
|
|
164
165
|
return;
|
|
165
|
-
|
|
166
|
+
d.updateConfig(
|
|
167
|
+
this.api,
|
|
168
|
+
this.currentNode,
|
|
169
|
+
{ rowSpacing: t },
|
|
170
|
+
`Changed row spacing to ${t}px`
|
|
171
|
+
), this._storeRowSpacing(t);
|
|
166
172
|
const e = Array.from(
|
|
167
173
|
this.currentNode.querySelectorAll(".spacer")
|
|
168
174
|
);
|
|
169
175
|
if (!e.length)
|
|
170
176
|
return;
|
|
171
|
-
const r = this.api.getDocumentModifier(),
|
|
172
|
-
e.forEach((
|
|
173
|
-
r.modifyHtml(
|
|
174
|
-
}), r.apply(new
|
|
177
|
+
const r = this.api.getDocumentModifier(), i = `${t}px`;
|
|
178
|
+
e.forEach((u) => {
|
|
179
|
+
r.modifyHtml(u).setStyle("height", i);
|
|
180
|
+
}), r.apply(new g(`Update row spacing to ${t}px`));
|
|
175
181
|
}
|
|
176
182
|
/**
|
|
177
183
|
* Stores column spacing value in block data attribute
|
|
@@ -180,7 +186,7 @@ class E extends b {
|
|
|
180
186
|
if (!this.currentNode)
|
|
181
187
|
return;
|
|
182
188
|
const e = this.currentNode.querySelector(".ins-recommendation-v3-block-v2");
|
|
183
|
-
e && this.api.getDocumentModifier().modifyHtml(e).setAttribute(
|
|
189
|
+
e && this.api.getDocumentModifier().modifyHtml(e).setAttribute(P.COLUMN_SPACING, t.toString()).apply(new g("Store column spacing"));
|
|
184
190
|
}
|
|
185
191
|
/**
|
|
186
192
|
* Stores row spacing value in block data attribute
|
|
@@ -189,7 +195,7 @@ class E extends b {
|
|
|
189
195
|
if (!this.currentNode)
|
|
190
196
|
return;
|
|
191
197
|
const e = this.currentNode.querySelector(".ins-recommendation-v3-block-v2");
|
|
192
|
-
e && this.api.getDocumentModifier().modifyHtml(e).setAttribute(
|
|
198
|
+
e && this.api.getDocumentModifier().modifyHtml(e).setAttribute(P.ROW_SPACING, t.toString()).apply(new g("Store row spacing"));
|
|
193
199
|
}
|
|
194
200
|
_listenToFormUpdates() {
|
|
195
201
|
this.api.onValueChanged(a.COLUMN_SPACING, (t) => {
|
|
@@ -211,6 +217,6 @@ class E extends b {
|
|
|
211
217
|
}
|
|
212
218
|
}
|
|
213
219
|
export {
|
|
214
|
-
|
|
215
|
-
|
|
220
|
+
R as SPACING_CONTROL_ID,
|
|
221
|
+
$ as SpacingControl
|
|
216
222
|
};
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
const n = `/* Utils */
|
|
2
2
|
.es-180w { width: 180px; }
|
|
3
3
|
|
|
4
|
-
/* Recommendation Controls */
|
|
5
|
-
.recommendation-controls-container >
|
|
6
|
-
|
|
4
|
+
/* Recommendation Controls - Main settings panel separators */
|
|
5
|
+
.recommendation-controls-container > div {
|
|
6
|
+
border-bottom: 1px solid #e0e0e0;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
.recommendation-controls-container >
|
|
9
|
+
.recommendation-controls-container > div:first-child {
|
|
10
10
|
padding-top: 0;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
.recommendation-controls-container > div:last-child {
|
|
14
|
+
border-bottom: none;
|
|
15
|
+
}
|
|
16
|
+
|
|
13
17
|
.container:has(.recommendation-controls-container) {
|
|
14
18
|
padding: 0
|
|
15
19
|
}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { ModificationDescription as f } from "../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
2
|
+
import { CURRENT_CONFIG_VERSION as u, DEFAULT_NODE_CONFIG as e } from "../constants/defaultConfig.js";
|
|
3
|
+
import { setCurrencyAttributes as g } from "../controls/main/utils.js";
|
|
4
|
+
import { hasMinimalConfig as a } from "../types/nodeConfig.js";
|
|
5
|
+
class y {
|
|
6
|
+
// ========================================================================
|
|
7
|
+
// Read Operations
|
|
8
|
+
// ========================================================================
|
|
9
|
+
/**
|
|
10
|
+
* Get configuration from a node, with defaults for missing values
|
|
11
|
+
*
|
|
12
|
+
* This is the primary way to read configuration from a block.
|
|
13
|
+
* Always returns a complete config object with defaults merged in.
|
|
14
|
+
* @example
|
|
15
|
+
* const config = RecommendationConfigService.getConfig(this.currentNode);
|
|
16
|
+
* console.log(config.strategy); // 'mostPopular'
|
|
17
|
+
* @param node - The immutable HTML node to read config from
|
|
18
|
+
* @returns Complete configuration with defaults for missing values
|
|
19
|
+
*/
|
|
20
|
+
static getConfig(i) {
|
|
21
|
+
if (!i)
|
|
22
|
+
return this.cloneDefaults();
|
|
23
|
+
if (!("getNodeConfig" in i) || typeof i.getNodeConfig != "function")
|
|
24
|
+
return this.cloneDefaults();
|
|
25
|
+
try {
|
|
26
|
+
const t = i.getNodeConfig();
|
|
27
|
+
return t ? this.mergeWithDefaults(t) : this.cloneDefaults();
|
|
28
|
+
} catch {
|
|
29
|
+
return this.cloneDefaults();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Check if a node has valid configuration stored
|
|
34
|
+
*
|
|
35
|
+
* Used for migration detection - returns false for legacy templates
|
|
36
|
+
* that need their configuration migrated.
|
|
37
|
+
* @param node - The immutable HTML node to check
|
|
38
|
+
* @returns True if node has valid config with version number
|
|
39
|
+
*/
|
|
40
|
+
static hasConfig(i) {
|
|
41
|
+
if (!i || !("getNodeConfig" in i) || typeof i.getNodeConfig != "function")
|
|
42
|
+
return !1;
|
|
43
|
+
try {
|
|
44
|
+
const t = i.getNodeConfig();
|
|
45
|
+
return a(t);
|
|
46
|
+
} catch {
|
|
47
|
+
return !1;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Get the configuration version from a node
|
|
52
|
+
* @param node - The immutable HTML node to check
|
|
53
|
+
* @returns Config version number, or 0 if no config exists
|
|
54
|
+
*/
|
|
55
|
+
static getConfigVersion(i) {
|
|
56
|
+
return this.hasConfig(i) && this.getConfig(i).configVersion || 0;
|
|
57
|
+
}
|
|
58
|
+
// ========================================================================
|
|
59
|
+
// Write Operations
|
|
60
|
+
// ========================================================================
|
|
61
|
+
/**
|
|
62
|
+
* Update specific configuration values
|
|
63
|
+
*
|
|
64
|
+
* Merges the updates with existing config and persists to node.
|
|
65
|
+
* This is the primary way to update configuration from controls.
|
|
66
|
+
* @example
|
|
67
|
+
* RecommendationConfigService.updateConfig(
|
|
68
|
+
* this.api,
|
|
69
|
+
* this.currentNode,
|
|
70
|
+
* { strategy: 'complementaryItems' },
|
|
71
|
+
* 'Changed recommendation algorithm'
|
|
72
|
+
* );
|
|
73
|
+
* @param api - Stripo extension API with document modifier
|
|
74
|
+
* @param node - The immutable HTML node to update
|
|
75
|
+
* @param updates - Partial config with values to update
|
|
76
|
+
* @param description - Human-readable description for undo/redo
|
|
77
|
+
* @returns The new complete configuration
|
|
78
|
+
*/
|
|
79
|
+
static updateConfig(i, t, o, n) {
|
|
80
|
+
const s = this.getConfig(t), c = this.deepMerge(s, o);
|
|
81
|
+
return this.saveConfig(i, t, c, n), c;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Initialize configuration for a new block
|
|
85
|
+
*
|
|
86
|
+
* Called when a block is first created (dropped into template).
|
|
87
|
+
* Can optionally merge in partial config from migration.
|
|
88
|
+
* @example
|
|
89
|
+
* // In Block.onCreated lifecycle
|
|
90
|
+
* RecommendationConfigService.initializeConfig(this.api, node);
|
|
91
|
+
* @param api - Stripo extension API with document modifier
|
|
92
|
+
* @param node - The immutable HTML node to initialize
|
|
93
|
+
* @param partialConfig - Optional partial config to merge with defaults
|
|
94
|
+
* @returns The initialized configuration
|
|
95
|
+
*/
|
|
96
|
+
static initializeConfig(i, t, o) {
|
|
97
|
+
const n = o ? this.mergeWithDefaults(o) : this.cloneDefaults();
|
|
98
|
+
return this.saveConfig(i, t, n, "Initialize recommendation block"), g({
|
|
99
|
+
currentNode: t,
|
|
100
|
+
documentModifier: i.getDocumentModifier(),
|
|
101
|
+
currency: n.currency
|
|
102
|
+
}), n;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Save complete configuration to a node
|
|
106
|
+
*
|
|
107
|
+
* Low-level method - prefer `updateConfig` or `initializeConfig` in most cases.
|
|
108
|
+
* @param api - Stripo extension API with document modifier
|
|
109
|
+
* @param node - The immutable HTML node to save to
|
|
110
|
+
* @param config - Complete configuration to save
|
|
111
|
+
* @param description - Human-readable description for undo/redo
|
|
112
|
+
*/
|
|
113
|
+
static saveConfig(i, t, o, n) {
|
|
114
|
+
try {
|
|
115
|
+
i.getDocumentModifier().modifyHtml(t).setNodeConfig(o).apply(new f(n));
|
|
116
|
+
} catch (s) {
|
|
117
|
+
console.warn("[RecommendationConfigService] Failed to save config:", s);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// ========================================================================
|
|
121
|
+
// Migration Helpers
|
|
122
|
+
// ========================================================================
|
|
123
|
+
/**
|
|
124
|
+
* Migrate configuration from legacy data-attributes
|
|
125
|
+
*
|
|
126
|
+
* Reads existing data-attributes and creates a proper node config.
|
|
127
|
+
* Used when loading templates created before node config was implemented.
|
|
128
|
+
* @param api - Stripo extension API with document modifier
|
|
129
|
+
* @param node - The block node to migrate
|
|
130
|
+
* @returns The migrated configuration
|
|
131
|
+
*/
|
|
132
|
+
static migrateFromDataAttributes(i, t) {
|
|
133
|
+
const o = {
|
|
134
|
+
configVersion: u
|
|
135
|
+
};
|
|
136
|
+
if ("getAttribute" in t && typeof t.getAttribute == "function") {
|
|
137
|
+
const n = t.getAttribute("data-layout");
|
|
138
|
+
(n === "horizontal" || n === "vertical") && (o.layout = n);
|
|
139
|
+
const s = t.getAttribute("data-card-composition");
|
|
140
|
+
s && (o.composition = s.split(",").filter(Boolean));
|
|
141
|
+
const c = t.getAttribute("data-column-spacing");
|
|
142
|
+
c && (o.columnSpacing = parseInt(c) || e.columnSpacing);
|
|
143
|
+
const r = t.getAttribute("data-row-spacing");
|
|
144
|
+
r && (o.rowSpacing = parseInt(r) || e.rowSpacing);
|
|
145
|
+
}
|
|
146
|
+
return this.initializeConfig(i, t, o);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Check if configuration needs migration
|
|
150
|
+
* @param node - The block node to check
|
|
151
|
+
* @returns True if migration is needed
|
|
152
|
+
*/
|
|
153
|
+
static needsMigration(i) {
|
|
154
|
+
return i ? this.hasConfig(i) ? this.getConfigVersion(i) < u : !0 : !1;
|
|
155
|
+
}
|
|
156
|
+
// ========================================================================
|
|
157
|
+
// Internal Helpers
|
|
158
|
+
// ========================================================================
|
|
159
|
+
/**
|
|
160
|
+
* Clone default config to avoid mutations
|
|
161
|
+
*/
|
|
162
|
+
static cloneDefaults() {
|
|
163
|
+
return {
|
|
164
|
+
...e,
|
|
165
|
+
currency: { ...e.currency },
|
|
166
|
+
omnibusPrice: { ...e.omnibusPrice },
|
|
167
|
+
omnibusDiscount: { ...e.omnibusDiscount },
|
|
168
|
+
composition: [...e.composition],
|
|
169
|
+
visibility: { ...e.visibility },
|
|
170
|
+
filters: [],
|
|
171
|
+
productIds: []
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Merge partial config with defaults
|
|
176
|
+
*
|
|
177
|
+
* Deep merges nested objects like currency, omnibus settings.
|
|
178
|
+
*/
|
|
179
|
+
static mergeWithDefaults(i) {
|
|
180
|
+
const t = this.cloneDefaults();
|
|
181
|
+
return {
|
|
182
|
+
...t,
|
|
183
|
+
...i,
|
|
184
|
+
currency: {
|
|
185
|
+
...t.currency,
|
|
186
|
+
...i.currency || {}
|
|
187
|
+
},
|
|
188
|
+
omnibusPrice: {
|
|
189
|
+
...t.omnibusPrice,
|
|
190
|
+
...i.omnibusPrice || {}
|
|
191
|
+
},
|
|
192
|
+
omnibusDiscount: {
|
|
193
|
+
...t.omnibusDiscount,
|
|
194
|
+
...i.omnibusDiscount || {}
|
|
195
|
+
},
|
|
196
|
+
visibility: {
|
|
197
|
+
...t.visibility,
|
|
198
|
+
...i.visibility || {}
|
|
199
|
+
},
|
|
200
|
+
composition: i.composition || t.composition,
|
|
201
|
+
filters: i.filters || [],
|
|
202
|
+
productIds: i.productIds || []
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Deep merge for nested objects
|
|
207
|
+
*
|
|
208
|
+
* Recursively merges source into target, preserving existing values
|
|
209
|
+
* that aren't explicitly overwritten.
|
|
210
|
+
*/
|
|
211
|
+
static deepMerge(i, t) {
|
|
212
|
+
return {
|
|
213
|
+
...i,
|
|
214
|
+
...t,
|
|
215
|
+
currency: {
|
|
216
|
+
...i.currency,
|
|
217
|
+
...t.currency || {}
|
|
218
|
+
},
|
|
219
|
+
omnibusPrice: {
|
|
220
|
+
...i.omnibusPrice,
|
|
221
|
+
...t.omnibusPrice || {}
|
|
222
|
+
},
|
|
223
|
+
omnibusDiscount: {
|
|
224
|
+
...i.omnibusDiscount,
|
|
225
|
+
...t.omnibusDiscount || {}
|
|
226
|
+
},
|
|
227
|
+
visibility: {
|
|
228
|
+
...i.visibility,
|
|
229
|
+
...t.visibility || {}
|
|
230
|
+
},
|
|
231
|
+
composition: t.composition ?? i.composition,
|
|
232
|
+
filters: t.filters ?? i.filters,
|
|
233
|
+
productIds: t.productIds ?? i.productIds
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
export {
|
|
238
|
+
y as RecommendationConfigService
|
|
239
|
+
};
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { RecommendationFeedSourceMaps as
|
|
2
|
-
import { useRecommendationApi as
|
|
3
|
-
import { useConfigStore as
|
|
4
|
-
import { defineStore as
|
|
5
|
-
import { DEFAULT_CARDS_IN_ROW as
|
|
6
|
-
import { generateCompleteFilterQuery as
|
|
7
|
-
const s =
|
|
1
|
+
import { RecommendationFeedSourceMaps as l, PriceAttributes as p } from "../../../../enums/extensions/recommendationBlock.js";
|
|
2
|
+
import { useRecommendationApi as m } from "../../../../services/recommendationApi.js";
|
|
3
|
+
import { useConfigStore as f } from "../../../../stores/config.js";
|
|
4
|
+
import { defineStore as d } from "pinia";
|
|
5
|
+
import { DEFAULT_CARDS_IN_ROW as g } from "../constants/layout.js";
|
|
6
|
+
import { generateCompleteFilterQuery as c } from "../utils/filterUtil.js";
|
|
7
|
+
const s = m(), h = () => ({
|
|
8
8
|
recommendationCampaignUrls: {},
|
|
9
9
|
recommendationProducts: [],
|
|
10
10
|
recommendationConfigs: {
|
|
11
|
-
cardsInRow:
|
|
11
|
+
cardsInRow: g,
|
|
12
12
|
currencySettings: {
|
|
13
13
|
name: "USD",
|
|
14
14
|
value: "USD",
|
|
@@ -135,8 +135,8 @@ const s = p(), g = () => ({
|
|
|
135
135
|
filterSelectionDrawerStatus: !1,
|
|
136
136
|
filterList: {},
|
|
137
137
|
filterGroup: 1
|
|
138
|
-
}),
|
|
139
|
-
state: () =>
|
|
138
|
+
}), R = d("guidoRecommendationExtension", {
|
|
139
|
+
state: () => h(),
|
|
140
140
|
getters: {
|
|
141
141
|
hasFilters: (e) => !!e.recommendationConfigs.filters.length,
|
|
142
142
|
getFilterGroupCount: (e) => {
|
|
@@ -146,7 +146,7 @@ const s = p(), g = () => ({
|
|
|
146
146
|
getActivePredictiveAlgorithms: (e) => {
|
|
147
147
|
const t = [];
|
|
148
148
|
return e.activePredictiveAlgorithms.forEach((r) => {
|
|
149
|
-
t.push(...
|
|
149
|
+
t.push(...l.filter((i) => i.id === r));
|
|
150
150
|
}), t.map((r) => ({
|
|
151
151
|
text: r.name,
|
|
152
152
|
value: r.key
|
|
@@ -161,7 +161,7 @@ const s = p(), g = () => ({
|
|
|
161
161
|
value: t.text
|
|
162
162
|
})),
|
|
163
163
|
getFilterList: (e) => Object.values(e.filterList).map((t) => {
|
|
164
|
-
const r = t.type === "defaultAttribute", i =
|
|
164
|
+
const r = t.type === "defaultAttribute", i = p.includes(t.attributeName);
|
|
165
165
|
let o = r ? t.attributeName : `product_attributes.${t.attributeName}`;
|
|
166
166
|
return o = i ? `${o}.${e.recommendationConfigs.currencySettings.value}` : o, {
|
|
167
167
|
text: t.displayName,
|
|
@@ -241,30 +241,32 @@ const s = p(), g = () => ({
|
|
|
241
241
|
});
|
|
242
242
|
},
|
|
243
243
|
generateFilterQuery() {
|
|
244
|
-
return
|
|
244
|
+
return c(this.recommendationConfigs.filters);
|
|
245
245
|
},
|
|
246
246
|
async fetchRecommendationProducts() {
|
|
247
|
-
var
|
|
248
|
-
const e = this.recommendationConfigs.filters.filter((n) => n.isValid), t =
|
|
247
|
+
var u;
|
|
248
|
+
const e = this.recommendationConfigs.filters.filter((n) => n.isValid), t = c(e), r = ((u = l.find((n) => n.key === this.recommendationConfigs.strategy)) == null ? void 0 : u.path) || "", i = f(), o = {
|
|
249
|
+
// Note: {itemId} and {campaignId} are template placeholders replaced at runtime
|
|
250
|
+
locale: this.recommendationConfigs.language,
|
|
251
|
+
currency: this.recommendationConfigs.currencySettings.value,
|
|
252
|
+
partnerName: i.partnerName,
|
|
253
|
+
productId: this.recommendationConfigs.strategy === "manualMerchandising" ? this.recommendationConfigs.productIds.join(",") : "{itemId}",
|
|
254
|
+
size: this.recommendationConfigs.size,
|
|
255
|
+
details: !0,
|
|
256
|
+
campaignId: "{campaignId}",
|
|
257
|
+
filter: t
|
|
258
|
+
};
|
|
259
|
+
this.recommendationConfigs.shuffleProducts && (o.shuffle = !0);
|
|
260
|
+
const a = await s.fetchRecommendationProducts(
|
|
249
261
|
r,
|
|
250
|
-
|
|
251
|
-
// TODO: Here will be optimized and filled carefully
|
|
252
|
-
locale: this.recommendationConfigs.language,
|
|
253
|
-
currency: this.recommendationConfigs.currencySettings.value,
|
|
254
|
-
partnerName: i.partnerName,
|
|
255
|
-
productId: this.recommendationConfigs.strategy === "manualMerchandising" ? this.recommendationConfigs.productIds.join(",") : "{itemId}",
|
|
256
|
-
size: this.recommendationConfigs.size,
|
|
257
|
-
details: !0,
|
|
258
|
-
campaignId: "{campaignId}",
|
|
259
|
-
filter: t
|
|
260
|
-
}
|
|
262
|
+
o
|
|
261
263
|
);
|
|
262
264
|
this.$patch({
|
|
263
|
-
recommendationProducts:
|
|
265
|
+
recommendationProducts: a
|
|
264
266
|
});
|
|
265
267
|
}
|
|
266
268
|
}
|
|
267
269
|
});
|
|
268
270
|
export {
|
|
269
|
-
|
|
271
|
+
R as useRecommendationExtensionStore
|
|
270
272
|
};
|