@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.
- package/lib/src/{CreatedOnBrandCrowd-de-de-CNqGW-GB.js → CreatedOnBrandCrowd-de-de-a7cNT5AA.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-en-us-BWZeor_R.js → CreatedOnBrandCrowd-en-us-BpZ89I9T.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-es-es-D_-5Qdpd.js → CreatedOnBrandCrowd-es-es-Db0Ot-mQ.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-fr-BC6Xo2uA.js → CreatedOnBrandCrowd-fr-ca-Mbd7Hhxh.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-ca-BC6Xo2uA.js → CreatedOnBrandCrowd-fr-fr-Mbd7Hhxh.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-pt-D10DwNv3.js → CreatedOnBrandCrowd-pt-br-B98aoT6y.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-br-D10DwNv3.js → CreatedOnBrandCrowd-pt-pt-B98aoT6y.js} +1 -1
- package/lib/src/{CreatedOnDcom-de-de-BDHrHOOB.js → CreatedOnDcom-de-de-b_GUYmhX.js} +1 -1
- package/lib/src/{CreatedOnDcom-en-us-EbniAwLE.js → CreatedOnDcom-en-us-BtTIwekM.js} +1 -1
- package/lib/src/{CreatedOnDcom-es-es-BpAIMuUH.js → CreatedOnDcom-es-es-WbhHNEg-.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-ca-BDSu4efU.js → CreatedOnDcom-fr-ca-DnQOAvS5.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-fr-BR7f1SWB.js → CreatedOnDcom-fr-fr-D7Q-aBNQ.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-br-DzY1XBcr.js → CreatedOnDcom-pt-br-DnqkF_ve.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-pt-1v5N9vgW.js → CreatedOnDcom-pt-pt-DNyyHF1o.js} +1 -1
- package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.js +4 -1
- package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +3 -0
- package/lib/src/brand-page-maker/composables/useEventTracker.d.ts +15 -0
- package/lib/src/brand-page-maker/composables/useEventTracker.js +36 -0
- package/lib/src/index.mjs +2 -2
- package/lib/src/{lib-BMP5cseh.js → lib-33AmrlUy.js} +14282 -14271
- package/lib/src/metadata-builder/builders/reorder-pages-builder.d.ts +13 -0
- package/lib/src/metadata-builder/builders/reorder-pages-builder.js +49 -0
- package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts +3 -0
- package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +3 -0
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.d.ts +3 -0
- package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.d.ts +3 -0
- package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +3 -0
- package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +3 -0
- package/lib/src/shared/side-bar/components/SideBarTabButton.mixin.d.ts +3 -0
- package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +3 -0
- package/lib/src/shared/template-settings/components/TemplatesSettings.mixin.d.ts +3 -0
- package/lib/src/tracker.d.ts +1 -1
- package/lib/src/tracker.js +1 -1
- package/lib/src/tracker.mjs +9 -7
- package/lib/src/{useEventTracker-Dmc2jFdN.js → useEventTracker-C5Ql5p7u.js} +56 -22
- package/package.json +1 -1
- package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.ts +9 -1
- package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.preview-gate.test.ts +38 -1
- package/src/brand-page-maker/components/preview-modal/PreviewModalWithState.test.ts +123 -0
- package/src/brand-page-maker/components/preview-modal/PreviewModalWithState.vue +25 -0
- package/src/brand-page-maker/composables/useEventTracker.ts +41 -0
- package/src/metadata-builder/builders/reorder-pages-builder.ts +80 -0
- 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
|
+
}
|
package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts
CHANGED
|
@@ -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;
|
package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts
CHANGED
|
@@ -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;
|
package/lib/src/tracker.d.ts
CHANGED
|
@@ -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';
|
package/lib/src/tracker.js
CHANGED
|
@@ -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';
|
package/lib/src/tracker.mjs
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import { A as N, E as O, G as _, P as A, a as
|
|
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
|
-
|
|
7
|
-
|
|
8
|
-
a as
|
|
9
|
-
S as
|
|
10
|
-
s as
|
|
11
|
-
C as
|
|
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
|
-
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
91
|
+
}, L = {
|
|
80
92
|
USE_TEXT: "use_text",
|
|
81
93
|
EXIT: "exit"
|
|
82
|
-
},
|
|
94
|
+
}, i = {
|
|
83
95
|
PREMIUM: "premium",
|
|
84
96
|
EXIT: "exit",
|
|
85
97
|
FREEMIUM: "freemium"
|
|
86
|
-
},
|
|
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 ? {} :
|
|
108
|
+
...e ? {} : T.value,
|
|
97
109
|
...A
|
|
98
110
|
}
|
|
99
111
|
});
|
|
100
112
|
});
|
|
101
|
-
},
|
|
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
|
-
|
|
131
|
+
T.value = { ...t, ...e };
|
|
120
132
|
},
|
|
121
133
|
setCustomGlobalEventProps: (e) => {
|
|
122
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
-
|
|
380
|
+
d as A,
|
|
349
381
|
E,
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
382
|
+
L as G,
|
|
383
|
+
r as P,
|
|
384
|
+
O as S,
|
|
353
385
|
S as T,
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
P as
|
|
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
|
@@ -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 {
|
|
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.
|
package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.preview-gate.test.ts
CHANGED
|
@@ -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 = '';
|