@designcrowd/library.brand-page 6.1.14 → 6.1.15

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 (43) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-CNqGW-GB.js → CreatedOnBrandCrowd-de-de-a7cNT5AA.js} +1 -1
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-BWZeor_R.js → CreatedOnBrandCrowd-en-us-BpZ89I9T.js} +1 -1
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-D_-5Qdpd.js → CreatedOnBrandCrowd-es-es-Db0Ot-mQ.js} +1 -1
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-BC6Xo2uA.js → CreatedOnBrandCrowd-fr-ca-Mbd7Hhxh.js} +1 -1
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-BC6Xo2uA.js → CreatedOnBrandCrowd-fr-fr-Mbd7Hhxh.js} +1 -1
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-D10DwNv3.js → CreatedOnBrandCrowd-pt-br-B98aoT6y.js} +1 -1
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-D10DwNv3.js → CreatedOnBrandCrowd-pt-pt-B98aoT6y.js} +1 -1
  8. package/lib/src/{CreatedOnDcom-de-de-BDHrHOOB.js → CreatedOnDcom-de-de-b_GUYmhX.js} +1 -1
  9. package/lib/src/{CreatedOnDcom-en-us-EbniAwLE.js → CreatedOnDcom-en-us-BtTIwekM.js} +1 -1
  10. package/lib/src/{CreatedOnDcom-es-es-BpAIMuUH.js → CreatedOnDcom-es-es-WbhHNEg-.js} +1 -1
  11. package/lib/src/{CreatedOnDcom-fr-ca-BDSu4efU.js → CreatedOnDcom-fr-ca-DnQOAvS5.js} +1 -1
  12. package/lib/src/{CreatedOnDcom-fr-fr-BR7f1SWB.js → CreatedOnDcom-fr-fr-D7Q-aBNQ.js} +1 -1
  13. package/lib/src/{CreatedOnDcom-pt-br-DzY1XBcr.js → CreatedOnDcom-pt-br-DnqkF_ve.js} +1 -1
  14. package/lib/src/{CreatedOnDcom-pt-pt-1v5N9vgW.js → CreatedOnDcom-pt-pt-DNyyHF1o.js} +1 -1
  15. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.js +4 -1
  16. package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +3 -0
  17. package/lib/src/brand-page-maker/composables/useEventTracker.d.ts +15 -0
  18. package/lib/src/brand-page-maker/composables/useEventTracker.js +36 -0
  19. package/lib/src/index.mjs +2 -2
  20. package/lib/src/{lib-BMP5cseh.js → lib-33AmrlUy.js} +14282 -14271
  21. package/lib/src/metadata-builder/builders/reorder-pages-builder.d.ts +13 -0
  22. package/lib/src/metadata-builder/builders/reorder-pages-builder.js +49 -0
  23. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts +3 -0
  24. package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +3 -0
  25. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.d.ts +3 -0
  26. package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.d.ts +3 -0
  27. package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +3 -0
  28. package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +3 -0
  29. package/lib/src/shared/side-bar/components/SideBarTabButton.mixin.d.ts +3 -0
  30. package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +3 -0
  31. package/lib/src/shared/template-settings/components/TemplatesSettings.mixin.d.ts +3 -0
  32. package/lib/src/tracker.d.ts +1 -1
  33. package/lib/src/tracker.js +1 -1
  34. package/lib/src/tracker.mjs +9 -7
  35. package/lib/src/{useEventTracker-Dmc2jFdN.js → useEventTracker-C5Ql5p7u.js} +56 -22
  36. package/package.json +1 -1
  37. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.ts +9 -1
  38. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.preview-gate.test.ts +38 -1
  39. package/src/brand-page-maker/components/preview-modal/PreviewModalWithState.test.ts +123 -0
  40. package/src/brand-page-maker/components/preview-modal/PreviewModalWithState.vue +25 -0
  41. package/src/brand-page-maker/composables/useEventTracker.ts +41 -0
  42. package/src/metadata-builder/builders/reorder-pages-builder.ts +80 -0
  43. package/src/tracker.ts +2 -0
@@ -0,0 +1,13 @@
1
+ import type { BrandPageModel } from '../../brand-page/models';
2
+ import { BaseMetadataBuilder, type BuilderResult, type MetadataBuilderRequest } from '../models';
3
+ import type { Logger } from '../logger';
4
+ export interface ReorderPagesPayload {
5
+ pageOrder: string[];
6
+ }
7
+ export declare class ReorderPagesBuilder extends BaseMetadataBuilder<ReorderPagesPayload> {
8
+ constructor(request: MetadataBuilderRequest<ReorderPagesPayload>, logger?: Logger);
9
+ validateAsync(): Promise<{
10
+ errors: string[];
11
+ }>;
12
+ buildAsync(model: BrandPageModel): Promise<BuilderResult>;
13
+ }
@@ -0,0 +1,49 @@
1
+ import { BaseMetadataBuilder, } from '../models';
2
+ export class ReorderPagesBuilder extends BaseMetadataBuilder {
3
+ constructor(request, logger) {
4
+ super(request, logger);
5
+ }
6
+ async validateAsync() {
7
+ const errors = [];
8
+ const payload = this.request.payload;
9
+ if (!payload?.pageOrder?.length) {
10
+ errors.push('page_order is required for reorder_pages');
11
+ }
12
+ return { errors };
13
+ }
14
+ async buildAsync(model) {
15
+ this.log('Build called');
16
+ const validation = await this.validateAsync();
17
+ if (validation.errors.length) {
18
+ return { request: this.request, model, errors: validation.errors };
19
+ }
20
+ const { pageOrder } = this.request.payload;
21
+ // Build pageId → routeId lookup from nav.routes
22
+ const pageIdToRouteId = new Map();
23
+ for (const route of model.nav.routes) {
24
+ pageIdToRouteId.set(route.pageId, route.id);
25
+ }
26
+ // Build new nav.orders from the flat page_order (array of pageIds)
27
+ const newOrders = [];
28
+ const seenRouteIds = new Set();
29
+ for (const pageId of pageOrder) {
30
+ const routeId = pageIdToRouteId.get(pageId);
31
+ if (!routeId)
32
+ continue;
33
+ newOrders.push({ routeId, subRoutes: [] });
34
+ seenRouteIds.add(routeId);
35
+ }
36
+ // Safety: append any routes not mentioned (don't lose pages)
37
+ for (const route of model.nav.routes) {
38
+ const routeId = pageIdToRouteId.get(route.pageId);
39
+ if (routeId && !seenRouteIds.has(routeId)) {
40
+ newOrders.push({ routeId, subRoutes: [] });
41
+ }
42
+ }
43
+ model.nav.orders = newOrders;
44
+ this.log({
45
+ message: `Reordered pages: ${pageOrder.join(', ')}`,
46
+ });
47
+ return { request: this.request, model };
48
+ }
49
+ }
@@ -637,6 +637,9 @@ declare const _default: import("vue").DefineComponent<{}, {
637
637
  }>;
638
638
  eventTracker: {
639
639
  sendShippingToggleEvent: (isEnabled: boolean) => void;
640
+ sendPreviewClickEvent: (ctaLocation: string) => void;
641
+ sendPreviewModalOpenEvent: (ctaLocation: string) => void;
642
+ sendPreviewModalContinuationEvent: (continuation: string, ctaLocation: string) => void;
640
643
  sendUndoEvent: (props: {
641
644
  entries_count: number;
642
645
  actor: string | undefined;
@@ -757,6 +757,9 @@ declare const _default: import("vue").DefineComponent<{}, {
757
757
  }>;
758
758
  bpEventTracker: {
759
759
  sendShippingToggleEvent: (isEnabled: boolean) => void;
760
+ sendPreviewClickEvent: (ctaLocation: string) => void;
761
+ sendPreviewModalOpenEvent: (ctaLocation: string) => void;
762
+ sendPreviewModalContinuationEvent: (continuation: string, ctaLocation: string) => void;
760
763
  sendUndoEvent: (props: {
761
764
  entries_count: number;
762
765
  actor: string | undefined;
@@ -489,6 +489,9 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
489
489
  }>;
490
490
  eventTracker: {
491
491
  sendShippingToggleEvent: (isEnabled: boolean) => void;
492
+ sendPreviewClickEvent: (ctaLocation: string) => void;
493
+ sendPreviewModalOpenEvent: (ctaLocation: string) => void;
494
+ sendPreviewModalContinuationEvent: (continuation: string, ctaLocation: string) => void;
492
495
  sendUndoEvent: (props: {
493
496
  entries_count: number;
494
497
  actor: string | undefined;
@@ -256,6 +256,9 @@ declare const _default: import("vue").DefineComponent<{}, {
256
256
  }>;
257
257
  eventTracker: {
258
258
  sendShippingToggleEvent: (isEnabled: boolean) => void;
259
+ sendPreviewClickEvent: (ctaLocation: string) => void;
260
+ sendPreviewModalOpenEvent: (ctaLocation: string) => void;
261
+ sendPreviewModalContinuationEvent: (continuation: string, ctaLocation: string) => void;
259
262
  sendUndoEvent: (props: {
260
263
  entries_count: number;
261
264
  actor: string | undefined;
@@ -4935,6 +4935,9 @@ declare const _default: import("vue").DefineComponent<{}, {
4935
4935
  onDraggingEnd: (ev?: any, routeId?: string, previousParentRouteId?: string) => void;
4936
4936
  eventTracker: {
4937
4937
  sendShippingToggleEvent: (isEnabled: boolean) => void;
4938
+ sendPreviewClickEvent: (ctaLocation: string) => void;
4939
+ sendPreviewModalOpenEvent: (ctaLocation: string) => void;
4940
+ sendPreviewModalContinuationEvent: (continuation: string, ctaLocation: string) => void;
4938
4941
  sendUndoEvent: (props: {
4939
4942
  entries_count: number;
4940
4943
  actor: string | undefined;
@@ -607,6 +607,9 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
607
607
  }>;
608
608
  eventTracker: {
609
609
  sendShippingToggleEvent: (isEnabled: boolean) => void;
610
+ sendPreviewClickEvent: (ctaLocation: string) => void;
611
+ sendPreviewModalOpenEvent: (ctaLocation: string) => void;
612
+ sendPreviewModalContinuationEvent: (continuation: string, ctaLocation: string) => void;
610
613
  sendUndoEvent: (props: {
611
614
  entries_count: number;
612
615
  actor: string | undefined;
@@ -17,6 +17,9 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
17
17
  isDesignCom: import("vue").ComputedRef<boolean>;
18
18
  eventTracker: {
19
19
  sendShippingToggleEvent: (isEnabled: boolean) => void;
20
+ sendPreviewClickEvent: (ctaLocation: string) => void;
21
+ sendPreviewModalOpenEvent: (ctaLocation: string) => void;
22
+ sendPreviewModalContinuationEvent: (continuation: string, ctaLocation: string) => void;
20
23
  sendUndoEvent: (props: {
21
24
  entries_count: number;
22
25
  actor: string | undefined;
@@ -948,6 +948,9 @@ declare const _default: import("vue").DefineComponent<{}, {
948
948
  }>;
949
949
  eventTracker: {
950
950
  sendShippingToggleEvent: (isEnabled: boolean) => void;
951
+ sendPreviewClickEvent: (ctaLocation: string) => void;
952
+ sendPreviewModalOpenEvent: (ctaLocation: string) => void;
953
+ sendPreviewModalContinuationEvent: (continuation: string, ctaLocation: string) => void;
951
954
  sendUndoEvent: (props: {
952
955
  entries_count: number;
953
956
  actor: string | undefined;
@@ -132,6 +132,9 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
132
132
  isDesignCom: import("vue").ComputedRef<boolean>;
133
133
  eventTracker: {
134
134
  sendShippingToggleEvent: (isEnabled: boolean) => void;
135
+ sendPreviewClickEvent: (ctaLocation: string) => void;
136
+ sendPreviewModalOpenEvent: (ctaLocation: string) => void;
137
+ sendPreviewModalContinuationEvent: (continuation: string, ctaLocation: string) => void;
135
138
  sendUndoEvent: (props: {
136
139
  entries_count: number;
137
140
  actor: string | undefined;
@@ -1,2 +1,2 @@
1
- export { useEventTracker, EVENTS, SELECT_LOCATIONS, UPGRADE_CTA_LOCATIONS, AI_CTA_LOCATIONS, TRIGGER_TYPE, PUBLISH_MODAL_CONTINUATION_EVENTS, GENERATE_TEXT_CONTINUATION_EVENTS, PUBLISH_OPTION_MODAL_CONTINUATION_EVENTS, } from './brand-page-maker/composables/useEventTracker';
1
+ export { useEventTracker, EVENTS, SELECT_LOCATIONS, UPGRADE_CTA_LOCATIONS, AI_CTA_LOCATIONS, TRIGGER_TYPE, PUBLISH_MODAL_CONTINUATION_EVENTS, GENERATE_TEXT_CONTINUATION_EVENTS, PUBLISH_OPTION_MODAL_CONTINUATION_EVENTS, PREVIEW_CTA_LOCATIONS, PREVIEW_MODAL_CONTINUATION_EVENTS, } from './brand-page-maker/composables/useEventTracker';
2
2
  export type { EventTracker, BpEventTrackerEvent, BpGlobalEventProps, BpUpsellEventProps, } from './brand-page-maker/composables/useEventTracker';
@@ -9,4 +9,4 @@
9
9
  // entry and the root `.` entry, or subscribers registered here won't receive
10
10
  // events published via the root. The multi-entry build hoists it into a shared
11
11
  // chunk (both `index` and `tracker` import it) — verified at build time.
12
- export { useEventTracker, EVENTS, SELECT_LOCATIONS, UPGRADE_CTA_LOCATIONS, AI_CTA_LOCATIONS, TRIGGER_TYPE, PUBLISH_MODAL_CONTINUATION_EVENTS, GENERATE_TEXT_CONTINUATION_EVENTS, PUBLISH_OPTION_MODAL_CONTINUATION_EVENTS, } from './brand-page-maker/composables/useEventTracker';
12
+ export { useEventTracker, EVENTS, SELECT_LOCATIONS, UPGRADE_CTA_LOCATIONS, AI_CTA_LOCATIONS, TRIGGER_TYPE, PUBLISH_MODAL_CONTINUATION_EVENTS, GENERATE_TEXT_CONTINUATION_EVENTS, PUBLISH_OPTION_MODAL_CONTINUATION_EVENTS, PREVIEW_CTA_LOCATIONS, PREVIEW_MODAL_CONTINUATION_EVENTS, } from './brand-page-maker/composables/useEventTracker';
@@ -1,12 +1,14 @@
1
- import { A as N, E as O, G as _, P as A, a as I, S as a, T as S, U as s, u as C } from "./useEventTracker-Dmc2jFdN.js";
1
+ import { A as N, E as O, G as _, P as I, a as A, b as a, c as S, S as s, T as C, U as L, u as P } from "./useEventTracker-C5Ql5p7u.js";
2
2
  export {
3
3
  N as AI_CTA_LOCATIONS,
4
4
  O as EVENTS,
5
5
  _ as GENERATE_TEXT_CONTINUATION_EVENTS,
6
- A as PUBLISH_MODAL_CONTINUATION_EVENTS,
7
- I as PUBLISH_OPTION_MODAL_CONTINUATION_EVENTS,
8
- a as SELECT_LOCATIONS,
9
- S as TRIGGER_TYPE,
10
- s as UPGRADE_CTA_LOCATIONS,
11
- C as useEventTracker
6
+ I as PREVIEW_CTA_LOCATIONS,
7
+ A as PREVIEW_MODAL_CONTINUATION_EVENTS,
8
+ a as PUBLISH_MODAL_CONTINUATION_EVENTS,
9
+ S as PUBLISH_OPTION_MODAL_CONTINUATION_EVENTS,
10
+ s as SELECT_LOCATIONS,
11
+ C as TRIGGER_TYPE,
12
+ L as UPGRADE_CTA_LOCATIONS,
13
+ P as useEventTracker
12
14
  };
@@ -38,11 +38,23 @@ const E = {
38
38
  WEBSITE_MAKER_UNDO: "website_maker_undo",
39
39
  WEBSITE_MAKER_REDO: "website_maker_redo",
40
40
  WEBSITE_MAKER_HISTORY_CAPPED: "website_maker_history_capped",
41
- WEBSITE_MAKER_HISTORY_OVERSIZED: "website_maker_history_oversized"
42
- }, R = {
41
+ WEBSITE_MAKER_HISTORY_OVERSIZED: "website_maker_history_oversized",
42
+ WEBSITE_MAKER_LIVE_PREVIEW_CLICK: "website_maker_live_preview_click",
43
+ WEBSITE_MAKER_LIVE_PREVIEW_MODAL: "website_maker_live_preview_modal"
44
+ }, r = {
45
+ MAKER: "maker",
46
+ MANAGE_WEBSITE: "manage_website"
47
+ }, p = {
48
+ EXIT: "exit",
49
+ // The same button reads "Back to Editor" on the editor and "Edit" on other
50
+ // surfaces — the continuation mirrors the label the user actually clicked.
51
+ BACK_TO_EDITOR: "back_to_editor",
52
+ EDIT: "edit",
53
+ PUBLISH: "publish"
54
+ }, O = {
43
55
  MAKER_PREVIEW: "maker_preview",
44
56
  SIDEBAR: "sidebar"
45
- }, p = {
57
+ }, M = {
46
58
  MANAGE_WEBSITE: "manage_website",
47
59
  MANAGE_WEBSITE_PUBLISH: "manage_website_publish",
48
60
  MANAGE_WEBSITE_UPGRADE: "manage_website_upgrade",
@@ -61,14 +73,14 @@ const E = {
61
73
  SAVE_CONTACT_SETTINGS: "save_contact_settings",
62
74
  NAV_TOP: "nav_top",
63
75
  NAV_BOTTOM: "nav_bottom"
64
- }, O = {
76
+ }, d = {
65
77
  AI_BUILDER_TAB: "ai_builder_tab",
66
78
  AI_BUILDER_CHAT_UPSELL: "ai_builder_chat_upsell"
67
79
  }, S = {
68
80
  AUTOMATIC: "automatic",
69
81
  USER_TRIGGERED: "user_triggered",
70
82
  AI_BUILDER: "ai_builder"
71
- }, d = {
83
+ }, P = {
72
84
  PUBLISH: "publish",
73
85
  EXIT: "exit",
74
86
  BUY_A_DOMAIN: "buy_a_domain",
@@ -76,14 +88,14 @@ const E = {
76
88
  COPY_LINK: "copy_link",
77
89
  VIEW_WEBSITE: "view_website",
78
90
  USE_EXISTING_DOMAIN: "use_existing_domain"
79
- }, M = {
91
+ }, L = {
80
92
  USE_TEXT: "use_text",
81
93
  EXIT: "exit"
82
- }, T = {
94
+ }, i = {
83
95
  PREMIUM: "premium",
84
96
  EXIT: "exit",
85
97
  FREEMIUM: "freemium"
86
- }, i = I(), n = I({
98
+ }, T = I(), n = I({
87
99
  upsellOpenEventProps: {},
88
100
  domainUpsellOpenEventProps: {},
89
101
  publishOpenEventProps: {}
@@ -93,12 +105,12 @@ const E = {
93
105
  scope: t,
94
106
  eventName: o,
95
107
  eventProps: {
96
- ...e ? {} : i.value,
108
+ ...e ? {} : T.value,
97
109
  ...A
98
110
  }
99
111
  });
100
112
  });
101
- }, P = () => ({
113
+ }, B = () => ({
102
114
  sendExperimentStartedEvent: (e, t) => {
103
115
  _(
104
116
  E.EXPERIMENT_STARTED,
@@ -116,10 +128,10 @@ const E = {
116
128
  location: "post_purchase",
117
129
  domain_type: "Free"
118
130
  };
119
- i.value = { ...t, ...e };
131
+ T.value = { ...t, ...e };
120
132
  },
121
133
  setCustomGlobalEventProps: (e) => {
122
- i.value = e;
134
+ T.value = e;
123
135
  },
124
136
  setUpsellBridgeState: (e) => {
125
137
  n.value.upsellOpenEventProps = e;
@@ -206,17 +218,17 @@ const E = {
206
218
  },
207
219
  sendPublishOptionsForFreeEvent: () => {
208
220
  _(E.WEBSITE_MAKER_PUBLISH_UPSELL_OPTION_MODAL, {
209
- upsell_option_continuation: T.FREEMIUM
221
+ upsell_option_continuation: i.FREEMIUM
210
222
  });
211
223
  },
212
224
  sendPublishOptionsForPremiumEvent: () => {
213
225
  _(E.WEBSITE_MAKER_PUBLISH_UPSELL_OPTION_MODAL, {
214
- upsell_option_continuation: T.PREMIUM
226
+ upsell_option_continuation: i.PREMIUM
215
227
  });
216
228
  },
217
229
  sendPublishOptionsForExitEvent: () => {
218
230
  _(E.WEBSITE_MAKER_PUBLISH_UPSELL_OPTION_MODAL, {
219
- upsell_option_continuation: T.EXIT
231
+ upsell_option_continuation: i.EXIT
220
232
  });
221
233
  },
222
234
  // Template sidebar events
@@ -330,6 +342,26 @@ const E = {
330
342
  is_enabled: e
331
343
  });
332
344
  },
345
+ // Live preview: the click is tracked separately from the modal opening —
346
+ // sign-in/save gating means a click doesn't always open the modal, and the
347
+ // post-sign-in return trip opens it without a click.
348
+ sendPreviewClickEvent: (e) => {
349
+ _(E.WEBSITE_MAKER_LIVE_PREVIEW_CLICK, {
350
+ cta_location: e
351
+ });
352
+ },
353
+ sendPreviewModalOpenEvent: (e) => {
354
+ _(E.WEBSITE_MAKER_LIVE_PREVIEW_MODAL, {
355
+ cta_location: e,
356
+ continuation: null
357
+ });
358
+ },
359
+ sendPreviewModalContinuationEvent: (e, t) => {
360
+ _(E.WEBSITE_MAKER_LIVE_PREVIEW_MODAL, {
361
+ cta_location: t,
362
+ continuation: e
363
+ });
364
+ },
333
365
  // Undo / Redo (BP-5506)
334
366
  sendUndoEvent: (e) => {
335
367
  _(E.WEBSITE_MAKER_UNDO, e);
@@ -345,13 +377,15 @@ const E = {
345
377
  }
346
378
  });
347
379
  export {
348
- O as A,
380
+ d as A,
349
381
  E,
350
- M as G,
351
- d as P,
352
- R as S,
382
+ L as G,
383
+ r as P,
384
+ O as S,
353
385
  S as T,
354
- p as U,
355
- T as a,
356
- P as u
386
+ M as U,
387
+ p as a,
388
+ P as b,
389
+ i as c,
390
+ B as u
357
391
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@designcrowd/library.brand-page",
3
3
  "description": "A collection of Maker/Designer applications",
4
- "version": "6.1.14",
4
+ "version": "6.1.15",
5
5
  "author": "Design.com Eng",
6
6
  "license": "UNLICENSED",
7
7
  "type": "module",
@@ -48,7 +48,11 @@ import AssetLibraryClient from '../../../clients/asset-library-clients';
48
48
  import { useShopConfigStore } from '@shared/ecommerce-settings/store/shop-settings-store';
49
49
  import type { ShopConfigData } from '@brand-page/models/shop.model';
50
50
  import { useProductConfigStore } from '@brand-page-maker/stores/product-config/product-config-store';
51
- import { UPGRADE_CTA_LOCATIONS } from '../../composables/useEventTracker';
51
+ import {
52
+ useEventTracker,
53
+ UPGRADE_CTA_LOCATIONS,
54
+ PREVIEW_CTA_LOCATIONS,
55
+ } from '../../composables/useEventTracker';
52
56
  import { commonTr } from '@src/composables/useTranslate';
53
57
  import { useSnapshot } from '../../../composables/useSnapshot';
54
58
  import { usePageNavigationStore } from '@src/shared/page-navigation/store/page-navigation-store';
@@ -460,6 +464,10 @@ export default defineComponent({
460
464
  this.$emit(EVENTS.Back);
461
465
  },
462
466
  onPreview() {
467
+ // Every click is counted, before the gating below — the modal-open event
468
+ // fires separately, so click → open reads as a funnel.
469
+ useEventTracker().sendPreviewClickEvent(PREVIEW_CTA_LOCATIONS.MAKER);
470
+
463
471
  // The preview frames a SAVED, owned draft. A signed-out customer can't have
464
472
  // one, and the save needs an owner — so sign-in comes first, via the host's
465
473
  // Save Progress flow.
@@ -1,6 +1,11 @@
1
- import { describe, test, expect, vi } from 'vitest';
1
+ import { describe, test, expect, vi, beforeEach } from 'vitest';
2
2
  import BrandPageMakerMixin from './BrandPageMaker.mixin';
3
3
  import { EVENTS } from '../../../constants/brand-page-maker';
4
+ import {
5
+ useEventTracker,
6
+ EVENTS as TRACKER_EVENTS,
7
+ PREVIEW_CTA_LOCATIONS,
8
+ } from '@brand-page-maker/composables/useEventTracker';
4
9
 
5
10
  // The preview frames a SAVED, owned draft, so who saves it decides when the modal
6
11
  // may open. Signed out: nobody owns a draft, so hand off to the host's Save Progress
@@ -68,6 +73,38 @@ describe('BrandPageMaker.onPreview', () => {
68
73
  });
69
74
  });
70
75
 
76
+ describe('BrandPageMaker.onPreview click analytics', () => {
77
+ const received: { name: string; props: any }[] = [];
78
+
79
+ useEventTracker().subscribe((event) =>
80
+ received.push({ name: event.eventName, props: event.eventProps }),
81
+ );
82
+
83
+ beforeEach(() => {
84
+ received.length = 0;
85
+ });
86
+
87
+ // The click is counted before the sign-in/save gating, so every branch —
88
+ // including ones where the modal never opens — reports the same event.
89
+ test.each([
90
+ ['signed out', { isUserAuthenticated: false }],
91
+ [
92
+ 'pre-purchase',
93
+ { containerStore: { isPrePurchase: true, livePreviewUrl: undefined } },
94
+ ],
95
+ ['post-purchase', {}],
96
+ ])('every click is counted: %s', (_, overrides) => {
97
+ onPreview.call(createContext(overrides as any));
98
+
99
+ expect(received).toEqual([
100
+ {
101
+ name: TRACKER_EVENTS.WEBSITE_MAKER_LIVE_PREVIEW_CLICK,
102
+ props: { cta_location: PREVIEW_CTA_LOCATIONS.MAKER },
103
+ },
104
+ ]);
105
+ });
106
+ });
107
+
71
108
  describe('BrandPageMaker livePreviewUrl watcher', () => {
72
109
  test('opens the preview once the host save hands back a URL', () => {
73
110
  const context = createContext({
@@ -7,6 +7,12 @@ import {
7
7
  useBrandPageContainerStore,
8
8
  useBrandPageMakerStore,
9
9
  } from '@brand-page-maker/stores';
10
+ import {
11
+ useEventTracker,
12
+ EVENTS,
13
+ PREVIEW_CTA_LOCATIONS,
14
+ PREVIEW_MODAL_CONTINUATION_EVENTS,
15
+ } from '@brand-page-maker/composables/useEventTracker';
10
16
 
11
17
  const PREVIEW_URL = 'https://brand.site/_p/request?token=signed';
12
18
 
@@ -243,4 +249,121 @@ describe('PreviewModalWithState', () => {
243
249
 
244
250
  expect(wrapper.emitted('edit')).toHaveLength(1);
245
251
  });
252
+
253
+ describe('analytics', () => {
254
+ const received: { name: string; props: any }[] = [];
255
+
256
+ useEventTracker().subscribe((event) =>
257
+ received.push({ name: event.eventName, props: event.eventProps }),
258
+ );
259
+
260
+ const openModal = async (props: Record<string, unknown> = {}) => {
261
+ vi.spyOn(containerStore, 'saveBrandPage').mockResolvedValue({
262
+ saved: true,
263
+ canPublish: true,
264
+ } as any);
265
+ vi.spyOn(containerStore, 'showSaveSuccessMessage').mockResolvedValue(
266
+ undefined,
267
+ );
268
+ vi.spyOn(
269
+ useBrandPageMakerStore(),
270
+ 'showNextNotificationMessage',
271
+ ).mockResolvedValue(undefined);
272
+
273
+ const wrapper = shallowMount(PreviewModalWithState, {
274
+ props: { visible: false, ...props },
275
+ });
276
+
277
+ await wrapper.setProps({ visible: true });
278
+ await flushPromises();
279
+
280
+ return wrapper;
281
+ };
282
+
283
+ beforeEach(() => {
284
+ received.length = 0;
285
+ });
286
+
287
+ test('opening fires the modal event, stamped with the editor surface by default', async () => {
288
+ await openModal();
289
+
290
+ expect(received).toEqual([
291
+ {
292
+ name: EVENTS.WEBSITE_MAKER_LIVE_PREVIEW_MODAL,
293
+ props: {
294
+ cta_location: PREVIEW_CTA_LOCATIONS.MAKER,
295
+ continuation: null,
296
+ },
297
+ },
298
+ ]);
299
+ });
300
+
301
+ test('the hosting surface stamps its own cta_location', async () => {
302
+ await openModal({ ctaLocation: PREVIEW_CTA_LOCATIONS.MANAGE_WEBSITE });
303
+
304
+ expect(received).toEqual([
305
+ {
306
+ name: EVENTS.WEBSITE_MAKER_LIVE_PREVIEW_MODAL,
307
+ props: {
308
+ cta_location: PREVIEW_CTA_LOCATIONS.MANAGE_WEBSITE,
309
+ continuation: null,
310
+ },
311
+ },
312
+ ]);
313
+ });
314
+
315
+ test.each([
316
+ ['close', PREVIEW_MODAL_CONTINUATION_EVENTS.EXIT],
317
+ // On the editor (cta=publish, the default) the button reads "Back to Editor".
318
+ ['edit', PREVIEW_MODAL_CONTINUATION_EVENTS.BACK_TO_EDITOR],
319
+ ['publish', PREVIEW_MODAL_CONTINUATION_EVENTS.PUBLISH],
320
+ ])('%s continues the modal event as %s', async (emitName, continuation) => {
321
+ const wrapper = await openModal();
322
+
323
+ received.length = 0;
324
+ await wrapper.findComponent(LivePreviewModal).vm.$emit(emitName);
325
+ await flushPromises();
326
+
327
+ expect(received).toEqual([
328
+ {
329
+ name: EVENTS.WEBSITE_MAKER_LIVE_PREVIEW_MODAL,
330
+ props: { cta_location: PREVIEW_CTA_LOCATIONS.MAKER, continuation },
331
+ },
332
+ ]);
333
+ });
334
+
335
+ // The manage page's button reads "Edit" (cta=edit), so its continuation is
336
+ // edit — the editor's back_to_editor case is covered above.
337
+ test('continuations carry the hosting surface and its label', async () => {
338
+ const wrapper = await openModal({
339
+ cta: 'edit',
340
+ ctaLocation: PREVIEW_CTA_LOCATIONS.MANAGE_WEBSITE,
341
+ });
342
+
343
+ received.length = 0;
344
+ await wrapper.findComponent(LivePreviewModal).vm.$emit('edit');
345
+ await flushPromises();
346
+
347
+ expect(received).toEqual([
348
+ {
349
+ name: EVENTS.WEBSITE_MAKER_LIVE_PREVIEW_MODAL,
350
+ props: {
351
+ cta_location: PREVIEW_CTA_LOCATIONS.MANAGE_WEBSITE,
352
+ continuation: PREVIEW_MODAL_CONTINUATION_EVENTS.EDIT,
353
+ },
354
+ },
355
+ ]);
356
+ });
357
+
358
+ // Retry re-runs the save, it isn't a decision about the preview — not tracked.
359
+ test('retry is not tracked', async () => {
360
+ const wrapper = await openModal();
361
+
362
+ received.length = 0;
363
+ await wrapper.findComponent(LivePreviewModal).vm.$emit('retry');
364
+ await flushPromises();
365
+
366
+ expect(received).toEqual([]);
367
+ });
368
+ });
246
369
  });
@@ -27,18 +27,26 @@ import {
27
27
  useBrandPageContainerStore,
28
28
  useBrandPageMakerStore,
29
29
  } from '@brand-page-maker/stores';
30
+ import {
31
+ useEventTracker,
32
+ PREVIEW_CTA_LOCATIONS,
33
+ PREVIEW_MODAL_CONTINUATION_EVENTS,
34
+ } from '@brand-page-maker/composables/useEventTracker';
30
35
  import type { UiDeviceMode } from '@shared/models';
31
36
 
32
37
  const props = defineProps({
33
38
  visible: { type: Boolean, default: false },
34
39
  // Per-surface header CTA; defaults to 'publish' so the editor is unchanged.
35
40
  cta: { type: String as PropType<LivePreviewCta>, default: 'publish' },
41
+ // Which surface hosts the preview — stamped on its analytics as cta_location.
42
+ ctaLocation: { type: String, default: PREVIEW_CTA_LOCATIONS.MAKER },
36
43
  });
37
44
 
38
45
  const emit = defineEmits<{ close: []; publish: []; edit: [] }>();
39
46
 
40
47
  const containerStore = useBrandPageContainerStore();
41
48
  const makerStore = useBrandPageMakerStore();
49
+ const eventTracker = useEventTracker();
42
50
 
43
51
  // The preview must step back for any modal opening over the editor.
44
52
  const isFlowModalOpen = computed(() => containerStore.isAnyModalVisible);
@@ -96,18 +104,34 @@ const announceExit = async (): Promise<void> => {
96
104
  };
97
105
 
98
106
  const onClose = async (): Promise<void> => {
107
+ // Escape funnels through the shell's close emit too, so it counts as an exit.
108
+ eventTracker.sendPreviewModalContinuationEvent(
109
+ PREVIEW_MODAL_CONTINUATION_EVENTS.EXIT,
110
+ props.ctaLocation,
111
+ );
99
112
  emit('close');
100
113
 
101
114
  await announceExit();
102
115
  };
103
116
 
104
117
  const onEdit = async (): Promise<void> => {
118
+ // Mirror the rendered label: cta=publish shows "Back to Editor", else "Edit".
119
+ eventTracker.sendPreviewModalContinuationEvent(
120
+ props.cta === 'publish'
121
+ ? PREVIEW_MODAL_CONTINUATION_EVENTS.BACK_TO_EDITOR
122
+ : PREVIEW_MODAL_CONTINUATION_EVENTS.EDIT,
123
+ props.ctaLocation,
124
+ );
105
125
  emit('edit');
106
126
 
107
127
  await announceExit();
108
128
  };
109
129
 
110
130
  const onPublish = (): void => {
131
+ eventTracker.sendPreviewModalContinuationEvent(
132
+ PREVIEW_MODAL_CONTINUATION_EVENTS.PUBLISH,
133
+ props.ctaLocation,
134
+ );
111
135
  // Route through the host's publish flow so pre-purchase still reaches checkout.
112
136
  publishing.value = true;
113
137
  emit('publish');
@@ -117,6 +141,7 @@ watch(
117
141
  () => props.visible,
118
142
  (isVisible) => {
119
143
  if (isVisible) {
144
+ eventTracker.sendPreviewModalOpenEvent(props.ctaLocation);
120
145
  openPreview();
121
146
  } else {
122
147
  previewUrl.value = '';