@useinsider/guido 3.3.0-beta.fb07834 → 3.3.1-beta.11641c6
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/composables/useHtmlValidator.js +36 -41
- package/dist/composables/useRecommendation.js +2 -2
- package/dist/enums/extensions/recommendationBlock.js +95 -41
- package/dist/enums/unsubscribe.js +25 -24
- package/dist/extensions/Blocks/Checkbox/control.js +23 -23
- package/dist/extensions/Blocks/RadioButton/control.js +15 -15
- package/dist/extensions/Blocks/Recommendation/block.js +43 -36
- package/dist/extensions/Blocks/Recommendation/services/configService.js +33 -26
- package/dist/extensions/Blocks/Recommendation/store/recommendation.js +23 -32
- package/dist/src/enums/extensions/recommendationBlock.d.ts +5 -1
- package/dist/src/enums/unsubscribe.d.ts +8 -3
- package/dist/src/extensions/Blocks/Recommendation/services/configService.d.ts +11 -3
- package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +1 -7
- package/package.json +1 -1
- package/dist/extensions/Blocks/Recommendation/validation/requiredFields.js +0 -33
- package/dist/src/extensions/Blocks/Recommendation/validation/requiredFields.d.ts +0 -21
|
@@ -1,37 +1,35 @@
|
|
|
1
|
-
import { useConfig as
|
|
2
|
-
import { TemplateTypes as
|
|
3
|
-
import { DISPLAY_CONDITIONS_REGEX as
|
|
1
|
+
import { useConfig as L } from "./useConfig.js";
|
|
2
|
+
import { TemplateTypes as V } from "../enums/defaults.js";
|
|
3
|
+
import { DISPLAY_CONDITIONS_REGEX as _, DISPLAY_CONDITIONS_EXCEPTIONS_REGEX as H, CampaignCouldNotBeSavedKey as P, CanNotMakeAnyChangesForRunningKey as G } from "../enums/html-validator.js";
|
|
4
4
|
import { ToasterTypeOptions as c } from "../enums/toaster.js";
|
|
5
|
-
import { itemsBlockDynamicVariables as
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
function Q(a) {
|
|
15
|
-
return [...a.matchAll(J)].map((u) => u[1]);
|
|
5
|
+
import { itemsBlockDynamicVariables as M } from "../extensions/Blocks/Items/enums/productEnums.js";
|
|
6
|
+
import { useRecommendationStore as $ } from "../stores/recommendation.js";
|
|
7
|
+
import { base64EncodeWithSpecialChars as X } from "../utils/base64.js";
|
|
8
|
+
import { useHttp as j } from "./useHttp.js";
|
|
9
|
+
import { useToaster as q } from "./useToaster.js";
|
|
10
|
+
import { useTranslations as z } from "./useTranslations.js";
|
|
11
|
+
const K = /recommendation-id="(\d+)"/g;
|
|
12
|
+
function U(a) {
|
|
13
|
+
return [...a.matchAll(K)].map((u) => u[1]);
|
|
16
14
|
}
|
|
17
|
-
function
|
|
15
|
+
function Y(a, u) {
|
|
18
16
|
return u.some((d) => a.startsWith(`${d}_`));
|
|
19
17
|
}
|
|
20
|
-
const
|
|
18
|
+
const ce = () => {
|
|
21
19
|
var y, h;
|
|
22
|
-
const { showToaster: a } =
|
|
20
|
+
const { showToaster: a } = q(), { post: u } = j(), { config: d } = L(), r = z(), g = $(), p = ((h = (y = d.value) == null ? void 0 : y.partner) == null ? void 0 : h.messageType) === V.transactional, b = async (e) => {
|
|
23
21
|
const t = await u(
|
|
24
22
|
"/newsletter/template-library/check-template-html-body",
|
|
25
|
-
{ html:
|
|
23
|
+
{ html: X(e) }
|
|
26
24
|
), { status: n, message: l } = t.data;
|
|
27
25
|
return n || a({
|
|
28
26
|
type: c.Alert,
|
|
29
27
|
message: n === void 0 ? l : r("newsletter.invalid-url-link-for-toaster")
|
|
30
|
-
}), r(
|
|
28
|
+
}), r(P), l === r(G) && a({
|
|
31
29
|
type: c.Alert,
|
|
32
30
|
message: r("newsletter.already-in-progress")
|
|
33
31
|
}), n;
|
|
34
|
-
}, w = (e) => !["if", "endif", "else", "elif", "now"].includes(e.toLowerCase()),
|
|
32
|
+
}, w = (e) => !["if", "endif", "else", "elif", "now"].includes(e.toLowerCase()), S = (e) => ["if", "endif"].includes(e.toLowerCase()), E = (e, s) => {
|
|
35
33
|
const t = e.match(/({%(.*?)%})/g);
|
|
36
34
|
let n = !0;
|
|
37
35
|
return t !== null && !p && t.forEach((l) => {
|
|
@@ -44,13 +42,13 @@ const ge = () => {
|
|
|
44
42
|
}), n = !1);
|
|
45
43
|
}
|
|
46
44
|
}), n;
|
|
47
|
-
},
|
|
45
|
+
}, A = async (e, s, t) => {
|
|
48
46
|
const n = t ? await b(e) : !0;
|
|
49
|
-
return
|
|
50
|
-
},
|
|
47
|
+
return E(e, s) && n;
|
|
48
|
+
}, I = (e) => e.length > 0 ? !0 : (a({
|
|
51
49
|
type: c.Warning,
|
|
52
50
|
message: r("newsletter.html-content-is-empty")
|
|
53
|
-
}), !1),
|
|
51
|
+
}), !1), k = (e) => {
|
|
54
52
|
const s = (e.match(/{/gm) || []).length, t = (e.match(/}/gm) || []).length;
|
|
55
53
|
return s > t && a({
|
|
56
54
|
type: c.Warning,
|
|
@@ -59,7 +57,7 @@ const ge = () => {
|
|
|
59
57
|
type: c.Warning,
|
|
60
58
|
message: r("custom-fields.missing-opening-braces")
|
|
61
59
|
}), s === t;
|
|
62
|
-
},
|
|
60
|
+
}, x = (e) => {
|
|
63
61
|
const s = e.match(/{{\s*(\w+\s+((\w+\|\w+)|(\w+)))\s*}}/gm) === null;
|
|
64
62
|
return s || a({
|
|
65
63
|
type: c.Warning,
|
|
@@ -68,10 +66,10 @@ const ge = () => {
|
|
|
68
66
|
}, T = (e, s) => {
|
|
69
67
|
const t = e.match(/{{([a-zA-Z0-9_\s]*)}}/gm);
|
|
70
68
|
if (t && !p) {
|
|
71
|
-
const n = new Set(s.map((i) => i.toLowerCase())), l =
|
|
69
|
+
const n = new Set(s.map((i) => i.toLowerCase())), l = U(e), o = [];
|
|
72
70
|
if (t.forEach((i) => {
|
|
73
71
|
const m = i.slice(2, -2).trim().toLowerCase();
|
|
74
|
-
(!n.has(m) || m === "") && !
|
|
72
|
+
(!n.has(m) || m === "") && !Y(m, l) && o.push(m);
|
|
75
73
|
}), o.length > 0) {
|
|
76
74
|
const i = `
|
|
77
75
|
<ul>
|
|
@@ -85,11 +83,11 @@ const ge = () => {
|
|
|
85
83
|
}
|
|
86
84
|
}
|
|
87
85
|
return !0;
|
|
88
|
-
},
|
|
86
|
+
}, F = (e) => {
|
|
89
87
|
const s = e.match(/{%(.*?)%}/g), t = [];
|
|
90
88
|
let n = !0;
|
|
91
89
|
if (s && s.forEach((l) => {
|
|
92
|
-
const o = l.match(
|
|
90
|
+
const o = l.match(_), i = l.match(H), m = (o == null ? void 0 : o.join("")) || "";
|
|
93
91
|
(!o || l !== m) && !i && (a({
|
|
94
92
|
type: c.Alert,
|
|
95
93
|
message: r("newsletter.display-conditions-invalid-syntax")
|
|
@@ -100,7 +98,7 @@ const ge = () => {
|
|
|
100
98
|
}), n = !1);
|
|
101
99
|
const v = f.match(/^[a-zA-Z]*$/g);
|
|
102
100
|
v && v.forEach((C) => {
|
|
103
|
-
|
|
101
|
+
S(C) && t.push(C);
|
|
104
102
|
});
|
|
105
103
|
});
|
|
106
104
|
}), t.length) {
|
|
@@ -111,28 +109,25 @@ const ge = () => {
|
|
|
111
109
|
}), n = !1);
|
|
112
110
|
}
|
|
113
111
|
return n;
|
|
114
|
-
},
|
|
112
|
+
}, W = (e) => {
|
|
115
113
|
const s = (e.match(/{% /gm) || []).length, t = (e.match(/ %}/gm) || []).length, n = s === t;
|
|
116
114
|
return n || a({
|
|
117
115
|
type: c.Warning,
|
|
118
116
|
message: r("custom-conditions.no-space-after-braces")
|
|
119
117
|
}), n;
|
|
120
|
-
},
|
|
118
|
+
}, N = (e) => (e.match(/({%(.*?)%})/g) || []).filter((t) => t.includes("if")).map((t) => (t.match(/{{.*}}/gm) || []).length).reduce((t, n) => t + n, 0) > 0 ? (a({
|
|
121
119
|
type: c.Warning,
|
|
122
120
|
message: r("custom-conditions.no-braces-inside-if-tag")
|
|
123
|
-
}), !1) : !0, N = () => S.hasInvalidBlock() ? (a({
|
|
124
|
-
type: c.Alert,
|
|
125
|
-
message: r(j)
|
|
126
121
|
}), !1) : !0, O = () => g.recommendationConfigs && Object.values(g.recommendationConfigs).find((s) => s.filters.find((t) => t.value === "")) !== void 0 ? (a({
|
|
127
122
|
type: c.Alert,
|
|
128
123
|
message: r("newsletter.fill-all-necessary-fields")
|
|
129
|
-
}), !1) : !0,
|
|
124
|
+
}), !1) : !0, B = (e) => {
|
|
130
125
|
const s = /src="[^"]*\.(svg|pst)"/gm;
|
|
131
126
|
return e.match(s) === null ? !0 : (a({
|
|
132
127
|
type: c.Alert,
|
|
133
128
|
message: r("newsletter.invalid-image-type")
|
|
134
129
|
}), !1);
|
|
135
|
-
},
|
|
130
|
+
}, R = (e) => {
|
|
136
131
|
const n = new DOMParser().parseFromString(e, "text/html").querySelectorAll(".checkbox-block-v2");
|
|
137
132
|
return Array.from(n).find((o) => {
|
|
138
133
|
var i;
|
|
@@ -141,7 +136,7 @@ const ge = () => {
|
|
|
141
136
|
type: c.Alert,
|
|
142
137
|
message: r("unsubscribe-templates.select-checkbox-groups")
|
|
143
138
|
}), !1) : !0;
|
|
144
|
-
},
|
|
139
|
+
}, D = (e) => {
|
|
145
140
|
const n = new DOMParser().parseFromString(e, "text/html").querySelectorAll(".radio-button-v2");
|
|
146
141
|
return Array.from(n).find((o) => {
|
|
147
142
|
var i;
|
|
@@ -155,12 +150,12 @@ const ge = () => {
|
|
|
155
150
|
var o, i;
|
|
156
151
|
const n = [
|
|
157
152
|
...s.map((m) => m.value),
|
|
158
|
-
...
|
|
153
|
+
...M,
|
|
159
154
|
...((i = (o = d.value) == null ? void 0 : o.template) == null ? void 0 : i.customFieldAttributes) ?? []
|
|
160
155
|
];
|
|
161
|
-
return await
|
|
156
|
+
return await A(e, n, t) && I(e) && k(e) && x(e) && T(e, n) && F(e) && W(e) && N(e) && O() && B(e) && R(e) && D(e);
|
|
162
157
|
} };
|
|
163
158
|
};
|
|
164
159
|
export {
|
|
165
|
-
|
|
160
|
+
ce as useHtmlValidator
|
|
166
161
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getRecommendationFeedSourceMaps as I, URLS as C } from "../enums/extensions/recommendationBlock.js";
|
|
2
2
|
import { MinDeviceViewport as R, DefaultPadding as b } from "../enums/recommendation.js";
|
|
3
3
|
import { useRecommendationExtensionStore as m } from "../extensions/Blocks/Recommendation/store/recommendation.js";
|
|
4
4
|
import { generateCompleteFilterQuery as h } from "../extensions/Blocks/Recommendation/utils/filterUtil.js";
|
|
@@ -63,7 +63,7 @@ const w = () => ({
|
|
|
63
63
|
shuffleProducts: o.shuffleProducts
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
|
-
const f = ((l = I.find((i) => i.key === e.strategy)) == null ? void 0 : l.path) || "", t = new URLSearchParams();
|
|
66
|
+
const f = ((l = I().find((i) => i.key === e.strategy)) == null ? void 0 : l.path) || "", t = new URLSearchParams();
|
|
67
67
|
if (t.set("locale", e.language), t.set("currency", e.currencyCode), t.set("partnerName", n.partnerName), t.set("size", e.size), t.set("details", "true"), t.set("campaignId", n.variationId), e.strategy === "manualMerchandising") {
|
|
68
68
|
const i = parseInt(e.size) || 6;
|
|
69
69
|
t.set("productId", e.productIds.slice(0, i).join(","));
|
|
@@ -1,44 +1,98 @@
|
|
|
1
|
-
|
|
1
|
+
import { useTranslations as a } from "../../composables/useTranslations.js";
|
|
2
|
+
const u = {
|
|
2
3
|
RECOMMENDATION_API_URL: "https://recommendationv2.api.useinsider.com"
|
|
3
|
-
},
|
|
4
|
+
}, l = {
|
|
4
5
|
CLIENT_ID: "clientId"
|
|
5
|
-
},
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
6
|
+
}, c = () => {
|
|
7
|
+
const e = a();
|
|
8
|
+
return [
|
|
9
|
+
{
|
|
10
|
+
id: 11,
|
|
11
|
+
key: "similarViewed",
|
|
12
|
+
name: e("action-builder.similar-viewed"),
|
|
13
|
+
path: "viewed-together"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
id: 12,
|
|
17
|
+
key: "similarBought",
|
|
18
|
+
name: e("action-builder.similar-bought"),
|
|
19
|
+
path: "purchased-together"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: 13,
|
|
23
|
+
key: "userBased",
|
|
24
|
+
name: e("action-builder.user-based"),
|
|
25
|
+
path: "user-based"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: 36,
|
|
29
|
+
key: "highestDiscounted",
|
|
30
|
+
name: e("journey-builder.highest-discounted-items"),
|
|
31
|
+
path: "highest-discounted"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: 38,
|
|
35
|
+
key: "manualMerchandising",
|
|
36
|
+
name: e("action-builder.manual-merchandising"),
|
|
37
|
+
path: "manual-merchandising"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: 39,
|
|
41
|
+
key: "newArrivals",
|
|
42
|
+
name: e("action-builder.new-arrivals"),
|
|
43
|
+
path: "new-arrivals"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: 40,
|
|
47
|
+
key: "trendingProducts",
|
|
48
|
+
name: e("journey-builder.trending-products"),
|
|
49
|
+
path: "trending"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: 46,
|
|
53
|
+
key: "mostValuableOfPartner",
|
|
54
|
+
name: e("journey-builder.most-valuable-products"),
|
|
55
|
+
path: "most-valuable"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: 61,
|
|
59
|
+
key: "mostPopular",
|
|
60
|
+
name: e("journey-builder.most-popular-items"),
|
|
61
|
+
path: "most-popular"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: 62,
|
|
65
|
+
key: "mostPurchased",
|
|
66
|
+
name: e("action-builder.most-purchased"),
|
|
67
|
+
path: "top-sellers"
|
|
68
|
+
}
|
|
69
|
+
];
|
|
70
|
+
}, d = ["discount", "omnibus_price", "omnibus_discount", "price", "original_price"], m = [
|
|
17
71
|
{ text: "before the amount", value: "0" },
|
|
18
72
|
{ text: "after the amount", value: "1" }
|
|
19
|
-
],
|
|
73
|
+
], p = [
|
|
20
74
|
{ text: "dot(.)", value: "." },
|
|
21
75
|
{ text: "comma(,)", value: "," },
|
|
22
76
|
{ text: "space( )", value: " " }
|
|
23
|
-
],
|
|
77
|
+
], v = [
|
|
24
78
|
{ text: "0", value: "0" },
|
|
25
79
|
{ text: "1", value: "1" },
|
|
26
80
|
{ text: "2", value: "2" },
|
|
27
81
|
{ text: "3", value: "3" },
|
|
28
82
|
{ text: "4", value: "4" },
|
|
29
83
|
{ text: "5", value: "5" }
|
|
30
|
-
],
|
|
84
|
+
], t = [
|
|
31
85
|
{ text: "is exactly", value: "=" },
|
|
32
86
|
{ text: "contains", value: "~" },
|
|
33
87
|
{ text: "does not contain", value: "!~" },
|
|
34
88
|
{ text: "any of", value: "||" }
|
|
35
|
-
],
|
|
89
|
+
], r = [
|
|
36
90
|
{ text: "is exactly", value: "=" },
|
|
37
91
|
{ text: "is not exactly", value: "!==" },
|
|
38
92
|
{ text: "contains", value: "~" },
|
|
39
93
|
{ text: "does not contain", value: "!~" },
|
|
40
94
|
{ text: "any of", value: "||" }
|
|
41
|
-
],
|
|
95
|
+
], n = [
|
|
42
96
|
{ text: "is equal to", value: "=" },
|
|
43
97
|
{ text: "is greater than", value: ">" },
|
|
44
98
|
{ text: "is less than", value: "<" }
|
|
@@ -46,39 +100,39 @@ const s = {
|
|
|
46
100
|
{ text: "is equal to", value: "=" },
|
|
47
101
|
{ text: "after", value: ">" },
|
|
48
102
|
{ text: "before", value: "<" }
|
|
49
|
-
],
|
|
103
|
+
], s = [
|
|
50
104
|
{ text: "true", value: "==" },
|
|
51
105
|
{ text: "false", value: "!=" }
|
|
52
|
-
],
|
|
53
|
-
if (!
|
|
54
|
-
return
|
|
55
|
-
switch (
|
|
106
|
+
], h = (e) => {
|
|
107
|
+
if (!e)
|
|
108
|
+
return t;
|
|
109
|
+
switch (e) {
|
|
56
110
|
case "Boolean":
|
|
57
|
-
return
|
|
111
|
+
return s;
|
|
58
112
|
case "Date":
|
|
59
113
|
return o;
|
|
60
114
|
case "Number":
|
|
61
|
-
return
|
|
115
|
+
return n;
|
|
62
116
|
case "String":
|
|
63
|
-
return
|
|
117
|
+
return t;
|
|
64
118
|
case "Strings":
|
|
65
|
-
return
|
|
119
|
+
return r;
|
|
66
120
|
default:
|
|
67
|
-
return
|
|
121
|
+
return t;
|
|
68
122
|
}
|
|
69
123
|
};
|
|
70
124
|
export {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
u as
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
125
|
+
d as PriceAttributes,
|
|
126
|
+
l as QUERY_PARAMS,
|
|
127
|
+
u as URLS,
|
|
128
|
+
v as currencyDecimalCounts,
|
|
129
|
+
m as currencyLocationMaps,
|
|
130
|
+
p as currencyOperators,
|
|
131
|
+
h as getOperatorOptions,
|
|
132
|
+
c as getRecommendationFeedSourceMaps,
|
|
133
|
+
r as operatorOptionsForArrayOfStrings,
|
|
134
|
+
s as operatorOptionsForBooleans,
|
|
81
135
|
o as operatorOptionsForDates,
|
|
82
|
-
|
|
83
|
-
|
|
136
|
+
n as operatorOptionsForNumbers,
|
|
137
|
+
t as operatorOptionsForStrings
|
|
84
138
|
};
|
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
import { useTranslations as R } from "../composables/useTranslations.js";
|
|
2
|
-
import { ProductType as
|
|
2
|
+
import { ProductType as n } from "../@types/config/schemas.js";
|
|
3
3
|
import "../@types/config/defaults.js";
|
|
4
4
|
import { getEnvironmentPrefix as S } from "../utils/environmentUtil.js";
|
|
5
|
-
const
|
|
5
|
+
const i = {
|
|
6
6
|
UNSUBSCRIBE_LINK_TYPE: 1,
|
|
7
7
|
PREFERENCES_LINK_TYPE: 3
|
|
8
|
-
},
|
|
8
|
+
}, B = {
|
|
9
9
|
UNSUBSCRIBE_LINK_REGEX: /{{ins-unsubscribe-link}}/g,
|
|
10
10
|
DATA_OGSB_BUTTON_CSS_REGEX: "\\[data-ogsb\\]\\s*\\.es-button\\.es-button-[0-9]+\\s*\\{(?:[^\\}]*)\\}",
|
|
11
11
|
GLOBAL_UNSUBSCRIBE_LINK_REGEX: /{{ins-global-unsubscribe-link}}/g,
|
|
12
12
|
PREFERENCES_UNSUBSCRIBE_LINK_REGEX: /{{ins-preferences-unsubscribe-link}}/g
|
|
13
|
-
},
|
|
14
|
-
UNSUBSCRIBE_URL: `https://mail.${
|
|
15
|
-
PREFERENCES_URL: `https://mail.${
|
|
13
|
+
}, s = S(), C = {
|
|
14
|
+
UNSUBSCRIBE_URL: `https://mail.${s}.com/user/v1/unsub`,
|
|
15
|
+
PREFERENCES_URL: `https://mail.${s}.com/user/v1/prefs`
|
|
16
16
|
}, U = {
|
|
17
|
-
[
|
|
18
|
-
[
|
|
19
|
-
[
|
|
20
|
-
},
|
|
21
|
-
name: "
|
|
22
|
-
sendGridId:
|
|
23
|
-
},
|
|
17
|
+
[n.EMAIL]: "email",
|
|
18
|
+
[n.ARCHITECT]: "journey",
|
|
19
|
+
[n.UNSUBSCRIBE_PAGES]: "email"
|
|
20
|
+
}, o = "iid", r = "G", c = () => ({
|
|
21
|
+
name: R()("onboarding-center.email-subscribers-global-unsub-card-title"),
|
|
22
|
+
sendGridId: r
|
|
23
|
+
}), u = "/email/unsubscribe-pages", E = {
|
|
24
24
|
GLOBAL_UNSUBSCRIBE: 1,
|
|
25
25
|
GLOBAL_UNSUBSCRIBE_CONFIRMATION_PAGE: 2,
|
|
26
26
|
SUBSCRIPTION_PREFERENCE_CENTER: 3,
|
|
27
27
|
SUBSCRIPTION_PREFERENCE_CONFIRMATION: 4,
|
|
28
28
|
RESUBSCRIBE: 5
|
|
29
|
-
},
|
|
29
|
+
}, b = {
|
|
30
30
|
[E.GLOBAL_UNSUBSCRIBE]: "custom-unsubscribe",
|
|
31
31
|
[E.SUBSCRIPTION_PREFERENCE_CENTER]: "custom-preferences"
|
|
32
32
|
}, T = {
|
|
@@ -39,7 +39,7 @@ const B = {
|
|
|
39
39
|
E.SUBSCRIPTION_PREFERENCE_CENTER,
|
|
40
40
|
E.SUBSCRIPTION_PREFERENCE_CONFIRMATION
|
|
41
41
|
]
|
|
42
|
-
},
|
|
42
|
+
}, P = () => {
|
|
43
43
|
const e = R();
|
|
44
44
|
return {
|
|
45
45
|
[E.GLOBAL_UNSUBSCRIBE]: e("unsubscription-preference.type-global-unsubscribe"),
|
|
@@ -48,22 +48,23 @@ const B = {
|
|
|
48
48
|
[E.SUBSCRIPTION_PREFERENCE_CENTER]: e("unsubscription-preference.type-subscription-preferences-center"),
|
|
49
49
|
[E.SUBSCRIPTION_PREFERENCE_CONFIRMATION]: e("unsubscription-preference.type-subscription-preferences-confirmation")
|
|
50
50
|
};
|
|
51
|
-
},
|
|
51
|
+
}, O = {
|
|
52
52
|
default: "{{ins-unsubscribe-link}}",
|
|
53
53
|
[E.GLOBAL_UNSUBSCRIBE]: "{{ins-global-unsubscribe-link}}",
|
|
54
54
|
[E.SUBSCRIPTION_PREFERENCE_CENTER]: "{{ins-preferences-unsubscribe-link}}"
|
|
55
55
|
};
|
|
56
56
|
export {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
r as DEFAULT_UNSUBSCRIBE_GROUP_SEND_GRID_ID,
|
|
58
|
+
o as INSIDER_ID,
|
|
59
|
+
B as LINK_REGEXES,
|
|
60
|
+
i as LINK_TYPES,
|
|
61
|
+
O as MERGE_TAGS,
|
|
62
62
|
E as PAGE_TYPES,
|
|
63
63
|
U as PRODUCT_TYPE_URL_SEGMENTS,
|
|
64
64
|
T as TYPE_COLLECTIONS,
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
u as UNSUBSCRIBE_PAGES_LINK,
|
|
66
|
+
b as UNSUBSCRIBE_SYNC_MODULE_TYPES,
|
|
67
67
|
C as URLS,
|
|
68
|
-
|
|
68
|
+
c as getDefaultUnsubscribeGroup,
|
|
69
|
+
P as getTypeTranslations
|
|
69
70
|
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var o = (
|
|
4
|
-
import { useHttp as
|
|
5
|
-
import {
|
|
6
|
-
import { Control as
|
|
7
|
-
const
|
|
8
|
-
class
|
|
1
|
+
var E = Object.defineProperty;
|
|
2
|
+
var d = (i, n, e) => n in i ? E(i, n, { enumerable: !0, configurable: !0, writable: !0, value: e }) : i[n] = e;
|
|
3
|
+
var o = (i, n, e) => d(i, typeof n != "symbol" ? n + "" : n, e);
|
|
4
|
+
import { useHttp as l } from "../../../composables/useHttp.js";
|
|
5
|
+
import { getDefaultUnsubscribeGroup as L, DEFAULT_UNSUBSCRIBE_GROUP_SEND_GRID_ID as h } from "../../../enums/unsubscribe.js";
|
|
6
|
+
import { Control as p, UIElementType as r, UEAttr as t, ModificationDescription as m } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
7
|
+
const b = "ui-elements-checkbox", u = "select", { get: C } = l();
|
|
8
|
+
class I extends p {
|
|
9
9
|
constructor() {
|
|
10
10
|
super(...arguments);
|
|
11
11
|
o(this, "currentNode");
|
|
@@ -13,13 +13,13 @@ class S extends h {
|
|
|
13
13
|
o(this, "unsubList", []);
|
|
14
14
|
}
|
|
15
15
|
getId() {
|
|
16
|
-
return
|
|
16
|
+
return b;
|
|
17
17
|
}
|
|
18
18
|
_setFormValues() {
|
|
19
19
|
if (this.selectedUnsubGroup = "", this.currentNode && "getAttribute" in this.currentNode) {
|
|
20
20
|
const e = this.currentNode.getAttribute("id");
|
|
21
21
|
if (e) {
|
|
22
|
-
const s = e ===
|
|
22
|
+
const s = e === h ? e : Number(e);
|
|
23
23
|
s && (this.selectedUnsubGroup = s);
|
|
24
24
|
}
|
|
25
25
|
}
|
|
@@ -29,18 +29,18 @@ class S extends h {
|
|
|
29
29
|
}
|
|
30
30
|
_getLabel(e, s = `${Math.random()}`) {
|
|
31
31
|
return `
|
|
32
|
-
<${
|
|
32
|
+
<${r.LABEL}
|
|
33
33
|
${t.LABEL.text}="${e}"
|
|
34
34
|
${t.LABEL.name}="${s}">
|
|
35
|
-
</${
|
|
35
|
+
</${r.LABEL}>
|
|
36
36
|
`;
|
|
37
37
|
}
|
|
38
38
|
_getSelectItem(e, s) {
|
|
39
39
|
return `
|
|
40
|
-
<${
|
|
40
|
+
<${r.SELECT_ITEM}
|
|
41
41
|
${t.SELECT_ITEM.text}="${e}"
|
|
42
42
|
${t.SELECT_ITEM.value}="${s}">
|
|
43
|
-
</${
|
|
43
|
+
</${r.SELECT_ITEM}>`;
|
|
44
44
|
}
|
|
45
45
|
_getSelect() {
|
|
46
46
|
return this.unsubList.map((e) => this._getSelectItem(e.name, e.sendGridId)).join("");
|
|
@@ -49,22 +49,22 @@ class S extends h {
|
|
|
49
49
|
return `
|
|
50
50
|
<div class="checkbox-controls-container">
|
|
51
51
|
<div class="checkbox-select-container container two-columns stretch">
|
|
52
|
-
<${
|
|
52
|
+
<${r.LABEL}
|
|
53
53
|
${t.LABEL.text}="${this.api.translate("Unsubscribe Group")}"
|
|
54
54
|
${t.LABEL.name}="${Math.random()}">
|
|
55
|
-
</${
|
|
55
|
+
</${r.LABEL}>
|
|
56
56
|
|
|
57
|
-
<${
|
|
57
|
+
<${r.SELECTPICKER}
|
|
58
58
|
${t.SELECTPICKER.name}="${u}"
|
|
59
59
|
${t.SELECTPICKER.placeholder}="${this.api.translate("Select Unsubscribe Group")}">
|
|
60
60
|
${this._getSelect()}
|
|
61
|
-
</${
|
|
61
|
+
</${r.SELECTPICKER}>
|
|
62
62
|
</div>
|
|
63
63
|
</div>
|
|
64
64
|
`;
|
|
65
65
|
}
|
|
66
66
|
_onSelectChange(e) {
|
|
67
|
-
this.currentNode && this.api.getDocumentModifier().modifyHtml(this.currentNode).setAttribute("id", e.toString()).apply(new
|
|
67
|
+
this.currentNode && this.api.getDocumentModifier().modifyHtml(this.currentNode).setAttribute("id", e.toString()).apply(new m(`Updated text to ${e}`));
|
|
68
68
|
}
|
|
69
69
|
_listenToFormUpdates() {
|
|
70
70
|
this.api.onValueChanged(u, (e) => this._onSelectChange(e));
|
|
@@ -76,18 +76,18 @@ class S extends h {
|
|
|
76
76
|
async onRender() {
|
|
77
77
|
const e = await C(
|
|
78
78
|
"/unsubscribe-groups/unsubscribe-list"
|
|
79
|
-
), s = [
|
|
79
|
+
), s = [L(), ...e.data], c = s.map((a) => ({
|
|
80
80
|
[t.SELECT_ITEM.text]: a.name,
|
|
81
81
|
[t.SELECT_ITEM.value]: a.sendGridId
|
|
82
82
|
}));
|
|
83
83
|
this.unsubList = s, this.api.setUIEAttribute(
|
|
84
84
|
u,
|
|
85
85
|
t.SELECTPICKER.items,
|
|
86
|
-
|
|
86
|
+
c
|
|
87
87
|
), this._setFormValues(), this._listenToFormUpdates();
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
export {
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
b as CHECKBOX_CONTROL_BLOCK_ID,
|
|
92
|
+
I as CheckboxControl
|
|
93
93
|
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var o = (r, n, t) =>
|
|
4
|
-
import { useHttp as
|
|
5
|
-
import {
|
|
6
|
-
import { Control as
|
|
7
|
-
const
|
|
8
|
-
class
|
|
1
|
+
var E = Object.defineProperty;
|
|
2
|
+
var d = (r, n, t) => n in r ? E(r, n, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[n] = t;
|
|
3
|
+
var o = (r, n, t) => d(r, typeof n != "symbol" ? n + "" : n, t);
|
|
4
|
+
import { useHttp as l } from "../../../composables/useHttp.js";
|
|
5
|
+
import { getDefaultUnsubscribeGroup as L, DEFAULT_UNSUBSCRIBE_GROUP_SEND_GRID_ID as p } from "../../../enums/unsubscribe.js";
|
|
6
|
+
import { Control as h, UIElementType as i, UEAttr as e, ModificationDescription as m } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
7
|
+
const b = "ui-elements-radio-button", u = "select", { get: $ } = l();
|
|
8
|
+
class I extends h {
|
|
9
9
|
constructor() {
|
|
10
10
|
super(...arguments);
|
|
11
11
|
o(this, "currentNode");
|
|
@@ -13,13 +13,13 @@ class S extends p {
|
|
|
13
13
|
o(this, "unsubList", []);
|
|
14
14
|
}
|
|
15
15
|
getId() {
|
|
16
|
-
return
|
|
16
|
+
return b;
|
|
17
17
|
}
|
|
18
18
|
_setFormValues() {
|
|
19
19
|
if (this.selectedUnsubGroup = "", this.currentNode && "getAttribute" in this.currentNode) {
|
|
20
20
|
const t = this.currentNode.getAttribute("id");
|
|
21
21
|
if (t) {
|
|
22
|
-
const s = t ===
|
|
22
|
+
const s = t === p ? t : Number(t);
|
|
23
23
|
s && (this.selectedUnsubGroup = s);
|
|
24
24
|
}
|
|
25
25
|
}
|
|
@@ -64,7 +64,7 @@ class S extends p {
|
|
|
64
64
|
`;
|
|
65
65
|
}
|
|
66
66
|
_onSelectChange(t) {
|
|
67
|
-
this.currentNode && this.api.getDocumentModifier().modifyHtml(this.currentNode).setAttribute("id", t.toString()).apply(new
|
|
67
|
+
this.currentNode && this.api.getDocumentModifier().modifyHtml(this.currentNode).setAttribute("id", t.toString()).apply(new m(`Updated text to ${t}`));
|
|
68
68
|
}
|
|
69
69
|
_listenToFormUpdates() {
|
|
70
70
|
this.api.onValueChanged(u, (t) => this._onSelectChange(t));
|
|
@@ -76,18 +76,18 @@ class S extends p {
|
|
|
76
76
|
async onRender() {
|
|
77
77
|
const t = await $(
|
|
78
78
|
"/unsubscribe-groups/unsubscribe-list"
|
|
79
|
-
), s = [
|
|
79
|
+
), s = [L(), ...t.data], c = s.map((a) => ({
|
|
80
80
|
[e.SELECT_ITEM.text]: a.name,
|
|
81
81
|
[e.SELECT_ITEM.value]: a.sendGridId
|
|
82
82
|
}));
|
|
83
83
|
this.unsubList = s, this.api.setUIEAttribute(
|
|
84
84
|
u,
|
|
85
85
|
e.SELECTPICKER.items,
|
|
86
|
-
|
|
86
|
+
c
|
|
87
87
|
), this._setFormValues(), this._listenToFormUpdates();
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
export {
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
b as CONTROL_BLOCK_ID,
|
|
92
|
+
I as RadioButtonControl
|
|
93
93
|
};
|
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
import { BlockId as
|
|
5
|
-
import { getMigrationBannerHtml as
|
|
6
|
-
import { Block as
|
|
7
|
-
import { regenerateMobileProductRows as
|
|
8
|
-
import { ensureMobileCssRulesExist as
|
|
9
|
-
import { RecommendationConfigService as
|
|
10
|
-
import { useRecommendationExtensionStore as
|
|
1
|
+
var k = Object.defineProperty;
|
|
2
|
+
var _ = (r, n, t) => n in r ? k(r, n, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[n] = t;
|
|
3
|
+
var g = (r, n, t) => _(r, typeof n != "symbol" ? n + "" : n, t);
|
|
4
|
+
import { BlockId as B } from "../../../enums/block.js";
|
|
5
|
+
import { getMigrationBannerHtml as b } from "../../../utils/migrationBannerHtml.js";
|
|
6
|
+
import { Block as R, BlockCompositionType as y, ModificationDescription as C } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
7
|
+
import { regenerateMobileProductRows as A } from "./controls/main/utils.js";
|
|
8
|
+
import { ensureMobileCssRulesExist as d, setMobileLayoutOptOut as p, hasMobileLayoutOptOut as D } from "./controls/mobileLayout/cssRules.js";
|
|
9
|
+
import { RecommendationConfigService as s } from "./services/configService.js";
|
|
10
|
+
import { useRecommendationExtensionStore as f } from "./store/recommendation.js";
|
|
11
11
|
import { getDefaultTemplate as E } from "./templates/grid/template.js";
|
|
12
|
-
const
|
|
13
|
-
let
|
|
14
|
-
class
|
|
12
|
+
const h = B.Recommendation, l = "recommendation-block-v2", m = "recommendation-id";
|
|
13
|
+
let I = !1;
|
|
14
|
+
class v extends R {
|
|
15
15
|
constructor() {
|
|
16
16
|
super();
|
|
17
17
|
/**
|
|
18
18
|
* Stores the ID generated in getTemplate() so onCreated() can reuse it.
|
|
19
19
|
* This avoids generating a new (different) ID in onCreated().
|
|
20
20
|
*/
|
|
21
|
-
|
|
21
|
+
g(this, "_pendingBlockId", null);
|
|
22
22
|
}
|
|
23
23
|
getId() {
|
|
24
|
-
return
|
|
24
|
+
return h;
|
|
25
25
|
}
|
|
26
26
|
getIcon() {
|
|
27
27
|
return "recommendation-icon";
|
|
28
28
|
}
|
|
29
29
|
getBlockCompositionType() {
|
|
30
|
-
return
|
|
30
|
+
return y.CONTAINER;
|
|
31
31
|
}
|
|
32
32
|
getName() {
|
|
33
33
|
return this.api.translate("Recommendation Block");
|
|
@@ -38,8 +38,8 @@ class q extends b {
|
|
|
38
38
|
);
|
|
39
39
|
}
|
|
40
40
|
getSettingsPanelTitleHtml() {
|
|
41
|
-
return
|
|
42
|
-
|
|
41
|
+
return b(
|
|
42
|
+
h,
|
|
43
43
|
this.api.translate("Recommendation Block"),
|
|
44
44
|
this.api.translate("This block is switched from the Old Version to the New Version. We recommend you check the Recommendation block and test your message to ensure it works properly.")
|
|
45
45
|
);
|
|
@@ -71,13 +71,20 @@ class q extends b {
|
|
|
71
71
|
return;
|
|
72
72
|
const i = this._pendingBlockId ?? this._generateNextId();
|
|
73
73
|
this._pendingBlockId = null, this._assignRecommendationId(t, i);
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
74
|
+
const { config: o, wasFreshDrop: c } = s.initializeConfig(
|
|
75
|
+
this.api,
|
|
76
|
+
t,
|
|
77
|
+
{ recommendationId: i }
|
|
78
|
+
), a = f();
|
|
79
|
+
if (a.setCurrentBlock(i), c) {
|
|
80
|
+
d(this.api);
|
|
81
|
+
const u = this._getBlockElement(t);
|
|
82
|
+
u && (p(this.api, u, !0), A({
|
|
83
|
+
currentNode: t,
|
|
84
|
+
documentModifier: this.api.getDocumentModifier()
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
87
|
+
a.patchCurrentBlockConfig({ language: o.language }, { triggerRefetch: !1 });
|
|
81
88
|
}
|
|
82
89
|
/**
|
|
83
90
|
* Called when the document changes or template is loaded
|
|
@@ -90,20 +97,20 @@ class q extends b {
|
|
|
90
97
|
if (!(!t || !("getNodeConfig" in t))) {
|
|
91
98
|
if (!this._getRecommendationId(t)) {
|
|
92
99
|
const e = this._generateNextId();
|
|
93
|
-
this._assignRecommendationId(t, e),
|
|
100
|
+
this._assignRecommendationId(t, e), s.hasConfig(t) && s.updateConfig(
|
|
94
101
|
this.api,
|
|
95
102
|
t,
|
|
96
103
|
{ recommendationId: e },
|
|
97
104
|
"Assign recommendation ID to legacy block"
|
|
98
105
|
);
|
|
99
106
|
}
|
|
100
|
-
|
|
107
|
+
s.needsMigration(t) && this._migrateFromLegacy(t);
|
|
101
108
|
try {
|
|
102
|
-
|
|
103
|
-
const e =
|
|
109
|
+
I || (d(this.api), I = !0);
|
|
110
|
+
const e = s.getConfig(t), i = this._getBlockElement(t);
|
|
104
111
|
if (i) {
|
|
105
112
|
const o = !e.mobileLayoutEnabled;
|
|
106
|
-
|
|
113
|
+
D(i) !== o && p(this.api, i, o);
|
|
107
114
|
}
|
|
108
115
|
} catch {
|
|
109
116
|
}
|
|
@@ -117,7 +124,7 @@ class q extends b {
|
|
|
117
124
|
*/
|
|
118
125
|
onDelete(t) {
|
|
119
126
|
const e = this._getRecommendationId(t);
|
|
120
|
-
e &&
|
|
127
|
+
e && f().removeBlockState(e);
|
|
121
128
|
}
|
|
122
129
|
/**
|
|
123
130
|
* Generates the next unique recommendation ID by scanning all existing blocks
|
|
@@ -129,7 +136,7 @@ class q extends b {
|
|
|
129
136
|
const e = this.api.getDocumentRoot();
|
|
130
137
|
e && "querySelectorAll" in e && e.querySelectorAll(`.${l}`).forEach((o) => {
|
|
131
138
|
if ("getAttribute" in o) {
|
|
132
|
-
const
|
|
139
|
+
const c = o.getAttribute(m), a = c ? parseInt(c) : 0;
|
|
133
140
|
a > t && (t = a);
|
|
134
141
|
}
|
|
135
142
|
});
|
|
@@ -148,7 +155,7 @@ class q extends b {
|
|
|
148
155
|
if (!i)
|
|
149
156
|
return;
|
|
150
157
|
const o = this.api.getDocumentModifier();
|
|
151
|
-
o.modifyHtml(i).setAttribute(m, e.toString()), o.apply(new
|
|
158
|
+
o.modifyHtml(i).setAttribute(m, e.toString()), o.apply(new C(`Assign recommendation ID ${e}`));
|
|
152
159
|
}
|
|
153
160
|
/**
|
|
154
161
|
* Gets the recommendation-id from a block node
|
|
@@ -178,10 +185,10 @@ class q extends b {
|
|
|
178
185
|
* Migrate configuration from legacy format
|
|
179
186
|
*/
|
|
180
187
|
_migrateFromLegacy(t) {
|
|
181
|
-
|
|
188
|
+
s.migrateFromDataAttributes(this.api, t);
|
|
182
189
|
}
|
|
183
190
|
}
|
|
184
191
|
export {
|
|
185
|
-
|
|
186
|
-
|
|
192
|
+
h as BLOCK_ID,
|
|
193
|
+
v as RecommendationBlock
|
|
187
194
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ModificationDescription as
|
|
2
|
-
import { CURRENT_CONFIG_VERSION as l, DEFAULT_NODE_CONFIG as
|
|
1
|
+
import { ModificationDescription as C } from "../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
2
|
+
import { CURRENT_CONFIG_VERSION as l, DEFAULT_NODE_CONFIG as c } from "../constants/defaultConfig.js";
|
|
3
3
|
import { setCurrencyAttributes as D } from "../controls/main/utils.js";
|
|
4
4
|
import { hasMinimalConfig as A } from "../types/nodeConfig.js";
|
|
5
5
|
function S(e) {
|
|
@@ -8,7 +8,7 @@ function S(e) {
|
|
|
8
8
|
function N(e) {
|
|
9
9
|
return e === "." || e === "," || e === " " || e === "";
|
|
10
10
|
}
|
|
11
|
-
class
|
|
11
|
+
class M {
|
|
12
12
|
// ========================================================================
|
|
13
13
|
// Read Operations
|
|
14
14
|
// ========================================================================
|
|
@@ -83,7 +83,7 @@ class V {
|
|
|
83
83
|
* @returns The new complete configuration
|
|
84
84
|
*/
|
|
85
85
|
static updateConfig(i, t, o, n) {
|
|
86
|
-
const
|
|
86
|
+
const r = this.getConfig(t), u = this.deepMerge(r, o);
|
|
87
87
|
return this.saveConfig(i, t, u, n), u;
|
|
88
88
|
}
|
|
89
89
|
/**
|
|
@@ -91,21 +91,28 @@ class V {
|
|
|
91
91
|
*
|
|
92
92
|
* Called when a block is first created (dropped into template).
|
|
93
93
|
* Can optionally merge in partial config from migration.
|
|
94
|
+
*
|
|
95
|
+
* The `wasFreshDrop` flag distinguishes a brand-new drop (no prior config)
|
|
96
|
+
* from a clone (Stripo replays the source's setNodeConfig payload before
|
|
97
|
+
* onCreated fires). Callers use this to skip side-effects already inherited
|
|
98
|
+
* from the source.
|
|
94
99
|
* @example
|
|
95
100
|
* // In Block.onCreated lifecycle
|
|
96
|
-
* RecommendationConfigService.initializeConfig(this.api, node);
|
|
101
|
+
* const { config, wasFreshDrop } = RecommendationConfigService.initializeConfig(this.api, node);
|
|
97
102
|
* @param api - Stripo extension API with document modifier
|
|
98
103
|
* @param node - The immutable HTML node to initialize
|
|
99
104
|
* @param partialConfig - Optional partial config to merge with defaults
|
|
100
|
-
* @returns The initialized configuration
|
|
105
|
+
* @returns The initialized configuration and whether the node was a fresh drop
|
|
101
106
|
*/
|
|
102
107
|
static initializeConfig(i, t, o) {
|
|
108
|
+
if (this.hasConfig(t))
|
|
109
|
+
return { config: o ? this.updateConfig(i, t, o, "Initialize recommendation block") : this.getConfig(t), wasFreshDrop: !1 };
|
|
103
110
|
const n = o ? this.mergeWithDefaults(o) : this.cloneDefaults();
|
|
104
111
|
return this.saveConfig(i, t, n, "Initialize recommendation block"), D({
|
|
105
112
|
currentNode: t,
|
|
106
113
|
documentModifier: i.getDocumentModifier(),
|
|
107
114
|
currency: n.currency
|
|
108
|
-
}), n;
|
|
115
|
+
}), { config: n, wasFreshDrop: !0 };
|
|
109
116
|
}
|
|
110
117
|
/**
|
|
111
118
|
* Save complete configuration to a node
|
|
@@ -118,9 +125,9 @@ class V {
|
|
|
118
125
|
*/
|
|
119
126
|
static saveConfig(i, t, o, n) {
|
|
120
127
|
try {
|
|
121
|
-
i.getDocumentModifier().modifyHtml(t).setNodeConfig(o).apply(new
|
|
122
|
-
} catch (
|
|
123
|
-
console.warn("[RecommendationConfigService] Failed to save config:",
|
|
128
|
+
i.getDocumentModifier().modifyHtml(t).setNodeConfig(o).apply(new C(n));
|
|
129
|
+
} catch (r) {
|
|
130
|
+
console.warn("[RecommendationConfigService] Failed to save config:", r);
|
|
124
131
|
}
|
|
125
132
|
}
|
|
126
133
|
// ========================================================================
|
|
@@ -157,29 +164,29 @@ class V {
|
|
|
157
164
|
s && typeof s == "object" && (Object.assign(o, s), o.configVersion = l);
|
|
158
165
|
} catch {
|
|
159
166
|
}
|
|
160
|
-
const
|
|
161
|
-
|
|
167
|
+
const r = t.getAttribute("data-layout");
|
|
168
|
+
r === "list" || r === "horizontal" ? o.layout = "list" : (r === "grid" || r === "vertical") && (o.layout = "grid");
|
|
162
169
|
const u = t.getAttribute("data-card-composition");
|
|
163
170
|
u && (o.composition = u.split(",").filter(Boolean));
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
const
|
|
167
|
-
if (
|
|
171
|
+
const b = t.getAttribute("data-column-spacing");
|
|
172
|
+
b && (o.columnSpacing = parseInt(b) || c.columnSpacing);
|
|
173
|
+
const p = t.getAttribute("data-row-spacing");
|
|
174
|
+
if (p && (o.rowSpacing = parseInt(p) || c.rowSpacing), !o.currency) {
|
|
168
175
|
const s = t.getAttribute("currency"), y = t.getAttribute("currency-symbol"), d = t.getAttribute("currency-alignment"), f = t.getAttribute("currency-thousand-separator"), g = t.getAttribute("currency-decimal-separator"), m = t.getAttribute("currency-decimal-count");
|
|
169
176
|
if (s || y || d || f || g || m) {
|
|
170
|
-
const a =
|
|
177
|
+
const a = c.currency, h = m ? parseInt(m) : NaN;
|
|
171
178
|
o.currency = {
|
|
172
179
|
code: s ?? a.code,
|
|
173
180
|
symbol: y ?? a.symbol,
|
|
174
181
|
alignment: d === "0" ? "before" : "after",
|
|
175
|
-
decimalCount: Number.isFinite(
|
|
182
|
+
decimalCount: Number.isFinite(h) ? h : a.decimalCount,
|
|
176
183
|
decimalSeparator: S(g) ? g : a.decimalSeparator,
|
|
177
184
|
thousandSeparator: N(f) ? f : a.thousandSeparator
|
|
178
185
|
};
|
|
179
186
|
}
|
|
180
187
|
}
|
|
181
188
|
}
|
|
182
|
-
return this.initializeConfig(i, t, o);
|
|
189
|
+
return this.initializeConfig(i, t, o).config;
|
|
183
190
|
}
|
|
184
191
|
/**
|
|
185
192
|
* Check if configuration needs migration
|
|
@@ -197,12 +204,12 @@ class V {
|
|
|
197
204
|
*/
|
|
198
205
|
static cloneDefaults() {
|
|
199
206
|
return {
|
|
200
|
-
...
|
|
201
|
-
currency: { ...
|
|
202
|
-
omnibusPrice: { ...
|
|
203
|
-
omnibusDiscount: { ...
|
|
204
|
-
composition: [...
|
|
205
|
-
visibility: { ...
|
|
207
|
+
...c,
|
|
208
|
+
currency: { ...c.currency },
|
|
209
|
+
omnibusPrice: { ...c.omnibusPrice },
|
|
210
|
+
omnibusDiscount: { ...c.omnibusDiscount },
|
|
211
|
+
composition: [...c.composition],
|
|
212
|
+
visibility: { ...c.visibility },
|
|
206
213
|
filters: [],
|
|
207
214
|
productIds: [],
|
|
208
215
|
recommendationId: 0
|
|
@@ -272,5 +279,5 @@ class V {
|
|
|
272
279
|
}
|
|
273
280
|
}
|
|
274
281
|
export {
|
|
275
|
-
|
|
282
|
+
M as RecommendationConfigService
|
|
276
283
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getRecommendationFeedSourceMaps as S, getOperatorOptions as R, PriceAttributes as y } from "../../../../enums/extensions/recommendationBlock.js";
|
|
2
2
|
import { useRecommendationApi as C } from "../../../../services/recommendationApi.js";
|
|
3
3
|
import { useConfigStore as G } from "../../../../stores/config.js";
|
|
4
4
|
import { defineStore as P } from "pinia";
|
|
@@ -7,9 +7,8 @@ import { EXCLUDED_ALGORITHM_IDS as D } from "../constants/defaultConfig.js";
|
|
|
7
7
|
import { getDefaultProducts as g } from "../templates/utils.js";
|
|
8
8
|
import { generateCompleteFilterQuery as b } from "../utils/filterUtil.js";
|
|
9
9
|
import { isFilterValid as w } from "../validation/filterSchema.js";
|
|
10
|
-
import { isConfigValid as v } from "../validation/requiredFields.js";
|
|
11
10
|
const h = C();
|
|
12
|
-
let
|
|
11
|
+
let u = null, m = null, d = null;
|
|
13
12
|
function k() {
|
|
14
13
|
return {
|
|
15
14
|
cardsInRow: F,
|
|
@@ -49,7 +48,7 @@ function I() {
|
|
|
49
48
|
filterSnapshot: null
|
|
50
49
|
};
|
|
51
50
|
}
|
|
52
|
-
const
|
|
51
|
+
const v = () => ({
|
|
53
52
|
recommendationCampaignUrls: {},
|
|
54
53
|
activePredictiveAlgorithms: [],
|
|
55
54
|
languages: {},
|
|
@@ -58,8 +57,8 @@ const N = () => ({
|
|
|
58
57
|
blockStates: {},
|
|
59
58
|
currentRecommendationId: null,
|
|
60
59
|
configVersion: 0
|
|
61
|
-
}),
|
|
62
|
-
state: () =>
|
|
60
|
+
}), _ = P("guidoRecommendationExtension", {
|
|
61
|
+
state: () => v(),
|
|
63
62
|
getters: {
|
|
64
63
|
// ====================================================================
|
|
65
64
|
// Proxy Getters — Backward Compatible Access to Current Block State
|
|
@@ -114,12 +113,12 @@ const N = () => ({
|
|
|
114
113
|
return [...new Set(t.map((e) => e.filterGroup))].sort((e, r) => e - r);
|
|
115
114
|
},
|
|
116
115
|
getActivePredictiveAlgorithms: (t) => {
|
|
117
|
-
const e = [];
|
|
118
|
-
return t.activePredictiveAlgorithms.filter((
|
|
119
|
-
|
|
120
|
-
}),
|
|
121
|
-
text:
|
|
122
|
-
value:
|
|
116
|
+
const e = S(), r = [];
|
|
117
|
+
return t.activePredictiveAlgorithms.filter((n) => !D.includes(n)).forEach((n) => {
|
|
118
|
+
r.push(...e.filter((c) => c.id === n));
|
|
119
|
+
}), r.map((n) => ({
|
|
120
|
+
text: n.name,
|
|
121
|
+
value: n.key
|
|
123
122
|
}));
|
|
124
123
|
},
|
|
125
124
|
getLanguages: (t) => Object.entries(t.languages).map(([e, r]) => ({
|
|
@@ -294,11 +293,11 @@ const N = () => ({
|
|
|
294
293
|
// ====================================================================
|
|
295
294
|
async fetchRecommendationCreateData() {
|
|
296
295
|
if (!this.activePredictiveAlgorithms.length) {
|
|
297
|
-
if (
|
|
298
|
-
await
|
|
296
|
+
if (u) {
|
|
297
|
+
await u;
|
|
299
298
|
return;
|
|
300
299
|
}
|
|
301
|
-
|
|
300
|
+
u = (async () => {
|
|
302
301
|
const {
|
|
303
302
|
activePredictiveAlgorithms: t,
|
|
304
303
|
languages: e,
|
|
@@ -311,26 +310,26 @@ const N = () => ({
|
|
|
311
310
|
this.currencyList = r;
|
|
312
311
|
})();
|
|
313
312
|
try {
|
|
314
|
-
await
|
|
313
|
+
await u;
|
|
315
314
|
} finally {
|
|
316
|
-
|
|
315
|
+
u = null;
|
|
317
316
|
}
|
|
318
317
|
}
|
|
319
318
|
},
|
|
320
319
|
async fetchRecommendationFilters() {
|
|
321
320
|
if (!Object.keys(this.filterList).length) {
|
|
322
|
-
if (
|
|
323
|
-
await
|
|
321
|
+
if (m) {
|
|
322
|
+
await m;
|
|
324
323
|
return;
|
|
325
324
|
}
|
|
326
|
-
|
|
325
|
+
m = (async () => {
|
|
327
326
|
const t = await h.fetchRecommendationFilters();
|
|
328
327
|
this.filterList = t;
|
|
329
328
|
})();
|
|
330
329
|
try {
|
|
331
|
-
await
|
|
330
|
+
await m;
|
|
332
331
|
} finally {
|
|
333
|
-
|
|
332
|
+
m = null;
|
|
334
333
|
}
|
|
335
334
|
}
|
|
336
335
|
},
|
|
@@ -399,14 +398,6 @@ const N = () => ({
|
|
|
399
398
|
generateFilterQuery() {
|
|
400
399
|
return b(this.recommendationConfigs.filters);
|
|
401
400
|
},
|
|
402
|
-
/**
|
|
403
|
-
* Validation-only check invoked at save-CTA time. Defined as an action
|
|
404
|
-
* (not a getter) so reading it does not register reactive tracking on
|
|
405
|
-
* every block's recommendationConfigs across user edits.
|
|
406
|
-
*/
|
|
407
|
-
hasInvalidBlock() {
|
|
408
|
-
return Object.values(this.blockStates).some((t) => !v(t.recommendationConfigs, this));
|
|
409
|
-
},
|
|
410
401
|
// ====================================================================
|
|
411
402
|
// Per-Block Product Fetching
|
|
412
403
|
// ====================================================================
|
|
@@ -426,7 +417,7 @@ const N = () => ({
|
|
|
426
417
|
},
|
|
427
418
|
async _doFetchProducts() {
|
|
428
419
|
var p;
|
|
429
|
-
const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, n = r.filters.filter((l) => l.isValid), c = b(n), i = ((p = S.find((l) => l.key === r.strategy)) == null ? void 0 : p.path) || "", o = G(), s = parseInt(r.size) || 6, a = {
|
|
420
|
+
const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, n = r.filters.filter((l) => l.isValid), c = b(n), i = ((p = S().find((l) => l.key === r.strategy)) == null ? void 0 : p.path) || "", o = G(), s = parseInt(r.size) || 6, a = {
|
|
430
421
|
locale: r.language,
|
|
431
422
|
currency: r.currencySettings.value,
|
|
432
423
|
partnerName: o.partnerName,
|
|
@@ -452,5 +443,5 @@ const N = () => ({
|
|
|
452
443
|
}
|
|
453
444
|
});
|
|
454
445
|
export {
|
|
455
|
-
|
|
446
|
+
_ as useRecommendationExtensionStore
|
|
456
447
|
};
|
|
@@ -6,7 +6,11 @@ export declare const URLS: {
|
|
|
6
6
|
export declare const QUERY_PARAMS: {
|
|
7
7
|
CLIENT_ID: string;
|
|
8
8
|
};
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Get recommendation feed source maps lazily so translated names resolve at access time.
|
|
11
|
+
* Must be called within a Vue component context or after Pinia is initialized.
|
|
12
|
+
*/
|
|
13
|
+
export declare const getRecommendationFeedSourceMaps: () => RecommendationFeedItem[];
|
|
10
14
|
export declare const PriceAttributes: string[];
|
|
11
15
|
export declare const currencyLocationMaps: TextValueObject[];
|
|
12
16
|
export declare const currencyOperators: TextValueObject[];
|
|
@@ -18,9 +18,14 @@ export declare const PRODUCT_TYPE_URL_SEGMENTS: {
|
|
|
18
18
|
readonly 97: "email";
|
|
19
19
|
};
|
|
20
20
|
export declare const INSIDER_ID = "iid";
|
|
21
|
-
export declare const
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
export declare const DEFAULT_UNSUBSCRIBE_GROUP_SEND_GRID_ID = "G";
|
|
22
|
+
/**
|
|
23
|
+
* Get the default unsubscribe group lazily so the translated name resolves at access time.
|
|
24
|
+
* Must be called within a Vue component context or after Pinia is initialized.
|
|
25
|
+
*/
|
|
26
|
+
export declare const getDefaultUnsubscribeGroup: () => {
|
|
27
|
+
name: string;
|
|
28
|
+
sendGridId: string;
|
|
24
29
|
};
|
|
25
30
|
export declare const UNSUBSCRIBE_PAGES_LINK = "/email/unsubscribe-pages";
|
|
26
31
|
export declare const PAGE_TYPES: {
|
|
@@ -95,15 +95,23 @@ export declare class RecommendationConfigService {
|
|
|
95
95
|
*
|
|
96
96
|
* Called when a block is first created (dropped into template).
|
|
97
97
|
* Can optionally merge in partial config from migration.
|
|
98
|
+
*
|
|
99
|
+
* The `wasFreshDrop` flag distinguishes a brand-new drop (no prior config)
|
|
100
|
+
* from a clone (Stripo replays the source's setNodeConfig payload before
|
|
101
|
+
* onCreated fires). Callers use this to skip side-effects already inherited
|
|
102
|
+
* from the source.
|
|
98
103
|
* @example
|
|
99
104
|
* // In Block.onCreated lifecycle
|
|
100
|
-
* RecommendationConfigService.initializeConfig(this.api, node);
|
|
105
|
+
* const { config, wasFreshDrop } = RecommendationConfigService.initializeConfig(this.api, node);
|
|
101
106
|
* @param api - Stripo extension API with document modifier
|
|
102
107
|
* @param node - The immutable HTML node to initialize
|
|
103
108
|
* @param partialConfig - Optional partial config to merge with defaults
|
|
104
|
-
* @returns The initialized configuration
|
|
109
|
+
* @returns The initialized configuration and whether the node was a fresh drop
|
|
105
110
|
*/
|
|
106
|
-
static initializeConfig(api: DocumentModifierApi, node: ImmutableHtmlNode, partialConfig?: PartialNodeConfig):
|
|
111
|
+
static initializeConfig(api: DocumentModifierApi, node: ImmutableHtmlNode, partialConfig?: PartialNodeConfig): {
|
|
112
|
+
config: RecommendationNodeConfig;
|
|
113
|
+
wasFreshDrop: boolean;
|
|
114
|
+
};
|
|
107
115
|
/**
|
|
108
116
|
* Save complete configuration to a node
|
|
109
117
|
*
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Orientation, Languages, Currency, NumericSeparator, FiltersResponse, Filter, RecommendationProduct } from '@@/Types/recommendation';
|
|
2
|
-
|
|
2
|
+
interface PerBlockConfigs {
|
|
3
3
|
cardsInRow: number;
|
|
4
4
|
currencySettings: {
|
|
5
5
|
name: string;
|
|
@@ -272,12 +272,6 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
|
|
|
272
272
|
deleteFilter(filter: Filter): void;
|
|
273
273
|
addFilter(filter: Filter): void;
|
|
274
274
|
generateFilterQuery(): string;
|
|
275
|
-
/**
|
|
276
|
-
* Validation-only check invoked at save-CTA time. Defined as an action
|
|
277
|
-
* (not a getter) so reading it does not register reactive tracking on
|
|
278
|
-
* every block's recommendationConfigs across user edits.
|
|
279
|
-
*/
|
|
280
|
-
hasInvalidBlock(): boolean;
|
|
281
275
|
fetchRecommendationProducts(): Promise<void>;
|
|
282
276
|
_doFetchProducts(): Promise<void>;
|
|
283
277
|
}>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@useinsider/guido",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.1-beta.11641c6",
|
|
4
4
|
"description": "Guido is a Vue + TypeScript wrapper for Email Plugin. Easily embed the email editor in your Vue applications.",
|
|
5
5
|
"main": "./dist/guido.umd.cjs",
|
|
6
6
|
"module": "./dist/library.js",
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
const o = [
|
|
2
|
-
{
|
|
3
|
-
key: "locale",
|
|
4
|
-
getValue: (e) => e.language,
|
|
5
|
-
getAvailableOptions: (e) => Object.keys(e.languages)
|
|
6
|
-
},
|
|
7
|
-
{
|
|
8
|
-
key: "currency",
|
|
9
|
-
getValue: (e) => e.currencySettings.value,
|
|
10
|
-
getAvailableOptions: (e) => e.currencyList.map((n) => n.text)
|
|
11
|
-
}
|
|
12
|
-
], l = "newsletter.recommendation-fill-required-fields";
|
|
13
|
-
function u(e, n) {
|
|
14
|
-
return o.filter((t) => {
|
|
15
|
-
var a;
|
|
16
|
-
if (t.condition && !t.condition(e))
|
|
17
|
-
return !1;
|
|
18
|
-
const i = t.getValue(e);
|
|
19
|
-
if (!i)
|
|
20
|
-
return !0;
|
|
21
|
-
const r = (a = t.getAvailableOptions) == null ? void 0 : a.call(t, n);
|
|
22
|
-
return r !== void 0 && !r.includes(i);
|
|
23
|
-
}).map((t) => t.key);
|
|
24
|
-
}
|
|
25
|
-
function s(e, n) {
|
|
26
|
-
return u(e, n).length === 0;
|
|
27
|
-
}
|
|
28
|
-
export {
|
|
29
|
-
o as REQUIRED_RECOMMENDATION_FIELDS,
|
|
30
|
-
l as RecommendationRequiredFieldsKey,
|
|
31
|
-
u as getInvalidFields,
|
|
32
|
-
s as isConfigValid
|
|
33
|
-
};
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { PerBlockConfigs } from '../store/recommendation';
|
|
2
|
-
import type { Currency, Languages } from '@@/Types/recommendation';
|
|
3
|
-
/**
|
|
4
|
-
* Structural slice of the recommendation extension store that descriptors may read.
|
|
5
|
-
* Add new fields here when a future descriptor needs them.
|
|
6
|
-
*/
|
|
7
|
-
export interface ExtensionStoreSlice {
|
|
8
|
-
languages: Languages;
|
|
9
|
-
currencyList: Currency[];
|
|
10
|
-
}
|
|
11
|
-
interface RequiredField {
|
|
12
|
-
key: string;
|
|
13
|
-
getValue: (config: PerBlockConfigs) => string;
|
|
14
|
-
getAvailableOptions?: (store: ExtensionStoreSlice) => string[];
|
|
15
|
-
condition?: (config: PerBlockConfigs) => boolean;
|
|
16
|
-
}
|
|
17
|
-
export declare const REQUIRED_RECOMMENDATION_FIELDS: RequiredField[];
|
|
18
|
-
export declare const RecommendationRequiredFieldsKey = "newsletter.recommendation-fill-required-fields";
|
|
19
|
-
export declare function getInvalidFields(config: PerBlockConfigs, store: ExtensionStoreSlice): string[];
|
|
20
|
-
export declare function isConfigValid(config: PerBlockConfigs, store: ExtensionStoreSlice): boolean;
|
|
21
|
-
export {};
|