@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,16 +1,16 @@
1
- import { DEFAULT_COLUMN_SPACING as n, DEFAULT_ROW_SPACING as s, DEFAULT_MOBILE_ROW_SPACING as R, DEFAULT_MOBILE_COLUMN_SPACING as U, DEFAULT_MOBILE_CARDS_IN_ROW as e, DEFAULT_CARDS_IN_ROW as C } from "./layout.js";
1
+ import { DEFAULT_COLUMN_SPACING as n, DEFAULT_ROW_SPACING as s, DEFAULT_MOBILE_ROW_SPACING as R, DEFAULT_MOBILE_COLUMN_SPACING as U, DEFAULT_MOBILE_CARDS_IN_ROW as e, DEFAULT_CARDS_IN_ROW as a } from "./layout.js";
2
2
  import { ATTR_PRODUCT_IMAGE as o, ATTR_PRODUCT_NAME as t, ATTR_PRODUCT_OLD_PRICE as _, ATTR_PRODUCT_PRICE as T, ATTR_PRODUCT_OMNIBUS_PRICE as r, ATTR_PRODUCT_OMNIBUS_DISCOUNT as i, ATTR_PRODUCT_BUTTON as I } from "./selectors.js";
3
- const D = {
3
+ const C = {
4
4
  code: "USD",
5
5
  symbol: "USD",
6
6
  alignment: "after",
7
7
  decimalCount: 2,
8
8
  decimalSeparator: ".",
9
9
  thousandSeparator: ","
10
- }, O = {
10
+ }, D = {
11
11
  textBefore: "",
12
12
  textAfter: ""
13
- }, a = {
13
+ }, O = {
14
14
  textBefore: "",
15
15
  textAfter: ""
16
16
  }, A = [
@@ -36,11 +36,13 @@ const D = {
36
36
  size: "6",
37
37
  shuffleProducts: !1,
38
38
  language: "en_US",
39
- currency: D,
39
+ currency: C,
40
40
  filters: [],
41
+ // Version NOT bumped: mergeWithDefaults() backfills '' for older configs.
42
+ strategyId: "",
41
43
  // Layout
42
44
  layout: "grid",
43
- cardsInRow: C,
45
+ cardsInRow: a,
44
46
  mobileCardsInRow: e,
45
47
  mobileLayoutEnabled: !1,
46
48
  previousMobileCardsInRow: e,
@@ -52,8 +54,8 @@ const D = {
52
54
  composition: A,
53
55
  visibility: c,
54
56
  // Element settings
55
- omnibusPrice: O,
56
- omnibusDiscount: a,
57
+ omnibusPrice: D,
58
+ omnibusDiscount: O,
57
59
  textTrimming: !1,
58
60
  // Price placement (block-level, affects all cards)
59
61
  // Default ON = current stacked look, so existing templates are unaffected.
@@ -71,10 +73,10 @@ const D = {
71
73
  export {
72
74
  m as CURRENT_CONFIG_VERSION,
73
75
  A as DEFAULT_COMPOSITION,
74
- D as DEFAULT_CURRENCY,
76
+ C as DEFAULT_CURRENCY,
75
77
  l as DEFAULT_NODE_CONFIG,
76
- a as DEFAULT_OMNIBUS_DISCOUNT,
77
- O as DEFAULT_OMNIBUS_PRICE,
78
+ O as DEFAULT_OMNIBUS_DISCOUNT,
79
+ D as DEFAULT_OMNIBUS_PRICE,
78
80
  c as DEFAULT_VISIBILITY,
79
81
  N as EXCLUDED_ALGORITHM_IDS
80
82
  };
@@ -1,23 +1,23 @@
1
- var c = Object.defineProperty;
2
- var l = (s, o, t) => o in s ? c(s, o, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[o] = t;
3
- var a = (s, o, t) => l(s, typeof o != "symbol" ? o + "" : o, t);
4
- import { UEAttr as h } from "../../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
5
- import { CommonControl as d } from "../../../common-control.js";
1
+ var d = Object.defineProperty;
2
+ var h = (r, s, t) => s in r ? d(r, s, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[s] = t;
3
+ var c = (r, s, t) => h(r, typeof s != "symbol" ? s + "" : s, t);
4
+ import { UEAttr as l } from "../../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
5
+ import { CommonControl as g } from "../../../common-control.js";
6
6
  import { RecommendationConfigService as n } from "../../services/configService.js";
7
7
  import { useRecommendationExtensionStore as m } from "../../store/recommendation.js";
8
- import { mapLegacyStrategy as g } from "../../utils/legacyStrategyMap.js";
9
- const u = "recommendation-algorithm-control", i = {
8
+ import { mapLegacyStrategy as u } from "../../utils/legacyStrategyMap.js";
9
+ const p = "recommendation-algorithm-control", i = {
10
10
  ALGORITHM: "strategy",
11
11
  PRODUCT_IDS: "productIds"
12
12
  };
13
- class R extends d {
13
+ class R extends g {
14
14
  constructor() {
15
15
  super(...arguments);
16
16
  // Store is used ONLY for API-fetched data (algorithms list), not for config
17
- a(this, "store", m());
17
+ c(this, "store", m());
18
18
  }
19
19
  getId() {
20
- return u;
20
+ return p;
21
21
  }
22
22
  getTemplate() {
23
23
  return `
@@ -46,11 +46,10 @@ class R extends d {
46
46
  super.onTemplateNodeUpdated(t), this._initializeSelectItems(), this._setFormValues();
47
47
  }
48
48
  _setFormValues() {
49
- const t = n.getConfig(this.currentNode), e = g(t.strategy) ?? t.strategy;
50
- this._setProductIdsVisibility(e), this.api.updateValues({
51
- [i.ALGORITHM]: e,
52
- [i.PRODUCT_IDS]: t.productIds.join(",")
53
- });
49
+ const t = n.getConfig(this.currentNode), e = u(t.strategy) ?? t.strategy;
50
+ this._setProductIdsVisibility(e);
51
+ const o = { [i.ALGORITHM]: e }, a = t.productIds.join(",");
52
+ this.api.getValues()[i.PRODUCT_IDS] !== a && (o[i.PRODUCT_IDS] = a), this.api.updateValues(o);
54
53
  }
55
54
  _initializeSelectItems() {
56
55
  var e;
@@ -59,35 +58,47 @@ class R extends d {
59
58
  try {
60
59
  this.api.setUIEAttribute(
61
60
  i.ALGORITHM,
62
- h.SELECTPICKER.items,
61
+ l.SELECTPICKER.items,
63
62
  t
64
63
  );
65
- } catch (r) {
66
- console.warn("[AlgorithmControl] Failed to set algorithm options:", r);
64
+ } catch (o) {
65
+ console.warn("[AlgorithmControl] Failed to set algorithm options:", o);
67
66
  }
68
67
  }
69
68
  _setProductIdsVisibility(t) {
70
- const r = (t ?? n.getConfig(this.currentNode).strategy) === "manualMerchandising";
71
- this.api.setVisibility(i.PRODUCT_IDS, r), this.api.setVisibility(`${i.PRODUCT_IDS}_label`, r);
69
+ const o = (t ?? n.getConfig(this.currentNode).strategy) === "manualMerchandising";
70
+ this.api.setVisibility(i.PRODUCT_IDS, o), this.api.setVisibility(`${i.PRODUCT_IDS}_label`, o);
72
71
  }
73
72
  _onAlgorithmChange(t) {
74
- !this.currentNode || n.getConfig(this.currentNode).strategy === t || (n.updateConfig(
73
+ if (!this.currentNode)
74
+ return;
75
+ const e = n.getConfig(this.currentNode);
76
+ if (e.strategy === t) {
77
+ this.store.recommendationConfigs.strategy !== t && this.store.patchCurrentBlockConfig({ strategy: e.strategy, filters: e.filters });
78
+ return;
79
+ }
80
+ n.updateConfig(
75
81
  this.api,
76
82
  this.currentNode,
77
83
  { strategy: t },
78
84
  `Changed algorithm to ${t}`
79
- ), this.store.patchCurrentBlockConfig({ strategy: t }), this._setProductIdsVisibility(t));
85
+ ), this.store.patchCurrentBlockConfig({ strategy: t }), this._setProductIdsVisibility(t);
80
86
  }
81
87
  _onProductIdsChange(t) {
82
88
  if (!this.currentNode)
83
89
  return;
84
- const e = t.split(",").map((r) => r.trim()).filter(Boolean);
90
+ const e = n.getConfig(this.currentNode);
91
+ if (e.productIds.join(",") === t) {
92
+ this.store.recommendationConfigs.productIds.join(",") !== t && this.store.patchCurrentBlockConfig({ productIds: e.productIds, filters: e.filters });
93
+ return;
94
+ }
95
+ const o = t === "" ? [] : t.split(",");
85
96
  n.updateConfig(
86
97
  this.api,
87
98
  this.currentNode,
88
- { productIds: e },
99
+ { productIds: o },
89
100
  "Updated product IDs"
90
- ), this.store.patchCurrentBlockConfig({ productIds: e });
101
+ ), this.store.patchCurrentBlockConfig({ productIds: o });
91
102
  }
92
103
  _listenToFormUpdates() {
93
104
  this.api.onValueChanged(i.ALGORITHM, (t) => {
@@ -98,6 +109,6 @@ class R extends d {
98
109
  }
99
110
  }
100
111
  export {
101
- u as ALGORITHM_CONTROL_ID,
112
+ p as ALGORITHM_CONTROL_ID,
102
113
  R as AlgorithmControl
103
114
  };
@@ -1,36 +1,39 @@
1
1
  var f = Object.defineProperty;
2
- var p = (d, l, t) => l in d ? f(d, l, { enumerable: !0, configurable: !0, writable: !0, value: t }) : d[l] = t;
3
- var s = (d, l, t) => p(d, typeof l != "symbol" ? l + "" : l, t);
4
- import { CommonControl as g } from "../../../common-control.js";
5
- import { DEFAULT_NODE_CONFIG as c } from "../../constants/defaultConfig.js";
2
+ var g = (d, a, t) => a in d ? f(d, a, { enumerable: !0, configurable: !0, writable: !0, value: t }) : d[a] = t;
3
+ var s = (d, a, t) => g(d, typeof a != "symbol" ? a + "" : a, t);
4
+ import { useConfig as p } from "../../../../../composables/useConfig.js";
5
+ import { CommonControl as y } from "../../../common-control.js";
6
+ import { DEFAULT_NODE_CONFIG as l } from "../../constants/defaultConfig.js";
6
7
  import { RecommendationConfigService as m } from "../../services/configService.js";
7
- import { useRecommendationExtensionStore as y } from "../../store/recommendation.js";
8
- import { AlgorithmControl as N } from "./algorithm.js";
9
- import { ALGORITHM_CONTROL_ID as tt } from "./algorithm.js";
8
+ import { useRecommendationExtensionStore as N } from "../../store/recommendation.js";
9
+ import { AlgorithmControl as I } from "./algorithm.js";
10
+ import { ALGORITHM_CONTROL_ID as nt } from "./algorithm.js";
10
11
  import { CurrencyControl as R } from "./currency.js";
11
- import { CURRENCY_CONTROL_ID as ot } from "./currency.js";
12
- import { FiltersControl as I } from "./filters.js";
13
- import { FILTERS_CONTROL_ID as nt } from "./filters.js";
14
- import { LayoutOrientationControl as _ } from "./layoutOrientation.js";
15
- import { LAYOUT_ORIENTATION_CONTROL_ID as st } from "./layoutOrientation.js";
16
- import { LocaleControl as b } from "./locale.js";
17
- import { LOCALE_CONTROL_ID as lt } from "./locale.js";
18
- import { PricePlacementControl as T } from "./pricePlacement.js";
19
- import { PRICE_PLACEMENT_CONTROL_ID as ut } from "./pricePlacement.js";
12
+ import { CURRENCY_CONTROL_ID as st } from "./currency.js";
13
+ import { FiltersControl as T } from "./filters.js";
14
+ import { FILTERS_CONTROL_ID as at } from "./filters.js";
15
+ import { LayoutOrientationControl as b } from "./layoutOrientation.js";
16
+ import { LAYOUT_ORIENTATION_CONTROL_ID as ut } from "./layoutOrientation.js";
17
+ import { LocaleControl as _ } from "./locale.js";
18
+ import { LOCALE_CONTROL_ID as mt } from "./locale.js";
19
+ import { PricePlacementControl as O } from "./pricePlacement.js";
20
+ import { PRICE_PLACEMENT_CONTROL_ID as Ct } from "./pricePlacement.js";
20
21
  import { ProductCountControl as P } from "./productCount.js";
21
- import { PRODUCT_COUNT_CONTROL_ID as mt } from "./productCount.js";
22
- import { ProductLayoutControl as O } from "./productLayout.js";
23
- import { PRODUCT_LAYOUT_CONTROL_ID as Ct } from "./productLayout.js";
22
+ import { PRODUCT_COUNT_CONTROL_ID as gt } from "./productCount.js";
23
+ import { ProductLayoutControl as S } from "./productLayout.js";
24
+ import { PRODUCT_LAYOUT_CONTROL_ID as yt } from "./productLayout.js";
24
25
  import { ShuffleControl as L } from "./shuffle.js";
25
- import { SHUFFLE_CONTROL_ID as pt } from "./shuffle.js";
26
- import { setCurrencyAttributes as S, getBlockElement as k, isPartnerManagedBlock as D, updateProductContentInPlace as E, regenerateProductRowsWithStyles as A } from "./utils.js";
27
- import { adjustProductsToSize as yt, formatProductPrice as Nt, getCardComposition as Rt, getCurrentLayout as It, regenerateMobileProductRows as _t, updatePricesInPlace as bt, updateSingleProductContent as Tt } from "./utils.js";
26
+ import { SHUFFLE_CONTROL_ID as It } from "./shuffle.js";
27
+ import { StrategyControl as k } from "./strategy.js";
28
+ import { STRATEGY_CONTROL_ID as Tt } from "./strategy.js";
29
+ import { setCurrencyAttributes as D, getBlockElement as E, isPartnerManagedBlock as v, updateProductContentInPlace as A, regenerateProductRowsWithStyles as w } from "./utils.js";
30
+ import { adjustProductsToSize as _t, formatProductPrice as Ot, getCardComposition as Pt, getCurrentLayout as St, regenerateMobileProductRows as Lt, updatePricesInPlace as kt, updateSingleProductContent as Dt } from "./utils.js";
28
31
  import { useDebounceFn as h } from "../../../../../node_modules/@vueuse/shared/index.js";
29
- const v = "recommendation-id", w = "ui-elements-recommendation-block";
30
- class Q extends g {
32
+ const x = "recommendation-id", B = "ui-elements-recommendation-block";
33
+ class et extends y {
31
34
  constructor() {
32
35
  super(...arguments);
33
- s(this, "store", y());
36
+ s(this, "store", N());
34
37
  s(this, "storeUnsubscription", () => {
35
38
  });
36
39
  s(this, "syncedBlockIds", /* @__PURE__ */ new Set());
@@ -44,6 +47,7 @@ class Q extends g {
44
47
  s(this, "shuffleControl", null);
45
48
  s(this, "pricePlacementControl", null);
46
49
  s(this, "layoutOrientationControl", null);
50
+ s(this, "strategyControl", null);
47
51
  /**
48
52
  * Debounced product fetch to prevent rapid API calls during config changes
49
53
  */
@@ -63,14 +67,14 @@ class Q extends g {
63
67
  */
64
68
  s(this, "_debouncedRegenerateWithProducts", h(() => {
65
69
  const t = this.store.recommendationProducts;
66
- if (!this.currentNode || !this.api || D(this.currentNode))
70
+ if (!this.currentNode || !this.api || v(this.currentNode))
67
71
  return;
68
72
  const e = this.api.getDocumentModifier();
69
- E({
73
+ A({
70
74
  currentNode: this.currentNode,
71
75
  documentModifier: e,
72
76
  products: t
73
- }) || A({
77
+ }) || w({
74
78
  currentNode: this.currentNode,
75
79
  documentModifier: e,
76
80
  products: t
@@ -78,10 +82,11 @@ class Q extends g {
78
82
  }, 100));
79
83
  }
80
84
  getId() {
81
- return w;
85
+ return B;
82
86
  }
83
87
  getTemplate() {
84
- return this.algorithmControl = new N(), this.localeControl = new b(), this.currencyControl = new R(), this.productCountControl = new P(), this.productLayoutControl = new O(), this.filtersControl = new I(), this.shuffleControl = new L(), this.pricePlacementControl = new T(), this.layoutOrientationControl = new _(), [
88
+ const t = p().isFeatureEnabled("reusableRecommendationStrategy");
89
+ return this.algorithmControl = t ? null : new I(), this.localeControl = new _(), this.currencyControl = new R(), this.productCountControl = t ? null : new P(), this.productLayoutControl = new S(), this.filtersControl = t ? null : new T(), this.shuffleControl = t ? null : new L(), this.pricePlacementControl = new O(), this.layoutOrientationControl = new b(), this.strategyControl = t ? new k() : null, [
85
90
  this.algorithmControl,
86
91
  this.localeControl,
87
92
  this.currencyControl,
@@ -90,10 +95,20 @@ class Q extends g {
90
95
  this.filtersControl,
91
96
  this.shuffleControl,
92
97
  this.pricePlacementControl,
93
- this.layoutOrientationControl
94
- ].forEach((e) => {
95
- e.api = this.api;
96
- }), `
98
+ this.layoutOrientationControl,
99
+ this.strategyControl
100
+ ].forEach((o) => {
101
+ o && (o.api = this.api);
102
+ }), t ? `
103
+ <div class="recommendation-controls-container">
104
+ ${this.strategyControl.getTemplate()}
105
+ ${this.layoutOrientationControl.getTemplate()}
106
+ ${this.localeControl.getTemplate()}
107
+ ${this.currencyControl.getTemplate()}
108
+ ${this.pricePlacementControl.getTemplate()}
109
+ ${this.productLayoutControl.getTemplate()}
110
+ </div>
111
+ ` : `
97
112
  <div class="recommendation-controls-container">
98
113
  ${this.layoutOrientationControl.getTemplate()}
99
114
  ${this.productCountControl.getTemplate()}
@@ -131,7 +146,8 @@ class Q extends g {
131
146
  this.productLayoutControl,
132
147
  this.filtersControl,
133
148
  this.shuffleControl,
134
- this.pricePlacementControl
149
+ this.pricePlacementControl,
150
+ this.strategyControl
135
151
  ].forEach((n) => {
136
152
  var i;
137
153
  n != null && n.api && (n.currentNode = t, (i = n.onTemplateNodeUpdated) == null || i.call(n, t));
@@ -147,7 +163,8 @@ class Q extends g {
147
163
  this.productLayoutControl,
148
164
  this.filtersControl,
149
165
  this.shuffleControl,
150
- this.pricePlacementControl
166
+ this.pricePlacementControl,
167
+ this.strategyControl
151
168
  ].forEach((e) => {
152
169
  var o;
153
170
  return (o = e == null ? void 0 : e.onDestroy) == null ? void 0 : o.call(e);
@@ -167,7 +184,8 @@ class Q extends g {
167
184
  this.productLayoutControl,
168
185
  this.filtersControl,
169
186
  this.shuffleControl,
170
- this.pricePlacementControl
187
+ this.pricePlacementControl,
188
+ this.strategyControl
171
189
  ].forEach((e) => {
172
190
  var o;
173
191
  e && (e.api = this.api, e.currentNode = this.currentNode, (o = e.onRender) == null || o.call(e));
@@ -189,6 +207,7 @@ class Q extends g {
189
207
  const t = m.getConfig(this.currentNode), e = this.store.currentRecommendationId, o = e !== null && ((r = this.store.blockStates[e]) == null ? void 0 : r.isInitialized);
190
208
  this.store.patchCurrentBlockConfig({
191
209
  strategy: t.strategy,
210
+ strategyId: t.strategyId,
192
211
  language: t.language,
193
212
  size: t.size,
194
213
  productIds: t.productIds,
@@ -251,26 +270,26 @@ class Q extends g {
251
270
  return;
252
271
  const t = m.getConfig(this.currentNode), e = {};
253
272
  let o = null, r = null, n = null;
254
- if (t.currency.code === c.currency.code) {
273
+ if (t.currency.code === l.currency.code) {
255
274
  const { currencyList: i } = this.store;
256
275
  i.length > 0 && (i.some(
257
- (u) => u.value === `price.${c.currency.code}`
276
+ (u) => u.value === `price.${l.currency.code}`
258
277
  ) || (o = i[0].value.replace("price.", ""), e.currency = {
259
- ...c.currency,
278
+ ...l.currency,
260
279
  code: o,
261
280
  symbol: o
262
281
  }));
263
282
  }
264
- if (t.strategy === c.strategy) {
283
+ if (t.strategy === l.strategy) {
265
284
  const i = this.store.getActivePredictiveAlgorithms;
266
285
  i.length > 0 && (i.some(
267
- (u) => u.value === c.strategy
286
+ (u) => u.value === l.strategy
268
287
  ) || (r = i[0].value, e.strategy = r));
269
288
  }
270
- if (t.language === c.language) {
289
+ if (t.language === l.language) {
271
290
  const i = this.store.getLanguages;
272
291
  i.length > 0 && (i.some(
273
- (u) => u.value === c.language
292
+ (u) => u.value === l.language
274
293
  ) || (n = i[0].value, e.language = n));
275
294
  }
276
295
  !o && !r && !n || (m.updateConfig(
@@ -278,7 +297,7 @@ class Q extends g {
278
297
  this.currentNode,
279
298
  e,
280
299
  "Applied smart defaults"
281
- ), o && e.currency && S({
300
+ ), o && e.currency && D({
282
301
  currentNode: this.currentNode,
283
302
  documentModifier: this.api.getDocumentModifier(),
284
303
  currency: e.currency
@@ -288,10 +307,10 @@ class Q extends g {
288
307
  name: o,
289
308
  value: o,
290
309
  symbol: o,
291
- alignment: c.currency.alignment === "before" ? "0" : "1",
292
- decimalCount: c.currency.decimalCount.toString(),
293
- decimalSeparator: c.currency.decimalSeparator,
294
- thousandSeparator: c.currency.thousandSeparator
310
+ alignment: l.currency.alignment === "before" ? "0" : "1",
311
+ decimalCount: l.currency.decimalCount.toString(),
312
+ decimalSeparator: l.currency.decimalSeparator,
313
+ thousandSeparator: l.currency.thousandSeparator
295
314
  }
296
315
  } : {},
297
316
  ...r ? { strategy: r } : {},
@@ -302,10 +321,10 @@ class Q extends g {
302
321
  * Reads the recommendation-id attribute from the block element within the node
303
322
  */
304
323
  _getRecommendationIdFromNode(t) {
305
- const e = k(t);
324
+ const e = E(t);
306
325
  if (!e || !("getAttribute" in e))
307
326
  return null;
308
- const o = e.getAttribute(v);
327
+ const o = e.getAttribute(x);
309
328
  if (!o)
310
329
  return null;
311
330
  const r = parseInt(o);
@@ -335,57 +354,66 @@ class Q extends g {
335
354
  }
336
355
  const i = t.$state.configVersion;
337
356
  i !== o && (o = i, this._persistFiltersToNodeConfig(), this._debouncedFetchProducts());
338
- const a = t.recommendationProducts, u = a !== e, C = Array.isArray(a) && a.length > 0;
339
- u && C && (e = a, this._debouncedRegenerateWithProducts());
357
+ const c = t.recommendationProducts, u = c !== e, C = Array.isArray(c) && c.length > 0;
358
+ u && C && (e = c, this._debouncedRegenerateWithProducts());
340
359
  });
341
360
  }
342
361
  /**
343
- * Persists the current filter state from Pinia store to the Stripo node config.
344
- * This ensures filters survive template save/reload cycles.
362
+ * Persists the current filter + strategy state from Pinia store to the
363
+ * Stripo node config. This ensures they survive template save/reload cycles
364
+ * (strategyId must be in esd-ext-config before any save — SD-149105).
365
+ *
366
+ * `size` rides along because assigning a strategy overwrites it in the
367
+ * store only. Without this write, `_syncNodeConfigToStore` re-seeds the
368
+ * store from the stale node config on the next panel open, and a block
369
+ * whose saved HTML has the strategy's slot count gets rebuilt against the
370
+ * old one — resetting migrator-applied per-element styles.
345
371
  */
346
372
  _persistFiltersToNodeConfig() {
347
373
  if (!this.currentNode || !this.api)
348
374
  return;
349
- const { filters: t } = this.store.recommendationConfigs;
350
- m.updateConfig(
375
+ const { filters: t, strategyId: e, size: o } = this.store.recommendationConfigs, r = m.getConfig(this.currentNode);
376
+ JSON.stringify(r.filters) === JSON.stringify(t) && r.strategyId === e && r.size === o || m.updateConfig(
351
377
  this.api,
352
378
  this.currentNode,
353
- { filters: t },
379
+ { filters: t, strategyId: e, size: o },
354
380
  "Update recommendation filters"
355
381
  );
356
382
  }
357
383
  }
358
384
  export {
359
- tt as ALGORITHM_CONTROL_ID,
360
- N as AlgorithmControl,
361
- w as CONTROL_BLOCK_ID,
362
- ot as CURRENCY_CONTROL_ID,
385
+ nt as ALGORITHM_CONTROL_ID,
386
+ I as AlgorithmControl,
387
+ B as CONTROL_BLOCK_ID,
388
+ st as CURRENCY_CONTROL_ID,
363
389
  R as CurrencyControl,
364
- nt as FILTERS_CONTROL_ID,
365
- I as FiltersControl,
366
- st as LAYOUT_ORIENTATION_CONTROL_ID,
367
- lt as LOCALE_CONTROL_ID,
368
- _ as LayoutOrientationControl,
369
- b as LocaleControl,
370
- ut as PRICE_PLACEMENT_CONTROL_ID,
371
- mt as PRODUCT_COUNT_CONTROL_ID,
372
- Ct as PRODUCT_LAYOUT_CONTROL_ID,
373
- T as PricePlacementControl,
390
+ at as FILTERS_CONTROL_ID,
391
+ T as FiltersControl,
392
+ ut as LAYOUT_ORIENTATION_CONTROL_ID,
393
+ mt as LOCALE_CONTROL_ID,
394
+ b as LayoutOrientationControl,
395
+ _ as LocaleControl,
396
+ Ct as PRICE_PLACEMENT_CONTROL_ID,
397
+ gt as PRODUCT_COUNT_CONTROL_ID,
398
+ yt as PRODUCT_LAYOUT_CONTROL_ID,
399
+ O as PricePlacementControl,
374
400
  P as ProductCountControl,
375
- O as ProductLayoutControl,
376
- Q as RecommendationBlockControl,
377
- pt as SHUFFLE_CONTROL_ID,
401
+ S as ProductLayoutControl,
402
+ et as RecommendationBlockControl,
403
+ It as SHUFFLE_CONTROL_ID,
404
+ Tt as STRATEGY_CONTROL_ID,
378
405
  L as ShuffleControl,
379
- yt as adjustProductsToSize,
380
- Nt as formatProductPrice,
381
- k as getBlockElement,
382
- Rt as getCardComposition,
383
- It as getCurrentLayout,
384
- D as isPartnerManagedBlock,
385
- _t as regenerateMobileProductRows,
386
- A as regenerateProductRowsWithStyles,
387
- S as setCurrencyAttributes,
388
- bt as updatePricesInPlace,
389
- E as updateProductContentInPlace,
390
- Tt as updateSingleProductContent
406
+ k as StrategyControl,
407
+ _t as adjustProductsToSize,
408
+ Ot as formatProductPrice,
409
+ E as getBlockElement,
410
+ Pt as getCardComposition,
411
+ St as getCurrentLayout,
412
+ v as isPartnerManagedBlock,
413
+ Lt as regenerateMobileProductRows,
414
+ w as regenerateProductRowsWithStyles,
415
+ D as setCurrencyAttributes,
416
+ kt as updatePricesInPlace,
417
+ A as updateProductContentInPlace,
418
+ Dt as updateSingleProductContent
391
419
  };
@@ -0,0 +1,132 @@
1
+ var d = Object.defineProperty;
2
+ var l = (n, a, t) => a in n ? d(n, a, { enumerable: !0, configurable: !0, writable: !0, value: t }) : n[a] = t;
3
+ var o = (n, a, t) => l(n, typeof a != "symbol" ? a + "" : a, t);
4
+ import { CommonControl as g } from "../../../common-control.js";
5
+ import { useRecommendationExtensionStore as y } from "../../store/recommendation.js";
6
+ const h = "recommendation-strategy-control", m = "https://academy.insiderone.com/docs/new-editor-email-recommendation-block";
7
+ class b extends g {
8
+ constructor() {
9
+ super(...arguments);
10
+ o(this, "store", y());
11
+ o(this, "storeUnsubscription", () => {
12
+ });
13
+ o(this, "listeners", []);
14
+ }
15
+ getId() {
16
+ return h;
17
+ }
18
+ getTemplate() {
19
+ const t = this.api.translate(
20
+ "You can assign a recommendation strategy by selecting an existing one or creating a new one to show specific content."
21
+ ), e = this.api.translate("For more information, you can"), s = this.api.translate("visit Academy");
22
+ return `
23
+ <div class="strategy-control-container">
24
+ <!-- A section heading, not a field label: the ue-label element renders
25
+ the panel's 13px field styling and the design asks for a 16px/600
26
+ heading. Kept outside a .container so the editor draws no rule. -->
27
+ <div class="strategy-control-header">
28
+ <h3 class="strategy-control-title">${this.api.translate("Recommendation Strategy")}</h3>
29
+ </div>
30
+ <div class="strategy-control-description-row">
31
+ <p class="strategy-control-description">
32
+ ${t}
33
+ ${e}
34
+ <!-- cspell:disable-next-line -->
35
+ <a href="${m}" target="_blank" rel="noopener noreferrer">${s}</a>.
36
+ </p>
37
+ </div>
38
+ <div data-strategy-empty-state>
39
+ ${this._GuTwoColumns([
40
+ this._GuButton({
41
+ name: "assignStrategy",
42
+ label: this.api.translate("Assign Strategy"),
43
+ id: "guido__btn-assign-strategy",
44
+ className: "strategy-control-cta accent"
45
+ }),
46
+ // Create round-trip ships in a later phase. Disabled, not dimmed:
47
+ // the design keeps it at full contrast.
48
+ this._GuButton({
49
+ name: "createStrategy",
50
+ label: this.api.translate("Create New Strategy"),
51
+ id: "guido__btn-create-strategy",
52
+ className: "strategy-control-cta primary",
53
+ disabled: !0
54
+ })
55
+ ], "strategy-control-cta-row")}
56
+ </div>
57
+ <div data-strategy-assigned-state style="display: none;">
58
+ <!-- The name band bleeds to the panel edges, so it is a sibling of the
59
+ actions row rather than sharing its 16px inset. -->
60
+ <div class="strategy-control-name-band">
61
+ <span class="strategy-control-name" data-strategy-name></span>
62
+ </div>
63
+ <div class="strategy-control-actions">
64
+ ${this._strategyAction({
65
+ id: "guido__btn-change-strategy",
66
+ label: this.api.translate("Change"),
67
+ modifier: "change"
68
+ })}
69
+ ${this._strategyAction({
70
+ id: "guido__btn-remove-strategy",
71
+ label: this.api.translate("Remove"),
72
+ modifier: "remove"
73
+ })}
74
+ </div>
75
+ </div>
76
+ </div>
77
+ `;
78
+ }
79
+ /**
80
+ * Change / Remove are icon+text actions in the design, not buttons — and
81
+ * `ue-button` cannot pair a caption with an arbitrary icon, so these are
82
+ * plain elements. Click wiring is by id, which works on any element.
83
+ *
84
+ * The icon is a CSS mask, not inline SVG: Stripo re-creates the control's
85
+ * markup through Angular, which rebuilds `<svg>` outside the SVG namespace
86
+ * (the view-box attribute comes back lowercased) and it never paints.
87
+ */
88
+ _strategyAction({ id: t, label: e, modifier: s }) {
89
+ return `
90
+ <button
91
+ id="${t}"
92
+ type="button"
93
+ class="strategy-control-action strategy-control-action--${s}">
94
+ <span>${e}</span>
95
+ </button>
96
+ `;
97
+ }
98
+ onRender() {
99
+ this._teardown(), this._setupButtonListeners(), this._renderState(), this.storeUnsubscription = this.store.$subscribe(() => {
100
+ this._renderState();
101
+ }), this.store.recommendationConfigs.strategyId && !this.store.strategies.length && this.store.fetchStrategies().catch(() => {
102
+ });
103
+ }
104
+ onDestroy() {
105
+ this._teardown();
106
+ }
107
+ _teardown() {
108
+ this.storeUnsubscription(), this.storeUnsubscription = () => {
109
+ }, this.listeners.forEach(({ element: t, handler: e }) => t.removeEventListener("click", e)), this.listeners = [];
110
+ }
111
+ _setupButtonListeners() {
112
+ const t = (e, s) => {
113
+ const r = this.getContainer().querySelector(e);
114
+ r && (r.addEventListener("click", s), this.listeners.push({ element: r, handler: s }));
115
+ };
116
+ t("#guido__btn-assign-strategy", () => this.store.openAssignStrategyDrawer()), t("#guido__btn-change-strategy", () => this.store.openAssignStrategyDrawer()), t("#guido__btn-remove-strategy", () => this.store.removeStrategy());
117
+ }
118
+ /**
119
+ * Toggles empty vs assigned state from the store's current block config.
120
+ * Display name comes from the listing; falls back to the raw id while the
121
+ * listing loads (or when the strategy is no longer listed).
122
+ */
123
+ _renderState() {
124
+ var c;
125
+ const t = this.getContainer(), e = t.querySelector("[data-strategy-empty-state]"), s = t.querySelector("[data-strategy-assigned-state]"), r = t.querySelector("[data-strategy-name]"), { strategyId: i } = this.store.recommendationConfigs;
126
+ !e || !s || (e.style.display = i ? "none" : "", s.style.display = i ? "" : "none", r && i && (r.textContent = ((c = this.store.assignedStrategy) == null ? void 0 : c.name) ?? `#${i}`));
127
+ }
128
+ }
129
+ export {
130
+ h as STRATEGY_CONTROL_ID,
131
+ b as StrategyControl
132
+ };