@useinsider/guido 2.1.0-beta.216503 → 2.1.0-beta.29e4650

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.
@@ -1,11 +1,11 @@
1
1
  var u = Object.defineProperty;
2
- var p = (r, i, t) => i in r ? u(r, i, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[i] = t;
3
- var g = (r, i, t) => p(r, typeof i != "symbol" ? i + "" : i, t);
2
+ var p = (r, o, t) => o in r ? u(r, o, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[o] = t;
3
+ var g = (r, o, t) => p(r, typeof o != "symbol" ? o + "" : o, t);
4
4
  import { Block as f, BlockCompositionType as I, ModificationDescription as h } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
5
- import { RecommendationConfigService as s } from "./services/configService.js";
5
+ import { RecommendationConfigService as c } from "./services/configService.js";
6
6
  import { useRecommendationExtensionStore as d } from "./store/recommendation.js";
7
7
  import { getDefaultTemplate as _ } from "./templates/grid/template.js";
8
- const k = "recommendation-block", c = "ins-recommendation-v3-block-v2", m = "recommendation-id";
8
+ const k = "recommendation-block", s = "ins-recommendation-v3-block-v2", a = "recommendation-id";
9
9
  class b extends f {
10
10
  constructor() {
11
11
  super();
@@ -50,7 +50,9 @@ class b extends f {
50
50
  */
51
51
  onCreated(t) {
52
52
  const e = this._pendingBlockId ?? this._generateNextId();
53
- this._pendingBlockId = null, this._assignRecommendationId(t, e), s.initializeConfig(this.api, t, { recommendationId: e }), d().setCurrentBlock(e);
53
+ this._pendingBlockId = null, this._assignRecommendationId(t, e);
54
+ const n = c.initializeConfig(this.api, t, { recommendationId: e }), i = d();
55
+ i.setCurrentBlock(e), i.patchCurrentBlockConfig({ language: n.language }, { triggerRefetch: !1 });
54
56
  }
55
57
  /**
56
58
  * Called when the document changes or template is loaded
@@ -63,14 +65,14 @@ class b extends f {
63
65
  if (!(!t || !("getNodeConfig" in t))) {
64
66
  if (!this._getRecommendationId(t)) {
65
67
  const e = this._generateNextId();
66
- this._assignRecommendationId(t, e), s.hasConfig(t) && s.updateConfig(
68
+ this._assignRecommendationId(t, e), c.hasConfig(t) && c.updateConfig(
67
69
  this.api,
68
70
  t,
69
71
  { recommendationId: e },
70
72
  "Assign recommendation ID to legacy block"
71
73
  );
72
74
  }
73
- s.needsMigration(t) && this._migrateFromLegacy(t);
75
+ c.needsMigration(t) && this._migrateFromLegacy(t);
74
76
  }
75
77
  }
76
78
  /**
@@ -91,9 +93,9 @@ class b extends f {
91
93
  let t = 0;
92
94
  try {
93
95
  const e = this.api.getDocumentRoot();
94
- e && "querySelectorAll" in e && e.querySelectorAll(`.${c}`).forEach((o) => {
95
- if ("getAttribute" in o) {
96
- const a = o.getAttribute(m), l = a ? parseInt(a) : 0;
96
+ e && "querySelectorAll" in e && e.querySelectorAll(`.${s}`).forEach((i) => {
97
+ if ("getAttribute" in i) {
98
+ const m = i.getAttribute(a), l = m ? parseInt(m) : 0;
97
99
  l > t && (t = l);
98
100
  }
99
101
  });
@@ -111,8 +113,8 @@ class b extends f {
111
113
  const n = this._getBlockElement(t);
112
114
  if (!n)
113
115
  return;
114
- const o = this.api.getDocumentModifier();
115
- o.modifyHtml(n).setAttribute(m, e.toString()), o.apply(new h(`Assign recommendation ID ${e}`));
116
+ const i = this.api.getDocumentModifier();
117
+ i.modifyHtml(n).setAttribute(a, e.toString()), i.apply(new h(`Assign recommendation ID ${e}`));
116
118
  }
117
119
  /**
118
120
  * Gets the recommendation-id from a block node
@@ -121,11 +123,11 @@ class b extends f {
121
123
  const e = this._getBlockElement(t);
122
124
  if (!e || !("getAttribute" in e))
123
125
  return null;
124
- const n = e.getAttribute(m);
126
+ const n = e.getAttribute(a);
125
127
  if (!n)
126
128
  return null;
127
- const o = parseInt(n);
128
- return Number.isNaN(o) ? null : o;
129
+ const i = parseInt(n);
130
+ return Number.isNaN(i) ? null : i;
129
131
  }
130
132
  /**
131
133
  * Gets the block element (the element with BLOCK_CLASS)
@@ -133,16 +135,16 @@ class b extends f {
133
135
  _getBlockElement(t) {
134
136
  if ("getAttribute" in t) {
135
137
  const e = t.getAttribute("class");
136
- if (e && e.includes(c))
138
+ if (e && e.includes(s))
137
139
  return t;
138
140
  }
139
- return "querySelector" in t ? t.querySelector(`.${c}`) : null;
141
+ return "querySelector" in t ? t.querySelector(`.${s}`) : null;
140
142
  }
141
143
  /**
142
144
  * Migrate configuration from legacy format
143
145
  */
144
146
  _migrateFromLegacy(t) {
145
- s.migrateFromDataAttributes(this.api, t);
147
+ c.migrateFromDataAttributes(this.api, t);
146
148
  }
147
149
  }
148
150
  export {
@@ -1,6 +1,6 @@
1
1
  var d = Object.defineProperty;
2
- var m = (l, n, t) => n in l ? d(l, n, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[n] = t;
3
- var i = (l, n, t) => m(l, typeof n != "symbol" ? n + "" : n, t);
2
+ var m = (c, s, t) => s in c ? d(c, s, { enumerable: !0, configurable: !0, writable: !0, value: t }) : c[s] = t;
3
+ var n = (c, s, t) => m(c, typeof s != "symbol" ? s + "" : s, t);
4
4
  import { CommonControl as h } from "../../../common-control.js";
5
5
  import { useRecommendationExtensionStore as C } from "../../store/recommendation.js";
6
6
  import { AlgorithmControl as f } from "./algorithm.js";
@@ -15,36 +15,34 @@ import { ProductLayoutControl as _ } from "./productLayout.js";
15
15
  import { PRODUCT_LAYOUT_CONTROL_ID as K } from "./productLayout.js";
16
16
  import { ShuffleControl as N } from "./shuffle.js";
17
17
  import { SHUFFLE_CONTROL_ID as J } from "./shuffle.js";
18
- import { regenerateProductRowsWithStyles as P, getBlockElement as b, updateProductContentInPlace as y } from "./utils.js";
19
- import { formatProductPrice as X, getCardComposition as Z, getCurrentLayout as tt, reapplySpacing as et, regenerateProductRows as ot, setCurrencyAttributes as rt, updatePricesInPlace as it, updateSingleProductContent as nt } from "./utils.js";
20
- import { useDebounceFn as c } from "../../../../../node_modules/@vueuse/shared/index.js";
21
- const T = "recommendation-id", L = "ui-elements-recommendation-block";
22
- class x extends h {
18
+ import { regenerateProductRowsWithStyles as b, getBlockElement as P, updateProductContentInPlace as y } from "./utils.js";
19
+ import { formatProductPrice as X, getCardComposition as Z, getCurrentLayout as tt, reapplySpacing as et, regenerateProductRows as ot, setCurrencyAttributes as rt, updatePricesInPlace as nt, updateSingleProductContent as it } from "./utils.js";
20
+ import { useDebounceFn as a } from "../../../../../node_modules/@vueuse/shared/index.js";
21
+ const I = "recommendation-id", T = "ui-elements-recommendation-block";
22
+ class B extends h {
23
23
  constructor() {
24
24
  super(...arguments);
25
- i(this, "store", C());
26
- i(this, "storeUnsubscription", () => {
25
+ n(this, "store", C());
26
+ n(this, "storeUnsubscription", () => {
27
27
  });
28
- // Track if initial data has been fetched per block ID to avoid redundant API calls
29
- i(this, "initializedBlocks", /* @__PURE__ */ new Map());
30
28
  // Sub-control instances for lifecycle management
31
- i(this, "algorithmControl", null);
32
- i(this, "localeControl", null);
33
- i(this, "currencyControl", null);
34
- i(this, "productLayoutControl", null);
35
- i(this, "filtersControl", null);
36
- i(this, "shuffleControl", null);
29
+ n(this, "algorithmControl", null);
30
+ n(this, "localeControl", null);
31
+ n(this, "currencyControl", null);
32
+ n(this, "productLayoutControl", null);
33
+ n(this, "filtersControl", null);
34
+ n(this, "shuffleControl", null);
37
35
  /**
38
36
  * Debounced product fetch to prevent rapid API calls during config changes
39
37
  */
40
- i(this, "_debouncedFetchProducts", c(() => {
38
+ n(this, "_debouncedFetchProducts", a(() => {
41
39
  this.store.fetchRecommendationProducts();
42
40
  }, 500));
43
41
  /**
44
42
  * Debounced regeneration when products arrive from API
45
43
  * Tries in-place update first to preserve styles, falls back to full regeneration
46
44
  */
47
- i(this, "_debouncedRegenerateWithProducts", c(() => {
45
+ n(this, "_debouncedRegenerateWithProducts", a(() => {
48
46
  const t = this.store.recommendationProducts;
49
47
  if (!this.currentNode || !this.api)
50
48
  return;
@@ -57,7 +55,7 @@ class x extends h {
57
55
  }, 100));
58
56
  }
59
57
  getId() {
60
- return L;
58
+ return T;
61
59
  }
62
60
  getTemplate() {
63
61
  return this.algorithmControl = new f(), this.localeControl = new R(), this.currencyControl = new p(), this.productLayoutControl = new _(), this.filtersControl = new g(), this.shuffleControl = new N(), `
@@ -72,8 +70,9 @@ class x extends h {
72
70
  `;
73
71
  }
74
72
  async onRender() {
73
+ var e;
75
74
  const t = this._getRecommendationIdFromNode(this.currentNode) ?? this.store.currentRecommendationId;
76
- if (t !== null && this.store.setCurrentBlock(t), this._listenStateUpdates(), t !== null && this.initializedBlocks.get(t)) {
75
+ if (t !== null && this.store.setCurrentBlock(t), this._listenStateUpdates(), t !== null && ((e = this.store.blockStates[t]) != null && e.isInitialized)) {
77
76
  this._initializeSubControls();
78
77
  return;
79
78
  }
@@ -88,16 +87,17 @@ class x extends h {
88
87
  console.warn("[Recommendation] Cannot regenerate - missing currentNode or api");
89
88
  return;
90
89
  }
91
- P({
90
+ b({
92
91
  currentNode: this.currentNode,
93
92
  documentModifier: this.api.getDocumentModifier(),
94
93
  products: t
95
94
  });
96
95
  }
97
96
  onTemplateNodeUpdated(t) {
97
+ var i;
98
98
  super.onTemplateNodeUpdated(t);
99
99
  const e = this._getRecommendationIdFromNode(t);
100
- e !== null && e !== this.store.currentRecommendationId && this.store.setCurrentBlock(e), e !== null && !this.initializedBlocks.get(e) && this._fetchBlockData(e), [
100
+ e !== null && e !== this.store.currentRecommendationId && this.store.setCurrentBlock(e), e !== null && !((i = this.store.blockStates[e]) != null && i.isInitialized) && this._fetchBlockData(e), [
101
101
  this.algorithmControl,
102
102
  this.localeControl,
103
103
  this.currencyControl,
@@ -105,8 +105,8 @@ class x extends h {
105
105
  this.filtersControl,
106
106
  this.shuffleControl
107
107
  ].forEach((r) => {
108
- var s;
109
- r != null && r.api && (r.currentNode = t, (s = r.onTemplateNodeUpdated) == null || s.call(r, t));
108
+ var l;
109
+ r != null && r.api && (r.currentNode = t, (l = r.onTemplateNodeUpdated) == null || l.call(r, t));
110
110
  });
111
111
  }
112
112
  onDestroy() {
@@ -145,30 +145,30 @@ class x extends h {
145
145
  * Marks the block as initialized to prevent redundant fetches on re-selection.
146
146
  */
147
147
  async _fetchBlockData(t) {
148
- t !== null && this.initializedBlocks.set(t, !0), (await Promise.allSettled([
148
+ t !== null && this.store.markBlockInitialized(t), (await Promise.allSettled([
149
149
  this.store.fetchRecommendationFilters(),
150
150
  this.store.fetchRecommendationCreateData(),
151
151
  this.store.fetchRecommendationProducts()
152
- ])).forEach((o, r) => {
152
+ ])).forEach((o, i) => {
153
153
  o.status === "rejected" && console.warn(`Recommendation block: ${[
154
154
  "fetchRecommendationFilters",
155
155
  "fetchRecommendationCreateData",
156
156
  "fetchRecommendationProducts"
157
- ][r]} failed`, o.reason);
157
+ ][i]} failed`, o.reason);
158
158
  });
159
159
  }
160
160
  /**
161
161
  * Reads the recommendation-id attribute from the block element within the node
162
162
  */
163
163
  _getRecommendationIdFromNode(t) {
164
- const e = b(t);
164
+ const e = P(t);
165
165
  if (!e || !("getAttribute" in e))
166
166
  return null;
167
- const o = e.getAttribute(T);
167
+ const o = e.getAttribute(I);
168
168
  if (!o)
169
169
  return null;
170
- const r = parseInt(o);
171
- return Number.isNaN(r) ? null : r;
170
+ const i = parseInt(o);
171
+ return Number.isNaN(i) ? null : i;
172
172
  }
173
173
  /**
174
174
  * Listen to store changes that require product refresh or regeneration.
@@ -181,17 +181,17 @@ class x extends h {
181
181
  const { store: t } = this;
182
182
  let e = t.recommendationProducts, o = t.$state.configVersion;
183
183
  this.storeUnsubscription = t.$subscribe(() => {
184
- const r = t.$state.configVersion;
185
- r !== o && (o = r, this._debouncedFetchProducts());
186
- const s = t.recommendationProducts, a = s !== e, u = Array.isArray(s) && s.length > 0;
187
- a && u && (e = s, this._debouncedRegenerateWithProducts());
184
+ const i = t.$state.configVersion;
185
+ i !== o && (o = i, this._debouncedFetchProducts());
186
+ const r = t.recommendationProducts, l = r !== e, u = Array.isArray(r) && r.length > 0;
187
+ l && u && (e = r, this._debouncedRegenerateWithProducts());
188
188
  });
189
189
  }
190
190
  }
191
191
  export {
192
192
  M as ALGORITHM_CONTROL_ID,
193
193
  f as AlgorithmControl,
194
- L as CONTROL_BLOCK_ID,
194
+ T as CONTROL_BLOCK_ID,
195
195
  W as CURRENCY_CONTROL_ID,
196
196
  p as CurrencyControl,
197
197
  H as FILTERS_CONTROL_ID,
@@ -200,18 +200,18 @@ export {
200
200
  R as LocaleControl,
201
201
  K as PRODUCT_LAYOUT_CONTROL_ID,
202
202
  _ as ProductLayoutControl,
203
- x as RecommendationBlockControl,
203
+ B as RecommendationBlockControl,
204
204
  J as SHUFFLE_CONTROL_ID,
205
205
  N as ShuffleControl,
206
206
  X as formatProductPrice,
207
- b as getBlockElement,
207
+ P as getBlockElement,
208
208
  Z as getCardComposition,
209
209
  tt as getCurrentLayout,
210
210
  et as reapplySpacing,
211
211
  ot as regenerateProductRows,
212
- P as regenerateProductRowsWithStyles,
212
+ b as regenerateProductRowsWithStyles,
213
213
  rt as setCurrencyAttributes,
214
- it as updatePricesInPlace,
214
+ nt as updatePricesInPlace,
215
215
  y as updateProductContentInPlace,
216
- nt as updateSingleProductContent
216
+ it as updateSingleProductContent
217
217
  };
@@ -1,13 +1,14 @@
1
- import { RecommendationFeedSourceMaps as u, PriceAttributes as g } from "../../../../enums/extensions/recommendationBlock.js";
2
- import { useRecommendationApi as S } from "../../../../services/recommendationApi.js";
3
- import { useConfigStore as p } from "../../../../stores/config.js";
4
- import { defineStore as b } from "pinia";
5
- import { DEFAULT_CARDS_IN_ROW as I } from "../constants/layout.js";
6
- import { generateCompleteFilterQuery as d } from "../utils/filterUtil.js";
7
- const l = S();
8
- function f() {
1
+ import { RecommendationFeedSourceMaps as d, PriceAttributes as S } from "../../../../enums/extensions/recommendationBlock.js";
2
+ import { useRecommendationApi as p } from "../../../../services/recommendationApi.js";
3
+ import { useConfigStore as b } from "../../../../stores/config.js";
4
+ import { defineStore as I } from "pinia";
5
+ import { DEFAULT_CARDS_IN_ROW as R } from "../constants/layout.js";
6
+ import { getDefaultProducts as k } from "../templates/utils.js";
7
+ import { generateCompleteFilterQuery as f } from "../utils/filterUtil.js";
8
+ const m = p();
9
+ function h() {
9
10
  return {
10
- cardsInRow: I,
11
+ cardsInRow: R,
11
12
  currencySettings: {
12
13
  name: "USD",
13
14
  value: "USD",
@@ -20,7 +21,7 @@ function f() {
20
21
  filters: [],
21
22
  productIds: [],
22
23
  id: 1,
23
- language: "tr_TR",
24
+ language: "en_US",
24
25
  orientation: "grid",
25
26
  recommendedProducts: [],
26
27
  sendProductRequestFlag: !1,
@@ -31,16 +32,17 @@ function f() {
31
32
  size: "6"
32
33
  };
33
34
  }
34
- function R() {
35
+ function C() {
35
36
  return {
36
- recommendationConfigs: f(),
37
+ recommendationConfigs: h(),
37
38
  recommendationProducts: [],
38
39
  filterStatus: !1,
39
40
  filterSelectionDrawerStatus: !1,
40
- filterGroup: 1
41
+ filterGroup: 1,
42
+ isInitialized: !1
41
43
  };
42
44
  }
43
- const k = () => ({
45
+ const y = () => ({
44
46
  recommendationCampaignUrls: {},
45
47
  activePredictiveAlgorithms: [],
46
48
  languages: {},
@@ -49,8 +51,8 @@ const k = () => ({
49
51
  blockStates: {},
50
52
  currentRecommendationId: null,
51
53
  configVersion: 0
52
- }), D = b("guidoRecommendationExtension", {
53
- state: () => k(),
54
+ }), A = I("guidoRecommendationExtension", {
55
+ state: () => y(),
54
56
  getters: {
55
57
  // ====================================================================
56
58
  // Proxy Getters — Backward Compatible Access to Current Block State
@@ -59,32 +61,32 @@ const k = () => ({
59
61
  * Proxy getter: delegates to blockStates[currentRecommendationId].recommendationConfigs
60
62
  * This allows all existing code that reads `store.recommendationConfigs` to work unchanged.
61
63
  */
62
- recommendationConfigs(e) {
63
- return e.currentRecommendationId !== null && e.blockStates[e.currentRecommendationId] ? e.blockStates[e.currentRecommendationId].recommendationConfigs : f();
64
+ recommendationConfigs(t) {
65
+ return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].recommendationConfigs : h();
64
66
  },
65
67
  /**
66
68
  * Proxy getter: delegates to blockStates[currentRecommendationId].recommendationProducts
67
69
  */
68
- recommendationProducts(e) {
69
- return e.currentRecommendationId !== null && e.blockStates[e.currentRecommendationId] ? e.blockStates[e.currentRecommendationId].recommendationProducts : [];
70
+ recommendationProducts(t) {
71
+ return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].recommendationProducts : [];
70
72
  },
71
73
  /**
72
74
  * Proxy getter: delegates to blockStates[currentRecommendationId].filterSelectionDrawerStatus
73
75
  */
74
- filterSelectionDrawerStatus(e) {
75
- return e.currentRecommendationId !== null && e.blockStates[e.currentRecommendationId] ? e.blockStates[e.currentRecommendationId].filterSelectionDrawerStatus : !1;
76
+ filterSelectionDrawerStatus(t) {
77
+ return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].filterSelectionDrawerStatus : !1;
76
78
  },
77
79
  /**
78
80
  * Proxy getter: delegates to blockStates[currentRecommendationId].filterStatus
79
81
  */
80
- filterStatus(e) {
81
- return e.currentRecommendationId !== null && e.blockStates[e.currentRecommendationId] ? e.blockStates[e.currentRecommendationId].filterStatus : !1;
82
+ filterStatus(t) {
83
+ return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].filterStatus : !1;
82
84
  },
83
85
  /**
84
86
  * Proxy getter: delegates to blockStates[currentRecommendationId].filterGroup
85
87
  */
86
- filterGroup(e) {
87
- return e.currentRecommendationId !== null && e.blockStates[e.currentRecommendationId] ? e.blockStates[e.currentRecommendationId].filterGroup : 1;
88
+ filterGroup(t) {
89
+ return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].filterGroup : 1;
88
90
  },
89
91
  // ====================================================================
90
92
  // Existing Getters (now reading through proxy)
@@ -93,39 +95,39 @@ const k = () => ({
93
95
  return !!this.recommendationConfigs.filters.length;
94
96
  },
95
97
  getFilterGroupCount() {
96
- const { filters: e } = this.recommendationConfigs;
97
- return e.length && e[e.length - 1].filterGroup || 0;
98
+ const { filters: t } = this.recommendationConfigs;
99
+ return t.length && t[t.length - 1].filterGroup || 0;
98
100
  },
99
- getActivePredictiveAlgorithms: (e) => {
101
+ getActivePredictiveAlgorithms: (t) => {
100
102
  const r = [];
101
- return e.activePredictiveAlgorithms.forEach((t) => {
102
- r.push(...u.filter((n) => n.id === t));
103
- }), r.map((t) => ({
104
- text: t.name,
105
- value: t.key
103
+ return t.activePredictiveAlgorithms.forEach((e) => {
104
+ r.push(...d.filter((n) => n.id === e));
105
+ }), r.map((e) => ({
106
+ text: e.name,
107
+ value: e.key
106
108
  }));
107
109
  },
108
- getLanguages: (e) => Object.entries(e.languages).map(([r, t]) => ({
109
- text: t,
110
+ getLanguages: (t) => Object.entries(t.languages).map(([r, e]) => ({
111
+ text: e,
110
112
  value: r
111
113
  })),
112
- getCurrencySymbolList: (e) => e.currencyList.map((r) => ({
114
+ getCurrencySymbolList: (t) => t.currencyList.map((r) => ({
113
115
  text: r.text,
114
116
  value: r.text
115
117
  })),
116
118
  getFilterList() {
117
- return Object.values(this.filterList).map((e) => {
118
- const r = e.type === "defaultAttribute", t = g.includes(e.attributeName);
119
- let n = r ? e.attributeName : `product_attributes.${e.attributeName}`;
120
- return n = t ? `${n}.${this.recommendationConfigs.currencySettings.value}` : n, {
121
- text: e.displayName,
119
+ return Object.values(this.filterList).map((t) => {
120
+ const r = t.type === "defaultAttribute", e = S.includes(t.attributeName);
121
+ let n = r ? t.attributeName : `product_attributes.${t.attributeName}`;
122
+ return n = e ? `${n}.${this.recommendationConfigs.currencySettings.value}` : n, {
123
+ text: t.displayName,
122
124
  value: n,
123
- type: e.attributeType
125
+ type: t.attributeType
124
126
  };
125
127
  });
126
128
  },
127
129
  getSelectedFilterGroup() {
128
- return (e) => [...this.recommendationConfigs.filters].filter((r) => r.filterGroup === e);
130
+ return (t) => [...this.recommendationConfigs.filters].filter((r) => r.filterGroup === t);
129
131
  }
130
132
  },
131
133
  actions: {
@@ -136,37 +138,44 @@ const k = () => ({
136
138
  * Sets the currently active block ID.
137
139
  * Creates a new entry in blockStates if one doesn't exist.
138
140
  */
139
- setCurrentBlock(e) {
140
- this.blockStates[e] || (this.blockStates = {
141
+ setCurrentBlock(t) {
142
+ this.blockStates[t] || (this.blockStates = {
141
143
  ...this.blockStates,
142
- [e]: R()
143
- }), this.currentRecommendationId = e;
144
+ [t]: C()
145
+ }), this.currentRecommendationId = t;
144
146
  },
145
147
  /**
146
148
  * Removes a block's state from the store.
147
149
  * Resets currentRecommendationId if it was the deleted block.
148
150
  */
149
- removeBlockState(e) {
151
+ removeBlockState(t) {
150
152
  const r = { ...this.blockStates };
151
- if (delete r[e], this.blockStates = r, this.currentRecommendationId === e) {
152
- const t = Object.keys(this.blockStates).map(Number);
153
- this.currentRecommendationId = t.length > 0 ? t[0] : null;
153
+ if (delete r[t], this.blockStates = r, this.currentRecommendationId === t) {
154
+ const e = Object.keys(this.blockStates).map(Number);
155
+ this.currentRecommendationId = e.length > 0 ? e[0] : null;
154
156
  }
155
157
  },
158
+ /**
159
+ * Marks a block as initialized (initial API data has been fetched).
160
+ * Automatically cleaned up when removeBlockState deletes the block entry.
161
+ */
162
+ markBlockInitialized(t) {
163
+ this.blockStates[t] && (this.blockStates[t].isInitialized = !0);
164
+ },
156
165
  /**
157
166
  * Patches the current block's recommendationConfigs.
158
167
  * Replaces `store.$patch({ recommendationConfigs: { ... } })` pattern.
159
168
  */
160
- patchCurrentBlockConfig(e, r = {}) {
169
+ patchCurrentBlockConfig(t, r = {}) {
161
170
  if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
162
171
  return;
163
- const t = this.blockStates[this.currentRecommendationId];
164
- t.recommendationConfigs = {
165
- ...t.recommendationConfigs,
166
- ...e,
172
+ const e = this.blockStates[this.currentRecommendationId];
173
+ e.recommendationConfigs = {
174
+ ...e.recommendationConfigs,
175
+ ...t,
167
176
  currencySettings: {
168
- ...t.recommendationConfigs.currencySettings,
169
- ...e.currencySettings || {}
177
+ ...e.recommendationConfigs.currencySettings,
178
+ ...t.currencySettings || {}
170
179
  }
171
180
  };
172
181
  const { triggerRefetch: n = !0 } = r;
@@ -180,8 +189,8 @@ const k = () => ({
180
189
  openFilterDrawer() {
181
190
  if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
182
191
  return;
183
- const e = this.blockStates[this.currentRecommendationId];
184
- e.recommendationConfigs.filters.length || (e.recommendationConfigs.filters = [{
192
+ const t = this.blockStates[this.currentRecommendationId];
193
+ t.recommendationConfigs.filters.length || (t.recommendationConfigs.filters = [{
185
194
  type: "standardFilter",
186
195
  attribute: "",
187
196
  operatorReplace: "",
@@ -192,7 +201,7 @@ const k = () => ({
192
201
  filterGroup: 1,
193
202
  isValid: !1,
194
203
  value: ""
195
- }]), e.filterSelectionDrawerStatus = !0;
204
+ }]), t.filterSelectionDrawerStatus = !0;
196
205
  },
197
206
  /**
198
207
  * Closes the filter selection drawer for the current block
@@ -207,26 +216,26 @@ const k = () => ({
207
216
  if (this.activePredictiveAlgorithms.length)
208
217
  return;
209
218
  const {
210
- activePredictiveAlgorithms: e,
219
+ activePredictiveAlgorithms: t,
211
220
  languages: r,
212
- currencies: t
213
- } = await l.fetchRecommendationCreateData();
214
- this.activePredictiveAlgorithms = e, this.languages = r;
215
- const [n] = t, o = n.value.includes(".") ? n.value.split(".")[1] : n.value;
221
+ currencies: e
222
+ } = await m.fetchRecommendationCreateData();
223
+ this.activePredictiveAlgorithms = t, this.languages = r;
224
+ const [n] = e, o = n.value.includes(".") ? n.value.split(".")[1] : n.value;
216
225
  if (this.currentRecommendationId !== null && this.blockStates[this.currentRecommendationId]) {
217
226
  const i = this.blockStates[this.currentRecommendationId];
218
227
  i.recommendationConfigs.currencySettings.name = n.text, i.recommendationConfigs.currencySettings.value = o, i.filterStatus = !!i.recommendationConfigs.filters.length;
219
228
  }
220
- this.currencyList = t;
229
+ this.currencyList = e;
221
230
  },
222
231
  async fetchRecommendationFilters() {
223
- const e = await l.fetchRecommendationFilters();
224
- this.filterList = e;
232
+ const t = await m.fetchRecommendationFilters();
233
+ this.filterList = t;
225
234
  },
226
235
  // ====================================================================
227
236
  // Per-Block Filter Actions
228
237
  // ====================================================================
229
- addFilterGroup(e) {
238
+ addFilterGroup(t) {
230
239
  this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId] || this.blockStates[this.currentRecommendationId].recommendationConfigs.filters.push({
231
240
  type: "standardFilter",
232
241
  attribute: "",
@@ -237,68 +246,71 @@ const k = () => ({
237
246
  value: "",
238
247
  filterNumber: 1,
239
248
  isValid: !0,
240
- filterGroup: e
249
+ filterGroup: t
241
250
  });
242
251
  },
243
- updateFilter(e) {
252
+ updateFilter(t) {
244
253
  if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
245
254
  return;
246
- const r = this.blockStates[this.currentRecommendationId], t = r.recommendationConfigs.filters.findIndex((n) => n.filterNumber === e.filterNumber && n.filterGroup === e.filterGroup);
247
- if (t !== -1) {
255
+ const r = this.blockStates[this.currentRecommendationId], e = r.recommendationConfigs.filters.findIndex((n) => n.filterNumber === t.filterNumber && n.filterGroup === t.filterGroup);
256
+ if (e !== -1) {
248
257
  const n = [...r.recommendationConfigs.filters];
249
- n[t] = e, e.value.length && e.operator && e.attribute && e.innerGroupOperator && e.outerGroupOperator ? n[t].isValid = !0 : n[t].isValid = !1, r.recommendationConfigs.filters = n;
258
+ n[e] = t, t.value.length && t.operator && t.attribute && t.innerGroupOperator && t.outerGroupOperator ? n[e].isValid = !0 : n[e].isValid = !1, r.recommendationConfigs.filters = n;
250
259
  }
251
260
  },
252
- deleteFilter(e) {
261
+ deleteFilter(t) {
253
262
  if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
254
263
  return;
255
- const r = this.blockStates[this.currentRecommendationId], t = [...r.recommendationConfigs.filters].findIndex((n) => n.filterNumber === e.filterNumber && n.filterGroup === e.filterGroup);
256
- if (t !== -1) {
264
+ const r = this.blockStates[this.currentRecommendationId], e = [...r.recommendationConfigs.filters].findIndex((n) => n.filterNumber === t.filterNumber && n.filterGroup === t.filterGroup);
265
+ if (e !== -1) {
257
266
  const n = [...r.recommendationConfigs.filters];
258
- n.splice(t, 1), r.recommendationConfigs.filters = n;
267
+ n.splice(e, 1), r.recommendationConfigs.filters = n;
259
268
  }
260
269
  },
261
- addFilter(e) {
270
+ addFilter(t) {
262
271
  if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
263
272
  return;
264
- const r = this.blockStates[this.currentRecommendationId], t = [...r.recommendationConfigs.filters], o = t.filter(
265
- (c) => c.filterGroup === e.filterGroup
266
- ).length + 1, i = t.findLastIndex((c) => c.filterGroup === e.filterGroup);
267
- i !== -1 ? t.splice(i + 1, 0, {
268
- ...e,
273
+ const r = this.blockStates[this.currentRecommendationId], e = [...r.recommendationConfigs.filters], o = e.filter(
274
+ (c) => c.filterGroup === t.filterGroup
275
+ ).length + 1, i = e.findLastIndex((c) => c.filterGroup === t.filterGroup);
276
+ i !== -1 ? e.splice(i + 1, 0, {
277
+ ...t,
269
278
  filterNumber: o
270
- }) : t.push({
271
- ...e,
279
+ }) : e.push({
280
+ ...t,
272
281
  filterNumber: o
273
- }), r.recommendationConfigs.filters = t;
282
+ }), r.recommendationConfigs.filters = e;
274
283
  },
275
284
  generateFilterQuery() {
276
- return d(this.recommendationConfigs.filters);
285
+ return f(this.recommendationConfigs.filters);
277
286
  },
278
287
  // ====================================================================
279
288
  // Per-Block Product Fetching
280
289
  // ====================================================================
281
290
  async fetchRecommendationProducts() {
282
- var m;
291
+ var u;
283
292
  if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
284
293
  return;
285
- const e = this.currentRecommendationId, r = this.blockStates[e], { recommendationConfigs: t } = r, n = t.filters.filter((a) => a.isValid), o = d(n), i = ((m = u.find((a) => a.key === t.strategy)) == null ? void 0 : m.path) || "", c = p(), s = {
286
- locale: t.language,
287
- currency: t.currencySettings.value,
294
+ const t = this.currentRecommendationId, r = this.blockStates[t], { recommendationConfigs: e } = r, n = e.filters.filter((l) => l.isValid), o = f(n), i = ((u = d.find((l) => l.key === e.strategy)) == null ? void 0 : u.path) || "", c = b(), s = {
295
+ locale: e.language,
296
+ currency: e.currencySettings.value,
288
297
  partnerName: c.partnerName,
289
- size: t.size,
298
+ size: e.size,
290
299
  details: !0,
291
300
  campaignId: c.variationId
292
301
  };
293
- t.strategy === "manualMerchandising" ? s.productId = t.productIds.join(",") : t.strategy === "similarViewed" && (s.productId = "{itemId}"), o && (s.filter = o), t.shuffleProducts && (s.shuffle = !0);
294
- const h = await l.fetchRecommendationProducts(
295
- i,
296
- s
297
- );
298
- this.blockStates[e] && (this.blockStates[e].recommendationProducts = h);
302
+ e.strategy === "manualMerchandising" ? s.productId = e.productIds.join(",") : e.strategy === "similarViewed" && (s.productId = "{itemId}"), o && (s.filter = o), e.shuffleProducts && (s.shuffle = !0);
303
+ const g = parseInt(e.size) || 6;
304
+ let a;
305
+ try {
306
+ a = await m.fetchRecommendationProducts(i, s);
307
+ } catch {
308
+ a = [];
309
+ }
310
+ this.blockStates[t] && (this.blockStates[t].recommendationProducts = a.length > 0 ? a : k(g));
299
311
  }
300
312
  }
301
313
  });
302
314
  export {
303
- D as useRecommendationExtensionStore
315
+ A as useRecommendationExtensionStore
304
316
  };
@@ -1,5 +1,5 @@
1
1
  import { DEFAULT_PRODUCTS_PER_ROW as L } from "../../constants/layout.js";
2
- import { DEFAULT_CARD_COMPOSITION as R, spacer as I, createBlockTemplate as E, DEFAULTS as S, getDefaultProducts as _, DEFAULT_CARD_VISIBILITY as b } from "../utils.js";
2
+ import { DEFAULT_CARD_COMPOSITION as R, spacer as I, getDefaultProducts as E, createBlockTemplate as S, DEFAULTS as _, DEFAULT_CARD_VISIBILITY as b } from "../utils.js";
3
3
  import { gridElementRenderer as A, ATTRIBUTE_CELL_CLASS as w, DEFAULT_CELL_PADDING as f } from "./elementRenderer.js";
4
4
  const D = `
5
5
  <tr class="recommendation-product-row">
@@ -55,11 +55,11 @@ function U(t, e, r) {
55
55
  return P(t, e, A, r);
56
56
  }
57
57
  function B(t) {
58
- const e = t ? `ins-recommendation-v3-block-${t}` : void 0, r = E("grid", e), c = U(
59
- _(),
58
+ const e = t ? `ins-recommendation-v3-block-${t}` : void 0, r = S("grid", e), c = U(
59
+ E(),
60
60
  L
61
61
  );
62
- return r.replace("{-{-TITLE-}-}", S.TITLE).replace("{-{-PRODUCT_ROWS-}-}", c);
62
+ return r.replace("{-{-TITLE-}-}", _.TITLE).replace("{-{-PRODUCT_ROWS-}-}", c);
63
63
  }
64
64
  export {
65
65
  B as getDefaultTemplate,
@@ -1,23 +1,23 @@
1
- import { ATTR_PRODUCT_IMAGE as a, ATTR_PRODUCT_NAME as o, ATTR_PRODUCT_OLD_PRICE as c, ATTR_PRODUCT_PRICE as s, ATTR_PRODUCT_OMNIBUS_PRICE as l, ATTR_PRODUCT_OMNIBUS_DISCOUNT as n, ATTR_PRODUCT_BUTTON as i } from "../constants/selectors.js";
1
+ import { ATTR_PRODUCT_IMAGE as a, ATTR_PRODUCT_NAME as o, ATTR_PRODUCT_OLD_PRICE as c, ATTR_PRODUCT_PRICE as l, ATTR_PRODUCT_OMNIBUS_PRICE as s, ATTR_PRODUCT_OMNIBUS_DISCOUNT as n, ATTR_PRODUCT_BUTTON as i } from "../constants/selectors.js";
2
2
  const m = {
3
3
  TITLE: "You May Also Like!"
4
- }, g = [
4
+ }, u = [
5
5
  a,
6
6
  o,
7
7
  c,
8
- s,
9
8
  l,
9
+ s,
10
10
  n,
11
11
  i
12
12
  ], b = {
13
13
  [a]: !0,
14
14
  [o]: !0,
15
- [s]: !0,
15
+ [l]: !0,
16
16
  [c]: !0,
17
- [l]: !1,
17
+ [s]: !1,
18
18
  [n]: !1,
19
19
  [i]: !0
20
- }, T = `
20
+ }, p = `
21
21
  <tr>
22
22
  <td class="spacer" style="height: 10px;"></td>
23
23
  </tr>
@@ -25,7 +25,7 @@ const m = {
25
25
  function R(t) {
26
26
  return !t || typeof t != "string" || t.trim() === "" ? d : t.startsWith("http://") ? t.replace("http://", "https://") : t;
27
27
  }
28
- function e(t) {
28
+ function T(t) {
29
29
  return {
30
30
  name: "Product Name",
31
31
  image_url: d,
@@ -40,23 +40,19 @@ function e(t) {
40
40
  category: []
41
41
  };
42
42
  }
43
- function D() {
44
- return [
45
- e("1"),
46
- e("2"),
47
- e("3"),
48
- e("4"),
49
- e("5"),
50
- e("6")
51
- ];
43
+ function D(t = 6) {
44
+ return Array.from(
45
+ { length: t },
46
+ (e, r) => T(String(r + 1))
47
+ );
52
48
  }
53
- function U(t = "grid", r) {
54
- const p = t === "list" ? `
49
+ function A(t = "grid", e) {
50
+ const r = t === "list" ? `
55
51
  data-layout="list"` : "";
56
52
  return `
57
53
  <td
58
54
  align="left"
59
- class="ins-recommendation-v3-block-v2 esd-block-recommendation-v3-block es-p20${r ? ` ${r}` : ""}"${p}>
55
+ class="ins-recommendation-v3-block-v2 esd-block-recommendation-v3-block es-p20${e ? ` ${e}` : ""}"${r}>
60
56
  <table width="100%" cellpadding="0" cellspacing="0" border="0">
61
57
  <tr>
62
58
  <td align="center">
@@ -88,7 +84,7 @@ function U(t = "grid", r) {
88
84
  </table>
89
85
  </td>
90
86
  </tr>
91
- ${T}
87
+ ${p}
92
88
  <tr>
93
89
  <td>
94
90
  <table
@@ -112,11 +108,11 @@ function U(t = "grid", r) {
112
108
  }
113
109
  export {
114
110
  m as DEFAULTS,
115
- g as DEFAULT_CARD_COMPOSITION,
111
+ u as DEFAULT_CARD_COMPOSITION,
116
112
  b as DEFAULT_CARD_VISIBILITY,
117
113
  d as PLACEHOLDER_IMAGE,
118
- U as createBlockTemplate,
114
+ A as createBlockTemplate,
119
115
  D as getDefaultProducts,
120
116
  R as sanitizeImageUrl,
121
- T as spacer
117
+ p as spacer
122
118
  };
@@ -1,34 +1,34 @@
1
- import { useHttp as a } from "../composables/useHttp.js";
1
+ import { useHttp as c } from "../composables/useHttp.js";
2
2
  import { URLS as m } from "../enums/extensions/recommendationBlock.js";
3
- const l = () => {
4
- const { get: r } = a();
3
+ const f = () => {
4
+ const { get: o } = c();
5
5
  return {
6
6
  fetchRecommendationCreateData: async () => {
7
7
  try {
8
- return (await r("/newsletter/recommendations/create-data")).data;
8
+ return (await o("/newsletter/recommendations/create-data")).data;
9
9
  } catch (e) {
10
10
  throw console.error("fetchUserModalState error:", e), e;
11
11
  }
12
12
  },
13
13
  fetchRecommendationFilters: async () => {
14
14
  try {
15
- const { data: e } = await r("/stripo/email-recommendation-attributes");
15
+ const { data: e } = await o("/stripo/email-recommendation-attributes");
16
16
  return e;
17
17
  } catch (e) {
18
18
  throw console.error("fetchRecommendationFilters error:", e), e;
19
19
  }
20
20
  },
21
- fetchRecommendationProducts: async (e, c) => {
21
+ fetchRecommendationProducts: async (e, a) => {
22
22
  var n;
23
23
  try {
24
- const t = decodeURIComponent(new URLSearchParams(Object.entries(c)).toString());
24
+ const t = decodeURIComponent(new URLSearchParams(Object.entries(a)).toString());
25
25
  console.debug("🏁 Recommendation API Query:", t);
26
- const { get: s } = a({
26
+ const { get: s } = c({
27
27
  headers: {}
28
- }), o = await s(
28
+ }), r = await s(
29
29
  `${m.RECOMMENDATION_API_URL}/v2/${e}?${t}`
30
30
  );
31
- return console.debug("Recommendation Data Response", o), ((n = o == null ? void 0 : o.data) == null ? void 0 : n.data) ?? [];
31
+ return ((n = r == null ? void 0 : r.data) == null ? void 0 : n.data) ?? [];
32
32
  } catch (t) {
33
33
  throw console.error("fetchRecommendationProducts error:", t), t;
34
34
  }
@@ -36,5 +36,5 @@ const l = () => {
36
36
  };
37
37
  };
38
38
  export {
39
- l as useRecommendationApi
39
+ f as useRecommendationApi
40
40
  };
@@ -16,7 +16,6 @@ export * from './utils';
16
16
  export declare class RecommendationBlockControl extends CommonControl {
17
17
  private store;
18
18
  private storeUnsubscription;
19
- private initializedBlocks;
20
19
  private algorithmControl;
21
20
  private localeControl;
22
21
  private currencyControl;
@@ -29,6 +29,8 @@ interface PerBlockState {
29
29
  filterStatus: boolean;
30
30
  filterSelectionDrawerStatus: boolean;
31
31
  filterGroup: number;
32
+ /** Whether initial API data (filters, algorithms, products) has been fetched for this block */
33
+ isInitialized: boolean;
32
34
  }
33
35
  interface StoreState {
34
36
  recommendationCampaignUrls: Record<string, string>;
@@ -189,6 +191,11 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
189
191
  * Resets currentRecommendationId if it was the deleted block.
190
192
  */
191
193
  removeBlockState(id: number): void;
194
+ /**
195
+ * Marks a block as initialized (initial API data has been fetched).
196
+ * Automatically cleaned up when removeBlockState deletes the block entry.
197
+ */
198
+ markBlockInitialized(id: number): void;
192
199
  /**
193
200
  * Patches the current block's recommendationConfigs.
194
201
  * Replaces `store.$patch({ recommendationConfigs: { ... } })` pattern.
@@ -44,7 +44,7 @@ export declare const PLACEHOLDER_IMAGE = "https://email-static.useinsider.com/st
44
44
  * @returns Sanitized HTTPS URL or placeholder
45
45
  */
46
46
  export declare function sanitizeImageUrl(url: string | undefined | null): string;
47
- export declare function getDefaultProducts(): RecommendationProduct[];
47
+ export declare function getDefaultProducts(count?: number): RecommendationProduct[];
48
48
  /**
49
49
  * Creates the block template wrapper HTML for recommendation blocks.
50
50
  * The template includes title placeholder and product container.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useinsider/guido",
3
- "version": "2.1.0-beta.0216503",
3
+ "version": "2.1.0-beta.29e4650",
4
4
  "description": "Guido is a Vue + TypeScript wrapper for Email Plugin. Easily embed the email editor in your Vue applications.",
5
5
  "main": "./dist/guido.umd.cjs",
6
6
  "module": "./dist/library.js",