@useinsider/guido 3.17.0-beta.e6704da → 3.17.0-beta.eae947f

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 (49) hide show
  1. package/README.md +5 -6
  2. package/dist/@types/config/schemas.js +6 -12
  3. package/dist/components/Guido.vue.js +6 -6
  4. package/dist/components/Guido.vue2.js +61 -63
  5. package/dist/composables/useCustomInterfaceAppearance.js +16 -19
  6. package/dist/composables/useRecommendation.js +34 -41
  7. package/dist/config/migrator/recommendationMigrator.js +4 -6
  8. package/dist/enums/academy.js +1 -2
  9. package/dist/enums/date.js +3 -4
  10. package/dist/enums/extensions/recommendationBlock.js +23 -25
  11. package/dist/extensions/Blocks/Items/block.js +98 -49
  12. package/dist/extensions/Blocks/Items/constants/currency.js +11 -0
  13. package/dist/extensions/Blocks/Items/controls/price/currencyLocation.js +25 -24
  14. package/dist/extensions/Blocks/Items/controls/price/currencySymbol.js +12 -11
  15. package/dist/extensions/Blocks/Items/template.js +153 -152
  16. package/dist/extensions/Blocks/Recommendation/constants/defaultConfig.js +11 -13
  17. package/dist/extensions/Blocks/Recommendation/controls/cardComposition/index.js +95 -96
  18. package/dist/extensions/Blocks/Recommendation/controls/main/index.js +154 -156
  19. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +68 -216
  20. package/dist/extensions/Blocks/common-control.js +19 -22
  21. package/dist/guido.css +1 -1
  22. package/dist/services/recommendationApi.js +29 -78
  23. package/dist/src/@types/config/schemas.d.ts +0 -12
  24. package/dist/src/composables/useConfig.d.ts +0 -2
  25. package/dist/src/composables/useRecommendation.d.ts +0 -1
  26. package/dist/src/enums/academy.d.ts +0 -1
  27. package/dist/src/enums/extensions/recommendationBlock.d.ts +0 -2
  28. package/dist/src/extensions/Blocks/Items/block.d.ts +21 -0
  29. package/dist/src/extensions/Blocks/Items/constants/currency.d.ts +19 -0
  30. package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +3 -14
  31. package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +10 -214
  32. package/dist/src/extensions/Blocks/Recommendation/types/nodeConfig.d.ts +0 -6
  33. package/dist/src/extensions/Blocks/common-control.d.ts +1 -4
  34. package/dist/src/services/recommendationApi.d.ts +1 -4
  35. package/dist/src/stores/config.d.ts +0 -18
  36. package/dist/utils/dateUtil.js +10 -23
  37. package/dist/utils/pairProductVariables.js +60 -59
  38. package/dist/utils/templatePreparation.js +34 -37
  39. package/package.json +2 -3
  40. package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue.js +0 -18
  41. package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue2.js +0 -70
  42. package/dist/components/organisms/extensions/recommendation/StrategyInfoBox.vue.js +0 -20
  43. package/dist/components/organisms/extensions/recommendation/StrategyInfoBox.vue2.js +0 -55
  44. package/dist/extensions/Blocks/Recommendation/controls/main/strategy.js +0 -141
  45. package/dist/src/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue.d.ts +0 -3
  46. package/dist/src/components/organisms/extensions/recommendation/StrategyInfoBox.vue.d.ts +0 -24
  47. package/dist/src/extensions/Blocks/Recommendation/controls/main/strategy.d.ts +0 -29
  48. package/dist/src/mock/api/recommendation-strategies.d.ts +0 -43
  49. package/dist/static/styles/components/recommendation-strategy.css.js +0 -171
@@ -1,101 +1,52 @@
1
- import { useHttp as p } from "../composables/useHttp.js";
2
- import { URLS as m, RRS_ACTIVE_EMAIL_FILTER as l, QUERY_PARAMS as h } from "../enums/extensions/recommendationBlock.js";
3
- const R = 100, y = (s) => s.reduce(
4
- (i, a, d) => (i[d] = {
5
- attributeName: a.attributeName,
6
- attributeJs: a.attributeJs,
7
- attributeType: a.attributeType,
8
- type: a.type,
9
- displayName: a.displayName,
10
- isFilterable: a.isFilterable
11
- }, i),
1
+ import { useHttp as d } from "../composables/useHttp.js";
2
+ import { QUERY_PARAMS as l, URLS as u } from "../enums/extensions/recommendationBlock.js";
3
+ const R = (o) => o.reduce(
4
+ (a, t, s) => (a[s] = {
5
+ attributeName: t.attributeName,
6
+ attributeJs: t.attributeJs,
7
+ attributeType: t.attributeType,
8
+ type: t.type,
9
+ displayName: t.displayName,
10
+ isFilterable: t.isFilterable
11
+ }, a),
12
12
  {}
13
- ), w = () => {
14
- const { get: s, post: i } = p(), { get: a } = p({ headers: {} }), d = "6KcLM9TwheVB1mgK";
13
+ ), f = () => {
14
+ const { get: o } = d(), { get: a } = d({ headers: {} }), t = "6KcLM9TwheVB1mgK";
15
15
  return {
16
16
  fetchRecommendationCreateData: async () => {
17
17
  try {
18
- return (await s("/newsletter/recommendations/create-data")).data;
18
+ return (await o("/newsletter/recommendations/create-data")).data;
19
19
  } catch (e) {
20
20
  throw console.error("fetchUserModalState error:", e), e;
21
21
  }
22
22
  },
23
23
  fetchRecommendationFilters: async () => {
24
24
  try {
25
- const { data: e } = await s(
26
- m.PRODUCT_ATTRIBUTES_PATH
27
- ), t = Array.isArray(e) ? e : (e == null ? void 0 : e.data) ?? [];
28
- return y(t);
25
+ const { data: e } = await o(
26
+ u.PRODUCT_ATTRIBUTES_PATH
27
+ ), n = Array.isArray(e) ? e : (e == null ? void 0 : e.data) ?? [];
28
+ return R(n);
29
29
  } catch (e) {
30
30
  throw console.error("fetchRecommendationFilters error:", e), e;
31
31
  }
32
32
  },
33
- fetchRecommendationProducts: async (e, t) => {
34
- var r;
33
+ fetchRecommendationProducts: async (e, n) => {
34
+ var i;
35
35
  try {
36
- const o = new URLSearchParams(Object.entries(t));
37
- o.set(h.CLIENT_ID, d);
38
- const c = decodeURIComponent(o.toString());
39
- console.debug("🏁 Recommendation API Query:", c);
40
- const n = await a(
41
- `${m.RECOMMENDATION_API_URL}/v2/${e}?${c}`
36
+ const r = new URLSearchParams(Object.entries(n));
37
+ r.set(l.CLIENT_ID, t);
38
+ const m = decodeURIComponent(r.toString());
39
+ console.debug("🏁 Recommendation API Query:", m);
40
+ const c = await a(
41
+ `${u.RECOMMENDATION_API_URL}/v2/${e}?${m}`
42
42
  );
43
- return ((r = n == null ? void 0 : n.data) == null ? void 0 : r.data) ?? [];
44
- } catch (o) {
45
- throw console.error("fetchRecommendationProducts error:", o), o;
46
- }
47
- },
48
- fetchRecommendationProductsByUrl: async (e) => {
49
- var t;
50
- try {
51
- const r = new RegExp(`[?&]${h.CLIENT_ID}=`).test(e), o = e.includes("?") ? "&" : "?", c = r ? e : `${e}${o}${h.CLIENT_ID}=${d}`, n = await a(
52
- c
53
- );
54
- return ((t = n == null ? void 0 : n.data) == null ? void 0 : t.data) ?? [];
43
+ return ((i = c == null ? void 0 : c.data) == null ? void 0 : i.data) ?? [];
55
44
  } catch (r) {
56
- throw console.error("fetchRecommendationProductsByUrl error:", r), r;
57
- }
58
- },
59
- fetchRecommendationStrategies: async () => {
60
- try {
61
- const e = /* @__PURE__ */ new Map();
62
- let t = 1;
63
- for (; ; ) {
64
- const { data: r } = await s(
65
- `${m.RECOMMENDATION_STRATEGIES_PATH}?filters=${encodeURIComponent(l)}&per_page=${R}&page=${t}`
66
- ), o = Array.isArray(r) ? r : (r == null ? void 0 : r.data) ?? [], c = e.size;
67
- if (o.forEach((n) => e.set(n.strategy_id, n)), o.length < R || e.size === c)
68
- break;
69
- t += 1;
70
- }
71
- return [...e.values()];
72
- } catch (e) {
73
- throw console.error("fetchRecommendationStrategies error:", e), e;
74
- }
75
- },
76
- generateStrategyEndpoint: async (e) => {
77
- try {
78
- const { data: t } = await i(
79
- `${m.RECOMMENDATION_STRATEGIES_PATH}/endpoint-generate`,
80
- {
81
- // Email designs have no campaign yet; backend only needs it
82
- // for previewer flows.
83
- campaignId: 0,
84
- pageTypes: [],
85
- isPreviewer: !1,
86
- strategy: e,
87
- userId: ""
88
- }
89
- );
90
- if (!t || typeof t != "object" || !("full_path" in t || "data" in t))
91
- throw new Error("Unexpected endpoint-generate response shape");
92
- return "full_path" in t ? t : t.data;
93
- } catch (t) {
94
- throw console.error("generateStrategyEndpoint error:", t), t;
45
+ throw console.error("fetchRecommendationProducts error:", r), r;
95
46
  }
96
47
  }
97
48
  };
98
49
  };
99
50
  export {
100
- w as useRecommendationApi
51
+ f as useRecommendationApi
101
52
  };
@@ -395,12 +395,6 @@ export declare const FeaturesSchema: v.ObjectSchema<{
395
395
  readonly allowlistEnabled: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
396
396
  /** Enable persistent link tracking-id assignment for the click heatmap (opt-in) */
397
397
  readonly linkTrackingIds: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
398
- /**
399
- * Assign a Reusable Recommendation Strategy (RRS) to recommendation blocks instead of
400
- * per-block algorithm settings. Hides Algorithm, Filters, Shuffle and Number of Products
401
- * (they live on the strategy) and adds the Assign Strategy flow.
402
- */
403
- readonly reusableRecommendationStrategy: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
404
398
  }, undefined>;
405
399
  /**
406
400
  * Default block types available in Stripo
@@ -800,12 +794,6 @@ export declare const GuidoConfigSchema: v.ObjectSchema<{
800
794
  readonly allowlistEnabled: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
801
795
  /** Enable persistent link tracking-id assignment for the click heatmap (opt-in) */
802
796
  readonly linkTrackingIds: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
803
- /**
804
- * Assign a Reusable Recommendation Strategy (RRS) to recommendation blocks instead of
805
- * per-block algorithm settings. Hides Algorithm, Filters, Shuffle and Number of Products
806
- * (they live on the strategy) and adds the Assign Strategy flow.
807
- */
808
- readonly reusableRecommendationStrategy: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
809
797
  }, undefined>, {}>;
810
798
  /** Block configuration */
811
799
  readonly blocks: v.OptionalSchema<v.ObjectSchema<{
@@ -99,7 +99,6 @@ export declare const useConfig: () => {
99
99
  autosave: boolean;
100
100
  allowlistEnabled: boolean;
101
101
  linkTrackingIds: boolean;
102
- reusableRecommendationStrategy: boolean;
103
102
  };
104
103
  blocks: {
105
104
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -234,7 +233,6 @@ export declare const useConfig: () => {
234
233
  autosave: boolean;
235
234
  allowlistEnabled: boolean;
236
235
  linkTrackingIds: boolean;
237
- reusableRecommendationStrategy: boolean;
238
236
  } | null>;
239
237
  blocks: import("vue").ComputedRef<{
240
238
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -18,7 +18,6 @@ export declare const useRecommendation: () => {
18
18
  getRecommendationCampaignData: (id: string) => CampaignData;
19
19
  buildCampaignUrl: (campaignId: string, overrides?: {
20
20
  strategy: string;
21
- strategyId: string;
22
21
  language: string;
23
22
  currencyCode: string;
24
23
  size: string;
@@ -8,6 +8,5 @@ export declare const ACADEMY_LINKS: {
8
8
  readonly EMAIL_EDITOR: "https://academy.insiderone.com/docs/email-drag-and-drop-editor";
9
9
  readonly GLOBAL_UNSUBSCRIBE: "https://academy.insiderone.com/docs/global-unsubscribe-preference-center";
10
10
  readonly AMP_FOR_EMAILS: "https://academy.insiderone.com/docs/amp-for-emails";
11
- readonly EMAIL_RECOMMENDATION_BLOCK: "https://academy.insiderone.com/docs/new-editor-email-recommendation-block";
12
11
  };
13
12
  export type AcademyLinkKey = keyof typeof ACADEMY_LINKS;
@@ -3,9 +3,7 @@ import type { RecommendationFeedItem } from '@@/Types/recommendation';
3
3
  export declare const URLS: {
4
4
  RECOMMENDATION_API_URL: string;
5
5
  PRODUCT_ATTRIBUTES_PATH: string;
6
- RECOMMENDATION_STRATEGIES_PATH: string;
7
6
  };
8
- export declare const RRS_ACTIVE_EMAIL_FILTER = "[sr_strategies.status][=][active]*[sr_strategies.suitable_channels][~][EMAIL]";
9
7
  export declare const QUERY_PARAMS: {
10
8
  CLIENT_ID: string;
11
9
  };
@@ -16,6 +16,8 @@ export declare const BLOCK_ID: BlockId;
16
16
  * - Onboarding support
17
17
  */
18
18
  export declare class ItemsBlock extends Block {
19
+ /** Block instances whose currency attrs were already self-healed this session (SD-147588 — undo-safe). */
20
+ private _currencyHealed;
19
21
  getId(): string;
20
22
  getIcon(): string;
21
23
  getBlockCompositionType(): BlockCompositionType;
@@ -42,4 +44,23 @@ export declare class ItemsBlock extends Block {
42
44
  * relies on this td-level fallback in pairProductVariables.
43
45
  */
44
46
  private _stampProductTdDomAttributes;
47
+ /**
48
+ * Whether the currency self-heal should run for this block. Two guards (SD-147588):
49
+ * 1. Config is only authoritative when the symbol was actually customized — a symbol still at
50
+ * the 'USD' sentinel may be a migrator default, so we trust the DOM's real value over a
51
+ * defaulted config and never overwrite it.
52
+ * 2. Heal each instance at most once per session, so the auto-fix can't fight undo (undo
53
+ * re-drifts the attr, which would otherwise re-trigger the heal forever).
54
+ */
55
+ private _shouldReconcileCurrency;
56
+ /** Marks a block instance's currency as reconciled so it is not healed again (undo-safe). */
57
+ private _markCurrencyHealed;
58
+ /**
59
+ * Stamps the export-read currency attrs onto every price `<p>` from config, so a template whose
60
+ * attrs drifted (e.g. a location toggle before the sync fix) self-heals to match the editor.
61
+ * Config is the source of truth — never derive from visible text. Callers gate this with
62
+ * `_shouldReconcileCurrency`. Returns true only when an attr actually changed, so the caller can
63
+ * skip an empty apply that would otherwise re-trigger onDocumentChanged and loop (SD-147588).
64
+ */
65
+ private _reconcileCurrencyDomAttributes;
45
66
  }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Single owner for the Items price currency export contract (SD-147588).
3
+ *
4
+ * `data-curency` is deliberately misspelled (one `r`) — it is the attribute the
5
+ * server-side export transform (pairProductVariables) actually reads, so every
6
+ * layer that writes it and the live reader (template, controls, block self-heal,
7
+ * pairProductVariables) MUST go through these constants. A typo fix or mapping change
8
+ * in one of them would otherwise silently break sync with the others and ship the wrong
9
+ * currency position/token to the inbox. Mirrors the Recommendation block's `CURRENCY_ATTR`.
10
+ *
11
+ * Exception: the legacy migrator reads the raw misspelled string on purpose — it parses
12
+ * old templates frozen with that exact attr name, so it must NOT follow a future rename here.
13
+ */
14
+ export declare const ITEMS_CURRENCY_ATTR: {
15
+ readonly POSITION: "data-curency";
16
+ readonly SYMBOL: "data-currency_symbol";
17
+ };
18
+ /** Currency location select value `'1'` = after (price then symbol), anything else = before. */
19
+ export declare function currencyPositionFromLocation(location: string | undefined): 'after' | 'before';
@@ -9,9 +9,8 @@ import { PricePlacementControl, PRICE_PLACEMENT_CONTROL_ID } from './pricePlacem
9
9
  import { ProductCountControl, PRODUCT_COUNT_CONTROL_ID } from './productCount';
10
10
  import { ProductLayoutControl, PRODUCT_LAYOUT_CONTROL_ID } from './productLayout';
11
11
  import { ShuffleControl, SHUFFLE_CONTROL_ID } from './shuffle';
12
- import { StrategyControl, STRATEGY_CONTROL_ID } from './strategy';
13
12
  export declare const CONTROL_BLOCK_ID = "ui-elements-recommendation-block";
14
- export { AlgorithmControl, ALGORITHM_CONTROL_ID, LocaleControl, LOCALE_CONTROL_ID, CurrencyControl, CURRENCY_CONTROL_ID, ProductCountControl, PRODUCT_COUNT_CONTROL_ID, ProductLayoutControl, PRODUCT_LAYOUT_CONTROL_ID, FiltersControl, FILTERS_CONTROL_ID, ShuffleControl, SHUFFLE_CONTROL_ID, LayoutOrientationControl, LAYOUT_ORIENTATION_CONTROL_ID, PricePlacementControl, PRICE_PLACEMENT_CONTROL_ID, StrategyControl, STRATEGY_CONTROL_ID, };
13
+ export { AlgorithmControl, ALGORITHM_CONTROL_ID, LocaleControl, LOCALE_CONTROL_ID, CurrencyControl, CURRENCY_CONTROL_ID, ProductCountControl, PRODUCT_COUNT_CONTROL_ID, ProductLayoutControl, PRODUCT_LAYOUT_CONTROL_ID, FiltersControl, FILTERS_CONTROL_ID, ShuffleControl, SHUFFLE_CONTROL_ID, LayoutOrientationControl, LAYOUT_ORIENTATION_CONTROL_ID, PricePlacementControl, PRICE_PLACEMENT_CONTROL_ID, };
15
14
  export * from './utils';
16
15
  /**
17
16
  * Main recommendation block control that composes all sub-controls
@@ -30,10 +29,7 @@ export declare class RecommendationBlockControl extends CommonControl {
30
29
  private shuffleControl;
31
30
  private pricePlacementControl;
32
31
  private layoutOrientationControl;
33
- private strategyControl;
34
32
  getId(): string;
35
- /** Every sub-control the coordinator owns, in panel order. */
36
- private get _subControls();
37
33
  getTemplate(): string;
38
34
  onRender(): Promise<void>;
39
35
  onTemplateNodeUpdated(node: ImmutableHtmlNode): void;
@@ -111,15 +107,8 @@ export declare class RecommendationBlockControl extends CommonControl {
111
107
  */
112
108
  private _listenStateUpdates;
113
109
  /**
114
- * Persists the current filter + strategy state from Pinia store to the
115
- * Stripo node config. This ensures they survive template save/reload cycles
116
- * (strategyId must be in esd-ext-config before any save — SD-149105).
117
- *
118
- * `size` rides along because assigning a strategy overwrites it in the
119
- * store only. Without this write, `_syncNodeConfigToStore` re-seeds the
120
- * store from the stale node config on the next panel open, and a block
121
- * whose saved HTML has the strategy's slot count gets rebuilt against the
122
- * old one — resetting migrator-applied per-element styles.
110
+ * Persists the current filter state from Pinia store to the Stripo node config.
111
+ * This ensures filters survive template save/reload cycles.
123
112
  */
124
113
  private _persistFiltersToNodeConfig;
125
114
  }