@useinsider/guido 3.19.0-beta.c8d2be8 → 3.19.0-beta.cd25cc8

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.
Files changed (82) hide show
  1. package/dist/@types/config/schemas.js +104 -91
  2. package/dist/components/Guido.vue.js +6 -6
  3. package/dist/components/Guido.vue2.js +96 -85
  4. package/dist/components/organisms/base/AuthErrorModal.vue.js +18 -0
  5. package/dist/components/organisms/base/AuthErrorModal.vue2.js +42 -0
  6. package/dist/components/organisms/header/EditorActions.vue.js +4 -4
  7. package/dist/components/organisms/header/EditorActions.vue2.js +23 -25
  8. package/dist/components/wrappers/WpModal.vue.js +1 -1
  9. package/dist/components/wrappers/WpModal.vue2.js +4 -3
  10. package/dist/composables/useActionsApi.js +52 -47
  11. package/dist/composables/useAuthError.js +52 -0
  12. package/dist/composables/useAutoSave.js +11 -11
  13. package/dist/composables/useCodeEditorApi.js +23 -9
  14. package/dist/composables/useCortexBlueprintBridge.js +122 -54
  15. package/dist/composables/useEmailTemplateApplier.js +111 -50
  16. package/dist/composables/useHttp.js +48 -49
  17. package/dist/composables/useLegacyStrategyConversion.js +23 -19
  18. package/dist/composables/useStripo.js +24 -20
  19. package/dist/composables/useToaster.js +17 -15
  20. package/dist/composables/useTranslations.js +3 -2
  21. package/dist/composables/useVersionHistoryApi.js +33 -24
  22. package/dist/composables/validators/useLiquidValidator.js +15 -15
  23. package/dist/config/migrator/index.js +14 -13
  24. package/dist/config/migrator/itemsBlockMigrator.js +236 -248
  25. package/dist/config/migrator/recommendationMigrator.js +28 -21
  26. package/dist/config/migrator/recommendationPartnerMigrator.js +56 -0
  27. package/dist/enums/extensions/recommendationBlock.js +30 -29
  28. package/dist/extensions/Blocks/Items/constants/cardLayout.js +20 -0
  29. package/dist/extensions/Blocks/Items/controls/name/trimming.js +18 -17
  30. package/dist/extensions/Blocks/Items/controls/settingsControl.js +114 -105
  31. package/dist/extensions/Blocks/Items/enums/productEnums.js +14 -9
  32. package/dist/extensions/Blocks/Items/layouts/horizontal.html.js +11 -9
  33. package/dist/extensions/Blocks/Items/template.js +219 -204
  34. package/dist/extensions/Blocks/Recommendation/block.js +21 -18
  35. package/dist/extensions/Blocks/Recommendation/controls/main/index.js +117 -93
  36. package/dist/extensions/Blocks/Recommendation/controls/main/strategy.js +72 -49
  37. package/dist/extensions/Blocks/Recommendation/controls/main/utils.js +209 -203
  38. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +130 -96
  39. package/dist/extensions/Blocks/Recommendation/utils/blockUrlConfig.js +25 -0
  40. package/dist/extensions/Blocks/Recommendation/utils/nodeConfigWriter.js +26 -21
  41. package/dist/extensions/Blocks/Recommendation/utils/partnerScope.js +25 -0
  42. package/dist/extensions/Blocks/Recommendation/utils/strategyCommit.js +40 -17
  43. package/dist/guido.css +1 -1
  44. package/dist/src/@types/config/schemas.d.ts +16 -0
  45. package/dist/src/components/organisms/base/AuthErrorModal.vue.d.ts +2 -0
  46. package/dist/src/components/wrappers/WpModal.vue.d.ts +5 -1
  47. package/dist/src/composables/useAuthError.d.ts +12 -0
  48. package/dist/src/composables/useConfig.d.ts +2 -0
  49. package/dist/src/composables/useCortexBlueprintBridge.d.ts +2 -3
  50. package/dist/src/composables/useEmailTemplateApplier.d.ts +18 -5
  51. package/dist/src/composables/useGuidoActions.d.ts +2 -0
  52. package/dist/src/composables/useHttp.d.ts +2 -0
  53. package/dist/src/config/migrator/index.d.ts +2 -1
  54. package/dist/src/config/migrator/recommendationPartnerMigrator.d.ts +19 -0
  55. package/dist/src/enums/extensions/recommendationBlock.d.ts +1 -1
  56. package/dist/src/extensions/Blocks/Items/constants/cardLayout.d.ts +44 -0
  57. package/dist/src/extensions/Blocks/Items/enums/productEnums.d.ts +3 -0
  58. package/dist/src/extensions/Blocks/Items/template.d.ts +19 -0
  59. package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +2 -0
  60. package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +16 -2
  61. package/dist/src/extensions/Blocks/Recommendation/types/nodeConfig.d.ts +6 -0
  62. package/dist/src/extensions/Blocks/Recommendation/utils/blockUrlConfig.d.ts +4 -0
  63. package/dist/src/extensions/Blocks/Recommendation/utils/nodeConfigWriter.d.ts +3 -1
  64. package/dist/src/extensions/Blocks/Recommendation/utils/partnerScope.d.ts +33 -0
  65. package/dist/src/extensions/Blocks/Recommendation/utils/strategyCommit.d.ts +7 -0
  66. package/dist/src/mock/cortexChatStore.d.ts +12 -0
  67. package/dist/src/stores/config.d.ts +20 -0
  68. package/dist/src/stores/guido-email-editor.d.ts +20 -10
  69. package/dist/src/stores/onboarding.d.ts +4 -0
  70. package/dist/src/stores/recommendation.d.ts +5 -0
  71. package/dist/src/utils/dateUtil.d.ts +10 -0
  72. package/dist/src/utils/genericUtil.d.ts +3 -0
  73. package/dist/src/utils/stripoEditorApi.d.ts +4 -0
  74. package/dist/static/styles/components/recommendation-strategy.css.js +9 -0
  75. package/dist/static/styles/components/version-history.css.js +2 -6
  76. package/dist/stores/guido-email-editor.js +3 -1
  77. package/dist/stores/onboarding.js +4 -0
  78. package/dist/stores/unsubscribe.js +3 -3
  79. package/dist/utils/pairProductVariables.js +71 -71
  80. package/dist/utils/stripoEditorApi.js +11 -0
  81. package/dist/utils/templatePreparation.js +61 -85
  82. package/package.json +2 -1
@@ -1,27 +1,31 @@
1
- import { useToaster as D } from "../../../../composables/useToaster.js";
2
- import { useTranslations as L } from "../../../../composables/useTranslations.js";
3
- import { getRecommendationFeedSourceMaps as F, strategyEditPath as U, URLS as E, getOperatorOptions as N, PriceAttributes as M } from "../../../../enums/extensions/recommendationBlock.js";
4
- import { ToasterTypeOptions as A } from "../../../../enums/toaster.js";
5
- import { useRecommendationApi as T } from "../../../../services/recommendationApi.js";
6
- import { useConfigStore as k } from "../../../../stores/config.js";
7
- import { defineStore as B } from "pinia";
1
+ import { useToaster as U } from "../../../../composables/useToaster.js";
2
+ import { useTranslations as M } from "../../../../composables/useTranslations.js";
3
+ import { getRecommendationFeedSourceMaps as w, strategyEditPath as N, strategyCreatePath as B, getOperatorOptions as z, PriceAttributes as E } from "../../../../enums/extensions/recommendationBlock.js";
4
+ import { ToasterTypeOptions as O } from "../../../../enums/toaster.js";
5
+ import { useRecommendationApi as A } from "../../../../services/recommendationApi.js";
6
+ import { useConfigStore as R } from "../../../../stores/config.js";
7
+ import { defineStore as x } from "pinia";
8
8
  import "../constants/selectors.js";
9
- import { DEFAULT_MOBILE_CARDS_IN_ROW as O, DEFAULT_CARDS_IN_ROW as z } from "../constants/layout.js";
10
- import { CURRENT_CONFIG_VERSION as C, DEFAULT_NODE_CONFIG as x, EXCLUDED_ALGORITHM_IDS as V } from "../constants/defaultConfig.js";
11
- import { getDefaultProducts as w } from "../templates/utils.js";
12
- import { generateCompleteFilterQuery as P } from "../utils/filterUtil.js";
13
- import { isLegacyStrategyConfig as j } from "../utils/legacyStrategyMigration.js";
14
- import { getPartnerRecommendationParams as $ } from "../utils/partnerCustomizations.js";
15
- import { sanitizeProductIds as q } from "../utils/productIds.js";
16
- import { isFilterValid as K } from "../validation/filterSchema.js";
17
- import { getInvalidFields as H, isConfigValid as J } from "../validation/requiredFields.js";
18
- const m = T();
19
- let S = null, p = null, y = null, I = "", R = null, b = 0;
20
- const g = /* @__PURE__ */ new Map();
9
+ import { DEFAULT_MOBILE_CARDS_IN_ROW as T, DEFAULT_CARDS_IN_ROW as V } from "../constants/layout.js";
10
+ import { CURRENT_CONFIG_VERSION as C, DEFAULT_NODE_CONFIG as j, EXCLUDED_ALGORITHM_IDS as $ } from "../constants/defaultConfig.js";
11
+ import { getDefaultProducts as P } from "../templates/utils.js";
12
+ import { generateCompleteFilterQuery as G } from "../utils/filterUtil.js";
13
+ import { isLegacyStrategyConfig as q } from "../utils/legacyStrategyMigration.js";
14
+ import { getPartnerRecommendationParams as K } from "../utils/partnerCustomizations.js";
15
+ import { sanitizeProductIds as H } from "../utils/productIds.js";
16
+ import { isFilterValid as J } from "../validation/filterSchema.js";
17
+ import { getInvalidFields as Q, isConfigValid as W } from "../validation/requiredFields.js";
18
+ const u = A();
19
+ let S = null, y = null, p = null, I = "", k = null, b = 0;
20
+ const m = /* @__PURE__ */ new Map(), D = /* @__PURE__ */ new Map();
21
+ function X(t) {
22
+ const e = D.get(t);
23
+ return e && e.token === m.get(t) ? e.outcome : !1;
24
+ }
21
25
  let l = null;
22
- function _() {
26
+ function L() {
23
27
  return {
24
- cardsInRow: z,
28
+ cardsInRow: V,
25
29
  currencySettings: {
26
30
  name: "USD",
27
31
  value: "USD",
@@ -35,7 +39,7 @@ function _() {
35
39
  productIds: [],
36
40
  id: 1,
37
41
  language: "en_US",
38
- mobileCardsInRow: O,
42
+ mobileCardsInRow: T,
39
43
  mobileLayoutEnabled: !1,
40
44
  orientation: "grid",
41
45
  recommendedProducts: [],
@@ -45,7 +49,7 @@ function _() {
45
49
  // that default is what reached buildCampaignUrl and baked a most-popular feed URL
46
50
  // for a block the user never configured (SD-149916). Legacy blocks still get their real
47
51
  // algorithm from the node-config sync or the save-time seed.
48
- strategy: k().isFeatureEnabled("reusableRecommendationStrategy") ? "" : "mostPopular",
52
+ strategy: R().isFeatureEnabled("reusableRecommendationStrategy") ? "" : "mostPopular",
49
53
  strategyId: "",
50
54
  nodeConfigVersion: C,
51
55
  textTrimming: !0,
@@ -56,9 +60,9 @@ function _() {
56
60
  priceHideIfSameAsDiscounted: !1
57
61
  };
58
62
  }
59
- function G() {
63
+ function _() {
60
64
  return {
61
- recommendationConfigs: _(),
65
+ recommendationConfigs: L(),
62
66
  recommendationProducts: [],
63
67
  filterStatus: !1,
64
68
  filterSelectionDrawerStatus: !1,
@@ -72,7 +76,7 @@ function G() {
72
76
  legacyConversionLoading: !1
73
77
  };
74
78
  }
75
- const Q = () => ({
79
+ const Y = () => ({
76
80
  recommendationCampaignUrls: {},
77
81
  activePredictiveAlgorithms: [],
78
82
  languages: {},
@@ -87,8 +91,8 @@ const Q = () => ({
87
91
  currentRecommendationId: null,
88
92
  strategyPanelOpen: !1,
89
93
  configVersion: 0
90
- }), ft = B("guidoRecommendationExtension", {
91
- state: () => Q(),
94
+ }), St = x("guidoRecommendationExtension", {
95
+ state: () => Y(),
92
96
  getters: {
93
97
  // ====================================================================
94
98
  // Proxy Getters — Backward Compatible Access to Current Block State
@@ -98,7 +102,7 @@ const Q = () => ({
98
102
  * This allows all existing code that reads `store.recommendationConfigs` to work unchanged.
99
103
  */
100
104
  recommendationConfigs(t) {
101
- return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].recommendationConfigs : _();
105
+ return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].recommendationConfigs : L();
102
106
  },
103
107
  /**
104
108
  * Proxy getter: delegates to blockStates[currentRecommendationId].recommendationProducts
@@ -119,7 +123,7 @@ const Q = () => ({
119
123
  return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].removeStrategyModalStatus : !1;
120
124
  },
121
125
  isLegacyStrategyBlock() {
122
- return k().isFeatureEnabled("reusableRecommendationStrategy") && j(this.recommendationConfigs);
126
+ return R().isFeatureEnabled("reusableRecommendationStrategy") && q(this.recommendationConfigs);
123
127
  },
124
128
  legacyConversionLoading(t) {
125
129
  return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].legacyConversionLoading ?? !1 : !1;
@@ -162,8 +166,8 @@ const Q = () => ({
162
166
  return [...new Set(t.map((e) => e.filterGroup))].sort((e, r) => e - r);
163
167
  },
164
168
  getActivePredictiveAlgorithms: (t) => {
165
- const e = F(), r = [];
166
- return t.activePredictiveAlgorithms.filter((n) => !V.includes(n)).forEach((n) => {
169
+ const e = w(), r = [];
170
+ return t.activePredictiveAlgorithms.filter((n) => !$.includes(n)).forEach((n) => {
167
171
  r.push(...e.filter((s) => s.id === n));
168
172
  }), r.map((n) => ({
169
173
  text: n.name,
@@ -181,7 +185,7 @@ const Q = () => ({
181
185
  getFilterList() {
182
186
  return Object.values(this.filterList).filter((t) => t.isFilterable !== 0 && t.isFilterable !== !1).map((t) => {
183
187
  let e;
184
- return t.type === "productAttribute" ? e = `product_attributes.${t.attributeName}` : M.includes(t.attributeName) ? e = `${t.attributeName}.${this.recommendationConfigs.currencySettings.value}` : e = t.attributeName, {
188
+ return t.type === "productAttribute" ? e = `product_attributes.${t.attributeName}` : E.includes(t.attributeName) ? e = `${t.attributeName}.${this.recommendationConfigs.currencySettings.value}` : e = t.attributeName, {
185
189
  text: t.displayName,
186
190
  value: e,
187
191
  type: t.attributeType
@@ -203,7 +207,7 @@ const Q = () => ({
203
207
  setCurrentBlock(t) {
204
208
  this.blockStates[t] || (this.blockStates = {
205
209
  ...this.blockStates,
206
- [t]: G()
210
+ [t]: _()
207
211
  }), this.currentRecommendationId = t;
208
212
  },
209
213
  /**
@@ -234,7 +238,7 @@ const Q = () => ({
234
238
  const r = this.blockStates[t];
235
239
  if (r) {
236
240
  const o = structuredClone(r);
237
- o.recommendationConfigs.id = e, o.recommendationConfigs.strategyId && k().isFeatureEnabled("reusableRecommendationStrategy") && (o.isInitialized = !1, o.syncedConfigFingerprint = null), this.blockStates = {
241
+ o.recommendationConfigs.id = e, o.recommendationConfigs.strategyId && R().isFeatureEnabled("reusableRecommendationStrategy") && (o.isInitialized = !1, o.syncedConfigFingerprint = null), this.blockStates = {
238
242
  ...this.blockStates,
239
243
  [e]: o
240
244
  };
@@ -275,7 +279,7 @@ const Q = () => ({
275
279
  decimalCount: String(e.currencyDecimalCount),
276
280
  decimalSeparator: r(e.currencyDecimalSeparator, ","),
277
281
  thousandSeparator: r(e.currencyThousandSeparator, ".")
278
- }, s = !this.blockStates[t], i = s ? G() : this.blockStates[t];
282
+ }, s = !this.blockStates[t], i = s ? _() : this.blockStates[t];
279
283
  i.recommendationConfigs = {
280
284
  ...i.recommendationConfigs,
281
285
  strategy: e.strategy,
@@ -314,7 +318,7 @@ const Q = () => ({
314
318
  * Creates a filter with the first available attribute and operator pre-selected.
315
319
  */
316
320
  createDefaultFilter(t, e) {
317
- const [r] = this.getFilterList, [n] = N(r == null ? void 0 : r.type);
321
+ const [r] = this.getFilterList, [n] = z(r == null ? void 0 : r.type);
318
322
  return {
319
323
  type: "standardFilter",
320
324
  attribute: (r == null ? void 0 : r.value) ?? "",
@@ -380,9 +384,9 @@ const Q = () => ({
380
384
  this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId] || (this.blockStates[this.currentRecommendationId].removeStrategyModalStatus = !1);
381
385
  },
382
386
  async fetchStrategies() {
383
- for (; R; )
387
+ for (; k; )
384
388
  try {
385
- await R;
389
+ await k;
386
390
  } catch {
387
391
  }
388
392
  if (this.strategiesFetched)
@@ -390,7 +394,7 @@ const Q = () => ({
390
394
  const t = b, e = (async () => {
391
395
  this.strategiesLoading = !0;
392
396
  try {
393
- const r = await m.fetchRecommendationStrategies();
397
+ const r = await u.fetchRecommendationStrategies();
394
398
  if (t !== b)
395
399
  return;
396
400
  this.strategies = r, this.strategiesFetched = !0;
@@ -398,11 +402,11 @@ const Q = () => ({
398
402
  this.strategiesLoading = !1, t === b && (this.strategiesSettled = !0);
399
403
  }
400
404
  })();
401
- R = e;
405
+ k = e;
402
406
  try {
403
407
  await e;
404
408
  } finally {
405
- R = null;
409
+ k = null;
406
410
  }
407
411
  },
408
412
  /**
@@ -434,9 +438,9 @@ const Q = () => ({
434
438
  _armStrategyPageReturn(t) {
435
439
  const e = window.open(t, "_blank");
436
440
  if (!e)
437
- return D().showToaster({
438
- type: A.Error,
439
- message: L()("discovery-strategy.error-description")
441
+ return U().showToaster({
442
+ type: O.Error,
443
+ message: M()("discovery-strategy.error-description")
440
444
  }), !1;
441
445
  e.opener = null, l == null || l();
442
446
  let r = !1;
@@ -471,20 +475,20 @@ const Q = () => ({
471
475
  * new strategy is offered; the user picks it themselves.
472
476
  */
473
477
  openStrategyCreation() {
474
- return this._armStrategyPageReturn(E.RECOMMENDATION_STRATEGY_CREATE_PATH);
478
+ return this._armStrategyPageReturn(B());
475
479
  },
476
480
  /**
477
481
  * Opens the strategy's edit page. Every return refreshes the list so the block reflects the
478
482
  * edited configuration.
479
483
  */
480
484
  openStrategyEdit(t) {
481
- return this._armStrategyPageReturn(U(t));
485
+ return this._armStrategyPageReturn(N(t));
482
486
  },
483
487
  async resolveStrategyUrlTemplate(t, e) {
484
488
  const r = typeof t.updated_at == "string" ? t.updated_at : "", n = r ? `${t.strategy_id}:${r}:${e}` : "", s = n ? this.strategyUrlTemplates[n] : void 0;
485
489
  if (s)
486
490
  return s;
487
- const { full_path: i = "" } = await m.generateStrategyEndpoint(t, e) ?? {};
491
+ const { full_path: i = "" } = await u.generateStrategyEndpoint(t, e) ?? {};
488
492
  return n && i && (this.strategyUrlTemplates = {
489
493
  ...this.strategyUrlTemplates,
490
494
  [n]: i
@@ -502,7 +506,8 @@ const Q = () => ({
502
506
  throw new Error("[Guido] convertLegacyStrategy called without an active block");
503
507
  this.blockStates[r].legacyConversionLoading = !0;
504
508
  try {
505
- const n = await m.migrateLegacyStrategy(t, e);
509
+ const n = await u.migrateLegacyStrategy(t, e);
510
+ this.invalidateStrategies();
506
511
  try {
507
512
  await this.fetchStrategies();
508
513
  } catch (o) {
@@ -532,7 +537,7 @@ const Q = () => ({
532
537
  this.patchCurrentBlockConfig({
533
538
  strategyId: "",
534
539
  strategy: "",
535
- size: x.size,
540
+ size: j.size,
536
541
  nodeConfigVersion: C
537
542
  });
538
543
  },
@@ -550,7 +555,7 @@ const Q = () => ({
550
555
  activePredictiveAlgorithms: t,
551
556
  languages: e,
552
557
  currencies: r
553
- } = await m.fetchRecommendationCreateData();
558
+ } = await u.fetchRecommendationCreateData();
554
559
  if (this.activePredictiveAlgorithms = t, this.languages = e, this.currentRecommendationId !== null && this.blockStates[this.currentRecommendationId]) {
555
560
  const n = this.blockStates[this.currentRecommendationId];
556
561
  n.filterStatus = !!n.recommendationConfigs.filters.length;
@@ -566,18 +571,18 @@ const Q = () => ({
566
571
  },
567
572
  async fetchRecommendationFilters() {
568
573
  if (!Object.keys(this.filterList).length) {
569
- if (p) {
570
- await p;
574
+ if (y) {
575
+ await y;
571
576
  return;
572
577
  }
573
- p = (async () => {
574
- const t = await m.fetchRecommendationFilters();
578
+ y = (async () => {
579
+ const t = await u.fetchRecommendationFilters();
575
580
  this.filterList = t;
576
581
  })();
577
582
  try {
578
- await p;
583
+ await y;
579
584
  } finally {
580
- p = null;
585
+ y = null;
581
586
  }
582
587
  }
583
588
  },
@@ -606,7 +611,7 @@ const Q = () => ({
606
611
  const n = [...e.recommendationConfigs.filters];
607
612
  n[r] = {
608
613
  ...t,
609
- isValid: K(t)
614
+ isValid: J(t)
610
615
  }, e.recommendationConfigs.filters = n;
611
616
  }
612
617
  },
@@ -620,7 +625,7 @@ const Q = () => ({
620
625
  let i = 1;
621
626
  n = n.map((o) => o.filterGroup === t.filterGroup ? { ...o, filterNumber: i++ } : o);
622
627
  } else {
623
- const i = [...new Set(n.map((a) => a.filterGroup))].sort((a, d) => a - d), o = new Map(i.map((a, d) => [a, d + 1]));
628
+ const i = [...new Set(n.map((a) => a.filterGroup))].sort((a, f) => a - f), o = new Map(i.map((a, f) => [a, f + 1]));
624
629
  n = n.map((a) => ({
625
630
  ...a,
626
631
  filterGroup: o.get(a.filterGroup) ?? a.filterGroup
@@ -644,7 +649,7 @@ const Q = () => ({
644
649
  }), e.recommendationConfigs.filters = r;
645
650
  },
646
651
  generateFilterQuery() {
647
- return P(this.recommendationConfigs.filters);
652
+ return G(this.recommendationConfigs.filters);
648
653
  },
649
654
  /**
650
655
  * Validation-only check invoked at save-CTA time. Defined as an action
@@ -652,14 +657,14 @@ const Q = () => ({
652
657
  * every block's recommendationConfigs across user edits.
653
658
  */
654
659
  hasInvalidBlock() {
655
- return Object.values(this.blockStates).some((t) => !J(t.recommendationConfigs, this));
660
+ return Object.values(this.blockStates).some((t) => !W(t.recommendationConfigs, this));
656
661
  },
657
662
  /**
658
663
  * Which required fields are missing across the design's blocks, so the save
659
664
  * toaster can name the cause instead of always showing the generic message.
660
665
  */
661
666
  invalidBlockFields() {
662
- return Object.values(this.blockStates).flatMap((t) => H(t.recommendationConfigs, this));
667
+ return Object.values(this.blockStates).flatMap((t) => Q(t.recommendationConfigs, this));
663
668
  },
664
669
  // ====================================================================
665
670
  // Per-Block Product Fetching
@@ -672,32 +677,32 @@ const Q = () => ({
672
677
  this.configVersion,
673
678
  b
674
679
  ].join(":");
675
- if (y && I === t) {
676
- await y;
680
+ if (p && I === t) {
681
+ await p;
677
682
  return;
678
683
  }
679
- I = t, y = this._doFetchProducts();
684
+ I = t, p = this._doFetchProducts();
680
685
  try {
681
- await y;
686
+ await p;
682
687
  } finally {
683
- I === t && (y = null, I = "");
688
+ I === t && (p = null, I = "");
684
689
  }
685
690
  },
686
691
  async _doFetchProducts() {
687
692
  var h;
688
- const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, n = k();
693
+ const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, n = R();
689
694
  if (r.strategyId && n.isFeatureEnabled("reusableRecommendationStrategy")) {
690
695
  await this._doFetchStrategyProducts(t);
691
696
  return;
692
697
  }
693
- const s = (g.get(t) ?? 0) + 1;
694
- g.set(t, s);
698
+ const s = (m.get(t) ?? 0) + 1;
699
+ m.set(t, s);
695
700
  const i = parseInt(r.size) || 6;
696
701
  if (!r.strategy) {
697
702
  this._setBlockProducts(t, [], i);
698
703
  return;
699
704
  }
700
- const o = r.filters.filter((f) => f.isValid), a = P(o), d = ((h = F().find((f) => f.key === r.strategy)) == null ? void 0 : h.path) || "", c = {
705
+ const o = r.filters.filter((g) => g.isValid), a = G(o), f = ((h = w().find((g) => g.key === r.strategy)) == null ? void 0 : h.path) || "", c = {
701
706
  locale: r.language,
702
707
  currency: r.currencySettings.value,
703
708
  partnerName: n.partnerName,
@@ -705,58 +710,87 @@ const Q = () => ({
705
710
  details: !0,
706
711
  campaignId: n.variationId
707
712
  };
708
- r.strategy === "manualMerchandising" ? c.productId = q(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(
713
+ r.strategy === "manualMerchandising" ? c.productId = H(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(
709
714
  c,
710
- $(n.partnerName, r.strategy)
715
+ K(n.partnerName, r.strategy)
711
716
  );
712
- let u;
717
+ let d;
713
718
  try {
714
- u = await m.fetchRecommendationProducts(d, c);
719
+ d = await u.fetchRecommendationProducts(f, c);
715
720
  } catch {
716
- u = [];
721
+ d = [];
717
722
  }
718
- g.get(t) === s && this._setBlockProducts(t, u, i);
723
+ m.get(t) === s && this._setBlockProducts(t, d, i);
719
724
  },
720
725
  /**
721
726
  * Block-scoped counterpart of `fetchRecommendationProducts`, which only ever serves the
722
727
  * selected block. The legacy conversion must refresh the products of the block that
723
728
  * started it even after the user selected another one.
729
+ * @returns whether real products arrived
724
730
  */
725
- async fetchStrategyProductsForBlock(t) {
726
- var e;
727
- (e = this.blockStates[t]) != null && e.recommendationConfigs.strategyId && await this._doFetchStrategyProducts(t);
731
+ async fetchStrategyProductsForBlock(t, e = {}) {
732
+ var r;
733
+ return (r = this.blockStates[t]) != null && r.recommendationConfigs.strategyId ? this._doFetchStrategyProducts(t, e) : !1;
728
734
  },
729
- async _doFetchStrategyProducts(t) {
730
- const e = (g.get(t) ?? 0) + 1;
731
- g.set(t, e);
732
- const { recommendationConfigs: r } = this.blockStates[t];
733
- let n = [], s = parseInt(r.size) || 6;
735
+ /**
736
+ * Reloads a block's products and adopts its strategy's current size, which may have
737
+ * moved since the block was assigned.
738
+ * @returns whether a fresh listing holds the strategy and its products arrived
739
+ */
740
+ async refreshStrategyBlock(t) {
741
+ var s;
742
+ const e = (s = this.blockStates[t]) == null ? void 0 : s.recommendationConfigs.strategyId;
743
+ if (!e)
744
+ return !1;
745
+ try {
746
+ await this.fetchStrategies();
747
+ } catch {
748
+ return !1;
749
+ }
750
+ const r = this.strategiesFetched ? this.strategies.find((i) => String(i.strategy_id) === e) : void 0;
751
+ if (!r || !await this.fetchStrategyProductsForBlock(t, { keepOnFailure: !0 }))
752
+ return !1;
753
+ const n = this.blockStates[t];
754
+ return (n == null ? void 0 : n.recommendationConfigs.strategyId) !== e ? !1 : (r.size !== void 0 && (n.recommendationConfigs = {
755
+ ...n.recommendationConfigs,
756
+ size: String(r.size)
757
+ }), !0);
758
+ },
759
+ _doFetchStrategyProducts(t, e = {}) {
760
+ const r = (m.get(t) ?? 0) + 1;
761
+ m.set(t, r);
762
+ const n = this._loadStrategyProducts(t, r, e);
763
+ return D.set(t, { token: r, outcome: n }), n;
764
+ },
765
+ async _loadStrategyProducts(t, e, { keepOnFailure: r = !1 }) {
766
+ const { recommendationConfigs: n } = this.blockStates[t];
767
+ let s = [], i = parseInt(n.size) || 6;
734
768
  try {
735
769
  await this.fetchStrategies();
736
- const i = this.strategies.find(
737
- (o) => String(o.strategy_id) === r.strategyId
770
+ const o = this.strategies.find(
771
+ (a) => String(a.strategy_id) === n.strategyId
738
772
  );
739
- if (i) {
740
- s = parseInt(String(i.size ?? "")) || s;
741
- const o = r.currencySettings.value, d = (await this.resolveStrategyUrlTemplate(i, o)).replaceAll("{locale}", r.language).replaceAll("{currency}", o), c = d.indexOf("?"), u = c === -1 ? d : d.slice(0, c), h = (c === -1 ? "" : d.slice(c + 1)).split("&").filter((v) => v && !v.startsWith("user_id=")), f = h.length ? `${u}?${h.join("&")}` : u;
742
- f && (n = await m.fetchRecommendationProductsByUrl(f));
773
+ if (o) {
774
+ i = parseInt(String(o.size ?? "")) || i;
775
+ const a = n.currencySettings.value, c = (await this.resolveStrategyUrlTemplate(o, a)).replaceAll("{locale}", n.language).replaceAll("{currency}", a), d = c.indexOf("?"), h = d === -1 ? c : c.slice(0, d), g = (d === -1 ? "" : c.slice(d + 1)).split("&").filter((F) => F && !F.startsWith("user_id=")), v = g.length ? `${h}?${g.join("&")}` : h;
776
+ v && (s = await u.fetchRecommendationProductsByUrl(v));
743
777
  }
744
778
  } catch {
745
- n = [];
779
+ s = [];
746
780
  }
747
- g.get(t) === e && this._setBlockProducts(t, n, s);
781
+ return m.get(t) !== e ? X(t) : !s.length && r ? !1 : (this._setBlockProducts(t, s, i), s.length > 0);
748
782
  },
749
783
  _setBlockProducts(t, e, r) {
750
784
  if (!this.blockStates[t])
751
785
  return;
752
- const n = e.length > 0 ? e : w(r);
786
+ const n = e.length > 0 ? e : P(r);
753
787
  this.blockStates[t].recommendationProducts = [
754
788
  ...n.slice(0, r),
755
- ...w(Math.max(0, r - n.length))
789
+ ...P(Math.max(0, r - n.length))
756
790
  ];
757
791
  }
758
792
  }
759
793
  });
760
794
  export {
761
- ft as useRecommendationExtensionStore
795
+ St as useRecommendationExtensionStore
762
796
  };
@@ -0,0 +1,25 @@
1
+ import { RRS_CONFIG_VERSION as d, DEFAULT_CURRENCY as t, DEFAULT_NODE_CONFIG as e } from "../constants/defaultConfig.js";
2
+ import { mapLegacyStrategy as n } from "./legacyStrategyMap.js";
3
+ function S(r) {
4
+ var a, u, c, s, l, o;
5
+ const y = !!r.strategyId || (r.configVersion ?? 0) >= d;
6
+ return {
7
+ strategy: n(r.strategy) || (y ? "" : e.strategy),
8
+ strategyId: r.strategyId ?? e.strategyId,
9
+ language: r.language ?? e.language,
10
+ size: r.size ?? e.size,
11
+ // Copied: the source can be a live node config or the shared defaults.
12
+ productIds: [...r.productIds ?? e.productIds],
13
+ filters: structuredClone(r.filters ?? e.filters),
14
+ shuffleProducts: r.shuffleProducts ?? e.shuffleProducts,
15
+ currencyCode: ((a = r.currency) == null ? void 0 : a.code) ?? t.code,
16
+ currencySymbol: ((u = r.currency) == null ? void 0 : u.symbol) ?? t.symbol,
17
+ currencyAlignment: ((c = r.currency) == null ? void 0 : c.alignment) ?? t.alignment,
18
+ currencyDecimalCount: ((s = r.currency) == null ? void 0 : s.decimalCount) ?? t.decimalCount,
19
+ currencyDecimalSeparator: ((l = r.currency) == null ? void 0 : l.decimalSeparator) ?? t.decimalSeparator,
20
+ currencyThousandSeparator: ((o = r.currency) == null ? void 0 : o.thousandSeparator) ?? t.thousandSeparator
21
+ };
22
+ }
23
+ export {
24
+ S as toBlockUrlConfig
25
+ };
@@ -1,32 +1,37 @@
1
- import { ModificationDescription as g } from "../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
2
- import { RECOMMENDATION_ID_ATTR as s } from "../constants/selectors.js";
3
- import { isPartnerManagedBlock as p, updateProductContentInPlace as C, regenerateProductRowsWithStyles as N } from "../controls/main/utils.js";
4
- import { RecommendationConfigService as m } from "../services/configService.js";
5
- let o = null;
6
- function D(n) {
7
- o = n;
1
+ import { ModificationDescription as m } from "../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
2
+ import { RECOMMENDATION_ID_ATTR as a } from "../constants/selectors.js";
3
+ import { isPartnerManagedBlock as C, updateProductContentInPlace as N, regenerateProductRowsWithStyles as p } from "../controls/main/utils.js";
4
+ import { RecommendationConfigService as l } from "../services/configService.js";
5
+ let e = null;
6
+ function O(n) {
7
+ e = n;
8
8
  }
9
- function P(n, r, c, l) {
10
- const i = o == null ? void 0 : o.getDocumentRootHtmlNode();
11
- if (!o || !i || !("querySelector" in i))
9
+ function R(n) {
10
+ const o = e == null ? void 0 : e.getDocumentRootHtmlNode();
11
+ return !o || !("querySelectorAll" in o) ? [] : o.querySelectorAll(`[${a}="${n}"]`).map((i) => l.getConfig(i));
12
+ }
13
+ function P(n, o, i, u) {
14
+ const c = e == null ? void 0 : e.getDocumentRootHtmlNode();
15
+ if (!e || !c || !("querySelector" in c))
12
16
  return !1;
13
- const e = i.querySelector(`[${s}="${n}"]`);
14
- if (!e)
17
+ const t = c.querySelector(`[${a}="${n}"]`);
18
+ if (!t)
15
19
  return !1;
16
- const t = o.getDocumentModifier(), a = m.getConfig(e), d = Object.keys(r).some((u) => JSON.stringify(a[u]) !== JSON.stringify(r[u]));
17
- if (m.stageConfig(t, e, r), p(e))
18
- return t.apply(new g(l)), !0;
20
+ const r = e.getDocumentModifier(), d = l.getConfig(t), s = Object.keys(o).some((g) => JSON.stringify(d[g]) !== JSON.stringify(o[g]));
21
+ if (l.stageConfig(r, t, o), C(t))
22
+ return r.apply(new m(u)), !0;
19
23
  let f = !1;
20
- return C({
21
- currentNode: e,
22
- documentModifier: t,
23
- products: c,
24
+ return N({
25
+ currentNode: t,
26
+ documentModifier: r,
27
+ products: i,
24
28
  onApplied: () => {
25
29
  f = !0;
26
30
  }
27
- }) || (f = N({ currentNode: e, documentModifier: t, products: c })), !f && d && t.apply(new g(l)), !0;
31
+ }) || (f = p({ currentNode: t, documentModifier: r, products: i })), !f && s && r.apply(new m(u)), !0;
28
32
  }
29
33
  export {
30
34
  P as commitBlockChangeOutsidePanel,
31
- D as registerNodeConfigWriter
35
+ R as readBlockNodeConfigs,
36
+ O as registerNodeConfigWriter
32
37
  };
@@ -0,0 +1,25 @@
1
+ import { ATTR_CUSTOM_PREFIX as f } from "../constants/selectors.js";
2
+ function o(t) {
3
+ if (typeof t == "string")
4
+ return t.trim() !== "";
5
+ if (t && typeof t == "object" && "strategyId" in t) {
6
+ const { strategyId: r } = t;
7
+ return (typeof r == "string" || typeof r == "number") && String(r).trim() !== "";
8
+ }
9
+ return !1;
10
+ }
11
+ function u({ config: t, blockId: r, partnerName: e, campaignUrls: n, rrsEnabled: i }) {
12
+ return e ? t.partnerName ? t.partnerName !== e : !i || !t.strategyId || !n ? !1 : !o(n[String(r)]) : !1;
13
+ }
14
+ function a({ config: t, campaignUrls: r, rrsEnabled: e }) {
15
+ return !t.strategyId || e && !!r;
16
+ }
17
+ function g(t) {
18
+ return t.filter((r) => !r.startsWith(f));
19
+ }
20
+ export {
21
+ a as canJudgeUnstampedBlock,
22
+ u as carriesForeignPartnerConfig,
23
+ o as isDefinedCampaignUrl,
24
+ g as withoutCustomAttributes
25
+ };