@useinsider/guido 3.6.0-beta.590990f → 3.6.0-beta.59a5e5f
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/useRecommendation.js +34 -33
- package/dist/composables/useSave.js +16 -17
- package/dist/composables/useStripoEventHandler.js +20 -15
- package/dist/enums/toaster.js +1 -1
- package/dist/extensions/Blocks/Recommendation/block.js +35 -16
- package/dist/extensions/Blocks/Recommendation/store/recommendation.js +13 -9
- package/dist/extensions/Blocks/Recommendation/useRecommendationBlockWarning.js +16 -0
- package/dist/extensions/Blocks/Recommendation/utils/partnerCustomizations.js +21 -0
- package/dist/extensions/Blocks/Recommendation/utils/recommendationBlockCount.js +9 -0
- package/dist/src/enums/toaster.d.ts +2 -1
- package/dist/src/extensions/Blocks/Recommendation/block.d.ts +13 -0
- package/dist/src/extensions/Blocks/Recommendation/useRecommendationBlockWarning.d.ts +11 -0
- package/dist/src/extensions/Blocks/Recommendation/utils/partnerCustomizations.d.ts +7 -0
- package/dist/src/extensions/Blocks/Recommendation/utils/recommendationBlockCount.d.ts +28 -0
- package/dist/src/extensions/Blocks/Recommendation/utils/recommendationBlockCount.test.d.ts +1 -0
- package/package.json +1 -1
- package/dist/composables/validators/useUnsubscribeBlockValidator.js +0 -24
- package/dist/src/composables/validators/useUnsubscribeBlockValidator.d.ts +0 -3
- /package/dist/src/{composables/validators/useUnsubscribeBlockValidator.test.d.ts → extensions/Blocks/Recommendation/block.test.d.ts} +0 -0
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
import { getRecommendationFeedSourceMaps as I, URLS as
|
|
2
|
-
import { MinDeviceViewport as
|
|
3
|
-
import { useRecommendationExtensionStore as
|
|
1
|
+
import { getRecommendationFeedSourceMaps as I, URLS as R } from "../enums/extensions/recommendationBlock.js";
|
|
2
|
+
import { MinDeviceViewport as C, DefaultPadding as b } from "../enums/recommendation.js";
|
|
3
|
+
import { useRecommendationExtensionStore as l } from "../extensions/Blocks/Recommendation/store/recommendation.js";
|
|
4
4
|
import { generateCompleteFilterQuery as h } from "../extensions/Blocks/Recommendation/utils/filterUtil.js";
|
|
5
|
+
import { getPartnerRecommendationParams as y } from "../extensions/Blocks/Recommendation/utils/partnerCustomizations.js";
|
|
5
6
|
import { useConfigStore as x } from "../stores/config.js";
|
|
6
|
-
const
|
|
7
|
+
const k = () => ({
|
|
7
8
|
calculateCardWidth: ({
|
|
8
|
-
mobileLeftPadding:
|
|
9
|
+
mobileLeftPadding: a,
|
|
9
10
|
mobileRightPadding: s,
|
|
10
|
-
cardsInRow:
|
|
11
|
-
unresponsive:
|
|
11
|
+
cardsInRow: c,
|
|
12
|
+
unresponsive: o
|
|
12
13
|
}) => {
|
|
13
|
-
const r =
|
|
14
|
-
return (
|
|
14
|
+
const r = o ? c : 1, e = a + s + (r - 1) * b;
|
|
15
|
+
return (C - e) / r;
|
|
15
16
|
},
|
|
16
|
-
getRecommendationCampaignData: (
|
|
17
|
-
const s =
|
|
18
|
-
if (!
|
|
17
|
+
getRecommendationCampaignData: (a) => {
|
|
18
|
+
const s = l(), c = Number(a), o = s.blockStates[c];
|
|
19
|
+
if (!o)
|
|
19
20
|
return {
|
|
20
21
|
textTrimming: !1,
|
|
21
22
|
orientation: "vertical",
|
|
@@ -28,7 +29,7 @@ const w = () => ({
|
|
|
28
29
|
discountBeforeTextValue: "",
|
|
29
30
|
discountAfterTextValue: ""
|
|
30
31
|
};
|
|
31
|
-
const { recommendationConfigs: r } =
|
|
32
|
+
const { recommendationConfigs: r } = o, e = r.orientation === "grid" ? "vertical" : "horizontal";
|
|
32
33
|
return {
|
|
33
34
|
textTrimming: r.textTrimming,
|
|
34
35
|
orientation: e,
|
|
@@ -42,35 +43,35 @@ const w = () => ({
|
|
|
42
43
|
discountAfterTextValue: ""
|
|
43
44
|
};
|
|
44
45
|
},
|
|
45
|
-
buildCampaignUrl: (
|
|
46
|
-
var
|
|
47
|
-
const
|
|
46
|
+
buildCampaignUrl: (a, s) => {
|
|
47
|
+
var m;
|
|
48
|
+
const c = l(), o = x(), r = Number(a);
|
|
48
49
|
let e;
|
|
49
50
|
if (s)
|
|
50
51
|
e = s;
|
|
51
52
|
else {
|
|
52
|
-
const
|
|
53
|
-
if (!
|
|
53
|
+
const i = c.blockStates[r];
|
|
54
|
+
if (!i)
|
|
54
55
|
return "";
|
|
55
|
-
const { recommendationConfigs:
|
|
56
|
+
const { recommendationConfigs: n } = i;
|
|
56
57
|
e = {
|
|
57
|
-
strategy:
|
|
58
|
-
language:
|
|
59
|
-
currencyCode:
|
|
60
|
-
size:
|
|
61
|
-
productIds:
|
|
62
|
-
filters:
|
|
63
|
-
shuffleProducts:
|
|
58
|
+
strategy: n.strategy,
|
|
59
|
+
language: n.language,
|
|
60
|
+
currencyCode: n.currencySettings.value,
|
|
61
|
+
size: n.size,
|
|
62
|
+
productIds: n.productIds,
|
|
63
|
+
filters: n.filters,
|
|
64
|
+
shuffleProducts: n.shuffleProducts
|
|
64
65
|
};
|
|
65
66
|
}
|
|
66
|
-
const f = ((
|
|
67
|
-
t.set("locale", e.language), t.set("currency", e.currencyCode), t.set("partnerName",
|
|
68
|
-
const g = e.filters.filter((
|
|
69
|
-
d && t.set("filter", d), e.shuffleProducts && t.set("shuffle", "true");
|
|
70
|
-
const p = decodeURIComponent(t.toString()), u = `${
|
|
71
|
-
return
|
|
67
|
+
const f = ((m = I().find((i) => i.key === e.strategy)) == null ? void 0 : m.path) || "", t = new URLSearchParams();
|
|
68
|
+
t.set("locale", e.language), t.set("currency", e.currencyCode), t.set("partnerName", o.partnerName), t.set("size", e.size), t.set("details", "true"), t.set("campaignId", o.variationId), e.strategy === "manualMerchandising" ? t.set("productId", e.productIds.join(",")) : e.strategy === "similarViewed" && t.set("productId", "{itemId}"), e.strategy === "userBased" && t.set("userId", "{user_id}");
|
|
69
|
+
const g = e.filters.filter((i) => i.isValid), d = h(g);
|
|
70
|
+
d && t.set("filter", d), e.shuffleProducts && t.set("shuffle", "true"), Object.entries(y(o.partnerName, e.strategy)).forEach(([i, n]) => t.set(i, n));
|
|
71
|
+
const p = decodeURIComponent(t.toString()), u = `${R.RECOMMENDATION_API_URL}/v2/${f}?${p}`;
|
|
72
|
+
return c.recommendationCampaignUrls[a] = u, u;
|
|
72
73
|
}
|
|
73
74
|
});
|
|
74
75
|
export {
|
|
75
|
-
|
|
76
|
+
k as useRecommendation
|
|
76
77
|
};
|
|
@@ -1,32 +1,31 @@
|
|
|
1
1
|
import { useActionsApi as x } from "./useActionsApi.js";
|
|
2
2
|
import { useConfig as y } from "./useConfig.js";
|
|
3
|
-
import { useSaveStart as w, useSaveComplete as
|
|
4
|
-
import { useSyncModuleExtractor as
|
|
5
|
-
import { useStripoApi as
|
|
6
|
-
import { useTemplatePreparation as
|
|
7
|
-
import { useHtmlValidator as
|
|
3
|
+
import { useSaveStart as w, useSaveComplete as C } from "./useGuidoActions.js";
|
|
4
|
+
import { useSyncModuleExtractor as E } from "./useSyncModuleExtractor.js";
|
|
5
|
+
import { useStripoApi as H } from "../services/stripoApi.js";
|
|
6
|
+
import { useTemplatePreparation as b } from "../utils/templatePreparation.js";
|
|
7
|
+
import { useHtmlValidator as q } from "./useHtmlValidator.js";
|
|
8
8
|
import { useCouponBlockValidator as L } from "./validators/useCouponBlockValidator.js";
|
|
9
9
|
import { useLiquidValidator as P } from "./validators/useLiquidValidator.js";
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
var a;
|
|
10
|
+
const z = () => {
|
|
11
|
+
const o = w(), s = C(), { validateHtml: r } = q(), { validateLiquidSyntax: n } = P(), { validateCouponBlockTags: l } = L(), { callbacks: a, isFeatureEnabled: d } = y(), { extractSyncModuleData: u } = E(), { setSyncModuleUnsubscriptionPages: c } = H(), { editorSave: m } = x();
|
|
12
|
+
return { save: async (p = !1, f = !1) => {
|
|
13
|
+
var i;
|
|
15
14
|
o();
|
|
16
|
-
const { prepareTemplateDetails:
|
|
17
|
-
if (!l(t.compiledHtml)
|
|
15
|
+
const { prepareTemplateDetails: v } = b(), t = await v();
|
|
16
|
+
if (!l(t.compiledHtml))
|
|
18
17
|
return;
|
|
19
|
-
if (
|
|
18
|
+
if (d("liquidSyntax")) {
|
|
20
19
|
if (!await n(t.compiledHtml))
|
|
21
20
|
return;
|
|
22
21
|
} else if (!await r(t.compiledHtml, t.dynamicContentList, !0))
|
|
23
22
|
return;
|
|
24
|
-
if ((
|
|
23
|
+
if ((i = a.value) != null && i.externalValidation && !await a.value.externalValidation(t) || !await m())
|
|
25
24
|
return;
|
|
26
|
-
const { unsubscribePayload:
|
|
27
|
-
return await
|
|
25
|
+
const { unsubscribePayload: S, stripoModules: V } = u(t.rawHtml);
|
|
26
|
+
return await c(S), t.modules = V, p || s({ ...t, silent: f }), t;
|
|
28
27
|
} };
|
|
29
28
|
};
|
|
30
29
|
export {
|
|
31
|
-
|
|
30
|
+
z as useSave
|
|
32
31
|
};
|
|
@@ -1,35 +1,40 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { useRecommendationBlockWarning as l } from "../extensions/Blocks/Recommendation/useRecommendationBlockWarning.js";
|
|
2
|
+
import { useStripoApi as m } from "../services/stripoApi.js";
|
|
3
|
+
import { useEditorStore as b } from "../stores/editor.js";
|
|
4
|
+
import { useOnboardingStore as p } from "../stores/onboarding.js";
|
|
5
|
+
import { useUnsubscribeStore as f } from "../stores/unsubscribe.js";
|
|
6
|
+
const B = () => {
|
|
7
|
+
const { updateSyncModule: r, getSyncModule: c } = m(), { warnIfMultipleBlocks: s } = l(), d = b(), a = f(), i = () => {
|
|
8
|
+
var o, t, n;
|
|
9
|
+
const e = (n = (t = (o = document.querySelector("ui-editor")) == null ? void 0 : o.shadowRoot) == null ? void 0 : t.querySelector("iframe")) == null ? void 0 : n.contentDocument;
|
|
10
|
+
e && s(e);
|
|
11
|
+
}, u = {
|
|
7
12
|
block_dropped: ({ blockName: e }) => {
|
|
8
13
|
if (e === "BLOCK_TEXT") {
|
|
9
|
-
const o =
|
|
10
|
-
if (t ||
|
|
14
|
+
const o = p(), t = !o.shouldShowOnboarding("textBlockOnboarding"), n = o.isActive("textBlockOnboarding");
|
|
15
|
+
if (t || n)
|
|
11
16
|
return;
|
|
12
17
|
o.start("textBlockOnboarding");
|
|
13
18
|
}
|
|
14
19
|
},
|
|
15
20
|
module_saved: async (e) => {
|
|
16
|
-
|
|
21
|
+
d.syncModulesEnabled && (console.debug("[module_saved] Saved module data:", e), await r(e));
|
|
17
22
|
},
|
|
18
23
|
module_dropped: async (e) => {
|
|
19
|
-
if (!
|
|
24
|
+
if (i(), !d.syncModulesEnabled)
|
|
20
25
|
return;
|
|
21
|
-
const { moduleId: o } = e, t = await
|
|
22
|
-
console.debug("[module_dropped] Sync module data:", t), t.unsubscriptionPreferencePages.length && await
|
|
26
|
+
const { moduleId: o } = e, t = await c(o);
|
|
27
|
+
console.debug("[module_dropped] Sync module data:", t), t.unsubscriptionPreferencePages.length && await a.fetchTemplates();
|
|
23
28
|
},
|
|
24
29
|
module_updated: async (e) => {
|
|
25
|
-
|
|
30
|
+
d.syncModulesEnabled && (console.debug("[module_updated] Updated module data:", e), await r(e));
|
|
26
31
|
}
|
|
27
32
|
};
|
|
28
33
|
return { handleEvent: async (e, o) => {
|
|
29
|
-
const t =
|
|
34
|
+
const t = u[e];
|
|
30
35
|
console.debug("Stripo Event: ", e, o), t && await t(o);
|
|
31
36
|
} };
|
|
32
37
|
};
|
|
33
38
|
export {
|
|
34
|
-
|
|
39
|
+
B as useStripoEventHandler
|
|
35
40
|
};
|
package/dist/enums/toaster.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var c = /* @__PURE__ */ ((r) => (r.Success = "success", r.Warning = "warning", r.Alert = "alert", r))(c || {});
|
|
1
|
+
var c = /* @__PURE__ */ ((r) => (r.Success = "success", r.Warning = "warning", r.Alert = "alert", r.Dark = "dark", r))(c || {});
|
|
2
2
|
export {
|
|
3
3
|
c as ToasterTypeOptions
|
|
4
4
|
};
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
var k = Object.defineProperty;
|
|
2
|
-
var
|
|
3
|
-
var d = (a, r, t) =>
|
|
4
|
-
import { BlockId as
|
|
5
|
-
import { getMigrationBannerHtml as
|
|
6
|
-
import { Block as
|
|
2
|
+
var B = (a, r, t) => r in a ? k(a, r, { enumerable: !0, configurable: !0, writable: !0, value: t }) : a[r] = t;
|
|
3
|
+
var d = (a, r, t) => B(a, typeof r != "symbol" ? r + "" : r, t);
|
|
4
|
+
import { BlockId as R } from "../../../enums/block.js";
|
|
5
|
+
import { getMigrationBannerHtml as y } from "../../../utils/migrationBannerHtml.js";
|
|
6
|
+
import { Block as D, BlockCompositionType as C, ModificationDescription as h } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
7
7
|
import { regenerateMobileProductRows as b } from "./controls/main/utils.js";
|
|
8
8
|
import { ensureMobileCssRulesExist as p, setMobileLayoutOptOut as f, hasMobileLayoutOptOut as A } from "./controls/mobileLayout/cssRules.js";
|
|
9
9
|
import { RecommendationConfigService as c } from "./services/configService.js";
|
|
10
10
|
import { useRecommendationExtensionStore as g } from "./store/recommendation.js";
|
|
11
11
|
import { getDefaultTemplate as E } from "./templates/grid/template.js";
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
import { useRecommendationBlockWarning as M } from "./useRecommendationBlockWarning.js";
|
|
13
|
+
const I = R.Recommendation, m = "recommendation-block-v2", u = "recommendation-id";
|
|
14
|
+
let _ = !1;
|
|
15
|
+
class H extends D {
|
|
15
16
|
constructor() {
|
|
16
17
|
super();
|
|
17
18
|
/**
|
|
@@ -21,7 +22,7 @@ class q extends R {
|
|
|
21
22
|
d(this, "_pendingBlockId", null);
|
|
22
23
|
}
|
|
23
24
|
getId() {
|
|
24
|
-
return
|
|
25
|
+
return I;
|
|
25
26
|
}
|
|
26
27
|
getIcon() {
|
|
27
28
|
return "recommendation-icon";
|
|
@@ -38,8 +39,8 @@ class q extends R {
|
|
|
38
39
|
);
|
|
39
40
|
}
|
|
40
41
|
getSettingsPanelTitleHtml() {
|
|
41
|
-
return
|
|
42
|
-
|
|
42
|
+
return y(
|
|
43
|
+
I,
|
|
43
44
|
this.api.translate("Recommendation Block"),
|
|
44
45
|
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
46
|
);
|
|
@@ -95,7 +96,7 @@ class q extends R {
|
|
|
95
96
|
documentModifier: this.api.getDocumentModifier()
|
|
96
97
|
}));
|
|
97
98
|
}
|
|
98
|
-
s.patchCurrentBlockConfig({ language: n.language }, { triggerRefetch: !1 });
|
|
99
|
+
s.patchCurrentBlockConfig({ language: n.language }, { triggerRefetch: !1 }), this._warnIfMultipleBlocks();
|
|
99
100
|
}
|
|
100
101
|
/**
|
|
101
102
|
* Called when the document changes or template is loaded
|
|
@@ -117,7 +118,7 @@ class q extends R {
|
|
|
117
118
|
}
|
|
118
119
|
this._healLingeringDuplicate(t), c.needsMigration(t) && this._migrateFromLegacy(t);
|
|
119
120
|
try {
|
|
120
|
-
|
|
121
|
+
_ || (p(this.api), _ = !0);
|
|
121
122
|
const e = c.getConfig(t), i = this._getBlockElement(t);
|
|
122
123
|
if (i) {
|
|
123
124
|
const n = !e.mobileLayoutEnabled;
|
|
@@ -137,6 +138,24 @@ class q extends R {
|
|
|
137
138
|
const e = this._getRecommendationId(t);
|
|
138
139
|
e && g().removeBlockState(e);
|
|
139
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* Warns (dark advisory toaster) when the design holds more than one live
|
|
143
|
+
* recommendation block. Triggered from the user-add paths only (fresh drop
|
|
144
|
+
* and duplicate) — never from document-load/migration, so opening a template
|
|
145
|
+
* that already has multiple blocks does not fire it.
|
|
146
|
+
*
|
|
147
|
+
* Counting lives in `useRecommendationBlockWarning` so the same DOM-based
|
|
148
|
+
* logic (which ignores the empty shells deletions leave behind, SD-143028)
|
|
149
|
+
* is shared with the `module_dropped` handler — recommendation blocks can
|
|
150
|
+
* also arrive inside a saved structure. Wrapped in try/catch because the
|
|
151
|
+
* document root may be unavailable during initial load.
|
|
152
|
+
*/
|
|
153
|
+
_warnIfMultipleBlocks() {
|
|
154
|
+
try {
|
|
155
|
+
M().warnIfMultipleBlocks(this.api.getDocumentRootHtmlNode());
|
|
156
|
+
} catch {
|
|
157
|
+
}
|
|
158
|
+
}
|
|
140
159
|
/**
|
|
141
160
|
* Generates the next unique recommendation ID by scanning all existing blocks
|
|
142
161
|
* in the document and finding the maximum existing ID + 1.
|
|
@@ -209,7 +228,7 @@ class q extends R {
|
|
|
209
228
|
/** Assigns a fresh id to a duplicated block and syncs DOM, node config and store. */
|
|
210
229
|
_handleDuplicate(t, e) {
|
|
211
230
|
const i = this._reassignDuplicateId(t, e), n = g();
|
|
212
|
-
n.cloneBlockState(e, i), n.setCurrentBlock(i);
|
|
231
|
+
n.cloneBlockState(e, i), n.setCurrentBlock(i), this._warnIfMultipleBlocks();
|
|
213
232
|
}
|
|
214
233
|
/**
|
|
215
234
|
* Core id-reassignment for a duplicated block: rewrites the DOM
|
|
@@ -291,6 +310,6 @@ class q extends R {
|
|
|
291
310
|
}
|
|
292
311
|
}
|
|
293
312
|
export {
|
|
294
|
-
|
|
295
|
-
|
|
313
|
+
I as BLOCK_ID,
|
|
314
|
+
H as RecommendationBlock
|
|
296
315
|
};
|
|
@@ -6,8 +6,9 @@ import { DEFAULT_CARDS_IN_ROW as F } from "../constants/layout.js";
|
|
|
6
6
|
import { EXCLUDED_ALGORITHM_IDS as D } from "../constants/defaultConfig.js";
|
|
7
7
|
import { getDefaultProducts as S } from "../templates/utils.js";
|
|
8
8
|
import { generateCompleteFilterQuery as b } from "../utils/filterUtil.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { getPartnerRecommendationParams as v } from "../utils/partnerCustomizations.js";
|
|
10
|
+
import { isFilterValid as w } from "../validation/filterSchema.js";
|
|
11
|
+
import { isConfigValid as N } from "../validation/requiredFields.js";
|
|
11
12
|
const h = y();
|
|
12
13
|
let m = null, u = null, d = null;
|
|
13
14
|
function I() {
|
|
@@ -49,7 +50,7 @@ function k() {
|
|
|
49
50
|
filterSnapshot: null
|
|
50
51
|
};
|
|
51
52
|
}
|
|
52
|
-
const
|
|
53
|
+
const x = () => ({
|
|
53
54
|
recommendationCampaignUrls: {},
|
|
54
55
|
activePredictiveAlgorithms: [],
|
|
55
56
|
languages: {},
|
|
@@ -58,8 +59,8 @@ const N = () => ({
|
|
|
58
59
|
blockStates: {},
|
|
59
60
|
currentRecommendationId: null,
|
|
60
61
|
configVersion: 0
|
|
61
|
-
}),
|
|
62
|
-
state: () =>
|
|
62
|
+
}), T = P("guidoRecommendationExtension", {
|
|
63
|
+
state: () => x(),
|
|
63
64
|
getters: {
|
|
64
65
|
// ====================================================================
|
|
65
66
|
// Proxy Getters — Backward Compatible Access to Current Block State
|
|
@@ -378,7 +379,7 @@ const N = () => ({
|
|
|
378
379
|
const n = [...e.recommendationConfigs.filters];
|
|
379
380
|
n[r] = {
|
|
380
381
|
...t,
|
|
381
|
-
isValid:
|
|
382
|
+
isValid: w(t)
|
|
382
383
|
}, e.recommendationConfigs.filters = n;
|
|
383
384
|
}
|
|
384
385
|
},
|
|
@@ -424,7 +425,7 @@ const N = () => ({
|
|
|
424
425
|
* every block's recommendationConfigs across user edits.
|
|
425
426
|
*/
|
|
426
427
|
hasInvalidBlock() {
|
|
427
|
-
return Object.values(this.blockStates).some((t) => !
|
|
428
|
+
return Object.values(this.blockStates).some((t) => !N(t.recommendationConfigs, this));
|
|
428
429
|
},
|
|
429
430
|
// ====================================================================
|
|
430
431
|
// Per-Block Product Fetching
|
|
@@ -453,7 +454,10 @@ const N = () => ({
|
|
|
453
454
|
details: !0,
|
|
454
455
|
campaignId: o.variationId
|
|
455
456
|
};
|
|
456
|
-
r.strategy === "manualMerchandising" ? a.productId = r.productIds.join(",") : r.strategy === "similarViewed" && (a.productId = "{itemId}"), r.strategy === "userBased" && (a.userId = "{user_id}"), c && (a.filter = c), r.shuffleProducts && (a.shuffle = !0)
|
|
457
|
+
r.strategy === "manualMerchandising" ? a.productId = r.productIds.join(",") : r.strategy === "similarViewed" && (a.productId = "{itemId}"), r.strategy === "userBased" && (a.userId = "{user_id}"), c && (a.filter = c), r.shuffleProducts && (a.shuffle = !0), Object.assign(
|
|
458
|
+
a,
|
|
459
|
+
v(o.partnerName, r.strategy)
|
|
460
|
+
);
|
|
457
461
|
let f;
|
|
458
462
|
try {
|
|
459
463
|
f = await h.fetchRecommendationProducts(i, a);
|
|
@@ -471,5 +475,5 @@ const N = () => ({
|
|
|
471
475
|
}
|
|
472
476
|
});
|
|
473
477
|
export {
|
|
474
|
-
|
|
478
|
+
T as useRecommendationExtensionStore
|
|
475
479
|
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { useToaster as r } from "../../../composables/useToaster.js";
|
|
2
|
+
import { useTranslations as s } from "../../../composables/useTranslations.js";
|
|
3
|
+
import { ToasterTypeOptions as n } from "../../../enums/toaster.js";
|
|
4
|
+
import { countLiveRecommendationBlocks as i } from "./utils/recommendationBlockCount.js";
|
|
5
|
+
const a = "newsletter.multiple-reco-blocks-warning", f = () => {
|
|
6
|
+
const { showToaster: o } = r(), t = s();
|
|
7
|
+
return { warnIfMultipleBlocks: (e) => {
|
|
8
|
+
i(e) > 1 && o({
|
|
9
|
+
type: n.Dark,
|
|
10
|
+
message: t(a)
|
|
11
|
+
});
|
|
12
|
+
} };
|
|
13
|
+
};
|
|
14
|
+
export {
|
|
15
|
+
f as useRecommendationBlockWarning
|
|
16
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const i = [
|
|
2
|
+
"ozonebg",
|
|
3
|
+
"ozonehr",
|
|
4
|
+
"ozonero",
|
|
5
|
+
"ozoneinfo",
|
|
6
|
+
"babybg",
|
|
7
|
+
"ozongr",
|
|
8
|
+
"iboodat",
|
|
9
|
+
"iboodbe",
|
|
10
|
+
"iboodde",
|
|
11
|
+
"iboodfr",
|
|
12
|
+
"iboodnl",
|
|
13
|
+
"iboodpl"
|
|
14
|
+
], r = ["interencheres", "interencherespreprod"], d = ["lodenfrey", "lodenfreyuat"], c = "manualMerchandising";
|
|
15
|
+
function s(e, n) {
|
|
16
|
+
const o = {};
|
|
17
|
+
return i.includes(e) && (o.excludePurchaseDay = "30", o.userId = "{user_id}"), r.includes(e) && (o.hp = "1"), d.includes(e) && n === c && (o.includeOutOfStockItems = "true"), o;
|
|
18
|
+
}
|
|
19
|
+
export {
|
|
20
|
+
s as getPartnerRecommendationParams
|
|
21
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const r = ".recommendation-block-v2", t = ".recommendation-product-row";
|
|
2
|
+
function n(o) {
|
|
3
|
+
return Array.from(o.querySelectorAll(r)).filter((e) => e.querySelector(t)).length;
|
|
4
|
+
}
|
|
5
|
+
export {
|
|
6
|
+
r as RECOMMENDATION_BLOCK_SELECTOR,
|
|
7
|
+
t as RECOMMENDATION_PRODUCT_ROW_SELECTOR,
|
|
8
|
+
n as countLiveRecommendationBlocks
|
|
9
|
+
};
|
|
@@ -55,6 +55,19 @@ export declare class RecommendationBlock extends Block {
|
|
|
55
55
|
* @param node - The block node being deleted
|
|
56
56
|
*/
|
|
57
57
|
onDelete(node: ImmutableHtmlNode): void;
|
|
58
|
+
/**
|
|
59
|
+
* Warns (dark advisory toaster) when the design holds more than one live
|
|
60
|
+
* recommendation block. Triggered from the user-add paths only (fresh drop
|
|
61
|
+
* and duplicate) — never from document-load/migration, so opening a template
|
|
62
|
+
* that already has multiple blocks does not fire it.
|
|
63
|
+
*
|
|
64
|
+
* Counting lives in `useRecommendationBlockWarning` so the same DOM-based
|
|
65
|
+
* logic (which ignores the empty shells deletions leave behind, SD-143028)
|
|
66
|
+
* is shared with the `module_dropped` handler — recommendation blocks can
|
|
67
|
+
* also arrive inside a saved structure. Wrapped in try/catch because the
|
|
68
|
+
* document root may be unavailable during initial load.
|
|
69
|
+
*/
|
|
70
|
+
private _warnIfMultipleBlocks;
|
|
58
71
|
/**
|
|
59
72
|
* Generates the next unique recommendation ID by scanning all existing blocks
|
|
60
73
|
* in the document and finding the maximum existing ID + 1.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { QueryableRoot } from './utils/recommendationBlockCount';
|
|
2
|
+
/**
|
|
3
|
+
* Advisory shown when a design ends up with more than one recommendation block,
|
|
4
|
+
* since multiple blocks can slow campaign delivery. Shared by the block
|
|
5
|
+
* lifecycle (direct drop / duplicate, counting the editor's document root) and
|
|
6
|
+
* the `module_dropped` event (counting the live editor iframe DOM, so
|
|
7
|
+
* recommendation blocks that arrive inside a saved structure are also covered).
|
|
8
|
+
*/
|
|
9
|
+
export declare const useRecommendationBlockWarning: () => {
|
|
10
|
+
warnIfMultipleBlocks: (root: QueryableRoot) => void;
|
|
11
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the extra recommendation feed query params for an account, if any.
|
|
3
|
+
* Accounts without customizations get an empty object.
|
|
4
|
+
* @param partnerName Account subdomain (`config.partner.name`)
|
|
5
|
+
* @param strategy Recommendation strategy key of the block
|
|
6
|
+
*/
|
|
7
|
+
export declare function getPartnerRecommendationParams(partnerName: string, strategy: string): Record<string, string>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Counts *live* recommendation blocks in a document.
|
|
3
|
+
*
|
|
4
|
+
* Deleting a recommendation block strips its inner content but leaves an empty
|
|
5
|
+
* `.recommendation-block-v2` container shell behind — present in every document
|
|
6
|
+
* representation the editor exposes (`getDocumentRoot`, `getDocumentRootHtmlNode`
|
|
7
|
+
* and even `getTemplateData`). A raw class count therefore over-reports after a
|
|
8
|
+
* delete→add cycle (SD-143028). The product row (`.recommendation-product-row`)
|
|
9
|
+
* is present on every live block from drop time (the default template ships
|
|
10
|
+
* product rows, both grid and list layouts) and is removed from a deleted
|
|
11
|
+
* block's leftover shell, so filtering by it cleanly separates live blocks from
|
|
12
|
+
* ghosts without reading any store.
|
|
13
|
+
*/
|
|
14
|
+
export declare const RECOMMENDATION_BLOCK_SELECTOR = ".recommendation-block-v2";
|
|
15
|
+
export declare const RECOMMENDATION_PRODUCT_ROW_SELECTOR = ".recommendation-product-row";
|
|
16
|
+
interface QueryableNode {
|
|
17
|
+
querySelector(selector: string): unknown;
|
|
18
|
+
}
|
|
19
|
+
export interface QueryableRoot {
|
|
20
|
+
querySelectorAll(selector: string): Iterable<QueryableNode>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Counts the live recommendation blocks reachable from `root`. Works on the
|
|
24
|
+
* editor's `ImmutableHtmlNode` document root (drop / duplicate paths) and on a
|
|
25
|
+
* DOM `Document` parsed from `getTemplateData()` HTML (saved-module drop path).
|
|
26
|
+
*/
|
|
27
|
+
export declare function countLiveRecommendationBlocks(root: QueryableRoot): number;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@useinsider/guido",
|
|
3
|
-
"version": "3.6.0-beta.
|
|
3
|
+
"version": "3.6.0-beta.59a5e5f",
|
|
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,24 +0,0 @@
|
|
|
1
|
-
import { ToasterTypeOptions as p } from "../../enums/toaster.js";
|
|
2
|
-
import { PAGE_TYPES as n } from "../../enums/unsubscribe.js";
|
|
3
|
-
import { DATA_ATTRIBUTES as b } from "../../extensions/Blocks/Unsubscribe/utils/constants.js";
|
|
4
|
-
import { useToaster as f } from "../useToaster.js";
|
|
5
|
-
import { useTranslations as m } from "../useTranslations.js";
|
|
6
|
-
const E = ".unsubscribe-block-v2", C = () => {
|
|
7
|
-
const { showToaster: i } = f(), r = m();
|
|
8
|
-
return { validateUnsubscribeBlockUniqueness: (c) => {
|
|
9
|
-
const u = new DOMParser().parseFromString(c, "text/html"), a = Array.from(u.querySelectorAll(E));
|
|
10
|
-
let s = 0, t = 0;
|
|
11
|
-
a.forEach((l) => {
|
|
12
|
-
const o = Number(l.getAttribute(b.PAGE_TYPE));
|
|
13
|
-
o === n.GLOBAL_UNSUBSCRIBE ? s += 1 : o === n.SUBSCRIPTION_PREFERENCE_CENTER && (t += 1);
|
|
14
|
-
});
|
|
15
|
-
const e = [];
|
|
16
|
-
return s > 1 && e.push(r("unsubscription-preference.global-unsub-added")), t > 1 && e.push(r("unsubscription-preference.pref-center-added")), e.length ? (i({
|
|
17
|
-
type: p.Alert,
|
|
18
|
-
message: e.join(" ")
|
|
19
|
-
}), !1) : !0;
|
|
20
|
-
} };
|
|
21
|
-
};
|
|
22
|
-
export {
|
|
23
|
-
C as useUnsubscribeBlockValidator
|
|
24
|
-
};
|