@useinsider/guido 3.7.0-beta.24a845f → 3.7.0-beta.24bdfa3
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/@types/config/schemas.js +70 -66
- package/dist/composables/usePreviewMode.js +15 -14
- package/dist/composables/useRecommendationPreview.js +100 -0
- package/dist/config/compiler/utils/recommendationCompilerUtils.js +90 -82
- package/dist/config/migrator/recommendation/htmlBuilder.js +59 -58
- package/dist/config/migrator/recommendation/settingsMapper.js +38 -33
- package/dist/extensions/Blocks/Items/block.js +11 -16
- package/dist/extensions/Blocks/Recommendation/block.js +59 -43
- package/dist/extensions/Blocks/Recommendation/constants/defaultConfig.js +41 -32
- package/dist/extensions/Blocks/Recommendation/controls/cardComposition/index.js +369 -288
- package/dist/extensions/Blocks/Recommendation/controls/main/index.js +84 -72
- package/dist/extensions/Blocks/Recommendation/controls/main/pricePlacement.js +133 -0
- package/dist/extensions/Blocks/Recommendation/controls/main/utils.js +68 -66
- package/dist/extensions/Blocks/Recommendation/iconsRegistry.js +21 -7
- package/dist/extensions/Blocks/Recommendation/recommendation.css.js +64 -4
- package/dist/extensions/Blocks/Recommendation/store/recommendation.js +7 -5
- package/dist/extensions/Blocks/Recommendation/templates/grid/elementRenderer.js +101 -72
- package/dist/extensions/Blocks/Recommendation/templates/grid/template.js +31 -30
- package/dist/extensions/Blocks/Recommendation/templates/index.js +9 -7
- package/dist/extensions/Blocks/Recommendation/templates/list/elementRenderer.js +74 -59
- package/dist/extensions/Blocks/Recommendation/templates/list/template.js +21 -21
- package/dist/extensions/Blocks/Recommendation/templates/utils.js +88 -57
- package/dist/src/@types/config/schemas.d.ts +16 -0
- package/dist/src/composables/useConfig.d.ts +4 -0
- package/dist/src/composables/useRecommendationPreview.d.ts +10 -0
- package/dist/src/composables/useRecommendationPreview.test.d.ts +1 -0
- package/dist/src/config/migrator/recommendation/settingsMapper.d.ts +1 -1
- package/dist/src/extensions/Blocks/Items/block.d.ts +0 -1
- package/dist/src/extensions/Blocks/Recommendation/block.d.ts +10 -0
- package/dist/src/extensions/Blocks/Recommendation/controls/cardComposition/index.d.ts +29 -3
- package/dist/src/extensions/Blocks/Recommendation/controls/index.d.ts +1 -1
- package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +3 -1
- package/dist/src/extensions/Blocks/Recommendation/controls/main/pricePlacement.d.ts +59 -0
- package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +2 -0
- package/dist/src/extensions/Blocks/Recommendation/templates/grid/elementRenderer.d.ts +16 -0
- package/dist/src/extensions/Blocks/Recommendation/templates/grid/template.d.ts +4 -4
- package/dist/src/extensions/Blocks/Recommendation/templates/list/elementRenderer.d.ts +13 -0
- package/dist/src/extensions/Blocks/Recommendation/templates/list/template.d.ts +3 -2
- package/dist/src/extensions/Blocks/Recommendation/templates/utils.d.ts +33 -1
- package/dist/src/extensions/Blocks/Recommendation/types/nodeConfig.d.ts +15 -0
- package/dist/src/stores/config.d.ts +36 -0
- package/package.json +1 -1
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { ATTR_PRODUCT_IMAGE as a, ATTR_PRODUCT_BUTTON as
|
|
2
|
-
import { DEFAULT_CARD_COMPOSITION as
|
|
3
|
-
import { listElementRenderer as
|
|
4
|
-
function
|
|
5
|
-
const
|
|
1
|
+
import { ATTR_PRODUCT_IMAGE as a, ATTR_PRODUCT_BUTTON as c } from "../../constants/selectors.js";
|
|
2
|
+
import { DEFAULT_CARD_COMPOSITION as R, spacer as m, buildElementRenderer as T, resolveInlinePriceOrder as O, DEFAULT_CARD_VISIBILITY as w } from "../utils.js";
|
|
3
|
+
import { listElementRenderer as y, renderInlineListPriceRow as I } from "./elementRenderer.js";
|
|
4
|
+
function g(t, r, n) {
|
|
5
|
+
const o = n ? "" : ' style="display: none;"', l = t.replace(/<tr>/, "").replace(/<\/tr>/, "");
|
|
6
6
|
return `<tr
|
|
7
7
|
class="recommendation-attribute-row"
|
|
8
|
-
data-attribute-type="${
|
|
9
|
-
data-visibility="${
|
|
8
|
+
data-attribute-type="${r}"
|
|
9
|
+
data-visibility="${n ? "1" : "0"}"${o}>${l}</tr>`;
|
|
10
10
|
}
|
|
11
|
-
const
|
|
11
|
+
const _ = `
|
|
12
12
|
<tr class="recommendation-product-row">
|
|
13
13
|
<td style="padding: 0 5px;">
|
|
14
14
|
<table
|
|
@@ -26,29 +26,29 @@ const y = `
|
|
|
26
26
|
</td>
|
|
27
27
|
</tr>
|
|
28
28
|
`;
|
|
29
|
-
function
|
|
30
|
-
const
|
|
29
|
+
function P(t, r = R, n = {}, o = {}) {
|
|
30
|
+
const { priceInline: l = !1 } = o, i = T(y, r, n), d = i[a](t), s = O(r), p = (e) => l && e === s.anchor ? I(t, s.originalFirst) : i[e](t), u = `
|
|
31
31
|
<td class="product-info-cell" valign="middle" style="padding: 15px;">
|
|
32
32
|
<table cellpadding="0" cellspacing="0" role="presentation" width="100%" style="table-layout: fixed;">
|
|
33
33
|
<tbody>
|
|
34
|
-
${
|
|
35
|
-
const
|
|
36
|
-
return
|
|
34
|
+
${r.filter((e) => e !== a && e !== c).filter((e) => !(l && e === s.skip)).filter((e) => i[e]).map((e) => {
|
|
35
|
+
const C = w[e] ?? !0;
|
|
36
|
+
return g(p(e), e, C);
|
|
37
37
|
}).join(`
|
|
38
38
|
`)}
|
|
39
39
|
</tbody>
|
|
40
40
|
</table>
|
|
41
41
|
</td>
|
|
42
|
-
`,
|
|
43
|
-
return
|
|
42
|
+
`, f = i[c](t), b = d + u + f;
|
|
43
|
+
return _.replace("{-{-PRODUCT_CONTENT-}-}", b);
|
|
44
44
|
}
|
|
45
|
-
function
|
|
46
|
-
return
|
|
47
|
-
const
|
|
48
|
-
return
|
|
45
|
+
function N(t, r, n = {}, o = {}) {
|
|
46
|
+
return t.map((l, i) => {
|
|
47
|
+
const d = P(l, r, n, o);
|
|
48
|
+
return i > 0 ? m + d : d;
|
|
49
49
|
}).join("");
|
|
50
50
|
}
|
|
51
51
|
export {
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
P as getListProductCard,
|
|
53
|
+
N as prepareProductRows
|
|
54
54
|
};
|
|
@@ -1,8 +1,36 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { ATTR_PRODUCT_PRICE as c, ATTR_PRODUCT_OLD_PRICE as l, ATTR_CUSTOM_PREFIX as m, ATTR_PRODUCT_IMAGE as p, ATTR_PRODUCT_NAME as b, ATTR_PRODUCT_OMNIBUS_PRICE as g, ATTR_PRODUCT_OMNIBUS_DISCOUNT as f, ATTR_PRODUCT_BUTTON as T } from "../constants/selectors.js";
|
|
2
|
+
import { useRecommendationExtensionStore as D } from "../store/recommendation.js";
|
|
3
|
+
import { formatPrice as P } from "../utils/priceFormatter.js";
|
|
4
|
+
function S() {
|
|
5
|
+
const t = D(), { currencySettings: e } = t.recommendationConfigs;
|
|
6
|
+
return {
|
|
7
|
+
code: e.value,
|
|
8
|
+
symbol: e.symbol,
|
|
9
|
+
alignment: e.alignment === "0" ? "before" : "after",
|
|
10
|
+
decimalCount: parseInt(e.decimalCount) || 2,
|
|
11
|
+
decimalSeparator: e.decimalSeparator,
|
|
12
|
+
thousandSeparator: e.thousandSeparator
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function w(t, e = "price") {
|
|
16
|
+
const r = S(), n = t[e], o = (n == null ? void 0 : n[r.code]) ?? Object.values(n ?? {})[0] ?? 0;
|
|
17
|
+
return P({
|
|
18
|
+
price: o,
|
|
19
|
+
currency: r
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
function h(t) {
|
|
3
23
|
return t.replace(/_/g, " ").replace(/\b\w/g, (e) => e.toUpperCase());
|
|
4
24
|
}
|
|
5
|
-
function
|
|
25
|
+
function N(t) {
|
|
26
|
+
const e = t.indexOf(c), r = t.indexOf(l), n = r !== -1 && (e === -1 || r < e);
|
|
27
|
+
return {
|
|
28
|
+
originalFirst: n,
|
|
29
|
+
anchor: n ? l : c,
|
|
30
|
+
skip: n ? c : l
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function I(t) {
|
|
6
34
|
const e = Array.isArray(t) ? t[t.length - 1] : t;
|
|
7
35
|
if (typeof e == "string")
|
|
8
36
|
return e;
|
|
@@ -10,57 +38,57 @@ function U(t) {
|
|
|
10
38
|
return String(e);
|
|
11
39
|
}
|
|
12
40
|
function C(t, e) {
|
|
13
|
-
const
|
|
14
|
-
return (
|
|
41
|
+
const r = Object.values(e).find((n) => n.attributeName === t);
|
|
42
|
+
return (r == null ? void 0 : r.type) === "defaultAttribute";
|
|
15
43
|
}
|
|
16
|
-
function
|
|
44
|
+
function U(t, e) {
|
|
17
45
|
return C(t, e) ? t : `product_attribute.${t}`;
|
|
18
46
|
}
|
|
19
|
-
const
|
|
20
|
-
function
|
|
21
|
-
const
|
|
22
|
-
if (!
|
|
47
|
+
const E = Symbol("customCellHtml");
|
|
48
|
+
function v(t, e, r = {}) {
|
|
49
|
+
const n = t[E];
|
|
50
|
+
if (!n)
|
|
23
51
|
return { ...t };
|
|
24
|
-
const
|
|
25
|
-
return e.filter((
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
var
|
|
29
|
-
const
|
|
30
|
-
return
|
|
52
|
+
const o = { ...t };
|
|
53
|
+
return e.filter((s) => s.startsWith(m) && !o[s]).forEach((s) => {
|
|
54
|
+
const i = s.substring(m.length), a = h(i), y = U(i, r), O = C(i, r);
|
|
55
|
+
o[s] = (d) => {
|
|
56
|
+
var u;
|
|
57
|
+
const R = O ? d[i] : (u = d.product_attributes) == null ? void 0 : u[i], A = I(R) ?? a;
|
|
58
|
+
return n(y, A);
|
|
31
59
|
};
|
|
32
|
-
}),
|
|
60
|
+
}), o;
|
|
33
61
|
}
|
|
34
|
-
const
|
|
62
|
+
const B = {
|
|
35
63
|
TITLE: "You May Also Like!"
|
|
36
|
-
},
|
|
37
|
-
u,
|
|
64
|
+
}, F = [
|
|
38
65
|
p,
|
|
39
|
-
m,
|
|
40
66
|
b,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
g
|
|
44
|
-
|
|
45
|
-
|
|
67
|
+
l,
|
|
68
|
+
c,
|
|
69
|
+
g,
|
|
70
|
+
f,
|
|
71
|
+
T
|
|
72
|
+
], V = {
|
|
46
73
|
[p]: !0,
|
|
47
74
|
[b]: !0,
|
|
48
|
-
[
|
|
49
|
-
[
|
|
50
|
-
[
|
|
51
|
-
[
|
|
52
|
-
|
|
75
|
+
[c]: !0,
|
|
76
|
+
[l]: !0,
|
|
77
|
+
[g]: !1,
|
|
78
|
+
[f]: !1,
|
|
79
|
+
[T]: !0
|
|
80
|
+
}, L = `
|
|
53
81
|
<tr>
|
|
54
82
|
<td class="spacer" style="height: 10px;"></td>
|
|
55
83
|
</tr>
|
|
56
|
-
`,
|
|
57
|
-
function
|
|
58
|
-
return !t || typeof t != "string" || t.trim() === "" ?
|
|
84
|
+
`, _ = "https://email-static.useinsider.com/stripo/modules/email-recommendation-v3/assets/images/image-placeholder.png";
|
|
85
|
+
function H(t) {
|
|
86
|
+
return !t || typeof t != "string" || t.trim() === "" ? _ : t.startsWith("http://") ? t.replace("http://", "https://") : t;
|
|
59
87
|
}
|
|
60
|
-
function
|
|
88
|
+
function x(t) {
|
|
61
89
|
return {
|
|
62
90
|
name: "Product Name",
|
|
63
|
-
image_url:
|
|
91
|
+
image_url: _,
|
|
64
92
|
price: { USD: 18 },
|
|
65
93
|
original_price: { USD: 20 },
|
|
66
94
|
discount: { USD: 2 },
|
|
@@ -72,19 +100,19 @@ function E(t) {
|
|
|
72
100
|
category: []
|
|
73
101
|
};
|
|
74
102
|
}
|
|
75
|
-
function
|
|
103
|
+
function W(t = 6) {
|
|
76
104
|
return Array.from(
|
|
77
105
|
{ length: t },
|
|
78
|
-
(e,
|
|
106
|
+
(e, r) => x(String(r + 1))
|
|
79
107
|
);
|
|
80
108
|
}
|
|
81
|
-
function
|
|
82
|
-
const
|
|
83
|
-
data-layout="list"` : "",
|
|
109
|
+
function j(t = "grid", e) {
|
|
110
|
+
const r = t === "list" ? `
|
|
111
|
+
data-layout="list"` : "", n = e ? ` ${e}` : "";
|
|
84
112
|
return `
|
|
85
113
|
<td
|
|
86
114
|
align="left"
|
|
87
|
-
class="${`recommendation-block-v2 esd-block-recommendation-v3-block es-p20${t === "list" ? " es-m-p0 ins-recommendation-list-layout" : ""}${
|
|
115
|
+
class="${`recommendation-block-v2 esd-block-recommendation-v3-block es-p20${t === "list" ? " es-m-p0 ins-recommendation-list-layout" : ""}${n}`}"${r}>
|
|
88
116
|
<table width="100%" cellpadding="0" cellspacing="0" border="0">
|
|
89
117
|
<tr>
|
|
90
118
|
<td align="center">
|
|
@@ -116,7 +144,7 @@ function x(t = "grid", e) {
|
|
|
116
144
|
</table>
|
|
117
145
|
</td>
|
|
118
146
|
</tr>
|
|
119
|
-
${
|
|
147
|
+
${L}
|
|
120
148
|
<tr>
|
|
121
149
|
<td>
|
|
122
150
|
<table
|
|
@@ -155,18 +183,21 @@ function x(t = "grid", e) {
|
|
|
155
183
|
`;
|
|
156
184
|
}
|
|
157
185
|
export {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
186
|
+
E as CUSTOM_CELL_HTML,
|
|
187
|
+
B as DEFAULTS,
|
|
188
|
+
F as DEFAULT_CARD_COMPOSITION,
|
|
189
|
+
V as DEFAULT_CARD_VISIBILITY,
|
|
190
|
+
_ as PLACEHOLDER_IMAGE,
|
|
191
|
+
v as buildElementRenderer,
|
|
192
|
+
j as createBlockTemplate,
|
|
193
|
+
w as formatProductPrice,
|
|
194
|
+
S as getCurrentCurrencyConfig,
|
|
195
|
+
W as getDefaultProducts,
|
|
166
196
|
C as isDefaultAttribute,
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
197
|
+
N as resolveInlinePriceOrder,
|
|
198
|
+
U as resolveProductAttrValue,
|
|
199
|
+
H as sanitizeImageUrl,
|
|
200
|
+
L as spacer,
|
|
201
|
+
h as toDisplayName,
|
|
202
|
+
I as toDisplayableAttributeValue
|
|
172
203
|
};
|
|
@@ -139,6 +139,10 @@ export declare const LegacyRecommendationConfigSchema: v.LooseObjectSchema<{
|
|
|
139
139
|
readonly size: v.OptionalSchema<v.UnionSchema<[v.StringSchema<undefined>, v.NumberSchema<undefined>], undefined>, undefined>;
|
|
140
140
|
/** Vertical responsiveness flag (legacy size=1 variants) */
|
|
141
141
|
readonly verticalResponsiveness: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
142
|
+
/** Legacy "Move to next line" price placement toggle (cardPricePlacement.js) */
|
|
143
|
+
readonly isPriceMovedToNextLine: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
144
|
+
/** Legacy "Hide if same as discounted" / delete-price-for-zero-sale toggle */
|
|
145
|
+
readonly isPriceDeletedForZeroSale: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
142
146
|
}, undefined>;
|
|
143
147
|
/**
|
|
144
148
|
* Migration-only inputs scoped to this template.
|
|
@@ -195,6 +199,10 @@ export declare const TemplateMigrationSchema: v.ObjectSchema<{
|
|
|
195
199
|
readonly size: v.OptionalSchema<v.UnionSchema<[v.StringSchema<undefined>, v.NumberSchema<undefined>], undefined>, undefined>;
|
|
196
200
|
/** Vertical responsiveness flag (legacy size=1 variants) */
|
|
197
201
|
readonly verticalResponsiveness: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
202
|
+
/** Legacy "Move to next line" price placement toggle (cardPricePlacement.js) */
|
|
203
|
+
readonly isPriceMovedToNextLine: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
204
|
+
/** Legacy "Hide if same as discounted" / delete-price-for-zero-sale toggle */
|
|
205
|
+
readonly isPriceDeletedForZeroSale: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
198
206
|
}, undefined>, undefined>, {}>;
|
|
199
207
|
}, undefined>;
|
|
200
208
|
/**
|
|
@@ -274,6 +282,10 @@ export declare const TemplateSchema: v.ObjectSchema<{
|
|
|
274
282
|
readonly size: v.OptionalSchema<v.UnionSchema<[v.StringSchema<undefined>, v.NumberSchema<undefined>], undefined>, undefined>;
|
|
275
283
|
/** Vertical responsiveness flag (legacy size=1 variants) */
|
|
276
284
|
readonly verticalResponsiveness: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
285
|
+
/** Legacy "Move to next line" price placement toggle (cardPricePlacement.js) */
|
|
286
|
+
readonly isPriceMovedToNextLine: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
287
|
+
/** Legacy "Hide if same as discounted" / delete-price-for-zero-sale toggle */
|
|
288
|
+
readonly isPriceDeletedForZeroSale: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
277
289
|
}, undefined>, undefined>, {}>;
|
|
278
290
|
}, undefined>, {}>;
|
|
279
291
|
}, undefined>;
|
|
@@ -665,6 +677,10 @@ export declare const GuidoConfigSchema: v.ObjectSchema<{
|
|
|
665
677
|
readonly size: v.OptionalSchema<v.UnionSchema<[v.StringSchema<undefined>, v.NumberSchema<undefined>], undefined>, undefined>;
|
|
666
678
|
/** Vertical responsiveness flag (legacy size=1 variants) */
|
|
667
679
|
readonly verticalResponsiveness: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
680
|
+
/** Legacy "Move to next line" price placement toggle (cardPricePlacement.js) */
|
|
681
|
+
readonly isPriceMovedToNextLine: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
682
|
+
/** Legacy "Hide if same as discounted" / delete-price-for-zero-sale toggle */
|
|
683
|
+
readonly isPriceDeletedForZeroSale: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
668
684
|
}, undefined>, undefined>, {}>;
|
|
669
685
|
}, undefined>, {}>;
|
|
670
686
|
}, undefined>, {}>;
|
|
@@ -60,6 +60,8 @@ export declare const useConfig: () => {
|
|
|
60
60
|
blockType?: string | undefined;
|
|
61
61
|
size?: string | number | undefined;
|
|
62
62
|
verticalResponsiveness?: boolean | undefined;
|
|
63
|
+
isPriceMovedToNextLine?: boolean | undefined;
|
|
64
|
+
isPriceDeletedForZeroSale?: boolean | undefined;
|
|
63
65
|
} & {
|
|
64
66
|
[key: string]: unknown;
|
|
65
67
|
};
|
|
@@ -186,6 +188,8 @@ export declare const useConfig: () => {
|
|
|
186
188
|
blockType?: string | undefined;
|
|
187
189
|
size?: string | number | undefined;
|
|
188
190
|
verticalResponsiveness?: boolean | undefined;
|
|
191
|
+
isPriceMovedToNextLine?: boolean | undefined;
|
|
192
|
+
isPriceDeletedForZeroSale?: boolean | undefined;
|
|
189
193
|
} & {
|
|
190
194
|
[key: string]: unknown;
|
|
191
195
|
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Substitutes recommendation product variables in compiled preview HTML with the
|
|
3
|
+
* blocks' fetched sample products, then simulates the email-service hide rule by
|
|
4
|
+
* emptying the original-price cell (DOM kept) for slots with no real discount.
|
|
5
|
+
* Returns the input unchanged when there are no reco blocks or no products.
|
|
6
|
+
*/
|
|
7
|
+
export declare function substituteRecommendationPreview(html: string): string;
|
|
8
|
+
export declare const useRecommendationPreview: () => {
|
|
9
|
+
substituteRecommendationPreview: typeof substituteRecommendationPreview;
|
|
10
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -3,5 +3,5 @@ import type { CurrencyConfig, RecommendationNodeConfig } from '@@/Extensions/Blo
|
|
|
3
3
|
import type { LegacyRecommendationConfig } from '@@/Types/config';
|
|
4
4
|
/** Defensive against missing/malformed legacy `currencySettings` — defaults are per-field, not whole-object. */
|
|
5
5
|
export declare function mapCurrency(legacy: unknown): CurrencyConfig;
|
|
6
|
-
export type SettingsPartial = Pick<RecommendationNodeConfig, 'recommendationId' | 'strategy' | 'productIds' | 'size' | 'shuffleProducts' | 'language' | 'currency' | 'filters' | 'layout' | 'cardsInRow' | 'mobileCardsInRow' | 'mobileLayoutEnabled' | 'previousMobileCardsInRow' | 'columnSpacing' | 'rowSpacing' | 'mobileColumnSpacing' | 'mobileRowSpacing' | 'omnibusPrice' | 'omnibusDiscount' | 'configVersion'>;
|
|
6
|
+
export type SettingsPartial = Pick<RecommendationNodeConfig, 'recommendationId' | 'strategy' | 'productIds' | 'size' | 'shuffleProducts' | 'language' | 'currency' | 'filters' | 'layout' | 'cardsInRow' | 'mobileCardsInRow' | 'mobileLayoutEnabled' | 'previousMobileCardsInRow' | 'columnSpacing' | 'rowSpacing' | 'mobileColumnSpacing' | 'mobileRowSpacing' | 'omnibusPrice' | 'omnibusDiscount' | 'priceMovedToNextLine' | 'priceHideIfSameAsDiscounted' | 'configVersion'>;
|
|
7
7
|
export declare function mapSettings(recCfg: LegacyRecommendationConfig, parsed: LegacyProductConfig, id: number): SettingsPartial;
|
|
@@ -104,6 +104,16 @@ export declare class RecommendationBlock extends Block {
|
|
|
104
104
|
* added classes via setAttribute.
|
|
105
105
|
*/
|
|
106
106
|
private _assignRecommendationId;
|
|
107
|
+
/**
|
|
108
|
+
* Stamps the `hide-price` attribute (read by email-service at send time) on
|
|
109
|
+
* the block element from the config flag.
|
|
110
|
+
*/
|
|
111
|
+
private _stampHidePrice;
|
|
112
|
+
/**
|
|
113
|
+
* Stamps `hide-price` from config only when the block lacks the attribute —
|
|
114
|
+
* heals templates saved before this feature without dirtying current ones.
|
|
115
|
+
*/
|
|
116
|
+
private _healHidePriceAttr;
|
|
107
117
|
/**
|
|
108
118
|
* Gets the recommendation-id from a block node
|
|
109
119
|
*/
|
|
@@ -43,6 +43,15 @@ export declare class RecommendationCardCompositionControl extends CommonControl
|
|
|
43
43
|
*/
|
|
44
44
|
private _tryReorderInPlace;
|
|
45
45
|
private _createBuiltInItemHtml;
|
|
46
|
+
/**
|
|
47
|
+
* Inline mode: the merged "Product Prices" group item. It moves as a unit in
|
|
48
|
+
* the main list (both keys stay adjacent) and contains a nested 2-item drag
|
|
49
|
+
* to reorder Product Price ↔ Product Original Price — which flips the inline
|
|
50
|
+
* render order via `resolveInlinePriceOrder`. The group keeps a single
|
|
51
|
+
* visibility toggle (`data-action-for="productPrice"`). Nested sub-items use a
|
|
52
|
+
* plain drag handle (no UE button → untouched by the reorder-icon rescue).
|
|
53
|
+
*/
|
|
54
|
+
private _createPriceGroupItemHtml;
|
|
46
55
|
private _createCustomItemHtml;
|
|
47
56
|
/**
|
|
48
57
|
* Builds select options from the store's filterList.
|
|
@@ -98,7 +107,23 @@ export declare class RecommendationCardCompositionControl extends CommonControl
|
|
|
98
107
|
*/
|
|
99
108
|
private _rescueReorderIconsToStore;
|
|
100
109
|
private _setupEventListeners;
|
|
110
|
+
/**
|
|
111
|
+
* Builds the composition key order from the orderable list, expanding the
|
|
112
|
+
* inline "Product Prices" group into its two sub-keys (in nested DOM order)
|
|
113
|
+
* so both price keys stay adjacent and in the user-chosen order.
|
|
114
|
+
*/
|
|
115
|
+
private _extractCompositionOrder;
|
|
101
116
|
private _setupDragAndDrop;
|
|
117
|
+
/**
|
|
118
|
+
* Wires drag/drop reordering for one item level on the shared list. Both the
|
|
119
|
+
* top-level items and the nested price sub-items use this; they never fight
|
|
120
|
+
* because each only sets its `dragged` ref when its own `itemSelector` matches
|
|
121
|
+
* at dragstart (and the top-level one additionally ignores drags originating
|
|
122
|
+
* inside `ignoreSelector`). Every drop re-reads the full composition via
|
|
123
|
+
* `_extractCompositionOrder`, so both levels commit through `_onReorder`
|
|
124
|
+
* identically.
|
|
125
|
+
*/
|
|
126
|
+
private _registerDragHandlers;
|
|
102
127
|
private _setupDeleteHandler;
|
|
103
128
|
private _onAddAttribute;
|
|
104
129
|
/**
|
|
@@ -155,9 +180,10 @@ export declare class RecommendationCardCompositionControl extends CommonControl
|
|
|
155
180
|
private _extractSegmentBgFromCard;
|
|
156
181
|
private _getControlContainer;
|
|
157
182
|
/**
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
183
|
+
* Ensures composition reorder is enabled. Both grid and list layouts now
|
|
184
|
+
* support reordering — top-level items and the nested price sub-items are all
|
|
185
|
+
* draggable. (Items render with `draggable="true"`; this just clears any stale
|
|
186
|
+
* disabled state.)
|
|
161
187
|
*/
|
|
162
188
|
private _updateOrderableState;
|
|
163
189
|
/**
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* // Or individual imports
|
|
10
10
|
* import { NameAlignControl, ButtonColorControl } from './controls';
|
|
11
11
|
*/
|
|
12
|
-
export { RecommendationBlockControl, CONTROL_BLOCK_ID, AlgorithmControl, ALGORITHM_CONTROL_ID, LocaleControl, LOCALE_CONTROL_ID, CurrencyControl, CURRENCY_CONTROL_ID, ProductCountControl, PRODUCT_COUNT_CONTROL_ID, ProductLayoutControl, PRODUCT_LAYOUT_CONTROL_ID, FiltersControl, FILTERS_CONTROL_ID, ShuffleControl, SHUFFLE_CONTROL_ID, LayoutOrientationControl, LAYOUT_ORIENTATION_CONTROL_ID, } from './main';
|
|
12
|
+
export { RecommendationBlockControl, CONTROL_BLOCK_ID, AlgorithmControl, ALGORITHM_CONTROL_ID, LocaleControl, LOCALE_CONTROL_ID, CurrencyControl, CURRENCY_CONTROL_ID, ProductCountControl, PRODUCT_COUNT_CONTROL_ID, ProductLayoutControl, PRODUCT_LAYOUT_CONTROL_ID, FiltersControl, FILTERS_CONTROL_ID, ShuffleControl, SHUFFLE_CONTROL_ID, LayoutOrientationControl, LAYOUT_ORIENTATION_CONTROL_ID, PricePlacementControl, PRICE_PLACEMENT_CONTROL_ID, } from './main';
|
|
13
13
|
export * from './main/utils';
|
|
14
14
|
export { NameControls } from './name';
|
|
15
15
|
export { PriceControls } from './price';
|
|
@@ -5,11 +5,12 @@ import { CurrencyControl, CURRENCY_CONTROL_ID } from './currency';
|
|
|
5
5
|
import { FiltersControl, FILTERS_CONTROL_ID } from './filters';
|
|
6
6
|
import { LayoutOrientationControl, LAYOUT_ORIENTATION_CONTROL_ID } from './layoutOrientation';
|
|
7
7
|
import { LocaleControl, LOCALE_CONTROL_ID } from './locale';
|
|
8
|
+
import { PricePlacementControl, PRICE_PLACEMENT_CONTROL_ID } from './pricePlacement';
|
|
8
9
|
import { ProductCountControl, PRODUCT_COUNT_CONTROL_ID } from './productCount';
|
|
9
10
|
import { ProductLayoutControl, PRODUCT_LAYOUT_CONTROL_ID } from './productLayout';
|
|
10
11
|
import { ShuffleControl, SHUFFLE_CONTROL_ID } from './shuffle';
|
|
11
12
|
export declare const CONTROL_BLOCK_ID = "ui-elements-recommendation-block";
|
|
12
|
-
export { AlgorithmControl, ALGORITHM_CONTROL_ID, LocaleControl, LOCALE_CONTROL_ID, CurrencyControl, CURRENCY_CONTROL_ID, ProductCountControl, PRODUCT_COUNT_CONTROL_ID, ProductLayoutControl, PRODUCT_LAYOUT_CONTROL_ID, FiltersControl, FILTERS_CONTROL_ID, ShuffleControl, SHUFFLE_CONTROL_ID, LayoutOrientationControl, LAYOUT_ORIENTATION_CONTROL_ID, };
|
|
13
|
+
export { AlgorithmControl, ALGORITHM_CONTROL_ID, LocaleControl, LOCALE_CONTROL_ID, CurrencyControl, CURRENCY_CONTROL_ID, ProductCountControl, PRODUCT_COUNT_CONTROL_ID, ProductLayoutControl, PRODUCT_LAYOUT_CONTROL_ID, FiltersControl, FILTERS_CONTROL_ID, ShuffleControl, SHUFFLE_CONTROL_ID, LayoutOrientationControl, LAYOUT_ORIENTATION_CONTROL_ID, PricePlacementControl, PRICE_PLACEMENT_CONTROL_ID, };
|
|
13
14
|
export * from './utils';
|
|
14
15
|
/**
|
|
15
16
|
* Main recommendation block control that composes all sub-controls
|
|
@@ -25,6 +26,7 @@ export declare class RecommendationBlockControl extends CommonControl {
|
|
|
25
26
|
private productLayoutControl;
|
|
26
27
|
private filtersControl;
|
|
27
28
|
private shuffleControl;
|
|
29
|
+
private pricePlacementControl;
|
|
28
30
|
private layoutOrientationControl;
|
|
29
31
|
getId(): string;
|
|
30
32
|
getTemplate(): string;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Price Placement Control
|
|
3
|
+
*
|
|
4
|
+
* Two block-level price settings ported from the legacy product block, shown
|
|
5
|
+
* above the Currency control in the main Settings tab:
|
|
6
|
+
*
|
|
7
|
+
* - "Product Price Orientation" (`priceMovedToNextLine`): a vertical/horizontal
|
|
8
|
+
* icon radio (mirrors the Items block control). `vertical` (default) keeps the
|
|
9
|
+
* price and original price on separate stacked rows (current Guido look);
|
|
10
|
+
* `horizontal` renders them inline on the same line and Card Composition
|
|
11
|
+
* collapses them into a single "Product Prices" entry.
|
|
12
|
+
* - "Hide if same as discounted" (`priceHideIfSameAsDiscounted`): a toggle.
|
|
13
|
+
* When ON, email-service blanks the redundant original price at send time when
|
|
14
|
+
* it equals the sale price (see the `hide-price` block attribute below).
|
|
15
|
+
*
|
|
16
|
+
* Orientation re-renders the rows (it changes the saved template layout).
|
|
17
|
+
* Hide-if-same NEVER touches the template — it only persists config + stamps the
|
|
18
|
+
* `hide-price` attribute; the visual hide is simulated in the preview and applied
|
|
19
|
+
* for real server-side by email-service.
|
|
20
|
+
*/
|
|
21
|
+
import type { RecommendationNodeConfig } from '../../types/nodeConfig';
|
|
22
|
+
import type { ImmutableHtmlNode } from '@stripoinc/ui-editor-extensions';
|
|
23
|
+
import { CommonControl } from '../../../common-control';
|
|
24
|
+
export declare const PRICE_PLACEMENT_CONTROL_ID = "recommendation-price-placement-control";
|
|
25
|
+
type Orientation = 'vertical' | 'horizontal';
|
|
26
|
+
/**
|
|
27
|
+
* Control for the block-level price orientation radio + hide-if-same toggle.
|
|
28
|
+
*/
|
|
29
|
+
export declare class PricePlacementControl extends CommonControl {
|
|
30
|
+
private store;
|
|
31
|
+
getId(): string;
|
|
32
|
+
getTemplate(): string;
|
|
33
|
+
onRender(): void;
|
|
34
|
+
onTemplateNodeUpdated(node: ImmutableHtmlNode): void;
|
|
35
|
+
_setFormValues(config: RecommendationNodeConfig): void;
|
|
36
|
+
_initializeHideToggle(config: RecommendationNodeConfig): void;
|
|
37
|
+
/**
|
|
38
|
+
* Disables the orientation radio when a price element is hidden via Card
|
|
39
|
+
* Composition — orientation is meaningless without both prices visible.
|
|
40
|
+
* Visibility lives on the attribute rows' `data-visibility` (set by the Card
|
|
41
|
+
* Composition control). Inline mode has no standalone original-price row, so
|
|
42
|
+
* the merged "Product Prices" entry (the price row) governs.
|
|
43
|
+
*/
|
|
44
|
+
_updateOrientationDisabled(): void;
|
|
45
|
+
_onOrientationChange(orientation: Orientation): void;
|
|
46
|
+
_onHideIfSameChange(value: boolean): void;
|
|
47
|
+
/**
|
|
48
|
+
* Mirrors the hide-if-same flag onto the durable `hide-price` block attribute
|
|
49
|
+
* read by email-service at send time.
|
|
50
|
+
*/
|
|
51
|
+
_stampHideIfSameAttr(value: boolean): void;
|
|
52
|
+
/**
|
|
53
|
+
* Rebuilds the product rows so the renderer re-reads the inline/stacked
|
|
54
|
+
* layout flag from the store. Used by the orientation change only.
|
|
55
|
+
*/
|
|
56
|
+
_regenerate(): void;
|
|
57
|
+
_listenToFormUpdates(): void;
|
|
58
|
+
}
|
|
59
|
+
export {};
|
|
@@ -24,6 +24,8 @@ export interface PerBlockConfigs {
|
|
|
24
24
|
unresponsive: boolean;
|
|
25
25
|
size: string;
|
|
26
26
|
customAttributes: string[];
|
|
27
|
+
priceMovedToNextLine: boolean;
|
|
28
|
+
priceHideIfSameAsDiscounted: boolean;
|
|
27
29
|
}
|
|
28
30
|
interface PerBlockState {
|
|
29
31
|
recommendationConfigs: PerBlockConfigs;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { RecommendationProduct } from '@@/Types/recommendation';
|
|
1
2
|
import { type ElementRenderer } from '../utils';
|
|
2
3
|
/**
|
|
3
4
|
* Grid element renderer
|
|
@@ -24,4 +25,19 @@ export declare const ATTRIBUTE_CELL_CLASS = "attribute-cell";
|
|
|
24
25
|
* card-composition control so both render identical filler markup.
|
|
25
26
|
*/
|
|
26
27
|
export declare function buildFillerCell(columnWidth: string, padding?: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Renders the inline price cell used when "Move to next line" is OFF: the sale
|
|
30
|
+
* price and original price sit side by side in a single attribute cell, each
|
|
31
|
+
* keeping its own `esd-extension-block-id` + `product-*` class so the per-element
|
|
32
|
+
* style controls and the compiler keep working.
|
|
33
|
+
*
|
|
34
|
+
* `originalFirst` preserves the card-composition order (original before sale when
|
|
35
|
+
* `productOldPrice` precedes `productPrice` in the composition) so the side-by-side
|
|
36
|
+
* order matches the stacked order.
|
|
37
|
+
*/
|
|
38
|
+
export declare function renderInlineGridPriceCell(product: RecommendationProduct, originalFirst?: boolean): string;
|
|
39
|
+
/**
|
|
40
|
+
* Standalone (stacked) original-price cell.
|
|
41
|
+
*/
|
|
42
|
+
export declare function renderGridOldPriceCell(product: RecommendationProduct): string;
|
|
27
43
|
export declare const gridElementRenderer: ElementRenderer;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { FiltersResponse, RecommendationProduct } from '@@/Types/recommendation';
|
|
2
|
-
import { type ElementRenderer } from '../utils';
|
|
2
|
+
import { type ElementRenderer, type PricePlacementFlags } from '../utils';
|
|
3
3
|
/**
|
|
4
4
|
* Generates attribute-aligned product rows for grid layout.
|
|
5
5
|
* Creates rows where each row contains one attribute type from all products.
|
|
@@ -9,7 +9,7 @@ import { type ElementRenderer } from '../utils';
|
|
|
9
9
|
* @param composition - Array defining order of card elements
|
|
10
10
|
* @returns HTML string for attribute-aligned rows
|
|
11
11
|
*/
|
|
12
|
-
export declare function prepareGridAttributeRows(products: RecommendationProduct[], productsPerRow: number, elementRenderer: ElementRenderer, composition?: string[], filterList?: FiltersResponse): string;
|
|
12
|
+
export declare function prepareGridAttributeRows(products: RecommendationProduct[], productsPerRow: number, elementRenderer: ElementRenderer, composition?: string[], filterList?: FiltersResponse, flags?: PricePlacementFlags): string;
|
|
13
13
|
/**
|
|
14
14
|
* Prepares grid product rows with attribute-aligned structure
|
|
15
15
|
* Groups products into rows, then generates attribute-aligned HTML for each group
|
|
@@ -19,7 +19,7 @@ export declare function prepareGridAttributeRows(products: RecommendationProduct
|
|
|
19
19
|
* @param composition - Array defining order of card elements
|
|
20
20
|
* @returns HTML string for all product rows
|
|
21
21
|
*/
|
|
22
|
-
export declare function prepareGridProductRows(products: RecommendationProduct[], productsPerRow: number, elementRenderer: ElementRenderer, composition?: string[], filterList?: FiltersResponse): string;
|
|
22
|
+
export declare function prepareGridProductRows(products: RecommendationProduct[], productsPerRow: number, elementRenderer: ElementRenderer, composition?: string[], filterList?: FiltersResponse, flags?: PricePlacementFlags): string;
|
|
23
23
|
/**
|
|
24
24
|
* Prepares grid product rows with attribute-aligned structure.
|
|
25
25
|
* Uses row-based rendering where each attribute type forms a single row across all products.
|
|
@@ -28,6 +28,6 @@ export declare function prepareGridProductRows(products: RecommendationProduct[]
|
|
|
28
28
|
* @param composition - Array defining element order
|
|
29
29
|
* @returns HTML string for product rows
|
|
30
30
|
*/
|
|
31
|
-
export declare function prepareProductRows(products: RecommendationProduct[], productsPerRow: number, composition?: string[], filterList?: FiltersResponse): string;
|
|
31
|
+
export declare function prepareProductRows(products: RecommendationProduct[], productsPerRow: number, composition?: string[], filterList?: FiltersResponse, flags?: PricePlacementFlags): string;
|
|
32
32
|
export declare function getDefaultTemplate(recommendationId?: number): string;
|
|
33
33
|
export declare function generateBlockTemplate(products: RecommendationProduct[], productsPerRow: number, title?: string, composition?: string[], mobileProductsPerRow?: number): string;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { RecommendationProduct } from '@@/Types/recommendation';
|
|
1
2
|
import { type ElementRenderer } from '../utils';
|
|
2
3
|
/**
|
|
3
4
|
* List element renderer
|
|
@@ -5,4 +6,16 @@ import { type ElementRenderer } from '../utils';
|
|
|
5
6
|
* - Name and Prices return `<tr><td>` rows for the info cell table
|
|
6
7
|
* All elements have esd-block-* classes for Stripo selection
|
|
7
8
|
*/
|
|
9
|
+
/**
|
|
10
|
+
* Standalone (stacked) original-price info row.
|
|
11
|
+
*/
|
|
12
|
+
export declare function renderListOldPriceRow(product: RecommendationProduct): string;
|
|
13
|
+
/**
|
|
14
|
+
* Inline price info row used when "Move to next line" is OFF: the sale price and
|
|
15
|
+
* original price sit in two cells of one row. Each keeps its block id + class so
|
|
16
|
+
* style controls and the compiler keep working. `originalFirst` preserves the
|
|
17
|
+
* card-composition order (original before sale by default) so it matches the
|
|
18
|
+
* stacked order.
|
|
19
|
+
*/
|
|
20
|
+
export declare function renderInlineListPriceRow(product: RecommendationProduct, originalFirst?: boolean): string;
|
|
8
21
|
export declare const listElementRenderer: ElementRenderer;
|