@useinsider/guido 3.20.1-beta.991508 → 3.20.1-beta.a9397b3

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 (33) hide show
  1. package/README.md +8 -0
  2. package/dist/@types/config/schemas.js +35 -33
  3. package/dist/components/Guido.vue.js +5 -5
  4. package/dist/components/Guido.vue2.js +70 -66
  5. package/dist/components/organisms/unsubscribe/LegacyUnsubscribeConvertedModal.vue.js +17 -0
  6. package/dist/components/organisms/unsubscribe/LegacyUnsubscribeConvertedModal.vue2.js +35 -0
  7. package/dist/composables/useLegacyStrategyConversion.js +16 -16
  8. package/dist/composables/useModuleRepair.js +40 -24
  9. package/dist/config/migrator/index.js +12 -11
  10. package/dist/config/migrator/legacyUnsubscribeTextMigrator.js +16 -0
  11. package/dist/enums/academy.js +2 -1
  12. package/dist/extensions/Blocks/Recommendation/controls/main/index.js +223 -296
  13. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +205 -219
  14. package/dist/extensions/Blocks/Recommendation/utils/nodeConfigWriter.js +36 -51
  15. package/dist/extensions/Blocks/Recommendation/utils/strategyCommit.js +35 -31
  16. package/dist/guido.css +1 -1
  17. package/dist/src/@types/config/schemas.d.ts +4 -0
  18. package/dist/src/components/organisms/unsubscribe/LegacyUnsubscribeConvertedModal.vue.d.ts +2 -0
  19. package/dist/src/composables/useConfig.d.ts +2 -0
  20. package/dist/src/composables/useModuleRepair.d.ts +2 -11
  21. package/dist/src/config/migrator/legacyUnsubscribeTextMigrator.d.ts +1 -0
  22. package/dist/src/enums/academy.d.ts +1 -0
  23. package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +3 -18
  24. package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +1 -8
  25. package/dist/src/extensions/Blocks/Recommendation/utils/nodeConfigWriter.d.ts +0 -7
  26. package/dist/src/stores/config.d.ts +20 -0
  27. package/dist/src/stores/editor.d.ts +25 -0
  28. package/dist/src/utils/legacyUnsubscribeConversion.d.ts +9 -0
  29. package/dist/stores/editor.js +16 -15
  30. package/dist/utils/legacyUnsubscribeConversion.js +86 -0
  31. package/package.json +1 -1
  32. package/dist/extensions/Blocks/Recommendation/utils/blockRefresh.js +0 -19
  33. package/dist/src/extensions/Blocks/Recommendation/utils/blockRefresh.d.ts +0 -17
package/README.md CHANGED
@@ -166,6 +166,7 @@ const config: GuidoConfigInput = {
166
166
  allowlistEnabled?: boolean, // Default: false - Pre-save domain-allowlist check (opt-in). Guido self-serves the block toaster (role lookup, deep-link, copy from window.trans).
167
167
  allowSaveWithErrors?: boolean, // Default: true - Allow the validation drawer's "Save and Continue" soft-save. Set false to hard-block invalid saves (transactional + unsubscribe pages).
168
168
  reusableRecommendationStrategy?: boolean, // Default: false - Assign an RRS strategy to recommendation blocks instead of per-block algorithm/filters/shuffle/product-count settings.
169
+ legacyUnsubscribeConversion?: boolean, // Default: false - Convert legacy unsubscribe blocks that have no unsubscribe link into text blocks (on load and on module drop/copy) and show a warning modal.
169
170
  },
170
171
 
171
172
  // Optional: Callbacks
@@ -667,6 +668,13 @@ multiple partners (e.g. architect) should key by partner and place the active pa
667
668
  first. Omit the prop and the repair is a safe no-op — nothing is rewritten and no
668
669
  toaster fires (useful before the host has wired the catalog).
669
670
 
671
+ With `features.legacyUnsubscribeConversion: true`, a dropped or copied module's legacy
672
+ unsubscribe block that has no unsubscribe link (the old editor reused it as plain text,
673
+ e.g. a company address) becomes a plain text block that keeps its content, and a warning
674
+ modal explains it. The same conversion runs when a template is opened. Register these
675
+ keys host-side: `email-editor.legacy-unsubscribe-converted-modal-title` and
676
+ `email-editor.legacy-unsubscribe-converted-modal-message`.
677
+
670
678
  ---
671
679
 
672
680
  ## Development
@@ -1,5 +1,5 @@
1
- import { ModuleFolderDefaults as f } from "../../enums/defaults.js";
2
- import { object as a, number as s, optional as e, string as t, picklist as m, pipe as i, minLength as b, custom as k, boolean as o, array as c, transform as y, unknown as r, record as g, fallback as R, literal as u, looseObject as C, variant as I, union as h, lazy as T } from "../../node_modules/valibot/dist/index.js";
1
+ import { ModuleFolderDefaults as S } from "../../enums/defaults.js";
2
+ import { object as a, number as s, optional as e, string as t, picklist as m, pipe as i, minLength as b, custom as k, boolean as o, array as n, transform as y, unknown as r, record as g, fallback as R, literal as u, looseObject as C, variant as I, union as h, lazy as T } from "../../node_modules/valibot/dist/index.js";
3
3
  const p = {
4
4
  /** Promotional/marketing emails */
5
5
  PROMOTIONAL: 1,
@@ -76,30 +76,30 @@ const p = {
76
76
  value: t()
77
77
  })
78
78
  )
79
- }), S = T(() => C({
79
+ }), f = T(() => C({
80
80
  text: e(t()),
81
81
  // eslint-disable-next-line camelcase -- backend field name
82
82
  tag_text: e(t()),
83
83
  value: e(t()),
84
- children: e(c(S)),
84
+ children: e(n(f)),
85
85
  // eslint-disable-next-line camelcase -- backend field name
86
- select_items: e(c(S))
87
- })), N = g(
86
+ select_items: e(n(f))
87
+ })), v = g(
88
88
  t(),
89
- R(c(S), [])
90
- ), P = C({
89
+ R(n(f), [])
90
+ ), N = C({
91
91
  /** Block ID (matches the dictionary key and the legacy HTML element id) */
92
92
  id: e(s()),
93
93
  /** Decimal places for price display (legacy data may use string or number) */
94
94
  decimalCount: e(h([t(), s()])),
95
95
  /** Pinned product IDs (empty array when filter-driven) */
96
- productIds: e(c(r())),
96
+ productIds: e(n(r())),
97
97
  /** Whether the block requested live products at send time */
98
98
  sendProductRequestFlag: e(o()),
99
99
  /** Whether to randomize product order */
100
100
  shuffleProducts: e(o()),
101
101
  /** Filter rules driving product selection */
102
- filters: e(c(r())),
102
+ filters: e(n(r())),
103
103
  /** Currency code (e.g. 'EUR') — sometimes absent in legacy data */
104
104
  currency: e(t()),
105
105
  /** Currency display settings (separators, alignment, decimals) */
@@ -109,7 +109,7 @@ const p = {
109
109
  /** Recommendation strategy key (e.g. 'newArrivals') */
110
110
  strategy: e(t()),
111
111
  /** Snapshot of products as rendered by the legacy block */
112
- recommendedProducts: e(c(r())),
112
+ recommendedProducts: e(n(r())),
113
113
  /** Number of product cards per row */
114
114
  cardsInRow: e(s()),
115
115
  /** Mobile-only padding (right) */
@@ -132,7 +132,7 @@ const p = {
132
132
  isPriceMovedToNextLine: e(o()),
133
133
  /** Legacy "Hide if same as discounted" / delete-price-for-zero-sale toggle */
134
134
  isPriceDeletedForZeroSale: e(o())
135
- }), v = a({
135
+ }), P = a({
136
136
  /**
137
137
  * Legacy recommendation block configs keyed by block ID.
138
138
  * Pass this when loading a template authored with the v1
@@ -140,7 +140,7 @@ const p = {
140
140
  * strategy, currency, locale, and layout data.
141
141
  */
142
142
  recommendationConfigs: e(
143
- g(t(), P),
143
+ g(t(), N),
144
144
  {}
145
145
  )
146
146
  }), x = a({
@@ -150,7 +150,7 @@ const p = {
150
150
  css: e(t(), ""),
151
151
  /** Preselected dynamic content items */
152
152
  preselectedDynamicContent: e(
153
- c(M),
153
+ n(M),
154
154
  []
155
155
  ),
156
156
  /**
@@ -159,11 +159,11 @@ const p = {
159
159
  * (first) partner's leaf attributes into the label→token map that repairs
160
160
  * label-form placeholders (`{{ Phone Number }}`) in dropped saved modules.
161
161
  */
162
- dynamicContentList: e(N, {}),
162
+ dynamicContentList: e(v, {}),
163
163
  /** Valid custom field attribute names from the partner's categorized fields */
164
- customFieldAttributes: e(c(t()), []),
164
+ customFieldAttributes: e(n(t()), []),
165
165
  /** Selected unsubscribe page IDs */
166
- selectedUnsubscribePages: e(c(s()), []),
166
+ selectedUnsubscribePages: e(n(s()), []),
167
167
  /** Force recreate template in Stripo storage (use true when updating externally modified templates) */
168
168
  forceRecreate: e(o(), !1),
169
169
  /**
@@ -176,7 +176,7 @@ const p = {
176
176
  trackIdCounter: e(
177
177
  i(
178
178
  s(),
179
- y((n) => Number.isFinite(n) ? Math.max(0, Math.floor(n)) : 0)
179
+ y((c) => Number.isFinite(c) ? Math.max(0, Math.floor(c)) : 0)
180
180
  ),
181
181
  0
182
182
  ),
@@ -190,11 +190,11 @@ const p = {
190
190
  recommendationCampaignUrls: e(
191
191
  i(
192
192
  r(),
193
- y((n) => n && typeof n == "object" ? { ...n } : void 0)
193
+ y((c) => c && typeof c == "object" ? { ...c } : void 0)
194
194
  )
195
195
  ),
196
196
  /** Migration-only inputs (legacy block configs) */
197
- migration: e(v, {})
197
+ migration: e(P, {})
198
198
  }), D = a({
199
199
  /** Sender display name */
200
200
  senderName: e(t(), ""),
@@ -210,9 +210,9 @@ const p = {
210
210
  /** Email header settings */
211
211
  emailHeader: e(D, { senderName: "", subject: "" }),
212
212
  /** Folder name for user-saved modules (used by Stripo plugin panel for path construction) */
213
- savedModulesFolderName: e(t(), f.SAVED_MODULES),
213
+ savedModulesFolderName: e(t(), S.SAVED_MODULES),
214
214
  /** Folder name for default/prebuilt modules (used by Stripo plugin panel for path construction) */
215
- defaultModulesFolderName: e(t(), f.DEFAULT_MODULES)
215
+ defaultModulesFolderName: e(t(), S.DEFAULT_MODULES)
216
216
  }), F = a({
217
217
  /** Whether to show the header bar */
218
218
  showHeader: e(o(), !0),
@@ -243,7 +243,9 @@ const p = {
243
243
  linkTrackingIds: e(o(), !1),
244
244
  /** Allow persisting a template that still has validation errors (drawer "Save and Continue" soft-save). Host sets false for transactional + unsubscribe. */
245
245
  allowSaveWithErrors: e(o(), !0),
246
- reusableRecommendationStrategy: e(o(), !1)
246
+ reusableRecommendationStrategy: e(o(), !1),
247
+ /** Convert linkless legacy unsubscribe blocks to text blocks and warn, on load and on module drop/copy (opt-in) */
248
+ legacyUnsubscribeConversion: e(o(), !1)
247
249
  }), w = m([
248
250
  "amp-accordion",
249
251
  "amp-carousel",
@@ -269,12 +271,12 @@ const p = {
269
271
  ]), j = a({
270
272
  /** Default blocks to exclude from the editor */
271
273
  excludeDefaults: e(
272
- c(w),
274
+ n(w),
273
275
  []
274
276
  ),
275
277
  /** Custom blocks to include in the editor */
276
278
  includeCustoms: e(
277
- c(B),
279
+ n(B),
278
280
  []
279
281
  )
280
282
  }), d = a({
@@ -306,13 +308,13 @@ const p = {
306
308
  ...d.entries,
307
309
  type: u("remove"),
308
310
  /** Strings or patterns to remove */
309
- targets: c(t())
311
+ targets: n(t())
310
312
  }), G = a({
311
313
  ...d.entries,
312
314
  type: u("custom"),
313
315
  /** Custom processor function */
314
316
  processor: k(
315
- (n) => typeof n == "function",
317
+ (c) => typeof c == "function",
316
318
  "processor must be a function"
317
319
  )
318
320
  }), V = I("type", [
@@ -322,7 +324,7 @@ const p = {
322
324
  G
323
325
  ]), z = a({
324
326
  /** Custom compiler rules to apply */
325
- customRules: e(c(V), []),
327
+ customRules: e(n(V), []),
326
328
  /** Skip default compiler rules */
327
329
  ignoreDefaultRules: e(o(), !1)
328
330
  }), W = a({
@@ -332,7 +334,7 @@ const p = {
332
334
  */
333
335
  externalValidation: e(
334
336
  k(
335
- (n) => typeof n == "function",
337
+ (c) => typeof c == "function",
336
338
  "externalValidation must be a function"
337
339
  )
338
340
  )
@@ -366,8 +368,8 @@ export {
366
368
  B as CustomBlockTypeSchema,
367
369
  G as CustomRuleSchema,
368
370
  w as DefaultBlockTypeSchema,
369
- N as DynamicContentListSchema,
370
- S as DynamicContentNodeSchema,
371
+ v as DynamicContentListSchema,
372
+ f as DynamicContentNodeSchema,
371
373
  M as DynamicContentSchema,
372
374
  O as EditorSchema,
373
375
  D as EmailHeaderSchema,
@@ -375,14 +377,14 @@ export {
375
377
  U as FeaturesSchema,
376
378
  K as GuidoConfigSchema,
377
379
  A as IdentitySchema,
378
- P as LegacyRecommendationConfigSchema,
380
+ N as LegacyRecommendationConfigSchema,
379
381
  p as MessageType,
380
382
  E as PartnerSchema,
381
383
  l as ProductType,
382
384
  _ as RegexRuleSchema,
383
385
  q as RemoveRuleSchema,
384
386
  H as ReplaceRuleSchema,
385
- v as TemplateMigrationSchema,
387
+ P as TemplateMigrationSchema,
386
388
  x as TemplateSchema,
387
389
  F as UISchema
388
390
  };
@@ -1,18 +1,18 @@
1
1
  import o from "./Guido.vue2.js";
2
2
  /* empty css */
3
3
  import i from "../_virtual/_plugin-vue2_normalizer.js";
4
- var t = function() {
4
+ var s = function() {
5
5
  var a = this, r = a._self._c, e = a._self._setupProxy;
6
- return r("div", { ref: "wrapperRef", staticClass: "guido-editor__wrapper", class: { "guido-editor__no-header": e.noHeader } }, [r(e.HeaderWrapper, { ref: "headerWrapperRef" }), r(e.AutoSaveController), e.editorStore.isPreviewModeOpen ? r(e.PreviewContainer) : a._e(), r("div", { directives: [{ name: "show", rawName: "v-show", value: !e.previewStore.isLoaded, expression: "!previewStore.isLoaded" }], staticClass: "guido-editor__container", class: { "guido-editor__no-header": e.noHeader }, attrs: { id: "guido-editor" } }), r(e.Toaster), r(e.AuthErrorModal), r(e.FilterSelectionDrawer), e.isRrsEnabled || e.hasAssignedStrategy ? r(e.AssignStrategyDrawer) : a._e(), e.isRrsEnabled || e.hasAssignedStrategy ? r(e.RemoveStrategyModal) : a._e(), e.isRrsEnabled ? r(e.LegacyStrategyUpdatedModal) : a._e(), r(e.SaveAsTemplateDrawer), e.isSaveValidationEnabled ? r(e.ValidationErrorDrawer) : a._e(), e.isTestPartner() ? a._e() : r(e.OnboardingWrapper, { on: { "onboarding-finished": function(_) {
6
+ return r("div", { ref: "wrapperRef", staticClass: "guido-editor__wrapper", class: { "guido-editor__no-header": e.noHeader } }, [r(e.HeaderWrapper, { ref: "headerWrapperRef" }), r(e.AutoSaveController), e.editorStore.isPreviewModeOpen ? r(e.PreviewContainer) : a._e(), r("div", { directives: [{ name: "show", rawName: "v-show", value: !e.previewStore.isLoaded, expression: "!previewStore.isLoaded" }], staticClass: "guido-editor__container", class: { "guido-editor__no-header": e.noHeader }, attrs: { id: "guido-editor" } }), r(e.Toaster), r(e.AuthErrorModal), r(e.FilterSelectionDrawer), e.isRrsEnabled || e.hasAssignedStrategy ? r(e.AssignStrategyDrawer) : a._e(), e.isRrsEnabled || e.hasAssignedStrategy ? r(e.RemoveStrategyModal) : a._e(), e.isRrsEnabled ? r(e.LegacyStrategyUpdatedModal) : a._e(), e.isLegacyUnsubscribeConversionEnabled ? r(e.LegacyUnsubscribeConvertedModal) : a._e(), r(e.SaveAsTemplateDrawer), e.isSaveValidationEnabled ? r(e.ValidationErrorDrawer) : a._e(), e.isTestPartner() ? a._e() : r(e.OnboardingWrapper, { on: { "onboarding-finished": function(_) {
7
7
  return e.emit("onboarding:finished");
8
8
  } } }), r(e.UnsubscribeWrapper), r(e.LoadingWrapper)], 1);
9
- }, s = [], n = /* @__PURE__ */ i(
9
+ }, t = [], n = /* @__PURE__ */ i(
10
10
  o,
11
- t,
12
11
  s,
12
+ t,
13
13
  !1,
14
14
  null,
15
- "1b5c844a"
15
+ "34bee5bb"
16
16
  );
17
17
  const v = n.exports;
18
18
  export {
@@ -1,35 +1,35 @@
1
- import { defineComponent as se, defineAsyncComponent as m, ref as W, computed as p, watch as G, onMounted as ie, onUnmounted as ce } from "vue";
2
- import { useCortexBlueprintBridge as de } from "../composables/useCortexBlueprintBridge.js";
3
- import { useEditorLock as me } from "../composables/useEditorLock.js";
4
- import { provideGuidoActions as le } from "../composables/useGuidoActions.js";
5
- import { useGuidoStateBridge as ue } from "../composables/useGuidoStateBridge.js";
6
- import { usePartner as pe } from "../composables/usePartner.js";
7
- import { useSaveValidationRollout as fe } from "../composables/useSaveValidationRollout.js";
8
- import { useStripo as ye } from "../composables/useStripo.js";
9
- import { useTimerClone as ge } from "../composables/useTimerClone.js";
1
+ import { defineComponent as ce, defineAsyncComponent as c, ref as W, computed as l, watch as G, onMounted as de, onUnmounted as me } from "vue";
2
+ import { useCortexBlueprintBridge as le } from "../composables/useCortexBlueprintBridge.js";
3
+ import { useEditorLock as ue } from "../composables/useEditorLock.js";
4
+ import { provideGuidoActions as pe } from "../composables/useGuidoActions.js";
5
+ import { useGuidoStateBridge as fe } from "../composables/useGuidoStateBridge.js";
6
+ import { usePartner as ye } from "../composables/usePartner.js";
7
+ import { useSaveValidationRollout as ge } from "../composables/useSaveValidationRollout.js";
8
+ import { useStripo as be } from "../composables/useStripo.js";
9
+ import { useTimerClone as ve } from "../composables/useTimerClone.js";
10
10
  import { migrate as V } from "../config/migrator/index.js";
11
11
  import { ModuleFolderDefaults as $ } from "../enums/defaults.js";
12
12
  import { RIBBON_SELECTOR as Se } from "../enums/onboarding.js";
13
13
  import { useRecommendationExtensionStore as E } from "../extensions/Blocks/Recommendation/store/recommendation.js";
14
- import ve from "./organisms/AutoSaveController.vue.js";
15
- import be from "./organisms/base/AuthErrorModal.vue.js";
16
- import he from "./organisms/base/Toaster.vue.js";
17
- import Ee from "./organisms/extensions/recommendation/FilterSelectionDrawer.vue.js";
18
- import we from "./organisms/header/HeaderWrapper.vue.js";
19
- import De from "./organisms/LoadingWrapper.vue.js";
20
- import Ce from "./organisms/save-as-template/SaveAsTemplateDrawer.vue.js";
21
- import ke from "./organisms/unsubscribe/UnsubscribeWrapper.vue.js";
22
- import Fe from "./organisms/validation/ValidationErrorDrawer.vue.js";
23
- import { useStripoApi as Re } from "../services/stripoApi.js";
24
- import { useConfigStore as Me } from "../stores/config.js";
25
- import { useDynamicContentStore as Te } from "../stores/dynamic-content.js";
14
+ import he from "./organisms/AutoSaveController.vue.js";
15
+ import Ee from "./organisms/base/AuthErrorModal.vue.js";
16
+ import we from "./organisms/base/Toaster.vue.js";
17
+ import Ce from "./organisms/extensions/recommendation/FilterSelectionDrawer.vue.js";
18
+ import De from "./organisms/header/HeaderWrapper.vue.js";
19
+ import ke from "./organisms/LoadingWrapper.vue.js";
20
+ import Fe from "./organisms/save-as-template/SaveAsTemplateDrawer.vue.js";
21
+ import Me from "./organisms/unsubscribe/UnsubscribeWrapper.vue.js";
22
+ import Re from "./organisms/validation/ValidationErrorDrawer.vue.js";
23
+ import { useStripoApi as Le } from "../services/stripoApi.js";
24
+ import { useConfigStore as Te } from "../stores/config.js";
25
+ import { useDynamicContentStore as Ue } from "../stores/dynamic-content.js";
26
26
  import { useEditorStore as w } from "../stores/editor.js";
27
27
  import { usePreviewStore as Ie } from "../stores/preview.js";
28
- import { useSaveValidationStore as Le } from "../stores/save-validation.js";
29
- import { useTemplateStore as Ue } from "../stores/template.js";
30
- import { useUnsubscribeStore as Ae } from "../stores/unsubscribe.js";
28
+ import { useSaveValidationStore as Ae } from "../stores/save-validation.js";
29
+ import { useTemplateStore as Be } from "../stores/template.js";
30
+ import { useUnsubscribeStore as Ne } from "../stores/unsubscribe.js";
31
31
  import { readTrackFloor as z } from "../utils/linkTrackingIds.js";
32
- const lt = /* @__PURE__ */ se({
32
+ const pt = /* @__PURE__ */ ce({
33
33
  __name: "Guido",
34
34
  props: {
35
35
  config: null,
@@ -37,25 +37,27 @@ const lt = /* @__PURE__ */ se({
37
37
  },
38
38
  emits: ["dynamic-content:open", "back", "save:start", "save:complete", "on-change", "ready", "onboarding:finished", "test-email:click"],
39
39
  setup(H, { expose: q, emit: r }) {
40
- const s = H, K = m(
40
+ const s = H, K = c(
41
41
  () => import("./organisms/email-preview/PreviewContainer.vue.js")
42
- ), j = m(
42
+ ), j = c(
43
43
  () => import("./organisms/onboarding/OnboardingWrapper.vue.js")
44
- ), J = m(
44
+ ), J = c(
45
45
  () => import("./organisms/extensions/recommendation/AssignStrategyDrawer.vue.js")
46
- ), Q = m(
46
+ ), Q = c(
47
47
  () => import("./organisms/extensions/recommendation/RemoveStrategyModal.vue.js")
48
- ), X = m(
48
+ ), X = c(
49
49
  () => import("./organisms/extensions/recommendation/LegacyStrategyUpdatedModal.vue.js")
50
- ), D = W(), f = W(), y = Te(), C = Ae(), o = Me();
50
+ ), Y = c(
51
+ () => import("./organisms/unsubscribe/LegacyUnsubscribeConvertedModal.vue.js")
52
+ ), C = W(), f = W(), y = Ue(), D = Ne(), o = Te();
51
53
  s.ready && o.init(s.config);
52
- const c = w(), Y = Ie(), l = p(() => c.hasChanges), { isTestPartner: Z } = pe(), { isEnabled: ee } = fe(), k = () => {
54
+ const d = w(), Z = Ie(), u = l(() => d.hasChanges), { isTestPartner: ee } = ye(), { isEnabled: te } = ge(), k = () => {
53
55
  var t;
54
- return (t = D.value) == null ? void 0 : t.handleSave(!0);
56
+ return (t = C.value) == null ? void 0 : t.handleSave(!0);
55
57
  }, F = (t) => {
56
- c.loadingStatus = t;
58
+ d.loadingStatus = t;
57
59
  };
58
- de(), ue();
60
+ le(), fe();
59
61
  const g = () => {
60
62
  var t, e;
61
63
  return {
@@ -66,15 +68,17 @@ const lt = /* @__PURE__ */ se({
66
68
  savedModulesFolderName: ((t = o.editor) == null ? void 0 : t.savedModulesFolderName) || $.SAVED_MODULES,
67
69
  defaultModulesFolderName: ((e = o.editor) == null ? void 0 : e.defaultModulesFolderName) || $.DEFAULT_MODULES
68
70
  };
69
- }, { initPlugin: R, preloadRuntime: M } = ye(), { runExclusive: T, beginMount: I, isCurrentMount: S } = me();
70
- let u = 0;
71
- const { getDefaultTemplate: L } = Re(), { cloneTimersOnSave: U, hasTimerBlocks: A } = ge(), te = p(() => {
71
+ }, { initPlugin: M, preloadRuntime: R } = be(), { runExclusive: L, beginMount: T, isCurrentMount: b } = ue();
72
+ let p = 0;
73
+ const { getDefaultTemplate: U } = Le(), { cloneTimersOnSave: I, hasTimerBlocks: A } = ve(), oe = l(() => {
72
74
  var t;
73
75
  return !((t = o.ui) != null && t.showHeader);
74
- }), oe = p(() => o.isFeatureEnabled("reusableRecommendationStrategy")), ne = p(
76
+ }), ne = l(() => o.isFeatureEnabled("reusableRecommendationStrategy")), re = l(
77
+ () => o.isFeatureEnabled("legacyUnsubscribeConversion")
78
+ ), ae = l(
75
79
  () => !!E().recommendationConfigs.strategyId
76
80
  );
77
- le({
81
+ pe({
78
82
  onBack: () => {
79
83
  console.debug("guido:back"), r("back");
80
84
  },
@@ -94,24 +98,24 @@ const lt = /* @__PURE__ */ se({
94
98
  }, N = () => {
95
99
  console.debug("dynamic-content:close", "Without Data"), document.dispatchEvent(new CustomEvent("dynamic-content:close", { detail: { text: "", value: "" } }));
96
100
  };
97
- G(() => l.value, () => {
98
- r("on-change", l.value);
101
+ G(() => u.value, () => {
102
+ r("on-change", u.value);
99
103
  });
100
104
  const v = (t) => {
101
- const e = t, { attribute: a, position: d } = e.detail;
102
- console.debug("dynamic-content:open", e.detail), r("dynamic-content:open", a, d);
105
+ const e = t, { attribute: a, position: m } = e.detail;
106
+ console.debug("dynamic-content:open", e.detail), r("dynamic-content:open", a, m);
103
107
  };
104
108
  let i = null;
105
- const b = () => {
109
+ const S = () => {
106
110
  var e;
107
111
  const t = document.querySelector(Se);
108
112
  (e = f.value) == null || e.style.setProperty("--ribbon-offset", `${(t == null ? void 0 : t.offsetHeight) ?? 0}px`);
109
113
  }, h = async () => {
110
114
  var t;
111
115
  try {
112
- o.initialized || o.init(s.config), c.templateId = o.templateId;
113
- const e = o.template, a = (e == null ? void 0 : e.html) || "", d = (e == null ? void 0 : e.css) || "", P = (e == null ? void 0 : e.preselectedDynamicContent) || [];
114
- C.selectedUnsubscribePages = (e == null ? void 0 : e.selectedUnsubscribePages) || [];
116
+ o.initialized || o.init(s.config), d.templateId = o.templateId;
117
+ const e = o.template, a = (e == null ? void 0 : e.html) || "", m = (e == null ? void 0 : e.css) || "", P = (e == null ? void 0 : e.preselectedDynamicContent) || [];
118
+ D.selectedUnsubscribePages = (e == null ? void 0 : e.selectedUnsubscribePages) || [];
115
119
  const _ = ((t = e == null ? void 0 : e.migration) == null ? void 0 : t.recommendationConfigs) ?? {}, O = o.isFeatureEnabled("linkTrackingIds"), x = {
116
120
  partnerName: o.partnerName,
117
121
  campaignUrls: e == null ? void 0 : e.recommendationCampaignUrls,
@@ -119,43 +123,43 @@ const lt = /* @__PURE__ */ se({
119
123
  };
120
124
  let n = {
121
125
  html: a && await V(a, _, x),
122
- css: d
126
+ css: m
123
127
  };
124
- n.html || (n = await L(), n.html = await V(n.html, _, x));
125
- const re = O ? z(n.html, (e == null ? void 0 : e.trackIdCounter) || 0) : 0;
126
- A(n.html) && (n.html = await U(n.html)), O && (c.trackIdSessionFloor = Math.max(re, z(n.html)));
127
- const ae = {
128
+ n.html || (n = await U(), n.html = await V(n.html, _, x));
129
+ const se = O ? z(n.html, (e == null ? void 0 : e.trackIdCounter) || 0) : 0;
130
+ A(n.html) && (n.html = await I(n.html)), O && (d.trackIdSessionFloor = Math.max(se, z(n.html)));
131
+ const ie = {
128
132
  preselectedDynamicContentList: P,
129
133
  onReady: () => {
130
134
  console.debug("guido:ready"), r("ready");
131
135
  }
132
136
  };
133
- u = I(), await R(n, g(), ae), y.selectedDynamicContentList = P;
137
+ p = T(), await M(n, g(), ie), y.selectedDynamicContentList = P;
134
138
  } catch (e) {
135
139
  console.error("Failed to initialize Stripo editor:", e);
136
140
  }
137
141
  };
138
- return ie(async () => {
142
+ return de(async () => {
139
143
  var e;
140
- console.debug("Guido says happy coding 🎉"), console.debug("🚗 Ka-Chow"), E().$reset(), w().$reset(), Ue().$reset(), Le().$reset(), b();
144
+ console.debug("Guido says happy coding 🎉"), console.debug("🚗 Ka-Chow"), E().$reset(), w().$reset(), Be().$reset(), Ae().$reset(), S();
141
145
  const t = (e = f.value) == null ? void 0 : e.parentElement;
142
- if (t && (i = new ResizeObserver(b), i.observe(t)), M(), s.ready)
146
+ if (t && (i = new ResizeObserver(S), i.observe(t)), R(), s.ready)
143
147
  await h();
144
148
  else {
145
- const a = G(() => s.ready, (d) => {
146
- d && (a(), h());
149
+ const a = G(() => s.ready, (m) => {
150
+ m && (a(), h());
147
151
  });
148
152
  }
149
153
  document.addEventListener("dynamic-content:open", v);
150
- }), ce(() => {
151
- if (i == null || i.disconnect(), document.removeEventListener("dynamic-content:open", v), E().disposeStrategyPageReturn(), S(u))
154
+ }), me(() => {
155
+ if (i == null || i.disconnect(), document.removeEventListener("dynamic-content:open", v), E().disposeStrategyPageReturn(), b(p))
152
156
  try {
153
157
  w().isStripoInitialized = !1;
154
158
  } catch (t) {
155
159
  console.debug("Failed to close the editor readiness gate on unmount", t);
156
160
  }
157
- T(async () => {
158
- if (S(u))
161
+ L(async () => {
162
+ if (b(p))
159
163
  try {
160
164
  window.UIEditor.removeEditor();
161
165
  } catch {
@@ -167,12 +171,12 @@ const lt = /* @__PURE__ */ se({
167
171
  insert: B,
168
172
  close: N
169
173
  },
170
- hasChanges: l,
174
+ hasChanges: u,
171
175
  saveSilent: k,
172
176
  setLoading: F
173
- }), { __sfc: !0, PreviewContainer: K, OnboardingWrapper: j, AssignStrategyDrawer: J, RemoveStrategyModal: Q, LegacyStrategyUpdatedModal: X, headerWrapperRef: D, wrapperRef: f, dynamicContentStore: y, unsubscribeStore: C, props: s, configStore: o, editorStore: c, previewStore: Y, hasChanges: l, isTestPartner: Z, isSaveValidationEnabled: ee, saveSilent: k, setLoading: F, emit: r, buildMetadata: g, initPlugin: R, preloadRuntime: M, runExclusive: T, beginMount: I, isCurrentMount: S, mountGeneration: u, getDefaultTemplate: L, cloneTimersOnSave: U, hasTimerBlocks: A, noHeader: te, isRrsEnabled: oe, hasAssignedStrategy: ne, insertDynamicContent: B, closeDynamicContent: N, handleDynamicContentOpen: v, ribbonObserver: i, updateRibbonOffset: b, startEditor: h, AutoSaveController: ve, AuthErrorModal: be, Toaster: he, FilterSelectionDrawer: Ee, HeaderWrapper: we, LoadingWrapper: De, SaveAsTemplateDrawer: Ce, UnsubscribeWrapper: ke, ValidationErrorDrawer: Fe };
177
+ }), { __sfc: !0, PreviewContainer: K, OnboardingWrapper: j, AssignStrategyDrawer: J, RemoveStrategyModal: Q, LegacyStrategyUpdatedModal: X, LegacyUnsubscribeConvertedModal: Y, headerWrapperRef: C, wrapperRef: f, dynamicContentStore: y, unsubscribeStore: D, props: s, configStore: o, editorStore: d, previewStore: Z, hasChanges: u, isTestPartner: ee, isSaveValidationEnabled: te, saveSilent: k, setLoading: F, emit: r, buildMetadata: g, initPlugin: M, preloadRuntime: R, runExclusive: L, beginMount: T, isCurrentMount: b, mountGeneration: p, getDefaultTemplate: U, cloneTimersOnSave: I, hasTimerBlocks: A, noHeader: oe, isRrsEnabled: ne, isLegacyUnsubscribeConversionEnabled: re, hasAssignedStrategy: ae, insertDynamicContent: B, closeDynamicContent: N, handleDynamicContentOpen: v, ribbonObserver: i, updateRibbonOffset: S, startEditor: h, AutoSaveController: he, AuthErrorModal: Ee, Toaster: we, FilterSelectionDrawer: Ce, HeaderWrapper: De, LoadingWrapper: ke, SaveAsTemplateDrawer: Fe, UnsubscribeWrapper: Me, ValidationErrorDrawer: Re };
174
178
  }
175
179
  });
176
180
  export {
177
- lt as default
181
+ pt as default
178
182
  };
@@ -0,0 +1,17 @@
1
+ import t from "./LegacyUnsubscribeConvertedModal.vue2.js";
2
+ import n from "../../../_virtual/_plugin-vue2_normalizer.js";
3
+ var r = function() {
4
+ var o = this, s = o._self._c, e = o._self._setupProxy;
5
+ return e.isVisible ? s(e.WpModal, { attrs: { id: "guido__legacy-unsubscribe-converted-modal", size: "small", state: "warning", "close-on-outside-click": !1, "footer-button-options": e.footerButtonOptions, title: e.trans("email-editor.legacy-unsubscribe-converted-modal-title") }, on: { close: e.close, "primary-action": e.close, "secondary-action": e.openAcademy } }, [s("p", [o._v(o._s(e.trans("email-editor.legacy-unsubscribe-converted-modal-message")))])]) : o._e();
6
+ }, a = [], i = /* @__PURE__ */ n(
7
+ t,
8
+ r,
9
+ a,
10
+ !1,
11
+ null,
12
+ null
13
+ );
14
+ const d = i.exports;
15
+ export {
16
+ d as default
17
+ };
@@ -0,0 +1,35 @@
1
+ import { defineComponent as s, computed as t } from "vue";
2
+ import i from "../../wrappers/WpModal.vue.js";
3
+ import { useTranslations as a } from "../../../composables/useTranslations.js";
4
+ import { ACADEMY_LINKS as c } from "../../../enums/academy.js";
5
+ import { useEditorStore as l } from "../../../stores/editor.js";
6
+ const B = /* @__PURE__ */ s({
7
+ __name: "LegacyUnsubscribeConvertedModal",
8
+ setup(p) {
9
+ const e = a(), o = l(), n = t(
10
+ () => o.isLegacyUnsubscribeModalRequested && o.isStripoInitialized
11
+ ), r = t(() => ({
12
+ cancelOrBackButton: {
13
+ type: "secondary",
14
+ styling: "ghost",
15
+ labelText: e("settings.cancel")
16
+ },
17
+ secondaryButton: {
18
+ type: "subtle-primary",
19
+ labelText: e("left-menu.visit-academy")
20
+ },
21
+ primaryButton: {
22
+ type: "primary",
23
+ labelText: e("action-builder.ok")
24
+ }
25
+ }));
26
+ return { __sfc: !0, trans: e, editorStore: o, isVisible: n, footerButtonOptions: r, close: () => {
27
+ o.isLegacyUnsubscribeModalRequested = !1;
28
+ }, openAcademy: () => {
29
+ window.open(c.LEGACY_UNSUBSCRIBE_MODULE, "_blank", "noopener,noreferrer");
30
+ }, WpModal: i };
31
+ }
32
+ });
33
+ export {
34
+ B as default
35
+ };
@@ -1,34 +1,34 @@
1
- import { useRecommendation as S } from "./useRecommendation.js";
1
+ import { useRecommendation as C } from "./useRecommendation.js";
2
2
  import { useToaster as I } from "./useToaster.js";
3
3
  import { useTranslations as v } from "./useTranslations.js";
4
4
  import { ToasterTypeOptions as g } from "../enums/toaster.js";
5
5
  import "../extensions/Blocks/Recommendation/constants/selectors.js";
6
6
  import { CURRENT_CONFIG_VERSION as L } from "../extensions/Blocks/Recommendation/constants/defaultConfig.js";
7
- import { useRecommendationExtensionStore as R } from "../extensions/Blocks/Recommendation/store/recommendation.js";
8
- import { resolveMigrationTarget as b, buildLegacyMigrationPayload as k } from "../extensions/Blocks/Recommendation/utils/legacyStrategyMigration.js";
7
+ import { useRecommendationExtensionStore as b } from "../extensions/Blocks/Recommendation/store/recommendation.js";
8
+ import { resolveMigrationTarget as k, buildLegacyMigrationPayload as R } from "../extensions/Blocks/Recommendation/utils/legacyStrategyMigration.js";
9
9
  import { commitBlockChangeOutsidePanel as T } from "../extensions/Blocks/Recommendation/utils/nodeConfigWriter.js";
10
10
  import { useConfigStore as h } from "../stores/config.js";
11
11
  const F = () => {
12
- const e = R(), o = h(), { buildCampaignUrl: m } = S(), { showToaster: c } = I(), a = v();
12
+ const e = b(), r = h(), { buildCampaignUrl: m } = C(), { showToaster: c } = I(), a = v();
13
13
  return { convertLegacyStrategy: async () => {
14
14
  const t = e.currentRecommendationId;
15
15
  if (t === null || !e.isLegacyStrategyBlock || e.legacyConversionLoading)
16
16
  return "";
17
- const { strategy: d, productIds: y, size: l, strategyId: p, nodeConfigVersion: u } = e.recommendationConfigs, f = { strategyId: p, size: l, nodeConfigVersion: u }, s = b({
18
- campaignId: o.campaignId,
19
- templateLibraryId: o.templateLibraryId
20
- }), C = k({
17
+ const { strategy: d, productIds: y, size: l, strategyId: p, nodeConfigVersion: u } = e.recommendationConfigs, f = { strategyId: p, size: l, nodeConfigVersion: u }, s = k({
18
+ campaignId: r.campaignId,
19
+ templateLibraryId: r.templateLibraryId
20
+ }), S = R({
21
21
  blockId: t,
22
22
  url: m(String(t)),
23
- campaignId: o.campaignId,
24
- variationId: o.variationId,
23
+ campaignId: r.campaignId,
24
+ variationId: r.variationId,
25
25
  strategy: d,
26
26
  productIds: y,
27
27
  target: s
28
28
  });
29
- let r;
29
+ let o;
30
30
  try {
31
- r = await e.convertLegacyStrategy(C, s);
31
+ o = await e.convertLegacyStrategy(S, s);
32
32
  } catch (i) {
33
33
  return console.error("[useLegacyStrategyConversion] migration failed", i), c({
34
34
  type: g.Error,
@@ -40,7 +40,7 @@ const F = () => {
40
40
  }), "";
41
41
  }
42
42
  try {
43
- await e.fetchRecommendationProductsForBlock(t);
43
+ await e.fetchStrategyProductsForBlock(t);
44
44
  } catch (i) {
45
45
  console.error("[useLegacyStrategyConversion] product refetch failed", i);
46
46
  }
@@ -48,16 +48,16 @@ const F = () => {
48
48
  return n ? T(
49
49
  t,
50
50
  {
51
- strategyId: r,
51
+ strategyId: o,
52
52
  size: n.recommendationConfigs.size,
53
53
  configVersion: L
54
54
  },
55
55
  n.recommendationProducts,
56
56
  "Converted legacy recommendation strategy"
57
- ) ? (e.currentRecommendationId === t && e.openLegacyStrategyUpdatedModal(), r) : (console.error("[useLegacyStrategyConversion] node write failed", t), e.revertLegacyConversion(t, f), c({
57
+ ) ? (e.currentRecommendationId === t && e.openLegacyStrategyUpdatedModal(), o) : (console.error("[useLegacyStrategyConversion] node write failed", t), e.revertLegacyConversion(t, f), c({
58
58
  type: g.Error,
59
59
  message: a("email-editor.legacy-strategy-update-failed")
60
- }), "") : r;
60
+ }), "") : o;
61
61
  } };
62
62
  };
63
63
  export {