@useinsider/guido 3.18.0 → 3.18.1-beta.636c82d

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 (28) hide show
  1. package/dist/components/Guido.vue.js +1 -1
  2. package/dist/components/Guido.vue2.js +86 -82
  3. package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue.js +13 -11
  4. package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue2.js +72 -56
  5. package/dist/components/organisms/header/EditorActions.vue.js +1 -1
  6. package/dist/components/organisms/header/EditorActions.vue2.js +54 -41
  7. package/dist/components/organisms/onboarding/OnboardingWrapper.vue2.js +20 -18
  8. package/dist/components/organisms/onboarding/RecommendationStrategyOnboarding.vue.js +21 -0
  9. package/dist/components/organisms/onboarding/RecommendationStrategyOnboarding.vue2.js +46 -0
  10. package/dist/composables/useActionsApi.js +82 -67
  11. package/dist/composables/useAutoSave.js +31 -26
  12. package/dist/composables/useEditorLock.js +20 -0
  13. package/dist/composables/useGuidoStateBridge.js +37 -31
  14. package/dist/composables/useSave.js +42 -39
  15. package/dist/enums/extensions/recommendationBlock.js +38 -31
  16. package/dist/extensions/Blocks/Recommendation/controls/main/strategy.js +35 -31
  17. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +129 -68
  18. package/dist/guido.css +1 -1
  19. package/dist/package.json.js +1 -1
  20. package/dist/src/components/organisms/onboarding/RecommendationStrategyOnboarding.vue.d.ts +2 -0
  21. package/dist/src/composables/useEditorLock.d.ts +10 -0
  22. package/dist/src/enums/extensions/recommendationBlock.d.ts +2 -0
  23. package/dist/src/extensions/Blocks/Recommendation/controls/main/strategy.d.ts +1 -0
  24. package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +49 -0
  25. package/dist/src/stores/onboarding.d.ts +377 -0
  26. package/dist/static/styles/components/recommendation-strategy.css.js +21 -4
  27. package/dist/stores/onboarding.js +41 -36
  28. package/package.json +2 -2
@@ -1,14 +1,20 @@
1
- import { useTranslations as r } from "../../composables/useTranslations.js";
2
- const l = {
1
+ import { useTranslations as n } from "../../composables/useTranslations.js";
2
+ const o = {
3
3
  RECOMMENDATION_API_URL: "https://recommendationv2.api.useinsider.com",
4
4
  // Relative path → same-origin as the embedding inone dashboard.
5
5
  PRODUCT_ATTRIBUTES_PATH: "/product-attributes/get-attributes",
6
6
  RECOMMENDATION_STRATEGIES_PATH: "/api/recommendation-strategies",
7
- RECOMMENDATION_STRATEGIES_PANEL_PATH: "/discovery/recommendation-strategies"
8
- }, c = {
7
+ RECOMMENDATION_STRATEGIES_PANEL_PATH: "/discovery/recommendation-strategies",
8
+ // Smart Recommender hides the Email channel unless the URL asks for it, so a strategy created
9
+ // without this flag can never be Email-suitable and would never reach the editor's list.
10
+ RECOMMENDATION_STRATEGY_CREATE_PATH: "/discovery/recommendation-strategies/create?isEmail=true"
11
+ }, d = (e) => {
12
+ const { RECOMMENDATION_STRATEGIES_PANEL_PATH: r } = o;
13
+ return `${r}/${e}/edit`;
14
+ }, m = {
9
15
  CLIENT_ID: "clientId"
10
- }, d = () => {
11
- const e = r();
16
+ }, p = () => {
17
+ const e = n();
12
18
  return [
13
19
  {
14
20
  id: 11,
@@ -71,14 +77,14 @@ const l = {
71
77
  path: "top-sellers"
72
78
  }
73
79
  ];
74
- }, m = ["discount", "omnibus_price", "omnibus_discount", "price", "original_price"], p = [
80
+ }, v = ["discount", "omnibus_price", "omnibus_discount", "price", "original_price"], h = [
75
81
  { text: "before the amount", value: "0" },
76
82
  { text: "after the amount", value: "1" }
77
- ], v = [
83
+ ], x = [
78
84
  { text: "dot(.)", value: "." },
79
85
  { text: "comma(,)", value: "," },
80
86
  { text: "space( )", value: " " }
81
- ], h = [
87
+ ], b = [
82
88
  { text: "0", value: "0" },
83
89
  { text: "1", value: "1" },
84
90
  { text: "2", value: "2" },
@@ -90,54 +96,55 @@ const l = {
90
96
  { text: "contains", value: "~" },
91
97
  { text: "does not contain", value: "!~" },
92
98
  { text: "any of", value: a }
93
- ], n = [
99
+ ], s = [
94
100
  { text: "is exactly", value: "=" },
95
101
  { text: "is not exactly", value: "!==" },
96
102
  { text: "contains", value: "~" },
97
103
  { text: "does not contain", value: "!~" },
98
104
  { text: "any of", value: a }
99
- ], o = [
105
+ ], i = [
100
106
  { text: "is equal to", value: "=" },
101
107
  { text: "is greater than", value: ">" },
102
108
  { text: "is less than", value: "<" }
103
- ], s = [
109
+ ], u = [
104
110
  { text: "is equal to", value: "=" },
105
111
  { text: "after", value: ">" },
106
112
  { text: "before", value: "<" }
107
- ], i = [
113
+ ], c = [
108
114
  { text: "true", value: "==" },
109
115
  { text: "false", value: "!=" }
110
- ], x = (e) => {
116
+ ], g = (e) => {
111
117
  if (!e)
112
118
  return t;
113
119
  switch (e) {
114
120
  case "Boolean":
115
- return i;
121
+ return c;
116
122
  case "Date":
117
- return s;
123
+ return u;
118
124
  case "Number":
119
- return o;
125
+ return i;
120
126
  case "String":
121
127
  return t;
122
128
  case "Strings":
123
- return n;
129
+ return s;
124
130
  default:
125
131
  return t;
126
132
  }
127
133
  };
128
134
  export {
129
135
  a as OP_ANY_OF,
130
- m as PriceAttributes,
131
- c as QUERY_PARAMS,
132
- l as URLS,
133
- h as currencyDecimalCounts,
134
- p as currencyLocationMaps,
135
- v as currencyOperators,
136
- x as getOperatorOptions,
137
- d as getRecommendationFeedSourceMaps,
138
- n as operatorOptionsForArrayOfStrings,
139
- i as operatorOptionsForBooleans,
140
- s as operatorOptionsForDates,
141
- o as operatorOptionsForNumbers,
142
- t as operatorOptionsForStrings
136
+ v as PriceAttributes,
137
+ m as QUERY_PARAMS,
138
+ o as URLS,
139
+ b as currencyDecimalCounts,
140
+ h as currencyLocationMaps,
141
+ x as currencyOperators,
142
+ g as getOperatorOptions,
143
+ p as getRecommendationFeedSourceMaps,
144
+ s as operatorOptionsForArrayOfStrings,
145
+ c as operatorOptionsForBooleans,
146
+ u as operatorOptionsForDates,
147
+ i as operatorOptionsForNumbers,
148
+ t as operatorOptionsForStrings,
149
+ d as strategyEditPath
143
150
  };
@@ -1,26 +1,28 @@
1
- var d = Object.defineProperty;
2
- var y = (r, s, t) => s in r ? d(r, s, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[s] = t;
3
- var o = (r, s, t) => y(r, typeof s != "symbol" ? s + "" : s, t);
4
- import { ACADEMY_LINKS as m } from "../../../../../enums/academy.js";
5
- import { CommonControl as h } from "../../../common-control.js";
6
- import { useRecommendationExtensionStore as u } from "../../store/recommendation.js";
7
- const p = "recommendation-strategy-control";
8
- class f extends h {
1
+ var m = Object.defineProperty;
2
+ var h = (o, a, t) => a in o ? m(o, a, { enumerable: !0, configurable: !0, writable: !0, value: t }) : o[a] = t;
3
+ var r = (o, a, t) => h(o, typeof a != "symbol" ? a + "" : a, t);
4
+ import { ACADEMY_LINKS as p } from "../../../../../enums/academy.js";
5
+ import { useOnboardingStore as u } from "../../../../../stores/onboarding.js";
6
+ import { CommonControl as S } from "../../../common-control.js";
7
+ import { useRecommendationExtensionStore as _ } from "../../store/recommendation.js";
8
+ const b = "recommendation-strategy-control";
9
+ class w extends S {
9
10
  constructor() {
10
11
  super(...arguments);
11
- o(this, "store", u());
12
- o(this, "storeUnsubscription", () => {
12
+ r(this, "store", _());
13
+ r(this, "onboardingStore", u());
14
+ r(this, "storeUnsubscription", () => {
13
15
  });
14
- o(this, "listeners", []);
15
- o(this, "lastPaintedState", null);
16
+ r(this, "listeners", []);
17
+ r(this, "lastPaintedState", null);
16
18
  }
17
19
  getId() {
18
- return p;
20
+ return b;
19
21
  }
20
22
  getTemplate() {
21
23
  const t = this.api.translate(
22
24
  "You can assign a recommendation strategy by selecting an existing one or creating a new one to show specific content."
23
- ), e = this.api.translate("For more information, you can"), a = this.api.translate("visit Academy");
25
+ ), e = this.api.translate("For more information, you can"), s = this.api.translate("visit Academy");
24
26
  return `
25
27
  <div class="strategy-control-container">
26
28
  <div class="strategy-control-header">
@@ -31,9 +33,9 @@ class f extends h {
31
33
  ${t}
32
34
  ${e}
33
35
  <a
34
- href="${m.EMAIL_RECOMMENDATION_BLOCK}"
36
+ href="${p.EMAIL_RECOMMENDATION_BLOCK}"
35
37
  target="_blank"
36
- rel="noopener noreferrer">${a}</a>.
38
+ rel="noopener noreferrer">${s}</a>.
37
39
  </p>
38
40
  </div>
39
41
  <div data-strategy-empty-state>
@@ -48,14 +50,14 @@ class f extends h {
48
50
  name: "createStrategy",
49
51
  label: this.api.translate("Create New Strategy"),
50
52
  id: "guido__btn-create-strategy",
51
- className: "strategy-control-cta primary",
52
- disabled: !0
53
+ className: "strategy-control-cta primary"
53
54
  })
54
55
  ], "strategy-control-cta-row")}
55
56
  </div>
56
57
  <div data-strategy-assigned-state style="display: none;">
57
58
  <div class="strategy-control-name-band">
58
59
  <span class="strategy-control-name" data-strategy-name></span>
60
+ <span class="strategy-control-name-skeleton" data-strategy-name-skeleton></span>
59
61
  </div>
60
62
  <div class="strategy-control-actions">
61
63
  ${this._strategyAction({
@@ -73,12 +75,12 @@ class f extends h {
73
75
  </div>
74
76
  `;
75
77
  }
76
- _strategyAction({ id: t, label: e, modifier: a }) {
78
+ _strategyAction({ id: t, label: e, modifier: s }) {
77
79
  return `
78
80
  <button
79
81
  id="${t}"
80
82
  type="button"
81
- class="strategy-control-action strategy-control-action--${a}">
83
+ class="strategy-control-action strategy-control-action--${s}">
82
84
  <span>${e}</span>
83
85
  </button>
84
86
  `;
@@ -88,6 +90,8 @@ class f extends h {
88
90
  this._renderState();
89
91
  }), this.store.recommendationConfigs.strategyId && !this.store.strategies.length && this.store.fetchStrategies().catch(() => {
90
92
  });
93
+ const t = this.store.currentRecommendationId;
94
+ t !== null && !!this.store.blockStates[t] && !this.store.recommendationConfigs.strategyId && this.onboardingStore.startOnboarding("recommendationStrategyOnboarding");
91
95
  }
92
96
  onDestroy() {
93
97
  this._teardown();
@@ -100,25 +104,25 @@ class f extends h {
100
104
  const t = this.getContainer();
101
105
  if (!t)
102
106
  return;
103
- const e = (a, n) => {
104
- const i = t.querySelector(a);
105
- i && (i.addEventListener("click", n), this.listeners.push({ element: i, handler: n }));
107
+ const e = (s, i) => {
108
+ const n = t.querySelector(s);
109
+ n && (n.addEventListener("click", i), this.listeners.push({ element: n, handler: i }));
106
110
  };
107
- e("#guido__btn-assign-strategy", () => this.store.openAssignStrategyDrawer()), e("#guido__btn-change-strategy", () => this.store.openAssignStrategyDrawer()), e("#guido__btn-remove-strategy", () => this.store.openRemoveStrategyModal());
111
+ e("#guido__btn-assign-strategy", () => this.store.openAssignStrategyDrawer()), e("#guido__btn-create-strategy", () => this.store.openStrategyCreation()), e("#guido__btn-change-strategy", () => this.store.openAssignStrategyDrawer()), e("#guido__btn-remove-strategy", () => this.store.openRemoveStrategyModal());
108
112
  }
109
113
  _renderState() {
110
- var l;
111
- const { strategyId: t } = this.store.recommendationConfigs, e = t ? ((l = this.store.assignedStrategy) == null ? void 0 : l.name) ?? "" : "", a = `${t}\0${e}`;
112
- if (a === this.lastPaintedState)
114
+ var y;
115
+ const { strategyId: t } = this.store.recommendationConfigs, e = t ? ((y = this.store.assignedStrategy) == null ? void 0 : y.name) ?? "" : "", s = !!t && !e && this.store.strategiesLoading, i = `${t}\0${e}\0${s}`;
116
+ if (i === this.lastPaintedState)
113
117
  return;
114
118
  const n = this.getContainer();
115
119
  if (!n)
116
120
  return;
117
- const i = n.querySelector("[data-strategy-empty-state]"), c = n.querySelector("[data-strategy-assigned-state]"), g = n.querySelector("[data-strategy-name]");
118
- !i || !c || (i.style.display = t ? "none" : "", c.style.display = t ? "" : "none", g && t && (g.textContent = e || `#${t}`), this.lastPaintedState = a);
121
+ const l = n.querySelector("[data-strategy-empty-state]"), g = n.querySelector("[data-strategy-assigned-state]"), c = n.querySelector("[data-strategy-name]"), d = n.querySelector("[data-strategy-name-skeleton]");
122
+ !l || !g || (l.style.display = t ? "none" : "", g.style.display = t ? "" : "none", c && (c.style.display = s ? "none" : "", t && !s && (c.textContent = e || `#${t}`)), d && (d.style.display = s ? "" : "none"), this.lastPaintedState = i);
119
123
  }
120
124
  }
121
125
  export {
122
- p as STRATEGY_CONTROL_ID,
123
- f as StrategyControl
126
+ b as STRATEGY_CONTROL_ID,
127
+ w as StrategyControl
124
128
  };
@@ -1,22 +1,31 @@
1
- import { getRecommendationFeedSourceMaps as b, getOperatorOptions as G, PriceAttributes as v } from "../../../../enums/extensions/recommendationBlock.js";
2
- import { useRecommendationApi as D } from "../../../../services/recommendationApi.js";
3
- import { useConfigStore as P } from "../../../../stores/config.js";
4
- import { defineStore as F } from "pinia";
1
+ import { getRecommendationFeedSourceMaps as C, strategyEditPath as _, URLS as D, getOperatorOptions as L, PriceAttributes as N } from "../../../../enums/extensions/recommendationBlock.js";
2
+ import { useRecommendationApi as U } from "../../../../services/recommendationApi.js";
3
+ import { useConfigStore as E } from "../../../../stores/config.js";
4
+ import { asText as w } from "../../../../utils/genericUtil.js";
5
+ import { defineStore as A } from "pinia";
5
6
  import "../constants/selectors.js";
6
- import { DEFAULT_MOBILE_CARDS_IN_ROW as _, DEFAULT_CARDS_IN_ROW as U } from "../constants/layout.js";
7
- import { DEFAULT_NODE_CONFIG as N, EXCLUDED_ALGORITHM_IDS as L } from "../constants/defaultConfig.js";
8
- import { getDefaultProducts as R } from "../templates/utils.js";
9
- import { generateCompleteFilterQuery as k } from "../utils/filterUtil.js";
10
- import { getPartnerRecommendationParams as x } from "../utils/partnerCustomizations.js";
11
- import { sanitizeProductIds as A } from "../utils/productIds.js";
12
- import { isFilterValid as B } from "../validation/filterSchema.js";
13
- import { isConfigValid as M } from "../validation/requiredFields.js";
14
- const u = D();
15
- let f = null, h = null, g = null, S = null;
16
- const p = /* @__PURE__ */ new Map();
17
- function w() {
7
+ import { DEFAULT_MOBILE_CARDS_IN_ROW as x, DEFAULT_CARDS_IN_ROW as B } from "../constants/layout.js";
8
+ import { DEFAULT_NODE_CONFIG as M, EXCLUDED_ALGORITHM_IDS as T } from "../constants/defaultConfig.js";
9
+ import { getDefaultProducts as v } from "../templates/utils.js";
10
+ import { generateCompleteFilterQuery as G } from "../utils/filterUtil.js";
11
+ import { getPartnerRecommendationParams as O } from "../utils/partnerCustomizations.js";
12
+ import { sanitizeProductIds as z } from "../utils/productIds.js";
13
+ import { isFilterValid as V } from "../validation/filterSchema.js";
14
+ import { isConfigValid as $ } from "../validation/requiredFields.js";
15
+ const d = U();
16
+ let g = null, h = null, S = null, p = null, I = 0;
17
+ const b = /* @__PURE__ */ new Map();
18
+ let u = null, y = null;
19
+ const j = (t, e) => {
20
+ const r = t.filter((s) => !e.has(String(s.strategy_id)));
21
+ if (!r.length)
22
+ return null;
23
+ const n = r.reduce((s, i) => w(i.created_at) > w(s.created_at) ? i : s);
24
+ return String(n.strategy_id);
25
+ };
26
+ function P() {
18
27
  return {
19
- cardsInRow: U,
28
+ cardsInRow: B,
20
29
  currencySettings: {
21
30
  name: "USD",
22
31
  value: "USD",
@@ -30,7 +39,7 @@ function w() {
30
39
  productIds: [],
31
40
  id: 1,
32
41
  language: "en_US",
33
- mobileCardsInRow: _,
42
+ mobileCardsInRow: x,
34
43
  mobileLayoutEnabled: !1,
35
44
  orientation: "grid",
36
45
  recommendedProducts: [],
@@ -46,9 +55,9 @@ function w() {
46
55
  priceHideIfSameAsDiscounted: !1
47
56
  };
48
57
  }
49
- function C() {
58
+ function F() {
50
59
  return {
51
- recommendationConfigs: w(),
60
+ recommendationConfigs: P(),
52
61
  recommendationProducts: [],
53
62
  filterStatus: !1,
54
63
  filterSelectionDrawerStatus: !1,
@@ -59,7 +68,7 @@ function C() {
59
68
  filterSnapshot: null
60
69
  };
61
70
  }
62
- const z = () => ({
71
+ const q = () => ({
63
72
  recommendationCampaignUrls: {},
64
73
  activePredictiveAlgorithms: [],
65
74
  languages: {},
@@ -68,11 +77,13 @@ const z = () => ({
68
77
  strategies: [],
69
78
  strategiesLoading: !1,
70
79
  strategyUrlTemplates: {},
80
+ lastCreatedStrategyId: null,
81
+ strategiesFetched: !1,
71
82
  blockStates: {},
72
83
  currentRecommendationId: null,
73
84
  configVersion: 0
74
- }), Y = F("guidoRecommendationExtension", {
75
- state: () => z(),
85
+ }), st = A("guidoRecommendationExtension", {
86
+ state: () => q(),
76
87
  getters: {
77
88
  // ====================================================================
78
89
  // Proxy Getters — Backward Compatible Access to Current Block State
@@ -82,7 +93,7 @@ const z = () => ({
82
93
  * This allows all existing code that reads `store.recommendationConfigs` to work unchanged.
83
94
  */
84
95
  recommendationConfigs(t) {
85
- return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].recommendationConfigs : w();
96
+ return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].recommendationConfigs : P();
86
97
  },
87
98
  /**
88
99
  * Proxy getter: delegates to blockStates[currentRecommendationId].recommendationProducts
@@ -137,8 +148,8 @@ const z = () => ({
137
148
  return [...new Set(t.map((e) => e.filterGroup))].sort((e, r) => e - r);
138
149
  },
139
150
  getActivePredictiveAlgorithms: (t) => {
140
- const e = b(), r = [];
141
- return t.activePredictiveAlgorithms.filter((n) => !L.includes(n)).forEach((n) => {
151
+ const e = C(), r = [];
152
+ return t.activePredictiveAlgorithms.filter((n) => !T.includes(n)).forEach((n) => {
142
153
  r.push(...e.filter((s) => s.id === n));
143
154
  }), r.map((n) => ({
144
155
  text: n.name,
@@ -156,7 +167,7 @@ const z = () => ({
156
167
  getFilterList() {
157
168
  return Object.values(this.filterList).filter((t) => t.isFilterable !== 0 && t.isFilterable !== !1).map((t) => {
158
169
  let e;
159
- return t.type === "productAttribute" ? e = `product_attributes.${t.attributeName}` : v.includes(t.attributeName) ? e = `${t.attributeName}.${this.recommendationConfigs.currencySettings.value}` : e = t.attributeName, {
170
+ return t.type === "productAttribute" ? e = `product_attributes.${t.attributeName}` : N.includes(t.attributeName) ? e = `${t.attributeName}.${this.recommendationConfigs.currencySettings.value}` : e = t.attributeName, {
160
171
  text: t.displayName,
161
172
  value: e,
162
173
  type: t.attributeType
@@ -178,7 +189,7 @@ const z = () => ({
178
189
  setCurrentBlock(t) {
179
190
  this.blockStates[t] || (this.blockStates = {
180
191
  ...this.blockStates,
181
- [t]: C()
192
+ [t]: F()
182
193
  }), this.currentRecommendationId = t;
183
194
  },
184
195
  /**
@@ -246,7 +257,7 @@ const z = () => ({
246
257
  decimalCount: String(e.currencyDecimalCount),
247
258
  decimalSeparator: r(e.currencyDecimalSeparator, ","),
248
259
  thousandSeparator: r(e.currencyThousandSeparator, ".")
249
- }, s = !this.blockStates[t], i = s ? C() : this.blockStates[t];
260
+ }, s = !this.blockStates[t], i = s ? F() : this.blockStates[t];
250
261
  i.recommendationConfigs = {
251
262
  ...i.recommendationConfigs,
252
263
  strategy: e.strategy,
@@ -285,7 +296,7 @@ const z = () => ({
285
296
  * Creates a filter with the first available attribute and operator pre-selected.
286
297
  */
287
298
  createDefaultFilter(t, e) {
288
- const [r] = this.getFilterList, [n] = G(r == null ? void 0 : r.type);
299
+ const [r] = this.getFilterList, [n] = L(r == null ? void 0 : r.type);
289
300
  return {
290
301
  type: "standardFilter",
291
302
  attribute: (r == null ? void 0 : r.value) ?? "",
@@ -345,29 +356,79 @@ const z = () => ({
345
356
  this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId] || (this.blockStates[this.currentRecommendationId].removeStrategyModalStatus = !1);
346
357
  },
347
358
  async fetchStrategies() {
348
- if (S) {
349
- await S;
359
+ if (p && await p, this.strategiesFetched)
350
360
  return;
351
- }
352
- S = (async () => {
361
+ const t = I;
362
+ p = (async () => {
353
363
  this.strategiesLoading = !0;
354
364
  try {
355
- this.strategies = await u.fetchRecommendationStrategies();
365
+ const e = await d.fetchRecommendationStrategies();
366
+ if (t !== I)
367
+ return;
368
+ if (this.strategies = e, this.strategiesFetched = !0, y) {
369
+ const r = j(e, y);
370
+ r && (this.lastCreatedStrategyId = r), y = new Set(e.map((n) => String(n.strategy_id)));
371
+ }
356
372
  } finally {
357
373
  this.strategiesLoading = !1;
358
374
  }
359
375
  })();
360
376
  try {
361
- await S;
377
+ await p;
362
378
  } finally {
363
- S = null;
379
+ p = null;
364
380
  }
365
381
  },
382
+ invalidateStrategies() {
383
+ this.strategiesFetched = !1, I += 1;
384
+ },
385
+ /**
386
+ * Opens a Smart Recommender strategy page in a new tab and refreshes the list every time
387
+ * the user comes back. `visibilitychange` covers the tab case; `focus` covers the page
388
+ * landing in a separate window, where this document never goes hidden.
389
+ *
390
+ * Deliberately NOT one-shot: the strategy tab stays open, so a user can create a second
391
+ * strategy in it and come back again — a listener that disarmed on the first return would
392
+ * leave that one missing from the list. Armed only once the user actually opens a strategy
393
+ * page, so anyone who never does pays nothing.
394
+ */
395
+ _armStrategyPageReturn(t) {
396
+ window.open(t, "_blank", "noopener"), u == null || u();
397
+ let e = !1;
398
+ const r = () => {
399
+ document.hidden || e || (e = !0, this.invalidateStrategies(), this.fetchStrategies().catch(() => {
400
+ }).finally(() => {
401
+ e = !1;
402
+ }));
403
+ };
404
+ document.addEventListener("visibilitychange", r), window.addEventListener("focus", r), u = () => {
405
+ document.removeEventListener("visibilitychange", r), window.removeEventListener("focus", r), u = null;
406
+ };
407
+ },
408
+ /** Lets the editor tear the return listeners down when it unmounts. */
409
+ disposeStrategyPageReturn() {
410
+ u == null || u(), y = null;
411
+ },
412
+ /**
413
+ * Opens Smart Recommender's strategy creation page. Every return refreshes the list, and any
414
+ * strategy that appeared since the page was opened is remembered so the drawer preselects it —
415
+ * including a second one created without ever closing that tab.
416
+ */
417
+ openStrategyCreation() {
418
+ y = new Set(this.strategies.map((t) => String(t.strategy_id))), this._armStrategyPageReturn(D.RECOMMENDATION_STRATEGY_CREATE_PATH);
419
+ },
420
+ /**
421
+ * Opens the strategy's edit page. Every return refreshes the list so the block reflects the
422
+ * edited configuration; nothing is preselected because the strategy is already assigned.
423
+ */
424
+ openStrategyEdit(t) {
425
+ this._armStrategyPageReturn(_(t));
426
+ },
366
427
  async resolveStrategyUrlTemplate(t, e) {
367
428
  const r = typeof t.updated_at == "string" ? t.updated_at : "", n = r ? `${t.strategy_id}:${r}:${e}` : "", s = n ? this.strategyUrlTemplates[n] : void 0;
368
429
  if (s)
369
430
  return s;
370
- const { full_path: i = "" } = await u.generateStrategyEndpoint(t, e) ?? {};
431
+ const { full_path: i = "" } = await d.generateStrategyEndpoint(t, e) ?? {};
371
432
  return n && i && (this.strategyUrlTemplates = {
372
433
  ...this.strategyUrlTemplates,
373
434
  [n]: i
@@ -380,23 +441,23 @@ const z = () => ({
380
441
  });
381
442
  },
382
443
  removeStrategy() {
383
- this.patchCurrentBlockConfig({ strategyId: "", size: N.size });
444
+ this.patchCurrentBlockConfig({ strategyId: "", size: M.size });
384
445
  },
385
446
  // ====================================================================
386
447
  // Shared Data Fetching (fetched once, used by all blocks)
387
448
  // ====================================================================
388
449
  async fetchRecommendationCreateData() {
389
450
  if (!this.activePredictiveAlgorithms.length) {
390
- if (f) {
391
- await f;
451
+ if (g) {
452
+ await g;
392
453
  return;
393
454
  }
394
- f = (async () => {
455
+ g = (async () => {
395
456
  const {
396
457
  activePredictiveAlgorithms: t,
397
458
  languages: e,
398
459
  currencies: r
399
- } = await u.fetchRecommendationCreateData();
460
+ } = await d.fetchRecommendationCreateData();
400
461
  if (this.activePredictiveAlgorithms = t, this.languages = e, this.currentRecommendationId !== null && this.blockStates[this.currentRecommendationId]) {
401
462
  const n = this.blockStates[this.currentRecommendationId];
402
463
  n.filterStatus = !!n.recommendationConfigs.filters.length;
@@ -404,9 +465,9 @@ const z = () => ({
404
465
  this.currencyList = r;
405
466
  })();
406
467
  try {
407
- await f;
468
+ await g;
408
469
  } finally {
409
- f = null;
470
+ g = null;
410
471
  }
411
472
  }
412
473
  },
@@ -417,7 +478,7 @@ const z = () => ({
417
478
  return;
418
479
  }
419
480
  h = (async () => {
420
- const t = await u.fetchRecommendationFilters();
481
+ const t = await d.fetchRecommendationFilters();
421
482
  this.filterList = t;
422
483
  })();
423
484
  try {
@@ -452,7 +513,7 @@ const z = () => ({
452
513
  const n = [...e.recommendationConfigs.filters];
453
514
  n[r] = {
454
515
  ...t,
455
- isValid: B(t)
516
+ isValid: V(t)
456
517
  }, e.recommendationConfigs.filters = n;
457
518
  }
458
519
  },
@@ -490,7 +551,7 @@ const z = () => ({
490
551
  }), e.recommendationConfigs.filters = r;
491
552
  },
492
553
  generateFilterQuery() {
493
- return k(this.recommendationConfigs.filters);
554
+ return G(this.recommendationConfigs.filters);
494
555
  },
495
556
  /**
496
557
  * Validation-only check invoked at save-CTA time. Defined as an action
@@ -498,33 +559,33 @@ const z = () => ({
498
559
  * every block's recommendationConfigs across user edits.
499
560
  */
500
561
  hasInvalidBlock() {
501
- return Object.values(this.blockStates).some((t) => !M(t.recommendationConfigs, this));
562
+ return Object.values(this.blockStates).some((t) => !$(t.recommendationConfigs, this));
502
563
  },
503
564
  // ====================================================================
504
565
  // Per-Block Product Fetching
505
566
  // ====================================================================
506
567
  async fetchRecommendationProducts() {
507
568
  if (!(this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])) {
508
- if (g) {
509
- await g;
569
+ if (S) {
570
+ await S;
510
571
  return;
511
572
  }
512
- g = this._doFetchProducts();
573
+ S = this._doFetchProducts();
513
574
  try {
514
- await g;
575
+ await S;
515
576
  } finally {
516
- g = null;
577
+ S = null;
517
578
  }
518
579
  }
519
580
  },
520
581
  async _doFetchProducts() {
521
- var d;
522
- const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, n = P();
582
+ var f;
583
+ const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, n = E();
523
584
  if (r.strategyId && n.isFeatureEnabled("reusableRecommendationStrategy")) {
524
585
  await this._doFetchStrategyProducts(t);
525
586
  return;
526
587
  }
527
- const s = r.filters.filter((m) => m.isValid), i = k(s), o = ((d = b().find((m) => m.key === r.strategy)) == null ? void 0 : d.path) || "", c = parseInt(r.size) || 6, a = {
588
+ const s = r.filters.filter((m) => m.isValid), i = G(s), o = ((f = C().find((m) => m.key === r.strategy)) == null ? void 0 : f.path) || "", c = parseInt(r.size) || 6, a = {
528
589
  locale: r.language,
529
590
  currency: r.currencySettings.value,
530
591
  partnerName: n.partnerName,
@@ -532,21 +593,21 @@ const z = () => ({
532
593
  details: !0,
533
594
  campaignId: n.variationId
534
595
  };
535
- r.strategy === "manualMerchandising" ? a.productId = A(r.productIds) : r.strategy === "similarViewed" && (a.productId = "{itemId}"), r.strategy === "userBased" && (a.userId = "{user_id}"), i && (a.filter = i), r.shuffleProducts && (a.shuffle = !0), Object.assign(
596
+ r.strategy === "manualMerchandising" ? a.productId = z(r.productIds) : r.strategy === "similarViewed" && (a.productId = "{itemId}"), r.strategy === "userBased" && (a.userId = "{user_id}"), i && (a.filter = i), r.shuffleProducts && (a.shuffle = !0), Object.assign(
536
597
  a,
537
- x(n.partnerName, r.strategy)
598
+ O(n.partnerName, r.strategy)
538
599
  );
539
600
  let l;
540
601
  try {
541
- l = await u.fetchRecommendationProducts(o, a);
602
+ l = await d.fetchRecommendationProducts(o, a);
542
603
  } catch {
543
604
  l = [];
544
605
  }
545
606
  this._setBlockProducts(t, l, c);
546
607
  },
547
608
  async _doFetchStrategyProducts(t) {
548
- const e = (p.get(t) ?? 0) + 1;
549
- p.set(t, e);
609
+ const e = (b.get(t) ?? 0) + 1;
610
+ b.set(t, e);
550
611
  const { recommendationConfigs: r } = this.blockStates[t];
551
612
  let n = [], s = parseInt(r.size) || 6;
552
613
  try {
@@ -556,25 +617,25 @@ const z = () => ({
556
617
  );
557
618
  if (i) {
558
619
  s = parseInt(String(i.size ?? "")) || s;
559
- const o = r.currencySettings.value, a = (await this.resolveStrategyUrlTemplate(i, o)).replaceAll("{locale}", r.language).replaceAll("{currency}", o), l = a.indexOf("?"), d = l === -1 ? a : a.slice(0, l), m = (l === -1 ? "" : a.slice(l + 1)).split("&").filter((I) => I && !I.startsWith("user_id=")), y = m.length ? `${d}?${m.join("&")}` : d;
560
- y && (n = await u.fetchRecommendationProductsByUrl(y));
620
+ const o = r.currencySettings.value, a = (await this.resolveStrategyUrlTemplate(i, o)).replaceAll("{locale}", r.language).replaceAll("{currency}", o), l = a.indexOf("?"), f = l === -1 ? a : a.slice(0, l), m = (l === -1 ? "" : a.slice(l + 1)).split("&").filter((k) => k && !k.startsWith("user_id=")), R = m.length ? `${f}?${m.join("&")}` : f;
621
+ R && (n = await d.fetchRecommendationProductsByUrl(R));
561
622
  }
562
623
  } catch {
563
624
  n = [];
564
625
  }
565
- p.get(t) === e && this._setBlockProducts(t, n, s);
626
+ b.get(t) === e && this._setBlockProducts(t, n, s);
566
627
  },
567
628
  _setBlockProducts(t, e, r) {
568
629
  if (!this.blockStates[t])
569
630
  return;
570
- const n = e.length > 0 ? e : R(r);
631
+ const n = e.length > 0 ? e : v(r);
571
632
  this.blockStates[t].recommendationProducts = [
572
633
  ...n.slice(0, r),
573
- ...R(Math.max(0, r - n.length))
634
+ ...v(Math.max(0, r - n.length))
574
635
  ];
575
636
  }
576
637
  }
577
638
  });
578
639
  export {
579
- Y as useRecommendationExtensionStore
640
+ st as useRecommendationExtensionStore
580
641
  };