@useinsider/guido 3.18.1-beta.fefef3c → 3.18.2-beta.32d291d
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/components/organisms/save-as-template/SaveAsTemplateDrawer.vue2.js +34 -34
- package/dist/composables/useHttp.js +24 -22
- package/dist/composables/useLegacyStrategyConversion.js +45 -45
- package/dist/enums/extensions/recommendationBlock.js +42 -36
- package/dist/extensions/Blocks/Recommendation/controls/main/index.js +23 -17
- package/dist/extensions/Blocks/Recommendation/store/recommendation.js +31 -12
- package/dist/extensions/Blocks/Recommendation/utils/legacyStrategyMigration.js +30 -60
- package/dist/node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js +29 -28
- package/dist/package.json.js +1 -1
- package/dist/services/recommendationApi.js +92 -92
- package/dist/services/templateLibraryApi.js +17 -14
- package/dist/src/enums/extensions/recommendationBlock.d.ts +4 -3
- package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +5 -1
- package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +28 -0
- package/dist/src/extensions/Blocks/Recommendation/utils/legacyStrategyMigration.d.ts +4 -16
- package/dist/src/utils/genericUtil.d.ts +6 -0
- package/dist/src/utils/liquidDynamicContent.d.ts +20 -0
- package/dist/utils/genericUtil.js +63 -54
- package/dist/utils/liquidDynamicContent.js +15 -0
- package/dist/utils/templatePreparation.js +54 -52
- package/package.json +3 -3
|
@@ -1,64 +1,64 @@
|
|
|
1
|
-
import { defineComponent as
|
|
2
|
-
import
|
|
3
|
-
import { useTranslations as
|
|
1
|
+
import { defineComponent as _, ref as c, computed as h, watch as C, toRef as N, nextTick as O } from "vue";
|
|
2
|
+
import b from "../../wrappers/WpDrawer.vue.js";
|
|
3
|
+
import { useTranslations as D } from "../../../composables/useTranslations.js";
|
|
4
4
|
import { useTemplateNameValidator as x } from "../../../composables/validators/saveAsTemplate.js";
|
|
5
5
|
import { useTemplateLibraryApi as B } from "../../../services/templateLibraryApi.js";
|
|
6
|
-
import { useEditorStore as
|
|
7
|
-
import { useSaveAsTemplateStore as
|
|
8
|
-
import { InMultiSelect as
|
|
9
|
-
import { useDebounceFn as
|
|
10
|
-
const
|
|
6
|
+
import { useEditorStore as k } from "../../../stores/editor.js";
|
|
7
|
+
import { useSaveAsTemplateStore as I } from "../../../stores/save-as-template.js";
|
|
8
|
+
import { InMultiSelect as M, InBasicTextInput as V } from "@useinsider/design-system-vue";
|
|
9
|
+
import { useDebounceFn as E } from "../../../node_modules/@vueuse/shared/index.js";
|
|
10
|
+
const J = /* @__PURE__ */ _({
|
|
11
11
|
__name: "SaveAsTemplateDrawer",
|
|
12
|
-
setup(
|
|
13
|
-
const
|
|
12
|
+
setup(R) {
|
|
13
|
+
const s = D(), o = k(), t = I(), { createTemplate: m } = B(), a = c(!1), n = c(!1), r = c(""), f = h(() => ({
|
|
14
14
|
primaryButton: {
|
|
15
15
|
styling: "solid",
|
|
16
16
|
type: "primary",
|
|
17
|
-
labelText:
|
|
17
|
+
labelText: s(a.value ? "newsletter.saving" : "products.save"),
|
|
18
18
|
loadingStatus: a.value,
|
|
19
19
|
disabledStatus: t.skeletonStatus
|
|
20
20
|
},
|
|
21
21
|
cancelOrBackButton: {
|
|
22
22
|
styling: "ghost",
|
|
23
23
|
type: "secondary",
|
|
24
|
-
labelText:
|
|
24
|
+
labelText: s("products.cancel"),
|
|
25
25
|
disabledStatus: a.value
|
|
26
26
|
}
|
|
27
|
-
})),
|
|
28
|
-
|
|
29
|
-
},
|
|
30
|
-
const e =
|
|
31
|
-
return
|
|
32
|
-
}, v =
|
|
33
|
-
t.templateName = e, await
|
|
34
|
-
}, 500),
|
|
35
|
-
|
|
36
|
-
},
|
|
27
|
+
})), p = () => {
|
|
28
|
+
r.value = "", o.isSaveAsTemplateDrawerOpen = !1;
|
|
29
|
+
}, l = async () => {
|
|
30
|
+
const e = N(t, "templateName"), { success: i, errorMessage: A } = await x(e).validate();
|
|
31
|
+
return r.value = A, i;
|
|
32
|
+
}, v = E(async (e) => {
|
|
33
|
+
t.templateName = e, await l();
|
|
34
|
+
}, 500), S = async (e) => {
|
|
35
|
+
n.value = !0, await t.addCategory(e), n.value = !1;
|
|
36
|
+
}, T = (e) => {
|
|
37
37
|
t.selectedCategories = e;
|
|
38
|
-
},
|
|
38
|
+
}, g = (e) => {
|
|
39
39
|
e && (t.selectedCategories = e);
|
|
40
|
-
},
|
|
40
|
+
}, y = () => {
|
|
41
41
|
t.selectedCategories = [];
|
|
42
42
|
}, w = async () => {
|
|
43
|
-
if (a.value = !0, !await
|
|
43
|
+
if (a.value = !0, !await l()) {
|
|
44
44
|
a.value = !1;
|
|
45
45
|
return;
|
|
46
46
|
}
|
|
47
|
-
const
|
|
48
|
-
a.value = !1,
|
|
49
|
-
},
|
|
50
|
-
|
|
47
|
+
const i = await m();
|
|
48
|
+
a.value = !1, i && p();
|
|
49
|
+
}, u = () => {
|
|
50
|
+
O(() => {
|
|
51
51
|
const e = document.querySelector("input#guido__template-name-input");
|
|
52
52
|
e == null || e.focus();
|
|
53
53
|
});
|
|
54
54
|
}, d = async () => {
|
|
55
|
-
t.$reset(), await t.fetchCategories(), t.skeletonStatus = !1,
|
|
55
|
+
t.$reset(), await t.fetchCategories(), t.skeletonStatus = !1, u();
|
|
56
56
|
};
|
|
57
|
-
return
|
|
58
|
-
|
|
59
|
-
}), { __sfc: !0, trans:
|
|
57
|
+
return C(() => o.isSaveAsTemplateDrawerOpen, (e) => {
|
|
58
|
+
e && d();
|
|
59
|
+
}), { __sfc: !0, trans: s, editorStore: o, saveAsTemplateStore: t, createTemplate: m, isSaving: a, isAddingOption: n, templateNameError: r, footerButtonGroupOptions: f, closeModal: p, validateTemplateName: l, handleTemplateName: v, handleAddOption: S, handleCategoryChange: T, handleSelectAllOptions: g, handleResetAllOptions: y, saveTemplate: w, focusToInput: u, initializeDrawer: d, WpDrawer: b, InBasicTextInput: V, InMultiSelect: M };
|
|
60
60
|
}
|
|
61
61
|
});
|
|
62
62
|
export {
|
|
63
|
-
|
|
63
|
+
J as default
|
|
64
64
|
};
|
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import { getCsrfToken as
|
|
2
|
-
import { ref as
|
|
3
|
-
const
|
|
4
|
-
const
|
|
1
|
+
import { getCsrfToken as O } from "../utils/genericUtil.js";
|
|
2
|
+
import { ref as m, computed as T } from "vue";
|
|
3
|
+
const X = (b = {}) => {
|
|
4
|
+
const p = m(!1), a = m(null), u = m(null), g = T(() => p.value), y = T(() => a.value !== null), v = {
|
|
5
5
|
baseURL: "",
|
|
6
6
|
timeout: 1e4,
|
|
7
7
|
retry: 0,
|
|
8
8
|
retryDelay: 1e3,
|
|
9
9
|
headers: {
|
|
10
10
|
"Content-Type": "application/json",
|
|
11
|
-
"X-CSRF-TOKEN":
|
|
11
|
+
"X-CSRF-TOKEN": O(),
|
|
12
|
+
Accept: "application/json",
|
|
13
|
+
"X-Requested-With": "XMLHttpRequest"
|
|
12
14
|
},
|
|
13
15
|
...b
|
|
14
16
|
}, w = (e, s) => {
|
|
@@ -22,22 +24,22 @@ const k = (b = {}) => {
|
|
|
22
24
|
}, e);
|
|
23
25
|
}), x = (e) => new Promise((s) => {
|
|
24
26
|
setTimeout(s, e);
|
|
25
|
-
}), i = async (e, s, t,
|
|
26
|
-
a.value = null,
|
|
27
|
-
const n = { ...v, ...
|
|
27
|
+
}), i = async (e, s, t, L = {}) => {
|
|
28
|
+
a.value = null, p.value = !0, u.value = new AbortController();
|
|
29
|
+
const n = { ...v, ...L }, D = w(s, n.baseURL), c = {
|
|
28
30
|
method: e,
|
|
29
31
|
headers: { ...n.headers },
|
|
30
32
|
signal: u.value.signal,
|
|
31
33
|
...n
|
|
32
34
|
};
|
|
33
35
|
t && ["POST", "PUT", "PATCH"].includes(e) && (t instanceof FormData ? (delete c.headers["Content-Type"], c.body = t) : c.body = JSON.stringify(t));
|
|
34
|
-
const E = async (
|
|
36
|
+
const E = async (h = 0) => {
|
|
35
37
|
try {
|
|
36
|
-
const o = [fetch(
|
|
38
|
+
const o = [fetch(D, c)];
|
|
37
39
|
n.timeout && o.push(P(n.timeout));
|
|
38
40
|
const r = await Promise.race(o);
|
|
39
41
|
if (!r.ok) {
|
|
40
|
-
const
|
|
42
|
+
const H = `HTTP Error: ${r.status} ${r.statusText}`, d = new Error(H);
|
|
41
43
|
throw d.status = r.status, d.statusText = r.statusText, d.response = r, d;
|
|
42
44
|
}
|
|
43
45
|
let f;
|
|
@@ -50,19 +52,19 @@ const k = (b = {}) => {
|
|
|
50
52
|
};
|
|
51
53
|
} catch (o) {
|
|
52
54
|
const r = o instanceof Error && o.name === "AbortError";
|
|
53
|
-
if (
|
|
54
|
-
return await x(n.retryDelay || 1e3), E(
|
|
55
|
+
if (h < (n.retry || 0) && !r)
|
|
56
|
+
return await x(n.retryDelay || 1e3), E(h + 1);
|
|
55
57
|
throw o instanceof Error ? o.name === "AbortError" ? a.value = { message: "Request was cancelled" } : a.value = { message: o.message } : a.value = o, o;
|
|
56
58
|
}
|
|
57
59
|
};
|
|
58
60
|
try {
|
|
59
61
|
return await E();
|
|
60
62
|
} finally {
|
|
61
|
-
|
|
63
|
+
p.value = !1, u.value = null;
|
|
62
64
|
}
|
|
63
|
-
}, C = (e, s) => i("GET", e, void 0, s),
|
|
65
|
+
}, C = (e, s) => i("GET", e, void 0, s), R = (e, s, t) => i("POST", e, s, t), $ = (e, s, t) => i("PUT", e, s, t), q = (e, s, t) => i("PATCH", e, s, t), A = (e, s) => i("DELETE", e, void 0, s), U = (e) => {
|
|
64
66
|
u.value && u.value.abort(e);
|
|
65
|
-
},
|
|
67
|
+
}, W = () => {
|
|
66
68
|
a.value = null;
|
|
67
69
|
};
|
|
68
70
|
return {
|
|
@@ -73,14 +75,14 @@ const k = (b = {}) => {
|
|
|
73
75
|
// Methods
|
|
74
76
|
request: i,
|
|
75
77
|
get: C,
|
|
76
|
-
post:
|
|
77
|
-
put:
|
|
78
|
-
patch:
|
|
78
|
+
post: R,
|
|
79
|
+
put: $,
|
|
80
|
+
patch: q,
|
|
79
81
|
delete: A,
|
|
80
|
-
cancel:
|
|
81
|
-
clearError:
|
|
82
|
+
cancel: U,
|
|
83
|
+
clearError: W
|
|
82
84
|
};
|
|
83
85
|
};
|
|
84
86
|
export {
|
|
85
|
-
|
|
87
|
+
X as useHttp
|
|
86
88
|
};
|
|
@@ -1,61 +1,61 @@
|
|
|
1
|
-
import { useRecommendation as
|
|
2
|
-
import { useToaster as
|
|
3
|
-
import { useTranslations as
|
|
4
|
-
import { ToasterTypeOptions as
|
|
1
|
+
import { useRecommendation as I } from "./useRecommendation.js";
|
|
2
|
+
import { useToaster as C } from "./useToaster.js";
|
|
3
|
+
import { useTranslations as v } from "./useTranslations.js";
|
|
4
|
+
import { ToasterTypeOptions as g } from "../enums/toaster.js";
|
|
5
5
|
import "../extensions/Blocks/Recommendation/constants/selectors.js";
|
|
6
6
|
import { CURRENT_CONFIG_VERSION as L } from "../extensions/Blocks/Recommendation/constants/defaultConfig.js";
|
|
7
|
-
import { useRecommendationExtensionStore as
|
|
8
|
-
import { resolveMigrationTarget as
|
|
9
|
-
import { commitBlockChangeOutsidePanel as
|
|
10
|
-
import { useConfigStore as
|
|
11
|
-
const
|
|
12
|
-
const
|
|
7
|
+
import { useRecommendationExtensionStore as b } from "../extensions/Blocks/Recommendation/store/recommendation.js";
|
|
8
|
+
import { resolveMigrationTarget as R, buildLegacyMigrationPayload as T } from "../extensions/Blocks/Recommendation/utils/legacyStrategyMigration.js";
|
|
9
|
+
import { commitBlockChangeOutsidePanel as h } from "../extensions/Blocks/Recommendation/utils/nodeConfigWriter.js";
|
|
10
|
+
import { useConfigStore as k } from "../stores/config.js";
|
|
11
|
+
const F = () => {
|
|
12
|
+
const e = b(), r = k(), { buildCampaignUrl: m } = I(), { showToaster: i } = C(), c = v();
|
|
13
13
|
return { convertLegacyStrategy: async () => {
|
|
14
|
-
const
|
|
15
|
-
if (
|
|
14
|
+
const t = e.currentRecommendationId;
|
|
15
|
+
if (t === null || !e.isLegacyStrategyBlock || e.legacyConversionLoading)
|
|
16
16
|
return "";
|
|
17
|
-
const { strategy: d, productIds: l,
|
|
18
|
-
campaignId:
|
|
19
|
-
templateLibraryId:
|
|
20
|
-
}),
|
|
21
|
-
blockId:
|
|
22
|
-
url:
|
|
23
|
-
campaignId:
|
|
24
|
-
variationId:
|
|
17
|
+
const { strategy: d, productIds: y, size: l, strategyId: p, nodeConfigVersion: u } = e.recommendationConfigs, f = { strategyId: p, size: l, nodeConfigVersion: u }, s = R({
|
|
18
|
+
campaignId: r.campaignId,
|
|
19
|
+
templateLibraryId: r.templateLibraryId
|
|
20
|
+
}), S = T({
|
|
21
|
+
blockId: t,
|
|
22
|
+
url: m(String(t)),
|
|
23
|
+
campaignId: r.campaignId,
|
|
24
|
+
variationId: r.variationId,
|
|
25
25
|
strategy: d,
|
|
26
|
-
productIds:
|
|
27
|
-
|
|
28
|
-
attributes: t.getFilterList,
|
|
29
|
-
target: i
|
|
26
|
+
productIds: y,
|
|
27
|
+
target: s
|
|
30
28
|
});
|
|
31
|
-
let
|
|
29
|
+
let o;
|
|
32
30
|
try {
|
|
33
|
-
|
|
31
|
+
o = await e.convertLegacyStrategy(S, s);
|
|
34
32
|
} catch (n) {
|
|
35
|
-
return console.error("[useLegacyStrategyConversion] migration failed", n),
|
|
36
|
-
type:
|
|
37
|
-
message:
|
|
33
|
+
return console.error("[useLegacyStrategyConversion] migration failed", n), i({
|
|
34
|
+
type: g.Error,
|
|
35
|
+
message: c("email-editor.legacy-strategy-update-failed")
|
|
38
36
|
}), "";
|
|
39
37
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
{ strategyId: r, size: u, configVersion: L },
|
|
38
|
+
try {
|
|
39
|
+
await e.fetchStrategyProductsForBlock(t);
|
|
40
|
+
} catch (n) {
|
|
41
|
+
console.error("[useLegacyStrategyConversion] product refetch failed", n);
|
|
42
|
+
}
|
|
43
|
+
const a = e.blockStates[t];
|
|
44
|
+
return a ? h(
|
|
45
|
+
t,
|
|
46
|
+
{
|
|
47
|
+
strategyId: o,
|
|
48
|
+
size: a.recommendationConfigs.size,
|
|
49
|
+
configVersion: L
|
|
50
|
+
},
|
|
54
51
|
a.recommendationProducts,
|
|
55
52
|
"Converted legacy recommendation strategy"
|
|
56
|
-
)
|
|
53
|
+
) ? (e.currentRecommendationId === t && e.openLegacyStrategyUpdatedModal(), o) : (console.error("[useLegacyStrategyConversion] node write failed", t), e.revertLegacyConversion(t, f), i({
|
|
54
|
+
type: g.Error,
|
|
55
|
+
message: c("email-editor.legacy-strategy-update-failed")
|
|
56
|
+
}), "") : o;
|
|
57
57
|
} };
|
|
58
58
|
};
|
|
59
59
|
export {
|
|
60
|
-
|
|
60
|
+
F as useLegacyStrategyConversion
|
|
61
61
|
};
|
|
@@ -1,15 +1,22 @@
|
|
|
1
|
-
import { useTranslations as
|
|
2
|
-
const
|
|
1
|
+
import { useTranslations as n } from "../../composables/useTranslations.js";
|
|
2
|
+
const a = {
|
|
3
3
|
RECOMMENDATION_API_URL: "https://recommendationv2.api.useinsider.com",
|
|
4
4
|
// Relative path → same-origin as the embedding inone dashboard.
|
|
5
5
|
PRODUCT_ATTRIBUTES_PATH: "/product-attributes/get-attributes",
|
|
6
6
|
RECOMMENDATION_STRATEGIES_PATH: "/api/recommendation-strategies",
|
|
7
7
|
RECOMMENDATION_STRATEGIES_PANEL_PATH: "/discovery/recommendation-strategies",
|
|
8
|
-
NEWSLETTER_RECOMMENDATIONS_PATH: "/newsletter/recommendations"
|
|
9
|
-
|
|
8
|
+
NEWSLETTER_RECOMMENDATIONS_PATH: "/newsletter/recommendations",
|
|
9
|
+
MIGRATE_STRATEGIES_PATH: "/newsletter/recommendations/migrate-strategies",
|
|
10
|
+
// The template route narrows the recommendations resource before the action: the id
|
|
11
|
+
// travels in the body, not the path.
|
|
12
|
+
TEMPLATE_MIGRATE_STRATEGIES_PATH: "/newsletter/recommendations/template/migrate-strategies"
|
|
13
|
+
}, c = {
|
|
14
|
+
campaign: a.MIGRATE_STRATEGIES_PATH,
|
|
15
|
+
template: a.TEMPLATE_MIGRATE_STRATEGIES_PATH
|
|
16
|
+
}, d = {
|
|
10
17
|
CLIENT_ID: "clientId"
|
|
11
|
-
},
|
|
12
|
-
const e =
|
|
18
|
+
}, m = () => {
|
|
19
|
+
const e = n();
|
|
13
20
|
return [
|
|
14
21
|
{
|
|
15
22
|
id: 11,
|
|
@@ -72,75 +79,74 @@ const l = {
|
|
|
72
79
|
path: "top-sellers"
|
|
73
80
|
}
|
|
74
81
|
];
|
|
75
|
-
},
|
|
82
|
+
}, p = ["discount", "omnibus_price", "omnibus_discount", "price", "original_price"], T = [
|
|
76
83
|
{ text: "before the amount", value: "0" },
|
|
77
84
|
{ text: "after the amount", value: "1" }
|
|
78
|
-
],
|
|
85
|
+
], v = [
|
|
79
86
|
{ text: "dot(.)", value: "." },
|
|
80
87
|
{ text: "comma(,)", value: "," },
|
|
81
88
|
{ text: "space( )", value: " " }
|
|
82
|
-
],
|
|
89
|
+
], A = [
|
|
83
90
|
{ text: "0", value: "0" },
|
|
84
91
|
{ text: "1", value: "1" },
|
|
85
92
|
{ text: "2", value: "2" },
|
|
86
93
|
{ text: "3", value: "3" },
|
|
87
94
|
{ text: "4", value: "4" },
|
|
88
95
|
{ text: "5", value: "5" }
|
|
89
|
-
],
|
|
96
|
+
], r = "||", t = [
|
|
90
97
|
{ text: "is exactly", value: "=" },
|
|
91
98
|
{ text: "contains", value: "~" },
|
|
92
99
|
{ text: "does not contain", value: "!~" },
|
|
93
|
-
{ text: "any of", value:
|
|
94
|
-
],
|
|
100
|
+
{ text: "any of", value: r }
|
|
101
|
+
], o = [
|
|
95
102
|
{ text: "is exactly", value: "=" },
|
|
96
103
|
{ text: "is not exactly", value: "!==" },
|
|
97
104
|
{ text: "contains", value: "~" },
|
|
98
105
|
{ text: "does not contain", value: "!~" },
|
|
99
|
-
{ text: "any of", value:
|
|
100
|
-
],
|
|
106
|
+
{ text: "any of", value: r }
|
|
107
|
+
], s = [
|
|
101
108
|
{ text: "is equal to", value: "=" },
|
|
102
109
|
{ text: "is greater than", value: ">" },
|
|
103
110
|
{ text: "is less than", value: "<" }
|
|
104
|
-
],
|
|
111
|
+
], i = [
|
|
105
112
|
{ text: "is equal to", value: "=" },
|
|
106
113
|
{ text: "after", value: ">" },
|
|
107
114
|
{ text: "before", value: "<" }
|
|
108
|
-
],
|
|
115
|
+
], u = [
|
|
109
116
|
{ text: "true", value: "==" },
|
|
110
117
|
{ text: "false", value: "!=" }
|
|
111
|
-
],
|
|
118
|
+
], E = (e) => {
|
|
112
119
|
if (!e)
|
|
113
120
|
return t;
|
|
114
121
|
switch (e) {
|
|
115
122
|
case "Boolean":
|
|
116
|
-
return
|
|
123
|
+
return u;
|
|
117
124
|
case "Date":
|
|
118
|
-
return
|
|
125
|
+
return i;
|
|
119
126
|
case "Number":
|
|
120
|
-
return
|
|
127
|
+
return s;
|
|
121
128
|
case "String":
|
|
122
129
|
return t;
|
|
123
130
|
case "Strings":
|
|
124
|
-
return
|
|
131
|
+
return o;
|
|
125
132
|
default:
|
|
126
133
|
return t;
|
|
127
134
|
}
|
|
128
135
|
};
|
|
129
136
|
export {
|
|
130
|
-
c as
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
i as
|
|
143
|
-
s as
|
|
144
|
-
o as operatorOptionsForNumbers,
|
|
137
|
+
c as MIGRATION_PATHS,
|
|
138
|
+
r as OP_ANY_OF,
|
|
139
|
+
p as PriceAttributes,
|
|
140
|
+
d as QUERY_PARAMS,
|
|
141
|
+
a as URLS,
|
|
142
|
+
A as currencyDecimalCounts,
|
|
143
|
+
T as currencyLocationMaps,
|
|
144
|
+
v as currencyOperators,
|
|
145
|
+
E as getOperatorOptions,
|
|
146
|
+
m as getRecommendationFeedSourceMaps,
|
|
147
|
+
o as operatorOptionsForArrayOfStrings,
|
|
148
|
+
u as operatorOptionsForBooleans,
|
|
149
|
+
i as operatorOptionsForDates,
|
|
150
|
+
s as operatorOptionsForNumbers,
|
|
145
151
|
t as operatorOptionsForStrings
|
|
146
152
|
};
|
|
@@ -19,18 +19,18 @@ import { LayoutOrientationControl as O } from "./layoutOrientation.js";
|
|
|
19
19
|
import { LAYOUT_ORIENTATION_CONTROL_ID as Ct } from "./layoutOrientation.js";
|
|
20
20
|
import { LocaleControl as L } from "./locale.js";
|
|
21
21
|
import { LOCALE_CONTROL_ID as yt } from "./locale.js";
|
|
22
|
-
import { PricePlacementControl as
|
|
22
|
+
import { PricePlacementControl as k } from "./pricePlacement.js";
|
|
23
23
|
import { PRICE_PLACEMENT_CONTROL_ID as _t } from "./pricePlacement.js";
|
|
24
|
-
import { ProductCountControl as
|
|
24
|
+
import { ProductCountControl as E } from "./productCount.js";
|
|
25
25
|
import { PRODUCT_COUNT_CONTROL_ID as Rt } from "./productCount.js";
|
|
26
|
-
import { ProductLayoutControl as
|
|
26
|
+
import { ProductLayoutControl as F } from "./productLayout.js";
|
|
27
27
|
import { PRODUCT_LAYOUT_CONTROL_ID as Tt } from "./productLayout.js";
|
|
28
|
-
import { ShuffleControl as
|
|
28
|
+
import { ShuffleControl as D } from "./shuffle.js";
|
|
29
29
|
import { SHUFFLE_CONTROL_ID as St } from "./shuffle.js";
|
|
30
30
|
import { StrategyControl as w } from "./strategy.js";
|
|
31
31
|
import { STRATEGY_CONTROL_ID as Lt } from "./strategy.js";
|
|
32
32
|
import { setCurrencyAttributes as A, getBlockElement as B, isPartnerManagedBlock as v, updateProductContentInPlace as x, regenerateProductRowsWithStyles as U } from "./utils.js";
|
|
33
|
-
import { adjustProductsToSize as
|
|
33
|
+
import { adjustProductsToSize as Et, formatProductPrice as Ft, getCardComposition as Dt, getCurrentLayout as wt, getMainContainerTbody as At, regenerateMobileProductRows as Bt, updatePricesInPlace as vt, updateSingleProductContent as xt } from "./utils.js";
|
|
34
34
|
import { useDebounceFn as f } from "../../../../../node_modules/@vueuse/shared/index.js";
|
|
35
35
|
const $ = "ui-elements-recommendation-block";
|
|
36
36
|
class at extends N {
|
|
@@ -39,8 +39,6 @@ class at extends N {
|
|
|
39
39
|
r(this, "store", R());
|
|
40
40
|
r(this, "storeUnsubscription", () => {
|
|
41
41
|
});
|
|
42
|
-
// blockId -> fingerprint of the node config as it looked at the last sync.
|
|
43
|
-
r(this, "syncedConfigs", /* @__PURE__ */ new Map());
|
|
44
42
|
// A config change waiting to reach the node config. Deferred so it can ride the
|
|
45
43
|
// re-render's single apply() — one user action must cost one undo press.
|
|
46
44
|
r(this, "pendingNodeConfigWrite", null);
|
|
@@ -120,7 +118,7 @@ class at extends N {
|
|
|
120
118
|
return this.rrsEnabled = p().isFeatureEnabled("reusableRecommendationStrategy"), this._subControls.forEach((e) => {
|
|
121
119
|
var o;
|
|
122
120
|
return (o = e == null ? void 0 : e.onDestroy) == null ? void 0 : o.call(e);
|
|
123
|
-
}), this.algorithmControl = new T(), this.localeControl = new L(), this.currencyControl = new P(), this.productCountControl = new
|
|
121
|
+
}), this.algorithmControl = new T(), this.localeControl = new L(), this.currencyControl = new P(), this.productCountControl = new E(), this.productLayoutControl = new F(), this.filtersControl = new S(), this.shuffleControl = new D(), this.pricePlacementControl = new k(), this.layoutOrientationControl = new O(), this.strategyControl = this.rrsEnabled ? new w() : null, this._subControls.forEach((e) => {
|
|
124
122
|
e && (e.api = this.api);
|
|
125
123
|
}), `
|
|
126
124
|
<div class="recommendation-controls-container">
|
|
@@ -200,11 +198,19 @@ class at extends N {
|
|
|
200
198
|
* fingerprint diff on this hook is the only way to notice (SD-149105).
|
|
201
199
|
* An unchanged fingerprint means the move came from us, so runtime store
|
|
202
200
|
* edits are never clobbered (SD-141049).
|
|
201
|
+
*
|
|
202
|
+
* The fingerprint is kept on the block's own store state so deleting the
|
|
203
|
+
* block drops it with the state it describes. A control-owned memo outlived
|
|
204
|
+
* that state and made a re-dropped saved module keep the defaults its wiped
|
|
205
|
+
* state was rebuilt with (SD-150347).
|
|
203
206
|
*/
|
|
204
207
|
_syncNodeConfigIfChanged(t) {
|
|
205
208
|
this.pendingNodeConfigWrite && this.pendingNodeConfigWrite.blockId !== t && this._flushPendingNodeConfig();
|
|
206
|
-
const e =
|
|
207
|
-
|
|
209
|
+
const e = this.store.blockStates[t];
|
|
210
|
+
if (!e)
|
|
211
|
+
return;
|
|
212
|
+
const o = JSON.stringify(c.getConfig(this.currentNode)), n = e.syncedConfigFingerprint;
|
|
213
|
+
e.syncedConfigFingerprint = o, n !== o && (this.pendingNodeConfigWrite || this._syncNodeConfigToStore());
|
|
208
214
|
}
|
|
209
215
|
_capturePendingNodeConfigWrite() {
|
|
210
216
|
const t = this.store.currentRecommendationId;
|
|
@@ -429,18 +435,18 @@ export {
|
|
|
429
435
|
_t as PRICE_PLACEMENT_CONTROL_ID,
|
|
430
436
|
Rt as PRODUCT_COUNT_CONTROL_ID,
|
|
431
437
|
Tt as PRODUCT_LAYOUT_CONTROL_ID,
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
438
|
+
k as PricePlacementControl,
|
|
439
|
+
E as ProductCountControl,
|
|
440
|
+
F as ProductLayoutControl,
|
|
435
441
|
at as RecommendationBlockControl,
|
|
436
442
|
St as SHUFFLE_CONTROL_ID,
|
|
437
443
|
Lt as STRATEGY_CONTROL_ID,
|
|
438
|
-
|
|
444
|
+
D as ShuffleControl,
|
|
439
445
|
w as StrategyControl,
|
|
440
|
-
|
|
441
|
-
|
|
446
|
+
Et as adjustProductsToSize,
|
|
447
|
+
Ft as formatProductPrice,
|
|
442
448
|
B as getBlockElement,
|
|
443
|
-
|
|
449
|
+
Dt as getCardComposition,
|
|
444
450
|
wt as getCurrentLayout,
|
|
445
451
|
At as getMainContainerTbody,
|
|
446
452
|
v as isPartnerManagedBlock,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { getRecommendationFeedSourceMaps as R, getOperatorOptions as
|
|
2
|
-
import { useRecommendationApi as
|
|
1
|
+
import { getRecommendationFeedSourceMaps as R, getOperatorOptions as F, PriceAttributes as P } from "../../../../enums/extensions/recommendationBlock.js";
|
|
2
|
+
import { useRecommendationApi as D } from "../../../../services/recommendationApi.js";
|
|
3
3
|
import { useConfigStore as k } from "../../../../stores/config.js";
|
|
4
4
|
import { defineStore as L } from "pinia";
|
|
5
5
|
import "../constants/selectors.js";
|
|
@@ -8,11 +8,11 @@ import { CURRENT_CONFIG_VERSION as y, DEFAULT_NODE_CONFIG as N, EXCLUDED_ALGORIT
|
|
|
8
8
|
import { getDefaultProducts as C } from "../templates/utils.js";
|
|
9
9
|
import { generateCompleteFilterQuery as v } from "../utils/filterUtil.js";
|
|
10
10
|
import { isLegacyStrategyConfig as x } from "../utils/legacyStrategyMigration.js";
|
|
11
|
-
import { getPartnerRecommendationParams as
|
|
12
|
-
import { sanitizeProductIds as
|
|
11
|
+
import { getPartnerRecommendationParams as B } from "../utils/partnerCustomizations.js";
|
|
12
|
+
import { sanitizeProductIds as z } from "../utils/productIds.js";
|
|
13
13
|
import { isFilterValid as A } from "../validation/filterSchema.js";
|
|
14
14
|
import { isConfigValid as O } from "../validation/requiredFields.js";
|
|
15
|
-
const m =
|
|
15
|
+
const m = D();
|
|
16
16
|
let f = null, g = null, h = null, S = null;
|
|
17
17
|
const p = /* @__PURE__ */ new Map();
|
|
18
18
|
function G() {
|
|
@@ -60,6 +60,7 @@ function w() {
|
|
|
60
60
|
filterGroup: 1,
|
|
61
61
|
isInitialized: !1,
|
|
62
62
|
filterSnapshot: null,
|
|
63
|
+
syncedConfigFingerprint: null,
|
|
63
64
|
legacyConversionLoading: !1
|
|
64
65
|
};
|
|
65
66
|
}
|
|
@@ -169,7 +170,7 @@ const E = () => ({
|
|
|
169
170
|
getFilterList() {
|
|
170
171
|
return Object.values(this.filterList).filter((t) => t.isFilterable !== 0 && t.isFilterable !== !1).map((t) => {
|
|
171
172
|
let e;
|
|
172
|
-
return t.type === "productAttribute" ? e = `product_attributes.${t.attributeName}` :
|
|
173
|
+
return t.type === "productAttribute" ? e = `product_attributes.${t.attributeName}` : P.includes(t.attributeName) ? e = `${t.attributeName}.${this.recommendationConfigs.currencySettings.value}` : e = t.attributeName, {
|
|
173
174
|
text: t.displayName,
|
|
174
175
|
value: e,
|
|
175
176
|
type: t.attributeType
|
|
@@ -254,7 +255,7 @@ const E = () => ({
|
|
|
254
255
|
const r = (o, c) => o === "." || o === "," || o === " " ? o : c, n = {
|
|
255
256
|
name: e.currencyCode,
|
|
256
257
|
value: e.currencyCode,
|
|
257
|
-
symbol: e.
|
|
258
|
+
symbol: e.currencySymbol,
|
|
258
259
|
alignment: e.currencyAlignment === "before" ? "0" : "1",
|
|
259
260
|
decimalCount: String(e.currencyDecimalCount),
|
|
260
261
|
decimalSeparator: r(e.currencyDecimalSeparator, ","),
|
|
@@ -298,7 +299,7 @@ const E = () => ({
|
|
|
298
299
|
* Creates a filter with the first available attribute and operator pre-selected.
|
|
299
300
|
*/
|
|
300
301
|
createDefaultFilter(t, e) {
|
|
301
|
-
const [r] = this.getFilterList, [n] =
|
|
302
|
+
const [r] = this.getFilterList, [n] = F(r == null ? void 0 : r.type);
|
|
302
303
|
return {
|
|
303
304
|
type: "standardFilter",
|
|
304
305
|
attribute: (r == null ? void 0 : r.value) ?? "",
|
|
@@ -421,6 +422,15 @@ const E = () => ({
|
|
|
421
422
|
this.blockStates[r] && (this.blockStates[r].legacyConversionLoading = !1);
|
|
422
423
|
}
|
|
423
424
|
},
|
|
425
|
+
/**
|
|
426
|
+
* Undoes the config half of a conversion whose document write never landed, so the
|
|
427
|
+
* panel and the drawer fall back to "Legacy Strategy" instead of showing an assignment
|
|
428
|
+
* the document never received.
|
|
429
|
+
*/
|
|
430
|
+
revertLegacyConversion(t, e) {
|
|
431
|
+
const r = this.blockStates[t];
|
|
432
|
+
r && (r.recommendationConfigs = { ...r.recommendationConfigs, ...e }, this.currentRecommendationId === t && this.configVersion++);
|
|
433
|
+
},
|
|
424
434
|
removeStrategy() {
|
|
425
435
|
this.patchCurrentBlockConfig({
|
|
426
436
|
strategyId: "",
|
|
@@ -578,9 +588,9 @@ const E = () => ({
|
|
|
578
588
|
details: !0,
|
|
579
589
|
campaignId: n.variationId
|
|
580
590
|
};
|
|
581
|
-
r.strategy === "manualMerchandising" ? a.productId =
|
|
591
|
+
r.strategy === "manualMerchandising" ? a.productId = z(r.productIds) : r.strategy === "similarViewed" && (a.productId = "{itemId}"), r.strategy === "userBased" && (a.userId = "{user_id}"), i && (a.filter = i), r.shuffleProducts && (a.shuffle = !0), Object.assign(
|
|
582
592
|
a,
|
|
583
|
-
|
|
593
|
+
B(n.partnerName, r.strategy)
|
|
584
594
|
);
|
|
585
595
|
let l;
|
|
586
596
|
try {
|
|
@@ -590,6 +600,15 @@ const E = () => ({
|
|
|
590
600
|
}
|
|
591
601
|
this._setBlockProducts(t, l, c);
|
|
592
602
|
},
|
|
603
|
+
/**
|
|
604
|
+
* Block-scoped counterpart of `fetchRecommendationProducts`, which only ever serves the
|
|
605
|
+
* selected block. The legacy conversion must refresh the products of the block that
|
|
606
|
+
* started it even after the user selected another one.
|
|
607
|
+
*/
|
|
608
|
+
async fetchStrategyProductsForBlock(t) {
|
|
609
|
+
var e;
|
|
610
|
+
(e = this.blockStates[t]) != null && e.recommendationConfigs.strategyId && await this._doFetchStrategyProducts(t);
|
|
611
|
+
},
|
|
593
612
|
async _doFetchStrategyProducts(t) {
|
|
594
613
|
const e = (p.get(t) ?? 0) + 1;
|
|
595
614
|
p.set(t, e);
|
|
@@ -602,8 +621,8 @@ const E = () => ({
|
|
|
602
621
|
);
|
|
603
622
|
if (i) {
|
|
604
623
|
s = parseInt(String(i.size ?? "")) || s;
|
|
605
|
-
const o = r.currencySettings.value, a = (await this.resolveStrategyUrlTemplate(i, o)).replaceAll("{locale}", r.language).replaceAll("{currency}", o), l = a.indexOf("?"), d = l === -1 ? a : a.slice(0, l), u = (l === -1 ? "" : a.slice(l + 1)).split("&").filter((
|
|
606
|
-
|
|
624
|
+
const o = r.currencySettings.value, a = (await this.resolveStrategyUrlTemplate(i, o)).replaceAll("{locale}", r.language).replaceAll("{currency}", o), l = a.indexOf("?"), d = l === -1 ? a : a.slice(0, l), u = (l === -1 ? "" : a.slice(l + 1)).split("&").filter((I) => I && !I.startsWith("user_id=")), b = u.length ? `${d}?${u.join("&")}` : d;
|
|
625
|
+
b && (n = await m.fetchRecommendationProductsByUrl(b));
|
|
607
626
|
}
|
|
608
627
|
} catch {
|
|
609
628
|
n = [];
|