@useinsider/guido 3.16.0 → 3.17.0-beta.3e9d6e7

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 (88) hide show
  1. package/README.md +1 -0
  2. package/dist/@types/config/schemas.js +12 -6
  3. package/dist/components/Guido.vue.js +6 -6
  4. package/dist/components/Guido.vue2.js +63 -61
  5. package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue.js +18 -0
  6. package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue2.js +67 -0
  7. package/dist/components/organisms/extensions/recommendation/StrategyInfoBox.vue.js +20 -0
  8. package/dist/components/organisms/extensions/recommendation/StrategyInfoBox.vue2.js +55 -0
  9. package/dist/composables/useCustomInterfaceAppearance.js +19 -16
  10. package/dist/composables/useRecommendation.js +43 -35
  11. package/dist/composables/useStripo.js +30 -29
  12. package/dist/config/migrator/itemsBlockMigrator.js +1 -1
  13. package/dist/config/migrator/recommendationMigrator.js +6 -4
  14. package/dist/enums/date.js +4 -3
  15. package/dist/enums/extensions/recommendationBlock.js +25 -23
  16. package/dist/enums/recommendation.js +17 -17
  17. package/dist/extensions/Blocks/Items/enums/productEnums.js +45 -45
  18. package/dist/extensions/Blocks/Recommendation/constants/defaultConfig.js +13 -11
  19. package/dist/extensions/Blocks/Recommendation/controls/main/algorithm.js +37 -26
  20. package/dist/extensions/Blocks/Recommendation/controls/main/index.js +115 -87
  21. package/dist/extensions/Blocks/Recommendation/controls/main/strategy.js +132 -0
  22. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +198 -51
  23. package/dist/extensions/Blocks/Recommendation/utils/productIds.js +6 -0
  24. package/dist/extensions/Blocks/common-control.js +22 -19
  25. package/dist/guido.css +1 -1
  26. package/dist/node_modules/@useinsider/design-system-organisms/dist/index-Dc9AygoZ.js +526 -0
  27. package/dist/node_modules/@useinsider/design-system-organisms/dist/index.js +9345 -0
  28. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InAccordion.js +174 -0
  29. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InBasicTextInput.js +381 -0
  30. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InBox.js +236 -0
  31. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InBulkActions.js +70 -0
  32. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InButton.js +350 -0
  33. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InButtonV2.js +371 -0
  34. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InCheckBox.js +152 -0
  35. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InChips.js +141 -0
  36. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InCustomDropDown.js +1047 -0
  37. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InDataTableV2.js +96050 -0
  38. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InDatePicker.js +2042 -0
  39. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InDrawer.js +166 -0
  40. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InDropDown.js +1098 -0
  41. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InIcons.js +55 -0
  42. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InInfoBox.js +265 -0
  43. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InLinks.js +184 -0
  44. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InLoading.js +50 -0
  45. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InModals.js +453 -0
  46. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InNoData.js +145 -0
  47. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InOnPageMessage.js +176 -0
  48. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InProgress.js +266 -0
  49. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InRadioButton.js +114 -0
  50. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InSegments.js +200 -0
  51. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InSelect.js +451 -0
  52. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InSkeleton.js +49 -0
  53. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InStatusText.js +119 -0
  54. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InTabs.js +4309 -0
  55. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InTagsText.js +129 -0
  56. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InTextInput.js +503 -0
  57. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InToasts.js +253 -0
  58. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InToggle.js +107 -0
  59. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InTooltip.js +134 -0
  60. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/InTooltipV2.js +464 -0
  61. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/chunks/_commonjsHelpers.BItOPCY9.js +28 -0
  62. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/chunks/_plugin-vue2_normalizer.WQT2Fc8L.js +23 -0
  63. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/chunks/clickOutside.qP9M0QCm.js +29 -0
  64. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/chunks/helpers.CgHNyjAJ.js +109 -0
  65. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/chunks/index.Bw_06igr.js +2339 -0
  66. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/chunks/localLocalesMixin.DYMhydo2.js +16 -0
  67. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/chunks/useLocalLocales.Ckuhy7d-.js +17 -0
  68. package/dist/node_modules/@useinsider/design-system-organisms/node_modules/@useinsider/design-system-vue/dist/chunks/vue-property-decorator.BtlM7Epa.js +188 -0
  69. package/dist/services/recommendationApi.js +77 -28
  70. package/dist/src/@types/config/schemas.d.ts +12 -0
  71. package/dist/src/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue.d.ts +3 -0
  72. package/dist/src/components/organisms/extensions/recommendation/StrategyInfoBox.vue.d.ts +24 -0
  73. package/dist/src/composables/useConfig.d.ts +2 -0
  74. package/dist/src/composables/useRecommendation.d.ts +1 -0
  75. package/dist/src/enums/extensions/recommendationBlock.d.ts +2 -0
  76. package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +12 -3
  77. package/dist/src/extensions/Blocks/Recommendation/controls/main/strategy.d.ts +37 -0
  78. package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +210 -10
  79. package/dist/src/extensions/Blocks/Recommendation/types/nodeConfig.d.ts +6 -0
  80. package/dist/src/extensions/Blocks/Recommendation/utils/productIds.d.ts +6 -0
  81. package/dist/src/extensions/Blocks/common-control.d.ts +4 -1
  82. package/dist/src/mock/api/recommendation-strategies.d.ts +43 -0
  83. package/dist/src/services/recommendationApi.d.ts +4 -1
  84. package/dist/src/stores/config.d.ts +18 -0
  85. package/dist/static/styles/components/recommendation-strategy.css.js +171 -0
  86. package/dist/utils/dateUtil.js +23 -10
  87. package/dist/utils/templatePreparation.js +37 -34
  88. package/package.json +2 -1
@@ -1,20 +1,21 @@
1
- import { getRecommendationFeedSourceMaps as g, getOperatorOptions as R, PriceAttributes as C } from "../../../../enums/extensions/recommendationBlock.js";
2
- import { useRecommendationApi as y } from "../../../../services/recommendationApi.js";
3
- import { useConfigStore as G } from "../../../../stores/config.js";
4
- import { defineStore as F } from "pinia";
1
+ import { getRecommendationFeedSourceMaps as p, getOperatorOptions as R, PriceAttributes as C } from "../../../../enums/extensions/recommendationBlock.js";
2
+ import { useRecommendationApi as w } from "../../../../services/recommendationApi.js";
3
+ import { useConfigStore as P } from "../../../../stores/config.js";
4
+ import { defineStore as G } from "pinia";
5
5
  import "../constants/selectors.js";
6
- import { DEFAULT_MOBILE_CARDS_IN_ROW as P, DEFAULT_CARDS_IN_ROW as D } from "../constants/layout.js";
7
- import { EXCLUDED_ALGORITHM_IDS as w } from "../constants/defaultConfig.js";
8
- import { getDefaultProducts as S } from "../templates/utils.js";
6
+ import { DEFAULT_MOBILE_CARDS_IN_ROW as D, DEFAULT_CARDS_IN_ROW as F } from "../constants/layout.js";
7
+ import { DEFAULT_NODE_CONFIG as v, EXCLUDED_ALGORITHM_IDS as _ } from "../constants/defaultConfig.js";
8
+ import { getDefaultProducts as y } from "../templates/utils.js";
9
9
  import { generateCompleteFilterQuery as b } from "../utils/filterUtil.js";
10
- import { getPartnerRecommendationParams as v } from "../utils/partnerCustomizations.js";
11
- import { isFilterValid as N } from "../validation/filterSchema.js";
10
+ import { getPartnerRecommendationParams as U } from "../utils/partnerCustomizations.js";
11
+ import { sanitizeProductIds as N } from "../utils/productIds.js";
12
+ import { isFilterValid as L } from "../validation/filterSchema.js";
12
13
  import { isConfigValid as x } from "../validation/requiredFields.js";
13
- const h = y();
14
- let m = null, u = null, d = null;
14
+ const l = w();
15
+ let m = null, u = null, d = null, f = null;
15
16
  function k() {
16
17
  return {
17
- cardsInRow: D,
18
+ cardsInRow: F,
18
19
  currencySettings: {
19
20
  name: "USD",
20
21
  value: "USD",
@@ -28,13 +29,14 @@ function k() {
28
29
  productIds: [],
29
30
  id: 1,
30
31
  language: "en_US",
31
- mobileCardsInRow: P,
32
+ mobileCardsInRow: D,
32
33
  mobileLayoutEnabled: !1,
33
34
  orientation: "grid",
34
35
  recommendedProducts: [],
35
36
  sendProductRequestFlag: !1,
36
37
  shuffleProducts: !1,
37
38
  strategy: "mostPopular",
39
+ strategyId: "",
38
40
  textTrimming: !0,
39
41
  unresponsive: !1,
40
42
  size: "6",
@@ -49,22 +51,26 @@ function I() {
49
51
  recommendationProducts: [],
50
52
  filterStatus: !1,
51
53
  filterSelectionDrawerStatus: !1,
54
+ assignStrategyDrawerStatus: !1,
52
55
  filterGroup: 1,
53
56
  isInitialized: !1,
54
57
  filterSnapshot: null
55
58
  };
56
59
  }
57
- const L = () => ({
60
+ const A = () => ({
58
61
  recommendationCampaignUrls: {},
59
62
  activePredictiveAlgorithms: [],
60
63
  languages: {},
61
64
  currencyList: [],
62
65
  filterList: {},
66
+ strategies: [],
67
+ strategiesLoading: !1,
68
+ strategyUrlTemplates: {},
63
69
  blockStates: {},
64
70
  currentRecommendationId: null,
65
71
  configVersion: 0
66
- }), $ = F("guidoRecommendationExtension", {
67
- state: () => L(),
72
+ }), Q = G("guidoRecommendationExtension", {
73
+ state: () => A(),
68
74
  getters: {
69
75
  // ====================================================================
70
76
  // Proxy Getters — Backward Compatible Access to Current Block State
@@ -88,6 +94,20 @@ const L = () => ({
88
94
  filterSelectionDrawerStatus(t) {
89
95
  return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].filterSelectionDrawerStatus : !1;
90
96
  },
97
+ /**
98
+ * Proxy getter: delegates to blockStates[currentRecommendationId].assignStrategyDrawerStatus
99
+ */
100
+ assignStrategyDrawerStatus(t) {
101
+ return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].assignStrategyDrawerStatus : !1;
102
+ },
103
+ /**
104
+ * The current block's assigned strategy record from the listing,
105
+ * or null when nothing is assigned / the strategy is no longer listed.
106
+ */
107
+ assignedStrategy(t) {
108
+ const { strategyId: e } = this.recommendationConfigs;
109
+ return e ? t.strategies.find((r) => String(r.strategy_id) === e) ?? null : null;
110
+ },
91
111
  /**
92
112
  * Proxy getter: delegates to blockStates[currentRecommendationId].filterStatus
93
113
  */
@@ -119,9 +139,9 @@ const L = () => ({
119
139
  return [...new Set(t.map((e) => e.filterGroup))].sort((e, r) => e - r);
120
140
  },
121
141
  getActivePredictiveAlgorithms: (t) => {
122
- const e = g(), r = [];
123
- return t.activePredictiveAlgorithms.filter((n) => !w.includes(n)).forEach((n) => {
124
- r.push(...e.filter((c) => c.id === n));
142
+ const e = p(), r = [];
143
+ return t.activePredictiveAlgorithms.filter((n) => !_.includes(n)).forEach((n) => {
144
+ r.push(...e.filter((s) => s.id === n));
125
145
  }), r.map((n) => ({
126
146
  text: n.name,
127
147
  value: n.key
@@ -192,10 +212,10 @@ const L = () => ({
192
212
  [e]: o
193
213
  };
194
214
  }
195
- const n = t.toString(), c = e.toString(), i = this.recommendationCampaignUrls[n];
215
+ const n = t.toString(), s = e.toString(), i = this.recommendationCampaignUrls[n];
196
216
  i && (this.recommendationCampaignUrls = {
197
217
  ...this.recommendationCampaignUrls,
198
- [c]: i
218
+ [s]: i
199
219
  });
200
220
  },
201
221
  /**
@@ -220,7 +240,7 @@ const L = () => ({
220
240
  * `isInitialized`) alone.
221
241
  */
222
242
  seedBlockUrlConfig(t, e) {
223
- const r = (o, s) => o === "." || o === "," || o === " " ? o : s, n = {
243
+ const r = (o, a) => o === "." || o === "," || o === " " ? o : a, n = {
224
244
  name: e.currencyCode,
225
245
  value: e.currencyCode,
226
246
  symbol: e.currencyCode,
@@ -228,17 +248,18 @@ const L = () => ({
228
248
  decimalCount: String(e.currencyDecimalCount),
229
249
  decimalSeparator: r(e.currencyDecimalSeparator, ","),
230
250
  thousandSeparator: r(e.currencyThousandSeparator, ".")
231
- }, c = !this.blockStates[t], i = c ? I() : this.blockStates[t];
251
+ }, s = !this.blockStates[t], i = s ? I() : this.blockStates[t];
232
252
  i.recommendationConfigs = {
233
253
  ...i.recommendationConfigs,
234
254
  strategy: e.strategy,
255
+ strategyId: e.strategyId,
235
256
  language: e.language,
236
257
  size: e.size,
237
258
  productIds: e.productIds,
238
259
  filters: e.filters,
239
260
  shuffleProducts: e.shuffleProducts,
240
261
  currencySettings: n
241
- }, c && (this.blockStates = {
262
+ }, s && (this.blockStates = {
242
263
  ...this.blockStates,
243
264
  [t]: i
244
265
  });
@@ -314,6 +335,89 @@ const L = () => ({
314
335
  t.filterSnapshot !== null && (t.recommendationConfigs.filters = t.filterSnapshot, t.filterSnapshot = null), t.filterSelectionDrawerStatus = !1;
315
336
  },
316
337
  // ====================================================================
338
+ // Reusable Recommendation Strategy (SD-149105)
339
+ // ====================================================================
340
+ /**
341
+ * Opens the Assign Strategy drawer for the current block.
342
+ * Selection state lives in the drawer component until Assign is
343
+ * pressed, so closing without assigning needs no snapshot/revert.
344
+ */
345
+ openAssignStrategyDrawer() {
346
+ this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId] || (this.blockStates[this.currentRecommendationId].assignStrategyDrawerStatus = !0);
347
+ },
348
+ closeAssignStrategyDrawer() {
349
+ this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId] || (this.blockStates[this.currentRecommendationId].assignStrategyDrawerStatus = !1);
350
+ },
351
+ /**
352
+ * Fetches the active + EMAIL strategy listing. Always fetches fresh
353
+ * (dead-strategy detection and post-create refresh need freshness);
354
+ * only concurrent in-flight calls share one request.
355
+ */
356
+ async fetchStrategies() {
357
+ if (f) {
358
+ await f;
359
+ return;
360
+ }
361
+ f = (async () => {
362
+ this.strategiesLoading = !0;
363
+ try {
364
+ this.strategies = await l.fetchRecommendationStrategies();
365
+ } finally {
366
+ this.strategiesLoading = !1;
367
+ }
368
+ })();
369
+ try {
370
+ await f;
371
+ } finally {
372
+ f = null;
373
+ }
374
+ },
375
+ /**
376
+ * Resolves a strategy's recommendation endpoint template via
377
+ * endpoint-generate, cached per strategy id + revision. Failures throw
378
+ * and are NOT cached, so the next attempt retries.
379
+ *
380
+ * The revision is part of the key because `full_path` bakes in the
381
+ * algorithm path and `size=` as they were when it was generated, while
382
+ * the listing is deliberately never cached — editing a strategy in the
383
+ * panel and re-assigning it here would otherwise call a stale endpoint.
384
+ */
385
+ async resolveStrategyUrlTemplate(t) {
386
+ const e = typeof t.updated_at == "string" ? t.updated_at : "", r = `${t.strategy_id}:${e}`, n = this.strategyUrlTemplates[r];
387
+ if (n)
388
+ return n;
389
+ const { full_path: s } = await l.generateStrategyEndpoint(t);
390
+ return this.strategyUrlTemplates = {
391
+ ...this.strategyUrlTemplates,
392
+ [r]: s
393
+ }, s;
394
+ },
395
+ /**
396
+ * Assigns a strategy to the current block. The config write is
397
+ * synchronous (before any await) so a block switch cannot misdirect
398
+ * it; the configVersion bump persists it to node config and triggers
399
+ * the product refetch via the coordinator control's subscription.
400
+ */
401
+ assignStrategy(t) {
402
+ this.patchCurrentBlockConfig({
403
+ strategyId: String(t.strategy_id),
404
+ ...t.size !== void 0 ? { size: String(t.size) } : {}
405
+ });
406
+ },
407
+ /**
408
+ * Clears the current block's strategy; it falls back to the per-block
409
+ * algorithm settings.
410
+ *
411
+ * `size` goes back to the default rather than staying on the removed
412
+ * strategy's count: the Number of Products control is hidden in RRS
413
+ * mode (D2), so a block left on the strategy's count would have no UI
414
+ * to correct it. The pre-assign count is not restored — that would
415
+ * need a persisted snapshot field; tracked for a later phase.
416
+ */
417
+ removeStrategy() {
418
+ this.patchCurrentBlockConfig({ strategyId: "", size: v.size });
419
+ },
420
+ // ====================================================================
317
421
  // Shared Data Fetching (fetched once, used by all blocks)
318
422
  // ====================================================================
319
423
  async fetchRecommendationCreateData() {
@@ -327,7 +431,7 @@ const L = () => ({
327
431
  activePredictiveAlgorithms: t,
328
432
  languages: e,
329
433
  currencies: r
330
- } = await h.fetchRecommendationCreateData();
434
+ } = await l.fetchRecommendationCreateData();
331
435
  if (this.activePredictiveAlgorithms = t, this.languages = e, this.currentRecommendationId !== null && this.blockStates[this.currentRecommendationId]) {
332
436
  const n = this.blockStates[this.currentRecommendationId];
333
437
  n.filterStatus = !!n.recommendationConfigs.filters.length;
@@ -348,7 +452,7 @@ const L = () => ({
348
452
  return;
349
453
  }
350
454
  u = (async () => {
351
- const t = await h.fetchRecommendationFilters();
455
+ const t = await l.fetchRecommendationFilters();
352
456
  this.filterList = t;
353
457
  })();
354
458
  try {
@@ -369,10 +473,10 @@ const L = () => ({
369
473
  deleteFilterGroup(t) {
370
474
  if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
371
475
  return;
372
- const e = this.blockStates[this.currentRecommendationId], r = e.recommendationConfigs.filters.filter((i) => i.filterGroup !== t), n = [...new Set(r.map((i) => i.filterGroup))].sort((i, o) => i - o), c = new Map(n.map((i, o) => [i, o + 1]));
476
+ const e = this.blockStates[this.currentRecommendationId], r = e.recommendationConfigs.filters.filter((i) => i.filterGroup !== t), n = [...new Set(r.map((i) => i.filterGroup))].sort((i, o) => i - o), s = new Map(n.map((i, o) => [i, o + 1]));
373
477
  e.recommendationConfigs.filters = r.map((i) => ({
374
478
  ...i,
375
- filterGroup: c.get(i.filterGroup) ?? i.filterGroup
479
+ filterGroup: s.get(i.filterGroup) ?? i.filterGroup
376
480
  }));
377
481
  },
378
482
  updateFilter(t) {
@@ -383,7 +487,7 @@ const L = () => ({
383
487
  const n = [...e.recommendationConfigs.filters];
384
488
  n[r] = {
385
489
  ...t,
386
- isValid: N(t)
490
+ isValid: L(t)
387
491
  }, e.recommendationConfigs.filters = n;
388
492
  }
389
493
  },
@@ -397,10 +501,10 @@ const L = () => ({
397
501
  let i = 1;
398
502
  n = n.map((o) => o.filterGroup === t.filterGroup ? { ...o, filterNumber: i++ } : o);
399
503
  } else {
400
- const i = [...new Set(n.map((s) => s.filterGroup))].sort((s, a) => s - a), o = new Map(i.map((s, a) => [s, a + 1]));
401
- n = n.map((s) => ({
402
- ...s,
403
- filterGroup: o.get(s.filterGroup) ?? s.filterGroup
504
+ const i = [...new Set(n.map((a) => a.filterGroup))].sort((a, c) => a - c), o = new Map(i.map((a, c) => [a, c + 1]));
505
+ n = n.map((a) => ({
506
+ ...a,
507
+ filterGroup: o.get(a.filterGroup) ?? a.filterGroup
404
508
  }));
405
509
  }
406
510
  e.recommendationConfigs.filters = n;
@@ -409,15 +513,15 @@ const L = () => ({
409
513
  addFilter(t) {
410
514
  if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
411
515
  return;
412
- const e = this.blockStates[this.currentRecommendationId], r = [...e.recommendationConfigs.filters], c = r.filter(
516
+ const e = this.blockStates[this.currentRecommendationId], r = [...e.recommendationConfigs.filters], s = r.filter(
413
517
  (o) => o.filterGroup === t.filterGroup
414
518
  ).length + 1, i = r.findLastIndex((o) => o.filterGroup === t.filterGroup);
415
519
  i !== -1 ? r.splice(i + 1, 0, {
416
520
  ...t,
417
- filterNumber: c
521
+ filterNumber: s
418
522
  }) : r.push({
419
523
  ...t,
420
- filterNumber: c
524
+ filterNumber: s
421
525
  }), e.recommendationConfigs.filters = r;
422
526
  },
423
527
  generateFilterQuery() {
@@ -449,8 +553,13 @@ const L = () => ({
449
553
  }
450
554
  },
451
555
  async _doFetchProducts() {
452
- var p;
453
- const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, n = r.filters.filter((l) => l.isValid), c = b(n), i = ((p = g().find((l) => l.key === r.strategy)) == null ? void 0 : p.path) || "", o = G(), s = parseInt(r.size) || 6, a = {
556
+ var S;
557
+ const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e;
558
+ if (r.strategyId) {
559
+ await this._doFetchStrategyProducts(t);
560
+ return;
561
+ }
562
+ const n = r.filters.filter((g) => g.isValid), s = b(n), i = ((S = p().find((g) => g.key === r.strategy)) == null ? void 0 : S.path) || "", o = P(), a = parseInt(r.size) || 6, c = {
454
563
  locale: r.language,
455
564
  currency: r.currencySettings.value,
456
565
  partnerName: o.partnerName,
@@ -458,26 +567,64 @@ const L = () => ({
458
567
  details: !0,
459
568
  campaignId: o.variationId
460
569
  };
461
- 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(
462
- a,
463
- v(o.partnerName, r.strategy)
570
+ r.strategy === "manualMerchandising" ? c.productId = N(r.productIds) : r.strategy === "similarViewed" && (c.productId = "{itemId}"), r.strategy === "userBased" && (c.userId = "{user_id}"), s && (c.filter = s), r.shuffleProducts && (c.shuffle = !0), Object.assign(
571
+ c,
572
+ U(o.partnerName, r.strategy)
464
573
  );
465
- let f;
574
+ let h;
466
575
  try {
467
- f = await h.fetchRecommendationProducts(i, a);
576
+ h = await l.fetchRecommendationProducts(i, c);
468
577
  } catch {
469
- f = [];
578
+ h = [];
470
579
  }
471
- if (this.blockStates[t]) {
472
- const l = f.length > 0 ? f : S(s);
473
- l.length < s ? this.blockStates[t].recommendationProducts = [
474
- ...l,
475
- ...S(s - l.length)
476
- ] : l.length > s ? this.blockStates[t].recommendationProducts = l.slice(0, s) : this.blockStates[t].recommendationProducts = l;
580
+ this._setBlockProducts(t, h, a);
581
+ },
582
+ /**
583
+ * Fetches products for a strategy-backed block: listing lookup →
584
+ * endpoint-generate template → fill {locale}/{currency}, drop
585
+ * {user_id} (resolved at send time) → fetch. Any failure (dead
586
+ * strategy, resolution error) falls back to placeholder products.
587
+ */
588
+ async _doFetchStrategyProducts(t) {
589
+ const { recommendationConfigs: e } = this.blockStates[t];
590
+ let r = [], n = parseInt(e.size) || 6;
591
+ try {
592
+ this.strategies.length || await this.fetchStrategies();
593
+ const s = this.strategies.find(
594
+ (i) => String(i.strategy_id) === e.strategyId
595
+ );
596
+ if (s) {
597
+ n = parseInt(String(s.size ?? "")) || n;
598
+ const i = await this.resolveStrategyUrlTemplate(s), o = new URL(
599
+ i.replaceAll("{locale}", e.language).replaceAll("{currency}", e.currencySettings.value)
600
+ );
601
+ o.searchParams.delete("user_id"), r = await l.fetchRecommendationProductsByUrl(o.toString());
602
+ }
603
+ } catch {
604
+ r = [];
477
605
  }
606
+ this._setBlockProducts(t, r, n);
607
+ },
608
+ /**
609
+ * Writes products to a block's state, padded/clipped to `size` so
610
+ * in-place content updates (which compare DOM element count vs
611
+ * products.length) succeed:
612
+ * - API returned nothing → fill entirely with defaults
613
+ * - fewer than requested → pad with dummies
614
+ * - more than requested → clip, preventing the renderer from extending
615
+ * its slot grid (which would reset migrator-applied styles).
616
+ */
617
+ _setBlockProducts(t, e, r) {
618
+ if (!this.blockStates[t])
619
+ return;
620
+ const n = e.length > 0 ? e : y(r);
621
+ n.length < r ? this.blockStates[t].recommendationProducts = [
622
+ ...n,
623
+ ...y(r - n.length)
624
+ ] : n.length > r ? this.blockStates[t].recommendationProducts = n.slice(0, r) : this.blockStates[t].recommendationProducts = n;
478
625
  }
479
626
  }
480
627
  });
481
628
  export {
482
- $ as useRecommendationExtensionStore
629
+ Q as useRecommendationExtensionStore
483
630
  };
@@ -0,0 +1,6 @@
1
+ function n(t) {
2
+ return t.map((i) => String(i ?? "").trim()).filter(Boolean).join(",");
3
+ }
4
+ export {
5
+ n as sanitizeProductIds
6
+ };
@@ -1,12 +1,12 @@
1
1
  var c = Object.defineProperty;
2
- var i = (s, r, e) => r in s ? c(s, r, { enumerable: !0, configurable: !0, writable: !0, value: e }) : s[r] = e;
3
- var u = (s, r, e) => i(s, typeof r != "symbol" ? r + "" : r, e);
2
+ var i = (l, a, e) => a in l ? c(l, a, { enumerable: !0, configurable: !0, writable: !0, value: e }) : l[a] = e;
3
+ var T = (l, a, e) => i(l, typeof a != "symbol" ? a + "" : a, e);
4
4
  import { Control as I, UIElementType as n, UEAttr as $ } from "../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
5
- class d extends I {
5
+ class _ extends I {
6
6
  constructor() {
7
7
  super(...arguments);
8
- u(this, "currentNode");
9
- u(this, "lastBlockInstanceId", null);
8
+ T(this, "currentNode");
9
+ T(this, "lastBlockInstanceId", null);
10
10
  }
11
11
  getContainer() {
12
12
  var e;
@@ -91,21 +91,21 @@ class d extends I {
91
91
  * and combines it with the text in Stripo's alert-message layout.
92
92
  */
93
93
  _setInfoMessageValue(e, t) {
94
- const E = this.getContainer(), o = E.querySelector(`[data-icon-key="${e}"]`), a = o == null ? void 0 : o.querySelector("ue-icon-component"), l = (a == null ? void 0 : a.outerHTML) ?? "";
94
+ const E = this.getContainer(), o = E.querySelector(`[data-icon-key="${e}"]`), r = o == null ? void 0 : o.querySelector("ue-icon-component"), s = (r == null ? void 0 : r.outerHTML) ?? "";
95
95
  this.api.setUIEAttribute(
96
96
  e,
97
97
  "value",
98
98
  `
99
99
  <div class="service-element alert-message-main" style="align-items: start;">
100
- ${l}
100
+ ${s}
101
101
  <div class="service-element alert-message-text">
102
102
  ${t}
103
103
  </div>
104
104
  </div>
105
105
  `
106
106
  );
107
- const T = E.querySelector(`[data-info-message="${e}"]`);
108
- T && (T.style.display = "");
107
+ const u = E.querySelector(`[data-info-message="${e}"]`);
108
+ u && (u.style.display = "");
109
109
  }
110
110
  _GuToggle(e) {
111
111
  return `
@@ -126,15 +126,15 @@ class d extends I {
126
126
  placeholder: t,
127
127
  options: E,
128
128
  className: o = "es-180w",
129
- searchable: a = !1
129
+ searchable: r = !1
130
130
  }) {
131
131
  return `
132
132
  <${n.SELECTPICKER}
133
133
  class="${o}"
134
134
  ${$.SELECTPICKER.name}="${e}"
135
- ${a ? `${$.SELECTPICKER.searchable}="true"` : ""}
135
+ ${r ? `${$.SELECTPICKER.searchable}="true"` : ""}
136
136
  ${$.SELECTPICKER.placeholder}="${t}">
137
- ${E.map((l) => this._GuSelectItem(l)).join("")}
137
+ ${E.map((s) => this._GuSelectItem(s)).join("")}
138
138
  </${n.SELECTPICKER}>
139
139
  `;
140
140
  }
@@ -176,12 +176,15 @@ class d extends I {
176
176
  </${n.RADIO_BUTTONS}>
177
177
  `;
178
178
  }
179
- _GuButton({ name: e, label: t, id: E = "" }) {
179
+ _GuButton({ name: e, label: t, id: E = "", className: o = "", icon: r = "", disabled: s = !1 }) {
180
180
  return `
181
181
  <${n.BUTTON}
182
182
  ${$.BUTTON.name}="${e}"
183
183
  ${E ? `id="${E}"` : ""}
184
- ${$.BUTTON.caption}="${t}"}>
184
+ ${o ? `class="${o}"` : ""}
185
+ ${r ? `${$.BUTTON.icon}="${r}"` : ""}
186
+ ${s ? `${$.BUTTON.disabled}="true"` : ""}
187
+ ${$.BUTTON.caption}="${t}">
185
188
  </${n.BUTTON}>
186
189
  `;
187
190
  }
@@ -230,11 +233,11 @@ class d extends I {
230
233
  */
231
234
  _GuOrderable(e, t) {
232
235
  let E = "";
233
- t.forEach((a) => {
234
- const l = $.ORDERABLE_ITEM && "name" in $.ORDERABLE_ITEM ? $.ORDERABLE_ITEM.name : "name";
236
+ t.forEach((r) => {
237
+ const s = $.ORDERABLE_ITEM && "name" in $.ORDERABLE_ITEM ? $.ORDERABLE_ITEM.name : "name";
235
238
  E += `
236
- <${n.ORDERABLE_ITEM} ${l}="${a.key}">
237
- ${a.content}
239
+ <${n.ORDERABLE_ITEM} ${s}="${r.key}">
240
+ ${r.content}
238
241
  </${n.ORDERABLE_ITEM}>
239
242
  `;
240
243
  });
@@ -305,5 +308,5 @@ class d extends I {
305
308
  }
306
309
  }
307
310
  export {
308
- d as CommonControl
311
+ _ as CommonControl
309
312
  };