@useinsider/guido 3.18.1-beta.e9a6c91 → 3.18.1-beta.fefef3c

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 (48) hide show
  1. package/README.md +21 -3
  2. package/dist/@types/config/schemas.js +59 -51
  3. package/dist/components/Guido.vue.js +4 -4
  4. package/dist/components/Guido.vue2.js +72 -70
  5. package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue.js +7 -9
  6. package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue2.js +83 -72
  7. package/dist/components/organisms/extensions/recommendation/LegacyStrategyUpdatedModal.vue.js +18 -0
  8. package/dist/components/organisms/extensions/recommendation/LegacyStrategyUpdatedModal.vue2.js +25 -0
  9. package/dist/components/organisms/extensions/recommendation/RemoveStrategyModal.vue2.js +24 -22
  10. package/dist/components/organisms/onboarding/OnboardingWrapper.vue2.js +28 -26
  11. package/dist/components/organisms/onboarding/RecommendationLegacyStrategyOnboarding.vue.js +21 -0
  12. package/dist/components/organisms/onboarding/RecommendationLegacyStrategyOnboarding.vue2.js +46 -0
  13. package/dist/composables/useCustomInterfaceAppearance.js +46 -42
  14. package/dist/composables/useHtmlValidator.js +79 -84
  15. package/dist/composables/useLegacyStrategyConversion.js +61 -0
  16. package/dist/composables/useRecommendation.js +18 -21
  17. package/dist/enums/extensions/recommendationBlock.js +25 -29
  18. package/dist/extensions/Blocks/Recommendation/block.js +39 -43
  19. package/dist/extensions/Blocks/Recommendation/controls/main/index.js +72 -71
  20. package/dist/extensions/Blocks/Recommendation/controls/main/strategy.js +70 -40
  21. package/dist/extensions/Blocks/Recommendation/controls/main/utils.js +45 -44
  22. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +108 -138
  23. package/dist/extensions/Blocks/Recommendation/utils/legacyStrategyMigration.js +72 -0
  24. package/dist/extensions/Blocks/Recommendation/utils/nodeConfigWriter.js +7 -7
  25. package/dist/extensions/Blocks/Recommendation/validation/requiredFields.js +12 -21
  26. package/dist/guido.css +1 -1
  27. package/dist/services/recommendationApi.js +93 -84
  28. package/dist/src/@types/config/schemas.d.ts +16 -0
  29. package/dist/src/components/organisms/extensions/recommendation/LegacyStrategyUpdatedModal.vue.d.ts +2 -0
  30. package/dist/src/components/organisms/onboarding/RecommendationLegacyStrategyOnboarding.vue.d.ts +2 -0
  31. package/dist/src/composables/useConfig.d.ts +4 -0
  32. package/dist/src/composables/useLegacyStrategyConversion.d.ts +3 -0
  33. package/dist/src/enums/extensions/recommendationBlock.d.ts +3 -2
  34. package/dist/src/extensions/Blocks/Recommendation/controls/main/strategy.d.ts +1 -0
  35. package/dist/src/extensions/Blocks/Recommendation/controls/main/utils.d.ts +4 -0
  36. package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +54 -50
  37. package/dist/src/extensions/Blocks/Recommendation/utils/legacyStrategyMigration.d.ts +44 -0
  38. package/dist/src/extensions/Blocks/Recommendation/validation/requiredFields.d.ts +0 -4
  39. package/dist/src/services/recommendationApi.d.ts +2 -1
  40. package/dist/src/stores/config.d.ts +322 -0
  41. package/dist/src/stores/onboarding.d.ts +421 -0
  42. package/dist/static/assets/icons/filled-arrow-rising.svg.js +5 -0
  43. package/dist/static/assets/icons/line-info.svg.js +5 -0
  44. package/dist/static/styles/components/recommendation-strategy.css.js +74 -43
  45. package/dist/stores/config.js +74 -60
  46. package/dist/stores/onboarding.js +6 -1
  47. package/dist/utils/templatePreparation.js +50 -50
  48. package/package.json +1 -1
@@ -1,91 +1,100 @@
1
- import { useHttp as l } from "../composables/useHttp.js";
2
- import { URLS as m, QUERY_PARAMS as u } from "../enums/extensions/recommendationBlock.js";
3
- const y = "[sr_strategies.status][=][active]*[sr_strategies.suitable_channels][~][EMAIL]", R = (c) => c.reduce(
4
- (s, r, i) => (s[i] = {
5
- attributeName: r.attributeName,
6
- attributeJs: r.attributeJs,
7
- attributeType: r.attributeType,
8
- type: r.type,
9
- displayName: r.displayName,
10
- isFilterable: r.isFilterable
11
- }, s),
1
+ import { useHttp as T } from "../composables/useHttp.js";
2
+ import { URLS as c, QUERY_PARAMS as m, TEMPLATE_MIGRATION_SCOPE_SEGMENT as _, MIGRATE_STRATEGIES_SEGMENT as u } from "../enums/extensions/recommendationBlock.js";
3
+ const h = "[sr_strategies.status][=][active]*[sr_strategies.suitable_channels][~][EMAIL]", S = (i) => i.reduce(
4
+ (d, o, E) => (d[E] = {
5
+ attributeName: o.attributeName,
6
+ attributeJs: o.attributeJs,
7
+ attributeType: o.attributeType,
8
+ type: o.type,
9
+ displayName: o.displayName,
10
+ isFilterable: o.isFilterable
11
+ }, d),
12
12
  {}
13
- ), _ = () => {
14
- const { get: c, post: s } = l(), { get: r } = l({ headers: {} }), i = "6KcLM9TwheVB1mgK";
13
+ ), f = () => {
14
+ const { get: i, post: d } = T(), { get: o } = T({ headers: {} }), E = "6KcLM9TwheVB1mgK", y = async () => {
15
+ try {
16
+ return (await i(`${c.NEWSLETTER_RECOMMENDATIONS_PATH}/create-data`)).data;
17
+ } catch (t) {
18
+ throw console.error("fetchUserModalState error:", t), t;
19
+ }
20
+ }, R = async () => {
21
+ try {
22
+ const { data: t } = await i(
23
+ c.PRODUCT_ATTRIBUTES_PATH
24
+ ), a = Array.isArray(t) ? t : (t == null ? void 0 : t.data) ?? [];
25
+ return S(a);
26
+ } catch (t) {
27
+ throw console.error("fetchRecommendationFilters error:", t), t;
28
+ }
29
+ }, l = async (t, a) => {
30
+ var e;
31
+ try {
32
+ const r = new URLSearchParams(Object.entries(a));
33
+ r.set(m.CLIENT_ID, E);
34
+ const n = decodeURIComponent(r.toString());
35
+ console.debug("🏁 Recommendation API Query:", n);
36
+ const s = await o(
37
+ `${c.RECOMMENDATION_API_URL}/v2/${t}?${n}`
38
+ );
39
+ return ((e = s == null ? void 0 : s.data) == null ? void 0 : e.data) ?? [];
40
+ } catch (r) {
41
+ throw console.error("fetchRecommendationProducts error:", r), r;
42
+ }
43
+ }, g = async (t) => {
44
+ var a;
45
+ try {
46
+ const e = new RegExp(`[?&]${m.CLIENT_ID}=`).test(t), r = t.includes("?") ? "&" : "?", n = e ? t : `${t}${r}${m.CLIENT_ID}=${E}`, s = await o(
47
+ n
48
+ );
49
+ return ((a = s == null ? void 0 : s.data) == null ? void 0 : a.data) ?? [];
50
+ } catch (e) {
51
+ return console.error("fetchRecommendationProductsByUrl error:", e), [];
52
+ }
53
+ }, p = async () => {
54
+ try {
55
+ const { data: t } = await i(
56
+ `${c.RECOMMENDATION_STRATEGIES_PATH}?filters=${encodeURIComponent(h)}`
57
+ );
58
+ return Array.isArray(t) ? t : (t == null ? void 0 : t.data) ?? [];
59
+ } catch (t) {
60
+ throw console.error("fetchRecommendationStrategies error:", t), t;
61
+ }
62
+ }, I = async (t, a) => {
63
+ try {
64
+ const { data: e } = await d(
65
+ `${c.RECOMMENDATION_STRATEGIES_PATH}/endpoint-generate`,
66
+ {
67
+ campaignId: 0,
68
+ pageTypes: [],
69
+ isPreviewer: !1,
70
+ strategy: t,
71
+ userId: "",
72
+ currency: a
73
+ }
74
+ );
75
+ return !e || typeof e != "object" || !("full_path" in e || "data" in e) ? (console.error("generateStrategyEndpoint unexpected response shape:", e), null) : "full_path" in e ? e : e.data;
76
+ } catch (e) {
77
+ return console.error("generateStrategyEndpoint error:", e), null;
78
+ }
79
+ }, A = (t) => t.scope === "template" ? `${c.NEWSLETTER_RECOMMENDATIONS_PATH}/${_}/${u}` : `${c.NEWSLETTER_RECOMMENDATIONS_PATH}/${u}`;
15
80
  return {
16
- fetchRecommendationCreateData: async () => {
17
- try {
18
- return (await c("/newsletter/recommendations/create-data")).data;
19
- } catch (e) {
20
- throw console.error("fetchUserModalState error:", e), e;
21
- }
22
- },
23
- fetchRecommendationFilters: async () => {
24
- try {
25
- const { data: e } = await c(
26
- m.PRODUCT_ATTRIBUTES_PATH
27
- ), o = Array.isArray(e) ? e : (e == null ? void 0 : e.data) ?? [];
28
- return R(o);
29
- } catch (e) {
30
- throw console.error("fetchRecommendationFilters error:", e), e;
31
- }
32
- },
33
- fetchRecommendationProducts: async (e, o) => {
34
- var t;
35
- try {
36
- const n = new URLSearchParams(Object.entries(o));
37
- n.set(u.CLIENT_ID, i);
38
- const d = decodeURIComponent(n.toString());
39
- console.debug("🏁 Recommendation API Query:", d);
40
- const a = await r(
41
- `${m.RECOMMENDATION_API_URL}/v2/${e}?${d}`
42
- );
43
- return ((t = a == null ? void 0 : a.data) == null ? void 0 : t.data) ?? [];
44
- } catch (n) {
45
- throw console.error("fetchRecommendationProducts error:", n), n;
46
- }
47
- },
48
- fetchRecommendationProductsByUrl: async (e) => {
49
- var o;
50
- try {
51
- const t = new RegExp(`[?&]${u.CLIENT_ID}=`).test(e), n = e.includes("?") ? "&" : "?", d = t ? e : `${e}${n}${u.CLIENT_ID}=${i}`, a = await r(
52
- d
53
- );
54
- return ((o = a == null ? void 0 : a.data) == null ? void 0 : o.data) ?? [];
55
- } catch (t) {
56
- return console.error("fetchRecommendationProductsByUrl error:", t), [];
57
- }
58
- },
59
- fetchRecommendationStrategies: async () => {
60
- try {
61
- const { data: e } = await c(
62
- `${m.RECOMMENDATION_STRATEGIES_PATH}?filters=${encodeURIComponent(y)}`
63
- );
64
- return Array.isArray(e) ? e : (e == null ? void 0 : e.data) ?? [];
65
- } catch (e) {
66
- throw console.error("fetchRecommendationStrategies error:", e), e;
67
- }
68
- },
69
- generateStrategyEndpoint: async (e, o) => {
70
- try {
71
- const { data: t } = await s(
72
- `${m.RECOMMENDATION_STRATEGIES_PATH}/endpoint-generate`,
73
- {
74
- campaignId: 0,
75
- pageTypes: [],
76
- isPreviewer: !1,
77
- strategy: e,
78
- userId: "",
79
- currency: o
80
- }
81
- );
82
- return !t || typeof t != "object" || !("full_path" in t || "data" in t) ? (console.error("generateStrategyEndpoint unexpected response shape:", t), null) : "full_path" in t ? t : t.data;
83
- } catch (t) {
84
- return console.error("generateStrategyEndpoint error:", t), null;
85
- }
81
+ fetchRecommendationCreateData: y,
82
+ fetchRecommendationFilters: R,
83
+ fetchRecommendationProducts: l,
84
+ fetchRecommendationProductsByUrl: g,
85
+ fetchRecommendationStrategies: p,
86
+ generateStrategyEndpoint: I,
87
+ migrateLegacyStrategy: async (t, a = { scope: "campaign" }) => {
88
+ const { data: e } = await d(
89
+ A(a),
90
+ t
91
+ ), r = e && typeof e == "object" && "data" in e ? e.data : e, n = r == null ? void 0 : r.strategyId;
92
+ if (n == null || n === "")
93
+ throw new Error("[Guido] migrate-strategies returned no strategyId");
94
+ return String(n);
86
95
  }
87
96
  };
88
97
  };
89
98
  export {
90
- _ as useRecommendationApi
99
+ f as useRecommendationApi
91
100
  };
@@ -50,6 +50,14 @@ export declare const IdentitySchema: v.ObjectSchema<{
50
50
  readonly userId: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, "userId is required">]>;
51
51
  /** Optional variation ID for A/B testing */
52
52
  readonly variationId: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
53
+ /** Optional numeric campaign ID of the host campaign; absent for templates and modules */
54
+ readonly campaignId: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
55
+ /**
56
+ * Optional numeric template-library id of the host template; absent for campaigns and
57
+ * modules. Distinct from `templateId`, which is the editor's document identity (a uuid /
58
+ * Stripo doc id) and is never an endpoint id.
59
+ */
60
+ readonly templateLibraryId: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
53
61
  }, undefined>;
54
62
  /**
55
63
  * Partner configuration - organization and product context
@@ -625,6 +633,14 @@ export declare const GuidoConfigSchema: v.ObjectSchema<{
625
633
  readonly userId: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, "userId is required">]>;
626
634
  /** Optional variation ID for A/B testing */
627
635
  readonly variationId: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
636
+ /** Optional numeric campaign ID of the host campaign; absent for templates and modules */
637
+ readonly campaignId: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
638
+ /**
639
+ * Optional numeric template-library id of the host template; absent for campaigns and
640
+ * modules. Distinct from `templateId`, which is the editor's document identity (a uuid /
641
+ * Stripo doc id) and is never an endpoint id.
642
+ */
643
+ readonly templateLibraryId: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
628
644
  }, undefined>;
629
645
  /** Partner configuration (required) */
630
646
  readonly partner: v.ObjectSchema<{
@@ -0,0 +1,2 @@
1
+ declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue/types/v3-component-options.js").ComponentOptionsMixin, import("vue/types/v3-component-options.js").ComponentOptionsMixin, {}, string, Readonly<import("vue").ExtractPropTypes<{}>>, {}>;
2
+ export default _default;
@@ -0,0 +1,2 @@
1
+ declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue/types/v3-component-options.js").ComponentOptionsMixin, import("vue/types/v3-component-options.js").ComponentOptionsMixin, {}, string, Readonly<import("vue").ExtractPropTypes<{}>>, {}>;
2
+ export default _default;
@@ -11,6 +11,8 @@ export declare const useConfig: () => {
11
11
  templateId: string;
12
12
  userId: string;
13
13
  variationId?: string | undefined;
14
+ campaignId?: string | undefined;
15
+ templateLibraryId?: string | undefined;
14
16
  };
15
17
  partner: {
16
18
  name: string;
@@ -146,6 +148,8 @@ export declare const useConfig: () => {
146
148
  templateId: string;
147
149
  userId: string;
148
150
  variationId?: string | undefined;
151
+ campaignId?: string | undefined;
152
+ templateLibraryId?: string | undefined;
149
153
  } | null>;
150
154
  partner: import("vue").ComputedRef<{
151
155
  name: string;
@@ -0,0 +1,3 @@
1
+ export declare const useLegacyStrategyConversion: () => {
2
+ convertLegacyStrategy: () => Promise<string>;
3
+ };
@@ -5,9 +5,10 @@ export declare const URLS: {
5
5
  PRODUCT_ATTRIBUTES_PATH: string;
6
6
  RECOMMENDATION_STRATEGIES_PATH: string;
7
7
  RECOMMENDATION_STRATEGIES_PANEL_PATH: string;
8
- RECOMMENDATION_STRATEGY_CREATE_PATH: string;
8
+ NEWSLETTER_RECOMMENDATIONS_PATH: string;
9
9
  };
10
- export declare const strategyEditPath: (strategyId: string | number) => string;
10
+ export declare const MIGRATE_STRATEGIES_SEGMENT = "migrate-strategies";
11
+ export declare const TEMPLATE_MIGRATION_SCOPE_SEGMENT = "template";
11
12
  export declare const QUERY_PARAMS: {
12
13
  CLIENT_ID: string;
13
14
  };
@@ -3,6 +3,7 @@ export declare const STRATEGY_CONTROL_ID = "recommendation-strategy-control";
3
3
  export declare class StrategyControl extends CommonControl {
4
4
  private store;
5
5
  private onboardingStore;
6
+ private legacyConversion;
6
7
  private storeUnsubscription;
7
8
  private listeners;
8
9
  private lastPaintedState;
@@ -88,6 +88,8 @@ export interface RegenerateWithStylesOptions extends Omit<RegenerateProductRowsO
88
88
  products?: RecommendationProduct[];
89
89
  /** Optional: pass layout directly to avoid stale DOM reads after setAttribute */
90
90
  layout?: Orientation;
91
+ /** Applies the batch even when the rows are unchanged, for callers that staged their own edits. */
92
+ forceApply?: boolean;
91
93
  }
92
94
  /**
93
95
  * Regenerates product rows while preserving user-applied styles, in a SINGLE commit.
@@ -151,6 +153,8 @@ export interface UpdateProductContentInPlaceOptions {
151
153
  currentNode: ImmutableHtmlNode | null | undefined;
152
154
  documentModifier: DocumentModifier;
153
155
  products: RecommendationProduct[];
156
+ /** Applies the batch even when the cards are unchanged, for callers that staged their own edits. */
157
+ forceApply?: boolean;
154
158
  }
155
159
  /**
156
160
  * Updates product content in-place without regenerating HTML structure.
@@ -1,4 +1,4 @@
1
- import type { Orientation, Languages, Currency, NumericSeparator, FiltersResponse, Filter, RecommendationCampaignUrlValue, RecommendationProduct, RrsStrategy } from '@@/Types/recommendation';
1
+ import type { Orientation, Languages, Currency, NumericSeparator, FiltersResponse, Filter, RecommendationCampaignUrlValue, RecommendationProduct, RrsMigrationPayload, RrsMigrationTarget, RrsStrategy } from '@@/Types/recommendation';
2
2
  export interface PerBlockConfigs {
3
3
  cardsInRow: number;
4
4
  currencySettings: {
@@ -22,6 +22,7 @@ export interface PerBlockConfigs {
22
22
  shuffleProducts: boolean;
23
23
  strategy: string;
24
24
  strategyId: string;
25
+ nodeConfigVersion: number;
25
26
  textTrimming: boolean;
26
27
  unresponsive: boolean;
27
28
  size: string;
@@ -36,11 +37,13 @@ interface PerBlockState {
36
37
  filterSelectionDrawerStatus: boolean;
37
38
  assignStrategyDrawerStatus: boolean;
38
39
  removeStrategyModalStatus: boolean;
40
+ legacyStrategyUpdatedModalStatus: boolean;
39
41
  filterGroup: number;
40
42
  /** Whether initial API data (filters, algorithms, products) has been fetched for this block */
41
43
  isInitialized: boolean;
42
44
  /** Snapshot of filters taken when the drawer opens, used to revert on cancel */
43
45
  filterSnapshot: Filter[] | null;
46
+ legacyConversionLoading: boolean;
44
47
  }
45
48
  /**
46
49
  * Persisted-config subset used by `seedBlockUrlConfig` to reconstruct
@@ -71,7 +74,6 @@ interface StoreState {
71
74
  strategies: RrsStrategy[];
72
75
  strategiesLoading: boolean;
73
76
  strategyUrlTemplates: Record<string, string>;
74
- strategiesFetched: boolean;
75
77
  blockStates: Record<number, PerBlockState>;
76
78
  currentRecommendationId: number | null;
77
79
  configVersion: number;
@@ -100,7 +102,6 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
100
102
  }[];
101
103
  strategiesLoading: boolean;
102
104
  strategyUrlTemplates: Record<string, string>;
103
- strategiesFetched: boolean;
104
105
  blockStates: Record<number, PerBlockState>;
105
106
  currentRecommendationId: number | null;
106
107
  configVersion: number;
@@ -127,7 +128,6 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
127
128
  }[];
128
129
  strategiesLoading: boolean;
129
130
  strategyUrlTemplates: Record<string, string>;
130
- strategiesFetched: boolean;
131
131
  blockStates: Record<number, PerBlockState>;
132
132
  currentRecommendationId: number | null;
133
133
  configVersion: number;
@@ -154,7 +154,6 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
154
154
  }[];
155
155
  strategiesLoading: boolean;
156
156
  strategyUrlTemplates: Record<string, string>;
157
- strategiesFetched: boolean;
158
157
  blockStates: Record<number, PerBlockState>;
159
158
  currentRecommendationId: number | null;
160
159
  configVersion: number;
@@ -178,7 +177,6 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
178
177
  }[];
179
178
  strategiesLoading: boolean;
180
179
  strategyUrlTemplates: Record<string, string>;
181
- strategiesFetched: boolean;
182
180
  blockStates: Record<number, PerBlockState>;
183
181
  currentRecommendationId: number | null;
184
182
  configVersion: number;
@@ -202,7 +200,53 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
202
200
  }[];
203
201
  strategiesLoading: boolean;
204
202
  strategyUrlTemplates: Record<string, string>;
205
- strategiesFetched: boolean;
203
+ blockStates: Record<number, PerBlockState>;
204
+ currentRecommendationId: number | null;
205
+ configVersion: number;
206
+ } & import("pinia").PiniaCustomStateProperties<StoreState>): boolean;
207
+ isLegacyStrategyBlock(): boolean;
208
+ legacyConversionLoading(state: {
209
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
210
+ activePredictiveAlgorithms: number[];
211
+ languages: Languages;
212
+ currencyList: {
213
+ text: string;
214
+ value: string;
215
+ }[];
216
+ filterList: FiltersResponse;
217
+ strategies: {
218
+ [x: string]: unknown;
219
+ strategy_id: number;
220
+ name: string;
221
+ status: string;
222
+ suitable_channels: string;
223
+ size?: (number | string) | undefined;
224
+ }[];
225
+ strategiesLoading: boolean;
226
+ strategyUrlTemplates: Record<string, string>;
227
+ blockStates: Record<number, PerBlockState>;
228
+ currentRecommendationId: number | null;
229
+ configVersion: number;
230
+ } & import("pinia").PiniaCustomStateProperties<StoreState>): boolean;
231
+ legacyStrategyUpdatedModalStatus(state: {
232
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
233
+ activePredictiveAlgorithms: number[];
234
+ languages: Languages;
235
+ currencyList: {
236
+ text: string;
237
+ value: string;
238
+ }[];
239
+ filterList: FiltersResponse;
240
+ strategies: {
241
+ [x: string]: unknown;
242
+ strategy_id: number;
243
+ name: string;
244
+ status: string;
245
+ suitable_channels: string;
246
+ size?: (number | string) | undefined;
247
+ }[];
248
+ strategiesLoading: boolean;
249
+ strategyUrlTemplates: Record<string, string>;
206
250
  blockStates: Record<number, PerBlockState>;
207
251
  currentRecommendationId: number | null;
208
252
  configVersion: number;
@@ -226,7 +270,6 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
226
270
  }[];
227
271
  strategiesLoading: boolean;
228
272
  strategyUrlTemplates: Record<string, string>;
229
- strategiesFetched: boolean;
230
273
  blockStates: Record<number, PerBlockState>;
231
274
  currentRecommendationId: number | null;
232
275
  configVersion: number;
@@ -253,7 +296,6 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
253
296
  }[];
254
297
  strategiesLoading: boolean;
255
298
  strategyUrlTemplates: Record<string, string>;
256
- strategiesFetched: boolean;
257
299
  blockStates: Record<number, PerBlockState>;
258
300
  currentRecommendationId: number | null;
259
301
  configVersion: number;
@@ -280,7 +322,6 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
280
322
  }[];
281
323
  strategiesLoading: boolean;
282
324
  strategyUrlTemplates: Record<string, string>;
283
- strategiesFetched: boolean;
284
325
  blockStates: Record<number, PerBlockState>;
285
326
  currentRecommendationId: number | null;
286
327
  configVersion: number;
@@ -308,7 +349,6 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
308
349
  }[];
309
350
  strategiesLoading: boolean;
310
351
  strategyUrlTemplates: Record<string, string>;
311
- strategiesFetched: boolean;
312
352
  blockStates: Record<number, PerBlockState>;
313
353
  currentRecommendationId: number | null;
314
354
  configVersion: number;
@@ -335,7 +375,6 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
335
375
  }[];
336
376
  strategiesLoading: boolean;
337
377
  strategyUrlTemplates: Record<string, string>;
338
- strategiesFetched: boolean;
339
378
  blockStates: Record<number, PerBlockState>;
340
379
  currentRecommendationId: number | null;
341
380
  configVersion: number;
@@ -362,7 +401,6 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
362
401
  }[];
363
402
  strategiesLoading: boolean;
364
403
  strategyUrlTemplates: Record<string, string>;
365
- strategiesFetched: boolean;
366
404
  blockStates: Record<number, PerBlockState>;
367
405
  currentRecommendationId: number | null;
368
406
  configVersion: number;
@@ -442,43 +480,14 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
442
480
  cancelFilterDrawer(): void;
443
481
  openAssignStrategyDrawer(): void;
444
482
  closeAssignStrategyDrawer(): void;
483
+ openLegacyStrategyUpdatedModal(): void;
484
+ closeLegacyStrategyUpdatedModal(): void;
445
485
  openRemoveStrategyModal(): void;
446
486
  closeRemoveStrategyModal(): void;
447
487
  fetchStrategies(): Promise<void>;
448
- invalidateStrategies(): void;
449
- /**
450
- * Opens a Smart Recommender strategy page in a new tab and refreshes the list every time
451
- * the user comes back. `visibilitychange` covers the tab case; `focus` covers the page
452
- * landing in a separate window, where this document never goes hidden.
453
- *
454
- * Deliberately NOT one-shot: the strategy tab stays open, so a user can create a second
455
- * strategy in it and come back again — a listener that disarmed on the first return would
456
- * leave that one missing from the list. Armed only once the user actually opens a strategy
457
- * page, so anyone who never does pays nothing.
458
- */
459
- _armStrategyPageReturn(url: string): void;
460
- /**
461
- * Reloads the products of the block the user is on, so an edit made in the strategy tab
462
- * lands on the canvas instead of waiting for the assign drawer to be reopened.
463
- *
464
- * Only the selected block: the canvas regeneration is driven off the active block's
465
- * product array, so refreshing an unselected block would fetch without redrawing it.
466
- */
467
- _refreshAssignedStrategyProducts(): Promise<void>;
468
- /** Lets the editor tear the return listeners down when it unmounts. */
469
- disposeStrategyPageReturn(): void;
470
- /**
471
- * Opens Smart Recommender's strategy creation page. Every return refreshes the list so the
472
- * new strategy is offered; the user picks it themselves.
473
- */
474
- openStrategyCreation(): void;
475
- /**
476
- * Opens the strategy's edit page. Every return refreshes the list so the block reflects the
477
- * edited configuration.
478
- */
479
- openStrategyEdit(strategyId: string | number): void;
480
488
  resolveStrategyUrlTemplate(strategy: RrsStrategy, currency: string): Promise<string>;
481
489
  assignStrategy(strategy: RrsStrategy): void;
490
+ convertLegacyStrategy(payload: RrsMigrationPayload, target?: RrsMigrationTarget): Promise<string>;
482
491
  removeStrategy(): void;
483
492
  fetchRecommendationCreateData(): Promise<void>;
484
493
  fetchRecommendationFilters(): Promise<void>;
@@ -494,11 +503,6 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
494
503
  * every block's recommendationConfigs across user edits.
495
504
  */
496
505
  hasInvalidBlock(): boolean;
497
- /**
498
- * Which required fields are missing across the design's blocks, so the save
499
- * toaster can name the cause instead of always showing the generic message.
500
- */
501
- invalidBlockFields(): string[];
502
506
  fetchRecommendationProducts(): Promise<void>;
503
507
  _doFetchProducts(): Promise<void>;
504
508
  _doFetchStrategyProducts(blockId: number): Promise<void>;
@@ -0,0 +1,44 @@
1
+ import type { Filter, RrsMigrationFilterGroup, RrsMigrationPayload, RrsMigrationTarget } from '@@/Types/recommendation';
2
+ type FilterAttribute = {
3
+ value: string;
4
+ type: string;
5
+ };
6
+ /**
7
+ * A block authored before reusable strategies: it still carries a plain feed
8
+ * configuration (compiled into a feed URL string) instead of a strategy id.
9
+ * Blocks created under RRS stamp `CURRENT_CONFIG_VERSION`, so the version is
10
+ * what separates "never converted" from "not assigned yet".
11
+ */
12
+ export declare function isLegacyStrategyConfig({ strategyId, nodeConfigVersion }: {
13
+ strategyId: string;
14
+ nodeConfigVersion: number;
15
+ }): boolean;
16
+ export declare function resolveMigrationTarget({ campaignId, templateLibraryId }: {
17
+ campaignId?: string;
18
+ templateLibraryId?: string;
19
+ }): RrsMigrationTarget;
20
+ /**
21
+ * Groups the block's valid filters the way the feed URL groups them, in the
22
+ * shape the migration endpoint validates. The URL's filter DSL states no
23
+ * attribute type and cannot express a mixed-operator group, which is exactly
24
+ * what this override exists to supply.
25
+ */
26
+ export declare function toMigrationFilterGroups(filters: Filter[], attributes: FilterAttribute[]): RrsMigrationFilterGroup[];
27
+ interface MigrationInputs {
28
+ blockId: number;
29
+ url: string;
30
+ campaignId: string;
31
+ variationId: string;
32
+ strategy: string;
33
+ productIds: string[];
34
+ filters: Filter[];
35
+ attributes: FilterAttribute[];
36
+ target: RrsMigrationTarget;
37
+ }
38
+ /**
39
+ * The server names and de-duplicates the strategy, so nothing here derives a name. The two
40
+ * routes take different identity fields — the campaign one names from `campaignId`/`variationId`
41
+ * (0 for modules, which carry no numeric campaign), the template one from `templateId`.
42
+ */
43
+ export declare function buildLegacyMigrationPayload({ blockId, url, campaignId, variationId, strategy, productIds, filters, attributes, target, }: MigrationInputs): RrsMigrationPayload;
44
+ export {};
@@ -15,11 +15,7 @@ export interface RequiredField {
15
15
  getAvailableOptions?: (store: ExtensionStoreSlice) => string[];
16
16
  condition?: (config: PerBlockConfigs) => boolean;
17
17
  }
18
- /** Field key of the strategy/algorithm descriptor, used to pick the toaster message. */
19
- export declare const STRATEGY_FIELD_KEY = "strategy";
20
18
  export declare const REQUIRED_RECOMMENDATION_FIELDS: RequiredField[];
21
19
  export declare const RecommendationRequiredFieldsKey = "newsletter.recommendation-fill-required-fields";
22
- /** Shown instead of the generic message when the only thing missing is the strategy. */
23
- export declare const RecommendationAssignStrategyKey = "newsletter.recommendation-assign-strategy";
24
20
  export declare function getInvalidFields(config: PerBlockConfigs, store: ExtensionStoreSlice, fields?: RequiredField[]): string[];
25
21
  export declare function isConfigValid(config: PerBlockConfigs, store: ExtensionStoreSlice): boolean;
@@ -1,4 +1,4 @@
1
- import type { InitialResponse, FiltersResponse, RecommendationProduct, RecommendationProductsParams, RrsEndpointGenerateResponse, RrsStrategy } from '@@/Types/recommendation';
1
+ import type { InitialResponse, FiltersResponse, RecommendationProduct, RecommendationProductsParams, RrsEndpointGenerateResponse, RrsMigrationPayload, RrsMigrationTarget, RrsStrategy } from '@@/Types/recommendation';
2
2
  export declare const useRecommendationApi: () => {
3
3
  fetchRecommendationCreateData: () => Promise<InitialResponse>;
4
4
  fetchRecommendationFilters: () => Promise<FiltersResponse>;
@@ -6,4 +6,5 @@ export declare const useRecommendationApi: () => {
6
6
  fetchRecommendationProductsByUrl: (url: string) => Promise<RecommendationProduct[]>;
7
7
  fetchRecommendationStrategies: () => Promise<RrsStrategy[]>;
8
8
  generateStrategyEndpoint: (strategy: RrsStrategy, currency: string) => Promise<RrsEndpointGenerateResponse | null>;
9
+ migrateLegacyStrategy: (payload: RrsMigrationPayload, target?: RrsMigrationTarget) => Promise<string>;
9
10
  };