@useinsider/guido 3.18.2-beta.d3f87c7 → 3.18.2-beta.dfce34a
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/extensions/recommendation/AssignStrategyDrawer.vue.js +1 -1
- package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue2.js +39 -34
- package/dist/extensions/Blocks/Recommendation/block.js +47 -32
- package/dist/extensions/Blocks/Recommendation/store/recommendation.js +120 -105
- package/dist/guido.css +1 -1
- package/dist/src/extensions/Blocks/Recommendation/block.d.ts +10 -0
- package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +14 -3
- package/package.json +1 -1
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
import { defineComponent as A, defineAsyncComponent as S, ref as
|
|
1
|
+
import { defineComponent as A, defineAsyncComponent as S, ref as v, computed as l, watch as h } from "vue";
|
|
2
2
|
import "@useinsider/design-system-organisms/style";
|
|
3
3
|
import { useToaster as C } from "../../../../composables/useToaster.js";
|
|
4
4
|
import { useTranslations as b } from "../../../../composables/useTranslations.js";
|
|
5
5
|
import { DOTTED_DATE_LOCALE as B } from "../../../../enums/date.js";
|
|
6
6
|
import { URLS as k } from "../../../../enums/extensions/recommendationBlock.js";
|
|
7
|
-
import { ToasterTypeOptions as
|
|
7
|
+
import { ToasterTypeOptions as g } from "../../../../enums/toaster.js";
|
|
8
8
|
import { useRecommendationExtensionStore as R } from "../../../../extensions/Blocks/Recommendation/store/recommendation.js";
|
|
9
|
-
import { commitStrategyChange as
|
|
9
|
+
import { commitStrategyChange as T } from "../../../../extensions/Blocks/Recommendation/utils/strategyCommit.js";
|
|
10
10
|
import N from "./StrategyInfoBoxContent.vue.js";
|
|
11
11
|
import { formatShortDate as P } from "../../../../utils/dateUtil.js";
|
|
12
|
-
import { asText as
|
|
12
|
+
import { asText as _ } from "../../../../utils/genericUtil.js";
|
|
13
13
|
import { escapeHtml as U } from "../../../../utils/htmlEscape.js";
|
|
14
14
|
import { InSkeleton as L } from "@useinsider/design-system-vue";
|
|
15
15
|
const rt = /* @__PURE__ */ A({
|
|
16
16
|
__name: "AssignStrategyDrawer",
|
|
17
17
|
setup(M) {
|
|
18
18
|
const m = () => import("@useinsider/design-system-organisms"), u = (t, r) => ({
|
|
19
|
-
render: (
|
|
19
|
+
render: (s) => s(L, { props: { sizing: { width: t, height: r } } })
|
|
20
20
|
}), w = S({
|
|
21
21
|
loader: async () => (await m()).OrgStrategyDetailModal,
|
|
22
22
|
loadingComponent: u(480, 240),
|
|
23
23
|
delay: 0
|
|
24
24
|
}), D = S({
|
|
25
25
|
loader: async () => (await m()).OrgStrategyDropdown
|
|
26
|
-
}),
|
|
26
|
+
}), i = "guido-edit-strategy-", o = b(), e = R(), { showToaster: n } = C(), a = v(null), c = v(!1), E = l(() => e.assignStrategyDrawerStatus ? o("email-editor.assign-strategy-description", { url: k.RECOMMENDATION_STRATEGIES_PANEL_PATH }) : "");
|
|
27
27
|
h(() => e.assignStrategyDrawerStatus, (t) => {
|
|
28
28
|
if (!t)
|
|
29
29
|
return;
|
|
30
30
|
const { strategyId: r } = e.recommendationConfigs;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
type:
|
|
31
|
+
a.value = r || null, c.value = !1, e.invalidateStrategies(), e.fetchStrategies().catch(() => {
|
|
32
|
+
n({
|
|
33
|
+
type: g.Error,
|
|
34
34
|
message: o("discovery-strategy.error-description")
|
|
35
35
|
});
|
|
36
36
|
});
|
|
37
37
|
});
|
|
38
38
|
const y = (t) => {
|
|
39
|
-
const r =
|
|
39
|
+
const r = _(t.updated_at || t.created_at);
|
|
40
40
|
if (!r)
|
|
41
41
|
return "";
|
|
42
|
-
const
|
|
43
|
-
return o("recommendation-strategy.last-updated-on", { value:
|
|
44
|
-
},
|
|
42
|
+
const s = P(r, B);
|
|
43
|
+
return o("recommendation-strategy.last-updated-on", { value: s });
|
|
44
|
+
}, I = l(() => e.strategies.map((t) => ({
|
|
45
45
|
text: t.name,
|
|
46
46
|
value: t.strategy_id,
|
|
47
47
|
infoBoxProps: {
|
|
@@ -49,7 +49,7 @@ const rt = /* @__PURE__ */ A({
|
|
|
49
49
|
theme: "light",
|
|
50
50
|
variant: "information",
|
|
51
51
|
className: "assign-strategy-info-box",
|
|
52
|
-
titleText: U(
|
|
52
|
+
titleText: U(_(t.name)),
|
|
53
53
|
descriptionStatus: !0,
|
|
54
54
|
descriptionText: y(t),
|
|
55
55
|
slot: N,
|
|
@@ -57,7 +57,7 @@ const rt = /* @__PURE__ */ A({
|
|
|
57
57
|
// The info box drops the option's value/text, so the id is the only channel
|
|
58
58
|
// that can carry the strategy back to the click handler.
|
|
59
59
|
buttonOptions: [{
|
|
60
|
-
id: `${
|
|
60
|
+
id: `${i}${t.strategy_id}`,
|
|
61
61
|
text: o("eureka.edit-strategy"),
|
|
62
62
|
type: "text",
|
|
63
63
|
// Resolved from Guido's own public/sprite.svg by InIcons; an unknown name would
|
|
@@ -65,19 +65,24 @@ const rt = /* @__PURE__ */ A({
|
|
|
65
65
|
icon: "line-open-website"
|
|
66
66
|
}]
|
|
67
67
|
}
|
|
68
|
-
}))),
|
|
68
|
+
}))), x = (t) => {
|
|
69
69
|
var f;
|
|
70
|
-
const r = (f = t == null ? void 0 : t.id) != null && f.startsWith(
|
|
70
|
+
const r = (f = t == null ? void 0 : t.id) != null && f.startsWith(i) ? t.id.slice(i.length) : "";
|
|
71
71
|
if (!r)
|
|
72
72
|
return;
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
const s = e.currentRecommendationId, d = e.recommendationConfigs.strategyId === r;
|
|
74
|
+
if (!e.openStrategyEdit(r)) {
|
|
75
|
+
n({
|
|
76
|
+
type: g.Error,
|
|
77
|
+
message: o("discovery-strategy.error-description")
|
|
78
|
+
});
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
String(a.value ?? "") === r && (a.value = null), d && (e.removeStrategy(), s !== null && T(s, "Removed recommendation strategy"));
|
|
82
|
+
}, p = l(() => {
|
|
83
|
+
const t = e.strategies.find((r) => String(r.strategy_id) === String(a.value ?? ""));
|
|
79
84
|
return t ? { ...t, fallback_config: null } : null;
|
|
80
|
-
}), O =
|
|
85
|
+
}), O = l(() => ({
|
|
81
86
|
primaryButton: {
|
|
82
87
|
styling: "solid",
|
|
83
88
|
type: "primary",
|
|
@@ -89,7 +94,7 @@ const rt = /* @__PURE__ */ A({
|
|
|
89
94
|
labelText: o("products.cancel")
|
|
90
95
|
}
|
|
91
96
|
}));
|
|
92
|
-
return { __sfc: !0, loadOrganisms: m, skeleton: u, OrgStrategyDetailModal: w, OrgStrategyDropdown: D, EDIT_BUTTON_ID_PREFIX:
|
|
97
|
+
return { __sfc: !0, loadOrganisms: m, skeleton: u, OrgStrategyDetailModal: w, OrgStrategyDropdown: D, EDIT_BUTTON_ID_PREFIX: i, trans: o, store: e, showToaster: n, selectedStrategyId: a, showSelectionError: c, drawerDescription: E, lastUpdatedText: y, strategyOptions: I, onInfoBoxButtonClick: x, selectedStrategy: p, footerButtonGroupOptions: O, closeDrawer: () => {
|
|
93
98
|
e.closeAssignStrategyDrawer();
|
|
94
99
|
}, assignStrategy: async () => {
|
|
95
100
|
const t = p.value;
|
|
@@ -100,23 +105,23 @@ const rt = /* @__PURE__ */ A({
|
|
|
100
105
|
let r = "";
|
|
101
106
|
try {
|
|
102
107
|
r = await e.resolveStrategyUrlTemplate(t, e.recommendationConfigs.currencySettings.value);
|
|
103
|
-
} catch (
|
|
104
|
-
console.error("[AssignStrategyDrawer] resolveStrategyUrlTemplate failed",
|
|
108
|
+
} catch (d) {
|
|
109
|
+
console.error("[AssignStrategyDrawer] resolveStrategyUrlTemplate failed", d);
|
|
105
110
|
}
|
|
106
111
|
if (!r) {
|
|
107
|
-
|
|
108
|
-
type:
|
|
112
|
+
n({
|
|
113
|
+
type: g.Error,
|
|
109
114
|
message: o("email-editor.strategy-assign-failed", { strategyName: t.name })
|
|
110
115
|
});
|
|
111
116
|
return;
|
|
112
117
|
}
|
|
113
|
-
const
|
|
114
|
-
e.assignStrategy(t),
|
|
115
|
-
type:
|
|
118
|
+
const s = e.currentRecommendationId;
|
|
119
|
+
e.assignStrategy(t), n({
|
|
120
|
+
type: g.Success,
|
|
116
121
|
message: o("email-editor.strategy-assigned-success", { strategyName: t.name })
|
|
117
|
-
}), e.closeAssignStrategyDrawer(),
|
|
122
|
+
}), e.closeAssignStrategyDrawer(), s !== null && await T(s, "Assigned recommendation strategy");
|
|
118
123
|
}, onSelect: (t) => {
|
|
119
|
-
|
|
124
|
+
a.value = t.value, c.value = !1;
|
|
120
125
|
} };
|
|
121
126
|
}
|
|
122
127
|
});
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
import { useConfig as
|
|
5
|
-
import { BlockId as
|
|
6
|
-
import { getMigrationBannerHtml as
|
|
7
|
-
import { Block as E, BlockCompositionType as S, ModificationDescription as
|
|
1
|
+
var y = Object.defineProperty;
|
|
2
|
+
var A = (l, c, t) => c in l ? y(l, c, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[c] = t;
|
|
3
|
+
var g = (l, c, t) => A(l, typeof c != "symbol" ? c + "" : c, t);
|
|
4
|
+
import { useConfig as h } from "../../../composables/useConfig.js";
|
|
5
|
+
import { BlockId as D } from "../../../enums/block.js";
|
|
6
|
+
import { getMigrationBannerHtml as C } from "../../../utils/migrationBannerHtml.js";
|
|
7
|
+
import { Block as E, BlockCompositionType as S, ModificationDescription as p } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
8
8
|
import { CURRENT_CONFIG_VERSION as N, PRE_RRS_CONFIG_VERSION as O } from "./constants/defaultConfig.js";
|
|
9
9
|
import { RECOMMENDATION_ID_ATTR as m } from "./constants/selectors.js";
|
|
10
10
|
import { regenerateMobileProductRows as M } from "./controls/main/utils.js";
|
|
11
|
-
import { ensureMobileCssRulesExist as
|
|
11
|
+
import { ensureMobileCssRulesExist as I, setMobileLayoutOptOut as R, hasMobileLayoutOptOut as w } from "./controls/mobileLayout/cssRules.js";
|
|
12
12
|
import { RecommendationConfigService as s } from "./services/configService.js";
|
|
13
13
|
import { useRecommendationExtensionStore as d } from "./store/recommendation.js";
|
|
14
|
-
import { getDefaultTemplate as
|
|
15
|
-
import { useRecommendationBlockWarning as
|
|
16
|
-
const k =
|
|
17
|
-
let
|
|
14
|
+
import { getDefaultTemplate as T } from "./templates/grid/template.js";
|
|
15
|
+
import { useRecommendationBlockWarning as x } from "./useRecommendationBlockWarning.js";
|
|
16
|
+
const k = D.Recommendation, u = "recommendation-block-v2", B = "hide-price";
|
|
17
|
+
let b = !1;
|
|
18
18
|
class j extends E {
|
|
19
19
|
constructor() {
|
|
20
20
|
super();
|
|
@@ -22,7 +22,9 @@ class j extends E {
|
|
|
22
22
|
* Stores the ID generated in getTemplate() so onCreated() can reuse it.
|
|
23
23
|
* This avoids generating a new (different) ID in onCreated().
|
|
24
24
|
*/
|
|
25
|
-
|
|
25
|
+
g(this, "_pendingBlockId", null);
|
|
26
|
+
/** Ids already reset under their new name, so the deferred pass skips their stale snapshot. */
|
|
27
|
+
g(this, "_resetSourceIds", /* @__PURE__ */ new Set());
|
|
26
28
|
}
|
|
27
29
|
getId() {
|
|
28
30
|
return k;
|
|
@@ -42,7 +44,7 @@ class j extends E {
|
|
|
42
44
|
);
|
|
43
45
|
}
|
|
44
46
|
getSettingsPanelTitleHtml() {
|
|
45
|
-
return
|
|
47
|
+
return C(
|
|
46
48
|
k,
|
|
47
49
|
this.api.translate("Recommendation Block"),
|
|
48
50
|
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.")
|
|
@@ -66,7 +68,7 @@ class j extends E {
|
|
|
66
68
|
*/
|
|
67
69
|
getTemplate() {
|
|
68
70
|
const t = this._generateNextId();
|
|
69
|
-
return this._pendingBlockId = t,
|
|
71
|
+
return this._pendingBlockId = t, T(t);
|
|
70
72
|
}
|
|
71
73
|
/**
|
|
72
74
|
* Called when a new block is dropped into the template
|
|
@@ -79,17 +81,17 @@ class j extends E {
|
|
|
79
81
|
const e = this._getRecommendationId(t);
|
|
80
82
|
if (e !== null && e > 0) {
|
|
81
83
|
if (this._detectDuplicate(e)) {
|
|
82
|
-
this._handleDuplicate(t, e);
|
|
84
|
+
this._handleDuplicate(t, e), this._scheduleArrivalReset(t);
|
|
83
85
|
return;
|
|
84
86
|
}
|
|
85
87
|
this._pendingBlockId === null && setTimeout(() => {
|
|
86
88
|
this._getBlockElement(t) && this._detectDuplicate(e) && this._handleDuplicate(t, e);
|
|
87
|
-
}, 0);
|
|
89
|
+
}, 0), this._scheduleArrivalReset(t);
|
|
88
90
|
return;
|
|
89
91
|
}
|
|
90
92
|
const i = this._pendingBlockId ?? this._generateNextId();
|
|
91
93
|
this._pendingBlockId = null, this._assignRecommendationId(t, i);
|
|
92
|
-
const n =
|
|
94
|
+
const n = h().isFeatureEnabled("reusableRecommendationStrategy"), o = n && !s.hasConfig(t), { config: r, wasFreshDrop: a } = s.initializeConfig(
|
|
93
95
|
this.api,
|
|
94
96
|
t,
|
|
95
97
|
{
|
|
@@ -100,16 +102,16 @@ class j extends E {
|
|
|
100
102
|
// at save for a block the user never configured.
|
|
101
103
|
...o ? { strategy: "" } : {}
|
|
102
104
|
}
|
|
103
|
-
),
|
|
104
|
-
if (
|
|
105
|
-
|
|
106
|
-
const
|
|
107
|
-
|
|
105
|
+
), f = d();
|
|
106
|
+
if (f.setCurrentBlock(i), this._stampHidePrice(t, r.priceHideIfSameAsDiscounted), a) {
|
|
107
|
+
I(this.api);
|
|
108
|
+
const _ = this._getBlockElement(t);
|
|
109
|
+
_ && (R(this.api, _, !0), M({
|
|
108
110
|
currentNode: t,
|
|
109
111
|
documentModifier: this.api.getDocumentModifier()
|
|
110
112
|
}));
|
|
111
113
|
}
|
|
112
|
-
|
|
114
|
+
f.patchCurrentBlockConfig({ language: r.language }, { triggerRefetch: !1 }), this._warnIfMultipleBlocks();
|
|
113
115
|
}
|
|
114
116
|
/**
|
|
115
117
|
* Called when the document changes or template is loaded
|
|
@@ -131,11 +133,11 @@ class j extends E {
|
|
|
131
133
|
}
|
|
132
134
|
this._healLingeringDuplicate(t), s.needsMigration(t) && this._migrateFromLegacy(t), this._healHidePriceAttr(t);
|
|
133
135
|
try {
|
|
134
|
-
|
|
136
|
+
b || (I(this.api), b = !0);
|
|
135
137
|
const e = s.getConfig(t), i = this._getBlockElement(t);
|
|
136
138
|
if (i) {
|
|
137
139
|
const n = !e.mobileLayoutEnabled;
|
|
138
|
-
w(i) !== n &&
|
|
140
|
+
w(i) !== n && R(this.api, i, n);
|
|
139
141
|
}
|
|
140
142
|
} catch {
|
|
141
143
|
}
|
|
@@ -165,7 +167,7 @@ class j extends E {
|
|
|
165
167
|
*/
|
|
166
168
|
_warnIfMultipleBlocks() {
|
|
167
169
|
try {
|
|
168
|
-
|
|
170
|
+
x().warnIfMultipleBlocks(this.api.getDocumentRootHtmlNode());
|
|
169
171
|
} catch {
|
|
170
172
|
}
|
|
171
173
|
}
|
|
@@ -187,6 +189,19 @@ class j extends E {
|
|
|
187
189
|
}
|
|
188
190
|
return t + 1;
|
|
189
191
|
}
|
|
192
|
+
/**
|
|
193
|
+
* Drops the "already fetched" claims of a block that arrived holding a baked id
|
|
194
|
+
* (saved module, paste, duplicate), so the settings panel reads its strategy again.
|
|
195
|
+
*
|
|
196
|
+
* Deferred a tick: the collision handlers rename a sibling first, and either sibling can be
|
|
197
|
+
* the renamed one depending on where the module was dropped (SD-149916).
|
|
198
|
+
*/
|
|
199
|
+
_scheduleArrivalReset(t) {
|
|
200
|
+
h().isFeatureEnabled("reusableRecommendationStrategy") && setTimeout(() => {
|
|
201
|
+
const e = this._getRecommendationId(t);
|
|
202
|
+
e !== null && e > 0 && !this._resetSourceIds.delete(e) && d().resetArrivedBlock(e);
|
|
203
|
+
}, 0);
|
|
204
|
+
}
|
|
190
205
|
/**
|
|
191
206
|
* Heals a duplicate that slipped past the create-time `_detectDuplicate`
|
|
192
207
|
* scan (or that was persisted by an older template before SD-142352).
|
|
@@ -241,7 +256,7 @@ class j extends E {
|
|
|
241
256
|
/** Assigns a fresh id to a duplicated block and syncs DOM, node config and store. */
|
|
242
257
|
_handleDuplicate(t, e) {
|
|
243
258
|
const i = this._reassignDuplicateId(t, e), n = d();
|
|
244
|
-
n.cloneBlockState(e, i), n.setCurrentBlock(i), this._warnIfMultipleBlocks();
|
|
259
|
+
n.cloneBlockState(e, i), n.setCurrentBlock(i), h().isFeatureEnabled("reusableRecommendationStrategy") && (this._resetSourceIds.add(e), n.resetArrivedBlock(i)), this._warnIfMultipleBlocks();
|
|
245
260
|
}
|
|
246
261
|
/**
|
|
247
262
|
* Core id-reassignment for a duplicated block: rewrites the DOM
|
|
@@ -274,7 +289,7 @@ class j extends E {
|
|
|
274
289
|
if (!("getAttribute" in t))
|
|
275
290
|
return;
|
|
276
291
|
const n = `ins-recommendation-v3-block-${e}`, o = `ins-recommendation-v3-block-${i}`, r = this.api.getDocumentModifier();
|
|
277
|
-
r.modifyHtml(t).removeClass(n).setClass(o), r.apply(new
|
|
292
|
+
r.modifyHtml(t).removeClass(n).setClass(o), r.apply(new p(
|
|
278
293
|
`Reassign recommendation instance class ${n} -> ${o}`
|
|
279
294
|
));
|
|
280
295
|
}
|
|
@@ -289,7 +304,7 @@ class j extends E {
|
|
|
289
304
|
if (!i)
|
|
290
305
|
return;
|
|
291
306
|
const n = this.api.getDocumentModifier();
|
|
292
|
-
n.modifyHtml(i).setAttribute(m, e.toString()), n.apply(new
|
|
307
|
+
n.modifyHtml(i).setAttribute(m, e.toString()), n.apply(new p(`Assign recommendation ID ${e}`));
|
|
293
308
|
}
|
|
294
309
|
/**
|
|
295
310
|
* Stamps the `hide-price` attribute (read by email-service at send time) on
|
|
@@ -297,7 +312,7 @@ class j extends E {
|
|
|
297
312
|
*/
|
|
298
313
|
_stampHidePrice(t, e) {
|
|
299
314
|
const i = this._getBlockElement(t);
|
|
300
|
-
i && this.api.getDocumentModifier().modifyHtml(i).setAttribute(
|
|
315
|
+
i && this.api.getDocumentModifier().modifyHtml(i).setAttribute(B, String(e)).apply(new p("Stamp hide-price"));
|
|
301
316
|
}
|
|
302
317
|
/**
|
|
303
318
|
* Stamps `hide-price` from config only when the block lacks the attribute —
|
|
@@ -305,7 +320,7 @@ class j extends E {
|
|
|
305
320
|
*/
|
|
306
321
|
_healHidePriceAttr(t) {
|
|
307
322
|
const e = this._getBlockElement(t);
|
|
308
|
-
if (!e || !("getAttribute" in e) || e.getAttribute(
|
|
323
|
+
if (!e || !("getAttribute" in e) || e.getAttribute(B) !== null)
|
|
309
324
|
return;
|
|
310
325
|
const { priceHideIfSameAsDiscounted: i } = s.getConfig(t);
|
|
311
326
|
this._stampHidePrice(t, i);
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import { getRecommendationFeedSourceMaps as
|
|
2
|
-
import { useRecommendationApi as
|
|
3
|
-
import { useConfigStore as
|
|
4
|
-
import { defineStore as
|
|
1
|
+
import { getRecommendationFeedSourceMaps as v, strategyEditPath as D, URLS as _, getOperatorOptions as A, PriceAttributes as N } from "../../../../enums/extensions/recommendationBlock.js";
|
|
2
|
+
import { useRecommendationApi as U } from "../../../../services/recommendationApi.js";
|
|
3
|
+
import { useConfigStore as k } from "../../../../stores/config.js";
|
|
4
|
+
import { defineStore as E } from "pinia";
|
|
5
5
|
import "../constants/selectors.js";
|
|
6
|
-
import { DEFAULT_MOBILE_CARDS_IN_ROW as
|
|
7
|
-
import { DEFAULT_NODE_CONFIG as
|
|
8
|
-
import { getDefaultProducts as
|
|
9
|
-
import { generateCompleteFilterQuery as
|
|
6
|
+
import { DEFAULT_MOBILE_CARDS_IN_ROW as L, DEFAULT_CARDS_IN_ROW as B } from "../constants/layout.js";
|
|
7
|
+
import { DEFAULT_NODE_CONFIG as x, EXCLUDED_ALGORITHM_IDS as M } from "../constants/defaultConfig.js";
|
|
8
|
+
import { getDefaultProducts as F } from "../templates/utils.js";
|
|
9
|
+
import { generateCompleteFilterQuery as w } from "../utils/filterUtil.js";
|
|
10
10
|
import { getPartnerRecommendationParams as O } from "../utils/partnerCustomizations.js";
|
|
11
|
-
import { sanitizeProductIds as
|
|
12
|
-
import { isFilterValid as
|
|
11
|
+
import { sanitizeProductIds as z } from "../utils/productIds.js";
|
|
12
|
+
import { isFilterValid as T } from "../validation/filterSchema.js";
|
|
13
13
|
import { getInvalidFields as V, isConfigValid as j } from "../validation/requiredFields.js";
|
|
14
|
-
const f =
|
|
14
|
+
const f = U();
|
|
15
15
|
let S = null, p = null, y = null, I = "", R = null, b = 0;
|
|
16
|
-
const
|
|
16
|
+
const g = /* @__PURE__ */ new Map();
|
|
17
17
|
let l = null;
|
|
18
18
|
function G() {
|
|
19
19
|
return {
|
|
20
|
-
cardsInRow:
|
|
20
|
+
cardsInRow: B,
|
|
21
21
|
currencySettings: {
|
|
22
22
|
name: "USD",
|
|
23
23
|
value: "USD",
|
|
@@ -31,7 +31,7 @@ function G() {
|
|
|
31
31
|
productIds: [],
|
|
32
32
|
id: 1,
|
|
33
33
|
language: "en_US",
|
|
34
|
-
mobileCardsInRow:
|
|
34
|
+
mobileCardsInRow: L,
|
|
35
35
|
mobileLayoutEnabled: !1,
|
|
36
36
|
orientation: "grid",
|
|
37
37
|
recommendedProducts: [],
|
|
@@ -41,7 +41,7 @@ function G() {
|
|
|
41
41
|
// that default is what reached buildCampaignUrl and baked a most-popular feed URL
|
|
42
42
|
// for a block the user never configured (SD-149916). Legacy blocks still get their real
|
|
43
43
|
// algorithm from the node-config sync or the save-time seed.
|
|
44
|
-
strategy:
|
|
44
|
+
strategy: k().isFeatureEnabled("reusableRecommendationStrategy") ? "" : "mostPopular",
|
|
45
45
|
strategyId: "",
|
|
46
46
|
textTrimming: !0,
|
|
47
47
|
unresponsive: !1,
|
|
@@ -51,7 +51,7 @@ function G() {
|
|
|
51
51
|
priceHideIfSameAsDiscounted: !1
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
|
-
function
|
|
54
|
+
function P() {
|
|
55
55
|
return {
|
|
56
56
|
recommendationConfigs: G(),
|
|
57
57
|
recommendationProducts: [],
|
|
@@ -80,7 +80,7 @@ const $ = () => ({
|
|
|
80
80
|
currentRecommendationId: null,
|
|
81
81
|
strategyPanelOpen: !1,
|
|
82
82
|
configVersion: 0
|
|
83
|
-
}),
|
|
83
|
+
}), nt = E("guidoRecommendationExtension", {
|
|
84
84
|
state: () => $(),
|
|
85
85
|
getters: {
|
|
86
86
|
// ====================================================================
|
|
@@ -146,12 +146,12 @@ const $ = () => ({
|
|
|
146
146
|
return [...new Set(t.map((e) => e.filterGroup))].sort((e, r) => e - r);
|
|
147
147
|
},
|
|
148
148
|
getActivePredictiveAlgorithms: (t) => {
|
|
149
|
-
const e =
|
|
150
|
-
return t.activePredictiveAlgorithms.filter((
|
|
151
|
-
r.push(...e.filter((s) => s.id ===
|
|
152
|
-
}), r.map((
|
|
153
|
-
text:
|
|
154
|
-
value:
|
|
149
|
+
const e = v(), r = [];
|
|
150
|
+
return t.activePredictiveAlgorithms.filter((i) => !M.includes(i)).forEach((i) => {
|
|
151
|
+
r.push(...e.filter((s) => s.id === i));
|
|
152
|
+
}), r.map((i) => ({
|
|
153
|
+
text: i.name,
|
|
154
|
+
value: i.key
|
|
155
155
|
}));
|
|
156
156
|
},
|
|
157
157
|
getLanguages: (t) => Object.entries(t.languages).map(([e, r]) => ({
|
|
@@ -165,7 +165,7 @@ const $ = () => ({
|
|
|
165
165
|
getFilterList() {
|
|
166
166
|
return Object.values(this.filterList).filter((t) => t.isFilterable !== 0 && t.isFilterable !== !1).map((t) => {
|
|
167
167
|
let e;
|
|
168
|
-
return t.type === "productAttribute" ? e = `product_attributes.${t.attributeName}` :
|
|
168
|
+
return t.type === "productAttribute" ? e = `product_attributes.${t.attributeName}` : N.includes(t.attributeName) ? e = `${t.attributeName}.${this.recommendationConfigs.currencySettings.value}` : e = t.attributeName, {
|
|
169
169
|
text: t.displayName,
|
|
170
170
|
value: e,
|
|
171
171
|
type: t.attributeType
|
|
@@ -187,7 +187,7 @@ const $ = () => ({
|
|
|
187
187
|
setCurrentBlock(t) {
|
|
188
188
|
this.blockStates[t] || (this.blockStates = {
|
|
189
189
|
...this.blockStates,
|
|
190
|
-
[t]:
|
|
190
|
+
[t]: P()
|
|
191
191
|
}), this.currentRecommendationId = t;
|
|
192
192
|
},
|
|
193
193
|
/**
|
|
@@ -197,32 +197,36 @@ const $ = () => ({
|
|
|
197
197
|
removeBlockState(t) {
|
|
198
198
|
const e = t.toString();
|
|
199
199
|
if (this.recommendationCampaignUrls[e]) {
|
|
200
|
-
const
|
|
201
|
-
delete
|
|
200
|
+
const i = { ...this.recommendationCampaignUrls };
|
|
201
|
+
delete i[e], this.recommendationCampaignUrls = i;
|
|
202
202
|
}
|
|
203
203
|
const r = { ...this.blockStates };
|
|
204
204
|
if (delete r[t], this.blockStates = r, this.currentRecommendationId === t) {
|
|
205
|
-
const
|
|
206
|
-
this.currentRecommendationId =
|
|
205
|
+
const i = Object.keys(this.blockStates).map(Number);
|
|
206
|
+
this.currentRecommendationId = i.length > 0 ? i[0] : null;
|
|
207
207
|
}
|
|
208
208
|
},
|
|
209
209
|
/**
|
|
210
210
|
* Deep-clones a block's state and mirrors its campaign URL under a new id.
|
|
211
211
|
* Invoked from `onCreated` when a duplicate is detected (SD-142352).
|
|
212
|
+
*
|
|
213
|
+
* The clone keeps the source's data but drops its "already fetched / already
|
|
214
|
+
* synced" claims for strategy blocks, so it fetches again like a fresh drop
|
|
215
|
+
* (SD-149916).
|
|
212
216
|
*/
|
|
213
217
|
cloneBlockState(t, e) {
|
|
214
218
|
const r = this.blockStates[t];
|
|
215
219
|
if (r) {
|
|
216
220
|
const o = structuredClone(r);
|
|
217
|
-
o.recommendationConfigs.id = e, this.blockStates = {
|
|
221
|
+
o.recommendationConfigs.id = e, o.recommendationConfigs.strategyId && k().isFeatureEnabled("reusableRecommendationStrategy") && (o.isInitialized = !1, o.syncedConfigFingerprint = null), this.blockStates = {
|
|
218
222
|
...this.blockStates,
|
|
219
223
|
[e]: o
|
|
220
224
|
};
|
|
221
225
|
}
|
|
222
|
-
const
|
|
223
|
-
|
|
226
|
+
const i = t.toString(), s = e.toString(), n = this.recommendationCampaignUrls[i];
|
|
227
|
+
n && (this.recommendationCampaignUrls = {
|
|
224
228
|
...this.recommendationCampaignUrls,
|
|
225
|
-
[s]:
|
|
229
|
+
[s]: n
|
|
226
230
|
});
|
|
227
231
|
},
|
|
228
232
|
/**
|
|
@@ -247,7 +251,7 @@ const $ = () => ({
|
|
|
247
251
|
* `isInitialized`) alone.
|
|
248
252
|
*/
|
|
249
253
|
seedBlockUrlConfig(t, e) {
|
|
250
|
-
const r = (o, a) => o === "." || o === "," || o === " " ? o : a,
|
|
254
|
+
const r = (o, a) => o === "." || o === "," || o === " " ? o : a, i = {
|
|
251
255
|
name: e.currencyCode,
|
|
252
256
|
value: e.currencyCode,
|
|
253
257
|
symbol: e.currencySymbol,
|
|
@@ -255,9 +259,9 @@ const $ = () => ({
|
|
|
255
259
|
decimalCount: String(e.currencyDecimalCount),
|
|
256
260
|
decimalSeparator: r(e.currencyDecimalSeparator, ","),
|
|
257
261
|
thousandSeparator: r(e.currencyThousandSeparator, ".")
|
|
258
|
-
}, s = !this.blockStates[t],
|
|
259
|
-
|
|
260
|
-
...
|
|
262
|
+
}, s = !this.blockStates[t], n = s ? P() : this.blockStates[t];
|
|
263
|
+
n.recommendationConfigs = {
|
|
264
|
+
...n.recommendationConfigs,
|
|
261
265
|
strategy: e.strategy,
|
|
262
266
|
strategyId: e.strategyId,
|
|
263
267
|
language: e.language,
|
|
@@ -265,10 +269,10 @@ const $ = () => ({
|
|
|
265
269
|
productIds: e.productIds,
|
|
266
270
|
filters: e.filters,
|
|
267
271
|
shuffleProducts: e.shuffleProducts,
|
|
268
|
-
currencySettings:
|
|
272
|
+
currencySettings: i
|
|
269
273
|
}, s && (this.blockStates = {
|
|
270
274
|
...this.blockStates,
|
|
271
|
-
[t]:
|
|
275
|
+
[t]: n
|
|
272
276
|
});
|
|
273
277
|
},
|
|
274
278
|
/**
|
|
@@ -287,18 +291,18 @@ const $ = () => ({
|
|
|
287
291
|
...t.currencySettings || {}
|
|
288
292
|
}
|
|
289
293
|
};
|
|
290
|
-
const { triggerRefetch:
|
|
291
|
-
|
|
294
|
+
const { triggerRefetch: i = !0 } = e;
|
|
295
|
+
i && this.configVersion++;
|
|
292
296
|
},
|
|
293
297
|
/**
|
|
294
298
|
* Creates a filter with the first available attribute and operator pre-selected.
|
|
295
299
|
*/
|
|
296
300
|
createDefaultFilter(t, e) {
|
|
297
|
-
const [r] = this.getFilterList, [
|
|
301
|
+
const [r] = this.getFilterList, [i] = A(r == null ? void 0 : r.type);
|
|
298
302
|
return {
|
|
299
303
|
type: "standardFilter",
|
|
300
304
|
attribute: (r == null ? void 0 : r.value) ?? "",
|
|
301
|
-
operator: (
|
|
305
|
+
operator: (i == null ? void 0 : i.value) ?? "",
|
|
302
306
|
innerGroupOperator: "*",
|
|
303
307
|
outerGroupOperator: "*",
|
|
304
308
|
filterNumber: e,
|
|
@@ -379,6 +383,16 @@ const $ = () => ({
|
|
|
379
383
|
R = null;
|
|
380
384
|
}
|
|
381
385
|
},
|
|
386
|
+
/**
|
|
387
|
+
* Clears what a block inherited from the id it arrived holding, so the panel fetches for it.
|
|
388
|
+
* A re-dropped saved module can keep the source's id — and its "already fetched" entry —
|
|
389
|
+
* while the strategy's product count has moved on (SD-149916).
|
|
390
|
+
*/
|
|
391
|
+
resetArrivedBlock(t) {
|
|
392
|
+
const e = this.blockStates[t];
|
|
393
|
+
e != null && e.recommendationConfigs.strategyId && (e.isInitialized = !1, e.syncedConfigFingerprint = null, this.invalidateStrategies(), this.fetchStrategies().catch(() => {
|
|
394
|
+
}));
|
|
395
|
+
},
|
|
382
396
|
invalidateStrategies() {
|
|
383
397
|
this.strategiesFetched = !1, this.strategiesSettled = !1, b += 1;
|
|
384
398
|
},
|
|
@@ -393,22 +407,23 @@ const $ = () => ({
|
|
|
393
407
|
* leave that one missing from the list. It disarms on the first return AFTER that tab is
|
|
394
408
|
* closed instead, so an ordinary alt-tab later in the session costs nothing. Armed only
|
|
395
409
|
* once the user actually opens a strategy page, so anyone who never does pays nothing.
|
|
410
|
+
* @returns whether a tab actually opened, so callers can skip work that assumes one did
|
|
396
411
|
*/
|
|
397
412
|
_armStrategyPageReturn(t) {
|
|
398
413
|
const e = window.open(t, "_blank");
|
|
399
414
|
if (!e)
|
|
400
|
-
return;
|
|
415
|
+
return !1;
|
|
401
416
|
e.opener = null, l == null || l();
|
|
402
417
|
let r = !1;
|
|
403
|
-
const
|
|
418
|
+
const i = () => {
|
|
404
419
|
document.hidden || r || (e != null && e.closed && (l == null || l()), r = !0, this.invalidateStrategies(), this.fetchStrategies().then(() => this._refreshAssignedStrategyProducts()).catch(() => {
|
|
405
420
|
}).finally(() => {
|
|
406
421
|
r = !1;
|
|
407
422
|
}));
|
|
408
423
|
};
|
|
409
|
-
document.addEventListener("visibilitychange",
|
|
410
|
-
document.removeEventListener("visibilitychange",
|
|
411
|
-
};
|
|
424
|
+
return document.addEventListener("visibilitychange", i), l = () => {
|
|
425
|
+
document.removeEventListener("visibilitychange", i), l = null;
|
|
426
|
+
}, !0;
|
|
412
427
|
},
|
|
413
428
|
/**
|
|
414
429
|
* Reloads the products of the block the user is on, so an edit made in the strategy tab
|
|
@@ -431,24 +446,24 @@ const $ = () => ({
|
|
|
431
446
|
* new strategy is offered; the user picks it themselves.
|
|
432
447
|
*/
|
|
433
448
|
openStrategyCreation() {
|
|
434
|
-
this._armStrategyPageReturn(_.RECOMMENDATION_STRATEGY_CREATE_PATH);
|
|
449
|
+
return this._armStrategyPageReturn(_.RECOMMENDATION_STRATEGY_CREATE_PATH);
|
|
435
450
|
},
|
|
436
451
|
/**
|
|
437
452
|
* Opens the strategy's edit page. Every return refreshes the list so the block reflects the
|
|
438
453
|
* edited configuration.
|
|
439
454
|
*/
|
|
440
455
|
openStrategyEdit(t) {
|
|
441
|
-
this._armStrategyPageReturn(D(t));
|
|
456
|
+
return this._armStrategyPageReturn(D(t));
|
|
442
457
|
},
|
|
443
458
|
async resolveStrategyUrlTemplate(t, e) {
|
|
444
|
-
const r = typeof t.updated_at == "string" ? t.updated_at : "",
|
|
459
|
+
const r = typeof t.updated_at == "string" ? t.updated_at : "", i = r ? `${t.strategy_id}:${r}:${e}` : "", s = i ? this.strategyUrlTemplates[i] : void 0;
|
|
445
460
|
if (s)
|
|
446
461
|
return s;
|
|
447
|
-
const { full_path:
|
|
448
|
-
return
|
|
462
|
+
const { full_path: n = "" } = await f.generateStrategyEndpoint(t, e) ?? {};
|
|
463
|
+
return i && n && (this.strategyUrlTemplates = {
|
|
449
464
|
...this.strategyUrlTemplates,
|
|
450
|
-
[
|
|
451
|
-
}),
|
|
465
|
+
[i]: n
|
|
466
|
+
}), n;
|
|
452
467
|
},
|
|
453
468
|
assignStrategy(t) {
|
|
454
469
|
this.patchCurrentBlockConfig({
|
|
@@ -460,7 +475,7 @@ const $ = () => ({
|
|
|
460
475
|
this.patchCurrentBlockConfig({
|
|
461
476
|
strategyId: "",
|
|
462
477
|
strategy: "",
|
|
463
|
-
size:
|
|
478
|
+
size: x.size
|
|
464
479
|
});
|
|
465
480
|
},
|
|
466
481
|
// ====================================================================
|
|
@@ -479,8 +494,8 @@ const $ = () => ({
|
|
|
479
494
|
currencies: r
|
|
480
495
|
} = await f.fetchRecommendationCreateData();
|
|
481
496
|
if (this.activePredictiveAlgorithms = t, this.languages = e, this.currentRecommendationId !== null && this.blockStates[this.currentRecommendationId]) {
|
|
482
|
-
const
|
|
483
|
-
|
|
497
|
+
const i = this.blockStates[this.currentRecommendationId];
|
|
498
|
+
i.filterStatus = !!i.recommendationConfigs.filters.length;
|
|
484
499
|
}
|
|
485
500
|
this.currencyList = r;
|
|
486
501
|
})();
|
|
@@ -519,41 +534,41 @@ const $ = () => ({
|
|
|
519
534
|
deleteFilterGroup(t) {
|
|
520
535
|
if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
|
|
521
536
|
return;
|
|
522
|
-
const e = this.blockStates[this.currentRecommendationId], r = e.recommendationConfigs.filters.filter((
|
|
523
|
-
e.recommendationConfigs.filters = r.map((
|
|
524
|
-
...
|
|
525
|
-
filterGroup: s.get(
|
|
537
|
+
const e = this.blockStates[this.currentRecommendationId], r = e.recommendationConfigs.filters.filter((n) => n.filterGroup !== t), i = [...new Set(r.map((n) => n.filterGroup))].sort((n, o) => n - o), s = new Map(i.map((n, o) => [n, o + 1]));
|
|
538
|
+
e.recommendationConfigs.filters = r.map((n) => ({
|
|
539
|
+
...n,
|
|
540
|
+
filterGroup: s.get(n.filterGroup) ?? n.filterGroup
|
|
526
541
|
}));
|
|
527
542
|
},
|
|
528
543
|
updateFilter(t) {
|
|
529
544
|
if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
|
|
530
545
|
return;
|
|
531
|
-
const e = this.blockStates[this.currentRecommendationId], r = e.recommendationConfigs.filters.findIndex((
|
|
546
|
+
const e = this.blockStates[this.currentRecommendationId], r = e.recommendationConfigs.filters.findIndex((i) => i.filterNumber === t.filterNumber && i.filterGroup === t.filterGroup);
|
|
532
547
|
if (r !== -1) {
|
|
533
|
-
const
|
|
534
|
-
|
|
548
|
+
const i = [...e.recommendationConfigs.filters];
|
|
549
|
+
i[r] = {
|
|
535
550
|
...t,
|
|
536
|
-
isValid:
|
|
537
|
-
}, e.recommendationConfigs.filters =
|
|
551
|
+
isValid: T(t)
|
|
552
|
+
}, e.recommendationConfigs.filters = i;
|
|
538
553
|
}
|
|
539
554
|
},
|
|
540
555
|
deleteFilter(t) {
|
|
541
556
|
if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
|
|
542
557
|
return;
|
|
543
|
-
const e = this.blockStates[this.currentRecommendationId], r = [...e.recommendationConfigs.filters].findIndex((
|
|
558
|
+
const e = this.blockStates[this.currentRecommendationId], r = [...e.recommendationConfigs.filters].findIndex((i) => i.filterNumber === t.filterNumber && i.filterGroup === t.filterGroup);
|
|
544
559
|
if (r !== -1) {
|
|
545
|
-
let
|
|
546
|
-
if (
|
|
547
|
-
let
|
|
548
|
-
|
|
560
|
+
let i = [...e.recommendationConfigs.filters];
|
|
561
|
+
if (i.splice(r, 1), i.some((n) => n.filterGroup === t.filterGroup)) {
|
|
562
|
+
let n = 1;
|
|
563
|
+
i = i.map((o) => o.filterGroup === t.filterGroup ? { ...o, filterNumber: n++ } : o);
|
|
549
564
|
} else {
|
|
550
|
-
const
|
|
551
|
-
|
|
565
|
+
const n = [...new Set(i.map((a) => a.filterGroup))].sort((a, u) => a - u), o = new Map(n.map((a, u) => [a, u + 1]));
|
|
566
|
+
i = i.map((a) => ({
|
|
552
567
|
...a,
|
|
553
568
|
filterGroup: o.get(a.filterGroup) ?? a.filterGroup
|
|
554
569
|
}));
|
|
555
570
|
}
|
|
556
|
-
e.recommendationConfigs.filters =
|
|
571
|
+
e.recommendationConfigs.filters = i;
|
|
557
572
|
}
|
|
558
573
|
},
|
|
559
574
|
addFilter(t) {
|
|
@@ -561,8 +576,8 @@ const $ = () => ({
|
|
|
561
576
|
return;
|
|
562
577
|
const e = this.blockStates[this.currentRecommendationId], r = [...e.recommendationConfigs.filters], s = r.filter(
|
|
563
578
|
(o) => o.filterGroup === t.filterGroup
|
|
564
|
-
).length + 1,
|
|
565
|
-
|
|
579
|
+
).length + 1, n = r.findLastIndex((o) => o.filterGroup === t.filterGroup);
|
|
580
|
+
n !== -1 ? r.splice(n + 1, 0, {
|
|
566
581
|
...t,
|
|
567
582
|
filterNumber: s
|
|
568
583
|
}) : r.push({
|
|
@@ -571,7 +586,7 @@ const $ = () => ({
|
|
|
571
586
|
}), e.recommendationConfigs.filters = r;
|
|
572
587
|
},
|
|
573
588
|
generateFilterQuery() {
|
|
574
|
-
return
|
|
589
|
+
return w(this.recommendationConfigs.filters);
|
|
575
590
|
},
|
|
576
591
|
/**
|
|
577
592
|
* Validation-only check invoked at save-CTA time. Defined as an action
|
|
@@ -611,30 +626,30 @@ const $ = () => ({
|
|
|
611
626
|
}
|
|
612
627
|
},
|
|
613
628
|
async _doFetchProducts() {
|
|
614
|
-
var
|
|
615
|
-
const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e,
|
|
616
|
-
if (r.strategyId &&
|
|
629
|
+
var h;
|
|
630
|
+
const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, i = k();
|
|
631
|
+
if (r.strategyId && i.isFeatureEnabled("reusableRecommendationStrategy")) {
|
|
617
632
|
await this._doFetchStrategyProducts(t);
|
|
618
633
|
return;
|
|
619
634
|
}
|
|
620
|
-
const s = (
|
|
621
|
-
|
|
622
|
-
const
|
|
635
|
+
const s = (g.get(t) ?? 0) + 1;
|
|
636
|
+
g.set(t, s);
|
|
637
|
+
const n = parseInt(r.size) || 6;
|
|
623
638
|
if (!r.strategy) {
|
|
624
|
-
this._setBlockProducts(t, [],
|
|
639
|
+
this._setBlockProducts(t, [], n);
|
|
625
640
|
return;
|
|
626
641
|
}
|
|
627
|
-
const o = r.filters.filter((d) => d.isValid), a =
|
|
642
|
+
const o = r.filters.filter((d) => d.isValid), a = w(o), u = ((h = v().find((d) => d.key === r.strategy)) == null ? void 0 : h.path) || "", c = {
|
|
628
643
|
locale: r.language,
|
|
629
644
|
currency: r.currencySettings.value,
|
|
630
|
-
partnerName:
|
|
645
|
+
partnerName: i.partnerName,
|
|
631
646
|
size: r.size,
|
|
632
647
|
details: !0,
|
|
633
|
-
campaignId:
|
|
648
|
+
campaignId: i.variationId
|
|
634
649
|
};
|
|
635
|
-
r.strategy === "manualMerchandising" ? c.productId =
|
|
650
|
+
r.strategy === "manualMerchandising" ? c.productId = z(r.productIds) : r.strategy === "similarViewed" && (c.productId = "{itemId}"), r.strategy === "userBased" && (c.userId = "{user_id}"), a && (c.filter = a), r.shuffleProducts && (c.shuffle = !0), Object.assign(
|
|
636
651
|
c,
|
|
637
|
-
O(
|
|
652
|
+
O(i.partnerName, r.strategy)
|
|
638
653
|
);
|
|
639
654
|
let m;
|
|
640
655
|
try {
|
|
@@ -642,39 +657,39 @@ const $ = () => ({
|
|
|
642
657
|
} catch {
|
|
643
658
|
m = [];
|
|
644
659
|
}
|
|
645
|
-
|
|
660
|
+
g.get(t) === s && this._setBlockProducts(t, m, n);
|
|
646
661
|
},
|
|
647
662
|
async _doFetchStrategyProducts(t) {
|
|
648
|
-
const e = (
|
|
649
|
-
|
|
663
|
+
const e = (g.get(t) ?? 0) + 1;
|
|
664
|
+
g.set(t, e);
|
|
650
665
|
const { recommendationConfigs: r } = this.blockStates[t];
|
|
651
|
-
let
|
|
666
|
+
let i = [], s = parseInt(r.size) || 6;
|
|
652
667
|
try {
|
|
653
668
|
await this.fetchStrategies();
|
|
654
|
-
const
|
|
669
|
+
const n = this.strategies.find(
|
|
655
670
|
(o) => String(o.strategy_id) === r.strategyId
|
|
656
671
|
);
|
|
657
|
-
if (
|
|
658
|
-
s = parseInt(String(
|
|
659
|
-
const o = r.currencySettings.value, u = (await this.resolveStrategyUrlTemplate(
|
|
660
|
-
d && (
|
|
672
|
+
if (n) {
|
|
673
|
+
s = parseInt(String(n.size ?? "")) || s;
|
|
674
|
+
const o = r.currencySettings.value, u = (await this.resolveStrategyUrlTemplate(n, o)).replaceAll("{locale}", r.language).replaceAll("{currency}", o), c = u.indexOf("?"), m = c === -1 ? u : u.slice(0, c), h = (c === -1 ? "" : u.slice(c + 1)).split("&").filter((C) => C && !C.startsWith("user_id=")), d = h.length ? `${m}?${h.join("&")}` : m;
|
|
675
|
+
d && (i = await f.fetchRecommendationProductsByUrl(d));
|
|
661
676
|
}
|
|
662
677
|
} catch {
|
|
663
|
-
|
|
678
|
+
i = [];
|
|
664
679
|
}
|
|
665
|
-
|
|
680
|
+
g.get(t) === e && this._setBlockProducts(t, i, s);
|
|
666
681
|
},
|
|
667
682
|
_setBlockProducts(t, e, r) {
|
|
668
683
|
if (!this.blockStates[t])
|
|
669
684
|
return;
|
|
670
|
-
const
|
|
685
|
+
const i = e.length > 0 ? e : F(r);
|
|
671
686
|
this.blockStates[t].recommendationProducts = [
|
|
672
|
-
...
|
|
673
|
-
...
|
|
687
|
+
...i.slice(0, r),
|
|
688
|
+
...F(Math.max(0, r - i.length))
|
|
674
689
|
];
|
|
675
690
|
}
|
|
676
691
|
}
|
|
677
692
|
});
|
|
678
693
|
export {
|
|
679
|
-
|
|
694
|
+
nt as useRecommendationExtensionStore
|
|
680
695
|
};
|
package/dist/guido.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
@charset "UTF-8";.gap-16[data-v-5553d071],.gap-16[data-v-0e1b0c54]{gap:16px}[data-v-73199fa4] .in-button-v2__wrapper{line-height:0}[data-v-22226124] .in-segments-wrapper__button_selected,[data-v-22226124] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb;color:#0010ac;border-color:#0010ac}[data-v-2cb418af] .in-progress-wrapper__progress p span:last-child{display:none!important}[data-v-2cb418af] .in-progress-description-status{display:none!important}.view-options-wrapper[data-v-87033101]{position:relative;display:inline-block}.new-tag[data-v-87033101]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-87033101] .guido__view-option-selection-desktop svg,[data-v-87033101] .guido__view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-87033101] .in-segments-wrapper__button_selected,[data-v-87033101] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-87033101] .in-tooltip-wrapper-v2__icon{cursor:pointer}.editor-toolbar[data-v-173c3a40]{gap:4px}.version-history-item[data-v-ee4b9c3f]{flex-basis:200px}.version-history[data-v-fad98586]{gap:8px}.version-history__toolbar[data-v-fad98586]{gap:4px}.view-options-wrapper[data-v-6ebabfe4]{position:relative;display:inline-block}.new-tag[data-v-6ebabfe4]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-6ebabfe4] .guido__verion-history-view-option-selection-desktop svg,[data-v-6ebabfe4] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-6ebabfe4] .in-segments-wrapper__button_selected,[data-v-6ebabfe4] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-6ebabfe4] .in-tooltip-wrapper-v2__icon{cursor:pointer}.auto-save-toggle[data-v-2c964af4]{position:relative}.auto-save-toggle__info-box[data-v-2c964af4]{position:absolute;top:100%;left:0;z-index:10;width:280px}.editor-actions[data-v-1ca6baf0]{gap:4px}.header-wrapper[data-v-d11dd577]{min-width:1000px}.guido-loading__wrapper[data-v-07c4b2d8]{height:100%;top:75px!important;bottom:0!important}.guido-editor__wrapper[data-v-cc5ee925]{--ribbon-offset: 0px;position:relative;width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__container[data-v-cc5ee925]{width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__no-header[data-v-cc5ee925]{height:calc(100vh - 75px - var(--ribbon-offset))}[data-v-293f1c47] .in-breadcrumb-wrapper__links{cursor:pointer}.templates-wrapper[data-v-91a26acd]{gap:16px;grid-template-columns:repeat(3,1fr)}.templates-wrapper .template-wrapper[data-v-91a26acd]{cursor:pointer}.templates-wrapper .template-wrapper .template-container[data-v-91a26acd]{height:274px;padding:2px;transition:none}.templates-wrapper .template-wrapper .template-container.selected[data-v-91a26acd]{padding:1px}.templates-wrapper .template-wrapper .template-container .thumbnail[data-v-91a26acd]{object-fit:cover;transform:scale(1)}[data-v-b9a93c6e] .guido__verion-history-view-option-selection-desktop svg,[data-v-b9a93c6e] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-b9a93c6e] .in-segments-wrapper__button_selected,[data-v-b9a93c6e] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}.error-list[data-v-c3fd5d4b]{gap:16px}.desktop-browser-header[data-v-d86c5af5]{height:79px;min-height:79px}.desktop-browser-header__left[data-v-d86c5af5]{-webkit-user-drag:none;height:79px;width:378px}.desktop-browser-header__center[data-v-d86c5af5]{height:79px;background-repeat:repeat-x;background-size:auto 100%;background-position:left top}.desktop-browser-header__right[data-v-d86c5af5]{-webkit-user-drag:none;height:79px;width:112px}.desktop-preview[data-v-cf946232]{min-width:602px;height:70vh;min-height:583px;border-radius:10px}.desktop-preview iframe[data-v-cf946232]{min-height:504px}.iframe-wrapper[data-v-f255b2bb]{width:258px}.iframe-scaled[data-v-f255b2bb]{width:320px;height:124.0310077519%;transform:scale(.80625);transform-origin:top left}.cropped-text[data-v-eb3d05d7]{width:220px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mobile-preview-wrapper__phone[data-v-3f472f96]{width:282px}.mobile-preview-wrapper__phone img[data-v-3f472f96]{object-fit:cover;border-radius:44px}.mobile-preview-wrapper__content[data-v-3f472f96]{width:258px;height:450px;left:12px}[data-v-6bcaca8a] .vueperslides__parallax-wrapper{padding-bottom:110px!important}[data-v-f16f20f8] .vueperslides__bullets{pointer-events:none!important}[data-v-f16f20f8] .vueperslides__parallax-wrapper{padding-bottom:110px!important}[data-v-bb3cca55] .vueperslides__bullets{pointer-events:none!important}[data-v-bb3cca55] .vueperslides__parallax-wrapper{height:110px!important;padding-bottom:110px!important}[data-v-ec2027ff] .vueperslides__bullets,[data-v-b09e80c4] .vueperslides__bullets{pointer-events:none!important}[data-v-b09e80c4] .vueperslides__parallax-wrapper{height:110px!important;padding-bottom:110px!important}[data-v-9bdef600] .vueperslides__parallax-wrapper{padding-bottom:110px!important}.assign-strategy-drawer-content .assign-strategy-select[data-v-
|
|
1
|
+
@charset "UTF-8";.gap-16[data-v-5553d071],.gap-16[data-v-0e1b0c54]{gap:16px}[data-v-73199fa4] .in-button-v2__wrapper{line-height:0}[data-v-22226124] .in-segments-wrapper__button_selected,[data-v-22226124] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb;color:#0010ac;border-color:#0010ac}[data-v-2cb418af] .in-progress-wrapper__progress p span:last-child{display:none!important}[data-v-2cb418af] .in-progress-description-status{display:none!important}.view-options-wrapper[data-v-87033101]{position:relative;display:inline-block}.new-tag[data-v-87033101]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-87033101] .guido__view-option-selection-desktop svg,[data-v-87033101] .guido__view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-87033101] .in-segments-wrapper__button_selected,[data-v-87033101] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-87033101] .in-tooltip-wrapper-v2__icon{cursor:pointer}.editor-toolbar[data-v-173c3a40]{gap:4px}.version-history-item[data-v-ee4b9c3f]{flex-basis:200px}.version-history[data-v-fad98586]{gap:8px}.version-history__toolbar[data-v-fad98586]{gap:4px}.view-options-wrapper[data-v-6ebabfe4]{position:relative;display:inline-block}.new-tag[data-v-6ebabfe4]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-6ebabfe4] .guido__verion-history-view-option-selection-desktop svg,[data-v-6ebabfe4] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-6ebabfe4] .in-segments-wrapper__button_selected,[data-v-6ebabfe4] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-6ebabfe4] .in-tooltip-wrapper-v2__icon{cursor:pointer}.auto-save-toggle[data-v-2c964af4]{position:relative}.auto-save-toggle__info-box[data-v-2c964af4]{position:absolute;top:100%;left:0;z-index:10;width:280px}.editor-actions[data-v-1ca6baf0]{gap:4px}.header-wrapper[data-v-d11dd577]{min-width:1000px}.guido-loading__wrapper[data-v-07c4b2d8]{height:100%;top:75px!important;bottom:0!important}.guido-editor__wrapper[data-v-cc5ee925]{--ribbon-offset: 0px;position:relative;width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__container[data-v-cc5ee925]{width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__no-header[data-v-cc5ee925]{height:calc(100vh - 75px - var(--ribbon-offset))}[data-v-293f1c47] .in-breadcrumb-wrapper__links{cursor:pointer}.templates-wrapper[data-v-91a26acd]{gap:16px;grid-template-columns:repeat(3,1fr)}.templates-wrapper .template-wrapper[data-v-91a26acd]{cursor:pointer}.templates-wrapper .template-wrapper .template-container[data-v-91a26acd]{height:274px;padding:2px;transition:none}.templates-wrapper .template-wrapper .template-container.selected[data-v-91a26acd]{padding:1px}.templates-wrapper .template-wrapper .template-container .thumbnail[data-v-91a26acd]{object-fit:cover;transform:scale(1)}[data-v-b9a93c6e] .guido__verion-history-view-option-selection-desktop svg,[data-v-b9a93c6e] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-b9a93c6e] .in-segments-wrapper__button_selected,[data-v-b9a93c6e] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}.error-list[data-v-c3fd5d4b]{gap:16px}.desktop-browser-header[data-v-d86c5af5]{height:79px;min-height:79px}.desktop-browser-header__left[data-v-d86c5af5]{-webkit-user-drag:none;height:79px;width:378px}.desktop-browser-header__center[data-v-d86c5af5]{height:79px;background-repeat:repeat-x;background-size:auto 100%;background-position:left top}.desktop-browser-header__right[data-v-d86c5af5]{-webkit-user-drag:none;height:79px;width:112px}.desktop-preview[data-v-cf946232]{min-width:602px;height:70vh;min-height:583px;border-radius:10px}.desktop-preview iframe[data-v-cf946232]{min-height:504px}.iframe-wrapper[data-v-f255b2bb]{width:258px}.iframe-scaled[data-v-f255b2bb]{width:320px;height:124.0310077519%;transform:scale(.80625);transform-origin:top left}.cropped-text[data-v-eb3d05d7]{width:220px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mobile-preview-wrapper__phone[data-v-3f472f96]{width:282px}.mobile-preview-wrapper__phone img[data-v-3f472f96]{object-fit:cover;border-radius:44px}.mobile-preview-wrapper__content[data-v-3f472f96]{width:258px;height:450px;left:12px}[data-v-6bcaca8a] .vueperslides__parallax-wrapper{padding-bottom:110px!important}[data-v-f16f20f8] .vueperslides__bullets{pointer-events:none!important}[data-v-f16f20f8] .vueperslides__parallax-wrapper{padding-bottom:110px!important}[data-v-bb3cca55] .vueperslides__bullets{pointer-events:none!important}[data-v-bb3cca55] .vueperslides__parallax-wrapper{height:110px!important;padding-bottom:110px!important}[data-v-ec2027ff] .vueperslides__bullets,[data-v-b09e80c4] .vueperslides__bullets{pointer-events:none!important}[data-v-b09e80c4] .vueperslides__parallax-wrapper{height:110px!important;padding-bottom:110px!important}[data-v-9bdef600] .vueperslides__parallax-wrapper{padding-bottom:110px!important}.assign-strategy-drawer-content .assign-strategy-select[data-v-184392c2]{width:100%;max-width:none}.assign-strategy-drawer-content .assign-strategy-select[data-v-184392c2] .in-skeleton{width:100%!important}.assign-strategy-drawer-content .assign-strategy-select[data-v-184392c2] .in-dropdown-box__container{width:413px}.assign-strategy-drawer .spaced-dot-sep{background-image:linear-gradient(90deg,#91949f 20%,#fff0 0);background-position:center bottom;background-repeat:repeat-x;background-size:5px 1px}.assign-strategy-drawer .spaced-dot-sep--top{background-position:center top}.assign-strategy-drawer .spaced-dot-sep--fc-n:first-child{background:none}
|
|
@@ -15,6 +15,8 @@ export declare class RecommendationBlock extends Block {
|
|
|
15
15
|
* This avoids generating a new (different) ID in onCreated().
|
|
16
16
|
*/
|
|
17
17
|
private _pendingBlockId;
|
|
18
|
+
/** Ids already reset under their new name, so the deferred pass skips their stale snapshot. */
|
|
19
|
+
private _resetSourceIds;
|
|
18
20
|
constructor();
|
|
19
21
|
getId(): string;
|
|
20
22
|
getIcon(): string;
|
|
@@ -73,6 +75,14 @@ export declare class RecommendationBlock extends Block {
|
|
|
73
75
|
* in the document and finding the maximum existing ID + 1.
|
|
74
76
|
*/
|
|
75
77
|
private _generateNextId;
|
|
78
|
+
/**
|
|
79
|
+
* Drops the "already fetched" claims of a block that arrived holding a baked id
|
|
80
|
+
* (saved module, paste, duplicate), so the settings panel reads its strategy again.
|
|
81
|
+
*
|
|
82
|
+
* Deferred a tick: the collision handlers rename a sibling first, and either sibling can be
|
|
83
|
+
* the renamed one depending on where the module was dropped (SD-149916).
|
|
84
|
+
*/
|
|
85
|
+
private _scheduleArrivalReset;
|
|
76
86
|
/**
|
|
77
87
|
* Heals a duplicate that slipped past the create-time `_detectDuplicate`
|
|
78
88
|
* scan (or that was persisted by an older template before SD-142352).
|
|
@@ -426,6 +426,10 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
|
|
|
426
426
|
/**
|
|
427
427
|
* Deep-clones a block's state and mirrors its campaign URL under a new id.
|
|
428
428
|
* Invoked from `onCreated` when a duplicate is detected (SD-142352).
|
|
429
|
+
*
|
|
430
|
+
* The clone keeps the source's data but drops its "already fetched / already
|
|
431
|
+
* synced" claims for strategy blocks, so it fetches again like a fresh drop
|
|
432
|
+
* (SD-149916).
|
|
429
433
|
*/
|
|
430
434
|
cloneBlockState(sourceId: number, newId: number): void;
|
|
431
435
|
/**
|
|
@@ -481,6 +485,12 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
|
|
|
481
485
|
openRemoveStrategyModal(): void;
|
|
482
486
|
closeRemoveStrategyModal(): void;
|
|
483
487
|
fetchStrategies(): Promise<void>;
|
|
488
|
+
/**
|
|
489
|
+
* Clears what a block inherited from the id it arrived holding, so the panel fetches for it.
|
|
490
|
+
* A re-dropped saved module can keep the source's id — and its "already fetched" entry —
|
|
491
|
+
* while the strategy's product count has moved on (SD-149916).
|
|
492
|
+
*/
|
|
493
|
+
resetArrivedBlock(id: number): void;
|
|
484
494
|
invalidateStrategies(): void;
|
|
485
495
|
/**
|
|
486
496
|
* Opens a Smart Recommender strategy page in a new tab and refreshes the list every time
|
|
@@ -493,8 +503,9 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
|
|
|
493
503
|
* leave that one missing from the list. It disarms on the first return AFTER that tab is
|
|
494
504
|
* closed instead, so an ordinary alt-tab later in the session costs nothing. Armed only
|
|
495
505
|
* once the user actually opens a strategy page, so anyone who never does pays nothing.
|
|
506
|
+
* @returns whether a tab actually opened, so callers can skip work that assumes one did
|
|
496
507
|
*/
|
|
497
|
-
_armStrategyPageReturn(url: string):
|
|
508
|
+
_armStrategyPageReturn(url: string): boolean;
|
|
498
509
|
/**
|
|
499
510
|
* Reloads the products of the block the user is on, so an edit made in the strategy tab
|
|
500
511
|
* lands on the canvas instead of waiting for the assign drawer to be reopened.
|
|
@@ -509,12 +520,12 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
|
|
|
509
520
|
* Opens Smart Recommender's strategy creation page. Every return refreshes the list so the
|
|
510
521
|
* new strategy is offered; the user picks it themselves.
|
|
511
522
|
*/
|
|
512
|
-
openStrategyCreation():
|
|
523
|
+
openStrategyCreation(): boolean;
|
|
513
524
|
/**
|
|
514
525
|
* Opens the strategy's edit page. Every return refreshes the list so the block reflects the
|
|
515
526
|
* edited configuration.
|
|
516
527
|
*/
|
|
517
|
-
openStrategyEdit(strategyId: string | number):
|
|
528
|
+
openStrategyEdit(strategyId: string | number): boolean;
|
|
518
529
|
resolveStrategyUrlTemplate(strategy: RrsStrategy, currency: string): Promise<string>;
|
|
519
530
|
assignStrategy(strategy: RrsStrategy): void;
|
|
520
531
|
removeStrategy(): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@useinsider/guido",
|
|
3
|
-
"version": "3.18.2-beta.
|
|
3
|
+
"version": "3.18.2-beta.dfce34a",
|
|
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",
|