@designcrowd/library.brand-page 6.1.3 → 6.1.4-ast-prepurchase
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-Lk8J1vHg.js → CreatedOnBrandCrowd-de-de-BFDE6VfS.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-en-us-BbXj5fb1.js → CreatedOnBrandCrowd-en-us-CRhl6-Cd.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-es-es-CjnqvYCi.js → CreatedOnBrandCrowd-es-es-VaP_-7dv.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-fr-Dbjv4qpN.js → CreatedOnBrandCrowd-fr-ca-BySGqvWO.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-ca-Dbjv4qpN.js → CreatedOnBrandCrowd-fr-fr-BySGqvWO.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-pt-BZIOPEvL.js → CreatedOnBrandCrowd-pt-br-BHjXVcSk.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-br-BZIOPEvL.js → CreatedOnBrandCrowd-pt-pt-BHjXVcSk.js} +1 -1
- package/lib/src/{CreatedOnDcom-de-de-aN4JMRDI.js → CreatedOnDcom-de-de-DIFO5IZY.js} +1 -1
- package/lib/src/{CreatedOnDcom-en-us-f3VD6Pz4.js → CreatedOnDcom-en-us-CcpDa04T.js} +1 -1
- package/lib/src/{CreatedOnDcom-es-es-CQhNdtRP.js → CreatedOnDcom-es-es-DHwY0lWp.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-ca-CFsC_XoO.js → CreatedOnDcom-fr-ca-BP3P0hJL.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-fr-J4ZtCBO9.js → CreatedOnDcom-fr-fr-Bai1giy3.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-br-C1yFugh_.js → CreatedOnDcom-pt-br-GgKiDrbK.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-pt-ycOo5lDn.js → CreatedOnDcom-pt-pt-uuuxCYR3.js} +1 -1
- package/lib/src/PreviewModal-DY2aAN0a.js +19931 -0
- package/lib/src/brand-page/components/page-footer/PageFooter.mixin.d.ts +0 -1
- package/lib/src/brand-page/components/page-footer/PageFooter.mixin.js +1 -4
- package/lib/src/brand-page/models/brand-page-context.model.d.ts +2 -0
- package/lib/src/brand-page/models/brand-page-context.model.js +12 -0
- package/lib/src/brand-page-maker/components/action-bar/ActionBar.mixin.d.ts +2 -0
- package/lib/src/brand-page-maker/components/action-bar/ActionBar.mixin.js +14 -1
- package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +134 -0
- package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.js +50 -0
- package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +130 -0
- package/lib/src/brand-page-maker/components/navigation/Navigation.mixin.d.ts +1 -0
- package/lib/src/brand-page-maker/components/navigation/Navigation.mixin.js +3 -0
- package/lib/src/brand-page-maker/components/preview/Preview.mixin.d.ts +14 -0
- package/lib/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.d.ts +130 -0
- package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +130 -0
- package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.d.ts +130 -0
- package/lib/src/brand-page-maker/components/seo-settings/UseExistingDomainModal.mixin.d.ts +130 -0
- package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +130 -0
- package/lib/src/brand-page-maker/components/upgrade-to-premium-button/UpgradeToPremiumButton.mixin.d.ts +130 -0
- package/lib/src/brand-page-maker/composables/useEventTracker.d.ts +1 -0
- package/lib/src/brand-page-maker/composables/useEventTracker.js +1 -0
- package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.d.ts +132 -0
- package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.js +22 -6
- package/lib/src/bundled-translations-D42tE0D2.js +179 -0
- package/lib/src/bundled-translations.de-DE-D9aWGgFt.js +179 -0
- package/lib/src/bundled-translations.es-ES-lk4B0xQ7.js +179 -0
- package/lib/src/bundled-translations.fr-CA-DhOBNt6q.js +179 -0
- package/lib/src/bundled-translations.fr-FR-CnpafQeG.js +179 -0
- package/lib/src/bundled-translations.pt-BR-C4PnKrd9.js +179 -0
- package/lib/src/bundled-translations.pt-PT-CfKDVQC-.js +179 -0
- package/lib/src/bundles/bundled-translations.de-DE.json +5 -0
- package/lib/src/bundles/bundled-translations.es-ES.json +5 -0
- package/lib/src/bundles/bundled-translations.fr-CA.json +5 -0
- package/lib/src/bundles/bundled-translations.fr-FR.json +5 -0
- package/lib/src/bundles/bundled-translations.json +5 -0
- package/lib/src/bundles/bundled-translations.pt-BR.json +5 -0
- package/lib/src/bundles/bundled-translations.pt-PT.json +5 -0
- package/lib/src/clients/brand-page-client.d.ts +1 -0
- package/lib/src/composables/useTranslate.d.ts +2 -1
- package/lib/src/composables/useTranslate.js +2 -1
- package/lib/src/constants/brand-page-maker.d.ts +2 -0
- package/lib/src/constants/brand-page-maker.js +5 -0
- package/lib/src/constants/live-preview.constants.d.ts +15 -0
- package/lib/src/constants/live-preview.constants.js +15 -0
- package/lib/src/css/library.brand-page-brandCrowd.min.css +264 -121
- package/lib/src/css/library.brand-page-brandPage.min.css +268 -121
- package/lib/src/css/library.brand-page-designCom.min.css +264 -121
- package/lib/src/css/library.brand-page-preview.min.css +264 -121
- package/lib/src/index.d.ts +2 -1
- package/lib/src/index.mjs +102150 -225
- package/lib/src/lib.js +2 -1
- package/lib/src/preview-modal.d.ts +5 -0
- package/lib/src/preview-modal.js +12 -0
- package/lib/src/preview-modal.mjs +6 -0
- package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.d.ts +130 -0
- package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +130 -0
- package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +130 -0
- package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +130 -0
- package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +144 -0
- package/lib/src/shared/side-bar/components/SideBar.mixin.d.ts +130 -0
- package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +130 -0
- package/lib/src/tracker.mjs +1 -1
- package/lib/src/{useEventTracker-DmQ6AkNn.js → useEventTracker-Dmc2jFdN.js} +5 -4
- package/package.json +5 -1
- package/src/brand-page/components/button/Button.vue +11 -0
- package/src/brand-page/components/button/Button.vue.test.ts +90 -0
- package/src/brand-page/components/image-gallery/masonry/MasonryGallery.vue +1 -0
- package/src/brand-page/components/images-section/ImagesSection.vue +10 -0
- package/src/brand-page/components/media/Video.vue +60 -1
- package/src/brand-page/components/page-footer/PageFooter.mixin.ts +1 -4
- package/src/brand-page/components/page-footer/PageFooter.vue +0 -1
- package/src/brand-page/components/payment/Payment.vue +3 -0
- package/src/brand-page/components/payment/request-payment/RequestPayment.vue +1 -0
- package/src/brand-page/components/payment/support-me/SupportMe.vue +3 -0
- package/src/brand-page/components/shop/CartModal.vue +9 -0
- package/src/brand-page/components/shop/Shop.vue +19 -0
- package/src/brand-page/components/shop/Shop.vue.test.ts +182 -2
- package/src/brand-page/components/social-links/SocialLinks.vue +1 -9
- package/src/brand-page/components/social-links/SocialLinks.vue.test.ts +28 -8
- package/src/brand-page/components/social-links/SocialLinksItems.vue +6 -2
- package/src/brand-page/components/testimonial-section/TestimonialSection.vue +2 -2
- package/src/brand-page/components/video/Video.vue +3 -0
- package/src/brand-page/models/brand-page-context.model.ts +23 -0
- package/src/brand-page-maker/components/action-bar/ActionBar.mixin.ts +15 -0
- package/src/brand-page-maker/components/action-bar/ActionBarNavigation.test.ts +95 -0
- package/src/brand-page-maker/components/action-bar/ActionBarNavigation.vue +19 -4
- package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.ts +57 -0
- package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.preview-gate.test.ts +113 -0
- package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.vue +26 -1
- package/src/brand-page-maker/components/navigation/Navigation.mixin.ts +3 -0
- package/src/brand-page-maker/components/navigation/Navigation.vue +1 -0
- package/src/brand-page-maker/components/preview-modal/PreviewModal.test.ts +162 -0
- package/src/brand-page-maker/components/preview-modal/PreviewModal.vue +347 -0
- package/src/brand-page-maker/components/preview-modal/PreviewModalWithState.test.ts +226 -0
- package/src/brand-page-maker/components/preview-modal/PreviewModalWithState.vue +149 -0
- package/src/brand-page-maker/components/preview-modal/i18n/preview-modal.de-DE.json +6 -0
- package/src/brand-page-maker/components/preview-modal/i18n/preview-modal.es-ES.json +6 -0
- package/src/brand-page-maker/components/preview-modal/i18n/preview-modal.fr-CA.json +6 -0
- package/src/brand-page-maker/components/preview-modal/i18n/preview-modal.fr-FR.json +6 -0
- package/src/brand-page-maker/components/preview-modal/i18n/preview-modal.json +6 -0
- package/src/brand-page-maker/components/preview-modal/i18n/preview-modal.pt-BR.json +6 -0
- package/src/brand-page-maker/components/preview-modal/i18n/preview-modal.pt-PT.json +6 -0
- package/src/brand-page-maker/components/rich-text-editor/RichTextEditor.vue +29 -17
- package/src/brand-page-maker/composables/useEventTracker.ts +1 -0
- package/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.save.test.ts +106 -0
- package/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.ts +40 -8
- package/src/bundles/bundled-translations.de-DE.json +5 -0
- package/src/bundles/bundled-translations.es-ES.json +5 -0
- package/src/bundles/bundled-translations.fr-CA.json +5 -0
- package/src/bundles/bundled-translations.fr-FR.json +5 -0
- package/src/bundles/bundled-translations.json +5 -0
- package/src/bundles/bundled-translations.pt-BR.json +5 -0
- package/src/bundles/bundled-translations.pt-PT.json +5 -0
- package/src/clients/brand-page-client.ts +2 -0
- package/src/composables/useTranslate.ts +2 -0
- package/src/constants/brand-page-maker.ts +5 -0
- package/src/constants/live-preview.constants.ts +15 -0
- package/src/lib.ts +5 -1
- package/src/preview-modal.ts +14 -0
- package/src/shared/common/i18n/common.de-DE.json +1 -0
- package/src/shared/common/i18n/common.es-ES.json +1 -0
- package/src/shared/common/i18n/common.fr-CA.json +1 -0
- package/src/shared/common/i18n/common.fr-FR.json +1 -0
- package/src/shared/common/i18n/common.json +1 -0
- package/src/shared/common/i18n/common.pt-BR.json +1 -0
- package/src/shared/common/i18n/common.pt-PT.json +1 -0
- package/src/shared/ecommerce-settings/store/cart-store.test.ts +38 -0
- package/lib/src/bundled-translations-2HkRBbBD.js +0 -177
- package/lib/src/bundled-translations.de-DE-CL9ZEhU2.js +0 -177
- package/lib/src/bundled-translations.es-ES-uj7Sliu0.js +0 -177
- package/lib/src/bundled-translations.fr-CA-BMnBtr_w.js +0 -177
- package/lib/src/bundled-translations.fr-FR-9PEZedzq.js +0 -177
- package/lib/src/bundled-translations.pt-BR-B3oNDkoe.js +0 -177
- package/lib/src/bundled-translations.pt-PT-DM7Vsf-h.js +0 -177
- package/lib/src/lib-CVwyHyBz.js +0 -121538
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
/>
|
|
18
18
|
<SocialLinksItems
|
|
19
19
|
:id="id"
|
|
20
|
-
:is-preview="isPreview"
|
|
21
20
|
:container-style="iconContainerStyle"
|
|
22
21
|
:icon-style="iconStyle"
|
|
23
22
|
:links="links"
|
|
@@ -33,10 +32,7 @@ import TextWrapper from '../text-wrapper/TextWrapper.vue';
|
|
|
33
32
|
import type { SocialLinksViewModel } from 'src/brand-page/view-models';
|
|
34
33
|
import { SOCIAL_LINKS_ICON_DISPLAY_STYLES } from '@brand-page/models';
|
|
35
34
|
import type { BrandPageContext, LinksItem } from '@brand-page/models';
|
|
36
|
-
import {
|
|
37
|
-
contentPaddingStyle as toContentPaddingStyle,
|
|
38
|
-
isPreviewMode,
|
|
39
|
-
} from '@brand-page/utils';
|
|
35
|
+
import { contentPaddingStyle as toContentPaddingStyle } from '@brand-page/utils';
|
|
40
36
|
import { computed } from 'vue';
|
|
41
37
|
|
|
42
38
|
const props = withDefaults(
|
|
@@ -89,10 +85,6 @@ const id = computed((): string => {
|
|
|
89
85
|
return props.viewModel.id;
|
|
90
86
|
});
|
|
91
87
|
|
|
92
|
-
const isPreview = computed((): boolean => {
|
|
93
|
-
return isPreviewMode(props.context);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
88
|
const links = computed((): LinksItem[] => {
|
|
97
89
|
return props.viewModel.links;
|
|
98
90
|
});
|
|
@@ -115,7 +115,6 @@ describe('Social Links', () => {
|
|
|
115
115
|
id: faker.datatype.uuid(),
|
|
116
116
|
containerStyle: {},
|
|
117
117
|
iconStyle: {},
|
|
118
|
-
isPreview: false,
|
|
119
118
|
links: [
|
|
120
119
|
{
|
|
121
120
|
id: 'social-link-facebook',
|
|
@@ -137,16 +136,13 @@ describe('Social Links', () => {
|
|
|
137
136
|
expect(anchor.attributes()['href']).toBe(undefined);
|
|
138
137
|
});
|
|
139
138
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const wrapper = shallowMount(SocialLinksItems, {
|
|
139
|
+
const mountWithContext = (context: BrandPageContext) =>
|
|
140
|
+
shallowMount(SocialLinksItems, {
|
|
144
141
|
propsData: {
|
|
145
142
|
context,
|
|
146
143
|
id: faker.datatype.uuid(),
|
|
147
144
|
containerStyle: {},
|
|
148
145
|
iconStyle: {},
|
|
149
|
-
isPreview: false,
|
|
150
146
|
links: [
|
|
151
147
|
{
|
|
152
148
|
id: 'social-link-facebook',
|
|
@@ -163,8 +159,32 @@ describe('Social Links', () => {
|
|
|
163
159
|
},
|
|
164
160
|
});
|
|
165
161
|
|
|
166
|
-
|
|
162
|
+
const hrefOf = (wrapper: ReturnType<typeof shallowMount>) =>
|
|
163
|
+
wrapper.find('.c-social-links__links-container li a').attributes()['href'];
|
|
164
|
+
|
|
165
|
+
// Published site: no preview flags — the real href renders. (unchanged)
|
|
166
|
+
test('href attribute should match url', () => {
|
|
167
|
+
expect(hrefOf(mountWithContext(createTestBrandPageContext()))).toBe(
|
|
168
|
+
'https://www.fb.com',
|
|
169
|
+
);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// Editor/maker canvas: href stripped so a designer can't click out. (unchanged)
|
|
173
|
+
test('editor preview (context.isPreview) strips the href', () => {
|
|
174
|
+
const context = { ...createTestBrandPageContext(), isPreview: true };
|
|
175
|
+
|
|
176
|
+
expect(hrefOf(mountWithContext(context))).toBe(undefined);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Customer live preview: href now RENDERS (BP-5959) so internal links resolve
|
|
180
|
+
// in-frame; external ones are blocked by the web-renderer preview gate instead.
|
|
181
|
+
test('live preview (context.isLivePreview) renders the href', () => {
|
|
182
|
+
const context = {
|
|
183
|
+
...createTestBrandPageContext(),
|
|
184
|
+
isPreview: false,
|
|
185
|
+
isLivePreview: true,
|
|
186
|
+
};
|
|
167
187
|
|
|
168
|
-
expect(
|
|
188
|
+
expect(hrefOf(mountWithContext(context))).toBe('https://www.fb.com');
|
|
169
189
|
});
|
|
170
190
|
});
|
|
@@ -45,7 +45,6 @@ interface Props {
|
|
|
45
45
|
id: string;
|
|
46
46
|
containerStyle: BrandPageCssStyle;
|
|
47
47
|
iconStyle: BrandPageCssStyle;
|
|
48
|
-
isPreview: boolean;
|
|
49
48
|
links: LinksItem[];
|
|
50
49
|
context: BrandPageContext;
|
|
51
50
|
contentIndex: number | undefined;
|
|
@@ -62,7 +61,12 @@ const isUrl = computed(() => {
|
|
|
62
61
|
});
|
|
63
62
|
|
|
64
63
|
const getValidInput = (value: string): string | undefined => {
|
|
65
|
-
|
|
64
|
+
// Strip the href in the EDITOR preview only (`context.isPreview`), so a
|
|
65
|
+
// designer can't click out of the canvas. In the customer LIVE preview
|
|
66
|
+
// (`context.isLivePreview`) the href stays so internal links resolve in-frame
|
|
67
|
+
// (see web-renderer resolveInternalPreviewPaths); external ones get blocked by
|
|
68
|
+
// the preview gate anyway. (BP-5959)
|
|
69
|
+
if (props.context.isPreview || !value) return undefined;
|
|
66
70
|
|
|
67
71
|
if (isEmail(value)) {
|
|
68
72
|
return `mailto:${value}`;
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
:hide-bullets-on-mobile="false"
|
|
34
34
|
>
|
|
35
35
|
<template #arrow-left>
|
|
36
|
-
<div id="button-prev">
|
|
36
|
+
<div id="button-prev" data-preview-interactive>
|
|
37
37
|
<Icon
|
|
38
38
|
classes="sm:tw-hidden tw--mb-1 tw-mr-2 tw-cursor-pointer"
|
|
39
39
|
name="chevron-left"
|
|
@@ -120,7 +120,7 @@
|
|
|
120
120
|
</div>
|
|
121
121
|
</template>
|
|
122
122
|
<template #arrow-right>
|
|
123
|
-
<div id="button-next">
|
|
123
|
+
<div id="button-next" data-preview-interactive>
|
|
124
124
|
<Icon
|
|
125
125
|
classes="sm:tw-hidden tw--mb-1 tw-ml-2 tw-cursor-pointer"
|
|
126
126
|
name="chevron-right"
|
|
@@ -8,7 +8,10 @@
|
|
|
8
8
|
:class="{ 'tw-pb-4': isCollapsed, 'tw-pb-0.5': !isCollapsed }"
|
|
9
9
|
:style="containerStyle"
|
|
10
10
|
>
|
|
11
|
+
<!-- Video rolls its own header, so the `collapsible` allow-list entry can't
|
|
12
|
+
reach it. Expanding is viewing, not acting. -->
|
|
11
13
|
<div
|
|
14
|
+
data-preview-interactive
|
|
12
15
|
class="tw-relative tw-text-center tw-w-full hover:tw-cursor-pointer"
|
|
13
16
|
:class="{ 'tw-mb-4': !isCollapsed }"
|
|
14
17
|
@click="onHeaderToggleClick"
|
|
@@ -49,11 +49,18 @@ export interface AbTestResult {
|
|
|
49
49
|
const AB_TEST_KEYS = {
|
|
50
50
|
BP_3926_FREEMIUM_WATERMARK: 'bc-bp-3926-freemium-cta-in-website-editor',
|
|
51
51
|
BP_5245_AI_WEBSITE_ASSISTANT: 'bc-bp-5245-ai-website-assistant-postpurchase',
|
|
52
|
+
// Two separate live-preview experiments — bc-net sends only the one for the
|
|
53
|
+
// current purchase state, and a user's value on each side is independent
|
|
54
|
+
// (BP-5873). Keys must match `CampaignNames.LivePreview*Test` in bc-net.
|
|
55
|
+
BP_5873_LIVE_PREVIEW_PREPURCHASE: 'bc-bp-5873-live-preview-prepurchase',
|
|
56
|
+
BP_5873_LIVE_PREVIEW_POSTPURCHASE: 'bc-bp-5873-live-preview-postpurchase',
|
|
52
57
|
};
|
|
53
58
|
|
|
54
59
|
export interface AbTest {
|
|
55
60
|
bp_3926_freemium_watermark?: AbTestResult;
|
|
56
61
|
bp_5245_ai_website_assistant?: AbTestResult;
|
|
62
|
+
bp_5873_live_preview_prepurchase?: AbTestResult;
|
|
63
|
+
bp_5873_live_preview_postpurchase?: AbTestResult;
|
|
57
64
|
}
|
|
58
65
|
|
|
59
66
|
export const MEDIA_SIZES = {
|
|
@@ -143,5 +150,21 @@ export const getAbTestResults = (abtestKeyValues: AbTest): AbTest => {
|
|
|
143
150
|
);
|
|
144
151
|
}
|
|
145
152
|
|
|
153
|
+
// AB Test for BP-5873 - Live preview (pre- and post-purchase run separately)
|
|
154
|
+
|
|
155
|
+
if (abtestKeyValues[AB_TEST_KEYS.BP_5873_LIVE_PREVIEW_PREPURCHASE]) {
|
|
156
|
+
abTests.bp_5873_live_preview_prepurchase = getValueType(
|
|
157
|
+
AB_TEST_KEYS.BP_5873_LIVE_PREVIEW_PREPURCHASE,
|
|
158
|
+
abtestKeyValues[AB_TEST_KEYS.BP_5873_LIVE_PREVIEW_PREPURCHASE],
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (abtestKeyValues[AB_TEST_KEYS.BP_5873_LIVE_PREVIEW_POSTPURCHASE]) {
|
|
163
|
+
abTests.bp_5873_live_preview_postpurchase = getValueType(
|
|
164
|
+
AB_TEST_KEYS.BP_5873_LIVE_PREVIEW_POSTPURCHASE,
|
|
165
|
+
abtestKeyValues[AB_TEST_KEYS.BP_5873_LIVE_PREVIEW_POSTPURCHASE],
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
146
169
|
return abTests;
|
|
147
170
|
};
|
|
@@ -2,6 +2,7 @@ import { EVENTS } from '../../../constants/brand-page-maker';
|
|
|
2
2
|
import {
|
|
3
3
|
useBrandPageMakerUserStore,
|
|
4
4
|
useBrandPageMakerStore,
|
|
5
|
+
useBrandPageContainerStore,
|
|
5
6
|
} from '@brand-page-maker/stores';
|
|
6
7
|
import { computed, defineComponent } from 'vue';
|
|
7
8
|
import { UPGRADE_CTA_LOCATIONS } from './../../composables/useEventTracker';
|
|
@@ -12,9 +13,20 @@ export default defineComponent({
|
|
|
12
13
|
setup() {
|
|
13
14
|
const userStore = useBrandPageMakerUserStore();
|
|
14
15
|
const brandPageMakerStore = useBrandPageMakerStore();
|
|
16
|
+
const containerStore = useBrandPageContainerStore();
|
|
15
17
|
|
|
16
18
|
return {
|
|
17
19
|
isAdmin: computed(() => userStore.isAdmin),
|
|
20
|
+
// BP-5873: the Preview button is behind an AB test, and pre/post purchase are
|
|
21
|
+
// two separate experiments. Pick the one for the current purchase state — a
|
|
22
|
+
// user's value on the other side is independent and must not leak across.
|
|
23
|
+
isLivePreviewEnabled: computed(() => {
|
|
24
|
+
const experiment = containerStore.isPrePurchase
|
|
25
|
+
? containerStore.abTests.bp_5873_live_preview_prepurchase
|
|
26
|
+
: containerStore.abTests.bp_5873_live_preview_postpurchase;
|
|
27
|
+
|
|
28
|
+
return !!experiment?.isVariation;
|
|
29
|
+
}),
|
|
18
30
|
isSaving: computed(() => brandPageMakerStore.isSaving),
|
|
19
31
|
isPublished: computed(() => brandPageMakerStore.isPublished),
|
|
20
32
|
isPublishButtonEnabled: computed(
|
|
@@ -32,6 +44,9 @@ export default defineComponent({
|
|
|
32
44
|
saveBrandPage() {
|
|
33
45
|
this.$emit(EVENTS.Save);
|
|
34
46
|
},
|
|
47
|
+
previewBrandPage() {
|
|
48
|
+
this.$emit(EVENTS.Preview);
|
|
49
|
+
},
|
|
35
50
|
saveAndPublishBrandPage(isActionBar: boolean) {
|
|
36
51
|
if (!this.isPublishButtonEnabled) {
|
|
37
52
|
return;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { describe, test, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { createPinia, setActivePinia } from 'pinia';
|
|
3
|
+
import { shallowMount } from '@vue/test-utils';
|
|
4
|
+
import ActionBarNavigation from './ActionBarNavigation.vue';
|
|
5
|
+
import { useBrandPageContainerStore } from '@brand-page-maker/stores';
|
|
6
|
+
import { getAbTestResults } from '@brand-page/models/brand-page-context.model';
|
|
7
|
+
|
|
8
|
+
// Must match `CampaignNames.LivePreview*` in bc-net. The two experiments share
|
|
9
|
+
// one set of variation values — they're told apart by campaign key, not value.
|
|
10
|
+
const PREPURCHASE = 'bc-bp-5873-live-preview-prepurchase';
|
|
11
|
+
const POSTPURCHASE = 'bc-bp-5873-live-preview-postpurchase';
|
|
12
|
+
const VARIATION_1 = 'bp-5873-variation-1';
|
|
13
|
+
const CONTROL = 'bp-5873-control';
|
|
14
|
+
|
|
15
|
+
const mountBar = () => shallowMount(ActionBarNavigation);
|
|
16
|
+
|
|
17
|
+
const hasPreviewButton = (wrapper: ReturnType<typeof mountBar>) =>
|
|
18
|
+
wrapper.find('[data-test-preview-button]').exists();
|
|
19
|
+
|
|
20
|
+
// The AB value arrives as the raw bc-net campaign string, so go through the real
|
|
21
|
+
// parser rather than hand-building an AbTestResult — that's the contract under test.
|
|
22
|
+
const setAbTest = (
|
|
23
|
+
store: ReturnType<typeof useBrandPageContainerStore>,
|
|
24
|
+
key: string,
|
|
25
|
+
value: string,
|
|
26
|
+
) => {
|
|
27
|
+
store.abTests = getAbTestResults({ [key]: value } as never);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
describe('ActionBarNavigation — BP-5873 preview AB test', () => {
|
|
31
|
+
let containerStore: ReturnType<typeof useBrandPageContainerStore>;
|
|
32
|
+
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
setActivePinia(createPinia());
|
|
35
|
+
containerStore = useBrandPageContainerStore();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test('hides Preview when no AB value has been sent', () => {
|
|
39
|
+
expect(hasPreviewButton(mountBar())).toBe(false);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('post-purchase: shows Preview on variation-1, hides it on control', () => {
|
|
43
|
+
containerStore.isPrePurchase = false;
|
|
44
|
+
|
|
45
|
+
setAbTest(containerStore, POSTPURCHASE, VARIATION_1);
|
|
46
|
+
expect(hasPreviewButton(mountBar())).toBe(true);
|
|
47
|
+
|
|
48
|
+
setAbTest(containerStore, POSTPURCHASE, CONTROL);
|
|
49
|
+
expect(hasPreviewButton(mountBar())).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('pre-purchase: shows Preview on variation-1, hides it on control', () => {
|
|
53
|
+
containerStore.isPrePurchase = true;
|
|
54
|
+
|
|
55
|
+
setAbTest(containerStore, PREPURCHASE, VARIATION_1);
|
|
56
|
+
expect(hasPreviewButton(mountBar())).toBe(true);
|
|
57
|
+
|
|
58
|
+
setAbTest(containerStore, PREPURCHASE, CONTROL);
|
|
59
|
+
expect(hasPreviewButton(mountBar())).toBe(false);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Two separate experiments, so a value on one side must never satisfy the other —
|
|
63
|
+
// otherwise a post-purchase variation would leak the button into pre-purchase.
|
|
64
|
+
test('the two experiments never read each other', () => {
|
|
65
|
+
containerStore.isPrePurchase = true;
|
|
66
|
+
setAbTest(containerStore, POSTPURCHASE, VARIATION_1);
|
|
67
|
+
expect(hasPreviewButton(mountBar())).toBe(false);
|
|
68
|
+
|
|
69
|
+
containerStore.isPrePurchase = false;
|
|
70
|
+
setAbTest(containerStore, PREPURCHASE, VARIATION_1);
|
|
71
|
+
expect(hasPreviewButton(mountBar())).toBe(false);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// The mobile nav row is equal columns: 3 with Save, 2 once the site is published and
|
|
75
|
+
// Save drops out. Preview must be a real column like the rest — while it was content
|
|
76
|
+
// width, Publish ate the whole remaining row on a published site.
|
|
77
|
+
test('Preview shares the mobile row equally with the other buttons', () => {
|
|
78
|
+
containerStore.isPrePurchase = false;
|
|
79
|
+
setAbTest(containerStore, POSTPURCHASE, VARIATION_1);
|
|
80
|
+
containerStore.brandPageStatus = 'Published';
|
|
81
|
+
|
|
82
|
+
const wrapper = mountBar();
|
|
83
|
+
const buttons = wrapper.findAllComponents({ name: 'Button' });
|
|
84
|
+
|
|
85
|
+
// Save is gone once published, so this is the two-column case.
|
|
86
|
+
expect(buttons).toHaveLength(2);
|
|
87
|
+
expect(hasPreviewButton(wrapper)).toBe(true);
|
|
88
|
+
|
|
89
|
+
// Every visible column carries the same width contract, so they halve the row.
|
|
90
|
+
buttons.forEach((button) => {
|
|
91
|
+
expect(button.classes()).toContain('tw-w-full');
|
|
92
|
+
expect(button.classes()).toContain('lg:tw-w-auto');
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
});
|
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
3
|
data-component="action-bar-navigation"
|
|
4
|
-
class="tw-flex tw-items-center tw-border-t tw-border-solid tw-border-grayscale-600 tw-h-12 tw-px-2 lg:tw-px-0 lg:tw-h-auto lg:tw-border-none tw-gap-5 tw-w-full lg:tw-justify-end tw-box-border"
|
|
4
|
+
class="tw-flex tw-items-center tw-border-t tw-border-solid tw-border-grayscale-600 tw-h-12 tw-px-2 lg:tw-px-0 lg:tw-h-auto lg:tw-border-none tw-gap-3 lg:tw-gap-5 tw-w-full lg:tw-justify-end tw-box-border"
|
|
5
5
|
>
|
|
6
|
+
<Button
|
|
7
|
+
v-if="!isAdmin && isLivePreviewEnabled"
|
|
8
|
+
:label="constantsTr('previewDisplayName')"
|
|
9
|
+
variant="no-border"
|
|
10
|
+
:white="true"
|
|
11
|
+
size="small-medium"
|
|
12
|
+
icon-left="preview"
|
|
13
|
+
icon-left-size="sm"
|
|
14
|
+
class="tw-w-full lg:tw-w-auto tw-inline-flex"
|
|
15
|
+
classes="tw-w-full lg:tw-w-auto tw-whitespace-nowrap !tw-px-0 lg:!tw-px-4"
|
|
16
|
+
data-test-preview-button
|
|
17
|
+
@on-click.stop="previewBrandPage"
|
|
18
|
+
/>
|
|
6
19
|
<Button
|
|
7
20
|
v-if="!isPublished"
|
|
8
21
|
:label="
|
|
@@ -13,7 +26,7 @@
|
|
|
13
26
|
:white="true"
|
|
14
27
|
size="small-medium"
|
|
15
28
|
class="tw-w-full lg:tw-w-auto"
|
|
16
|
-
classes="tw-px-6 tw-w-full lg:tw-w-auto"
|
|
29
|
+
classes="!tw-px-3 lg:!tw-px-6 tw-w-full lg:tw-w-auto tw-whitespace-nowrap"
|
|
17
30
|
@on-click.stop="saveBrandPage"
|
|
18
31
|
/>
|
|
19
32
|
<Button
|
|
@@ -33,7 +46,7 @@
|
|
|
33
46
|
:disabled="!isPublishButtonEnabled"
|
|
34
47
|
size="small-medium"
|
|
35
48
|
class="tw-w-full lg:tw-w-auto"
|
|
36
|
-
classes="tw-px-6 tw-w-full lg:tw-w-auto"
|
|
49
|
+
classes="!tw-px-3 lg:!tw-px-6 tw-w-full lg:tw-w-auto tw-whitespace-nowrap"
|
|
37
50
|
@on-click.stop="saveAndPublishBrandPage(true)"
|
|
38
51
|
/>
|
|
39
52
|
</div>
|
|
@@ -41,7 +54,8 @@
|
|
|
41
54
|
<script>
|
|
42
55
|
import { Button } from '@designcrowd/fe-shared-lib';
|
|
43
56
|
import ActionBarMixin from './ActionBar.mixin.ts';
|
|
44
|
-
|
|
57
|
+
// Preview reuses the translated sidebar tab label — no new Smartling string.
|
|
58
|
+
import { actionBarTr, constantsTr } from '@src/composables/useTranslate';
|
|
45
59
|
|
|
46
60
|
export default {
|
|
47
61
|
components: {
|
|
@@ -52,6 +66,7 @@ export default {
|
|
|
52
66
|
return {
|
|
53
67
|
...ActionBarMixin.setup(props, context),
|
|
54
68
|
actionBarTr,
|
|
69
|
+
constantsTr,
|
|
55
70
|
};
|
|
56
71
|
},
|
|
57
72
|
};
|
|
@@ -177,6 +177,7 @@ export default defineComponent({
|
|
|
177
177
|
mounted: false,
|
|
178
178
|
debounceOnResize: undefined as DebounceHandle | undefined,
|
|
179
179
|
showSaveSuccessMessage: false,
|
|
180
|
+
isPreviewModalVisible: false,
|
|
180
181
|
};
|
|
181
182
|
},
|
|
182
183
|
computed: {
|
|
@@ -303,6 +304,24 @@ export default defineComponent({
|
|
|
303
304
|
|
|
304
305
|
this.$emit(EVENTS.Initialised);
|
|
305
306
|
},
|
|
307
|
+
watch: {
|
|
308
|
+
// Pre-purchase only: the host's save has produced the signed link, so the frame
|
|
309
|
+
// can open with it already in hand — no waiting inside the modal. No link means
|
|
310
|
+
// the save failed or the customer was sent to register, and the editor has
|
|
311
|
+
// already said so, so nothing opens.
|
|
312
|
+
'containerStore.livePreviewUrl'(livePreviewUrl?: string) {
|
|
313
|
+
if (
|
|
314
|
+
!livePreviewUrl ||
|
|
315
|
+
!this.containerStore.isPrePurchase ||
|
|
316
|
+
this.isPreviewModalVisible
|
|
317
|
+
) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
this.isPreviewModalVisible = true;
|
|
322
|
+
this.$emit(EVENTS.Preview);
|
|
323
|
+
},
|
|
324
|
+
},
|
|
306
325
|
mounted() {
|
|
307
326
|
if (window) {
|
|
308
327
|
window.removeEventListener('resize', this.onResizeWithDebounce);
|
|
@@ -434,9 +453,47 @@ export default defineComponent({
|
|
|
434
453
|
: UPGRADE_CTA_LOCATIONS.EDITOR_PUBLISH_TOP,
|
|
435
454
|
});
|
|
436
455
|
},
|
|
456
|
+
onPreviewPublish() {
|
|
457
|
+
// Same host publish flow as the editor button, tracked as its own location.
|
|
458
|
+
this.$emit(EVENTS.Publish, {
|
|
459
|
+
eventButtonLocation: UPGRADE_CTA_LOCATIONS.EDITOR_PREVIEW_PUBLISH,
|
|
460
|
+
});
|
|
461
|
+
},
|
|
437
462
|
onBackBrandPage() {
|
|
438
463
|
this.$emit(EVENTS.Back);
|
|
439
464
|
},
|
|
465
|
+
onPreview() {
|
|
466
|
+
// The preview frames a SAVED, owned draft. A signed-out customer can't have
|
|
467
|
+
// one, and the save needs an owner — so sign-in comes first, via the host's
|
|
468
|
+
// Save Progress flow.
|
|
469
|
+
if (!this.isUserAuthenticated) {
|
|
470
|
+
this.$emit(EVENTS.LivePreviewClicked);
|
|
471
|
+
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// Pre-purchase drafts are saved by the HOST (`prepurchase/upsert`), never by
|
|
476
|
+
// the maker store. Ask for that save and stay closed until it hands back a
|
|
477
|
+
// preview URL (see the `livePreviewUrl` watcher). Opening first would mean
|
|
478
|
+
// waiting inside the modal on a save it cannot see the outcome of, which is
|
|
479
|
+
// how the loader used to hang forever when a save failed or asked the customer
|
|
480
|
+
// to register (BP-5870). A failed save now surfaces the editor's own error and
|
|
481
|
+
// nothing opens.
|
|
482
|
+
if (this.containerStore.isPrePurchase) {
|
|
483
|
+
this.containerStore.livePreviewUrl = undefined;
|
|
484
|
+
this.$emit(EVENTS.LivePreviewClicked);
|
|
485
|
+
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// Post-purchase saves through the maker store, which reports its own result —
|
|
490
|
+
// so the modal can open first and show its loader while that runs.
|
|
491
|
+
this.isPreviewModalVisible = true;
|
|
492
|
+
this.$emit(EVENTS.Preview);
|
|
493
|
+
},
|
|
494
|
+
onClosePreview() {
|
|
495
|
+
this.isPreviewModalVisible = false;
|
|
496
|
+
},
|
|
440
497
|
onChangeTemplateConfirmModalCancel() {
|
|
441
498
|
this.brandPageMakerStore.onChangeTemplateConfirmModalCancel();
|
|
442
499
|
},
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { describe, test, expect, vi } from 'vitest';
|
|
2
|
+
import BrandPageMakerMixin from './BrandPageMaker.mixin';
|
|
3
|
+
import { EVENTS } from '../../../constants/brand-page-maker';
|
|
4
|
+
|
|
5
|
+
// The preview frames a SAVED, owned draft, so who saves it decides when the modal
|
|
6
|
+
// may open. Signed out: nobody owns a draft, so hand off to the host's Save Progress
|
|
7
|
+
// flow. Post-purchase: the modal saves through the maker store itself, so it can open
|
|
8
|
+
// first and show its loader.
|
|
9
|
+
//
|
|
10
|
+
// Pre-purchase: the HOST owns the save, so nothing opens until that save hands back a
|
|
11
|
+
// signed URL — the `livePreviewUrl` watcher is what opens the modal.
|
|
12
|
+
//
|
|
13
|
+
// Mounting the whole editor to reach these branches would dwarf what is tested, so the
|
|
14
|
+
// mixin's methods and watcher are driven directly.
|
|
15
|
+
const onPreview = (BrandPageMakerMixin as any).methods.onPreview;
|
|
16
|
+
const onLivePreviewUrlChanged = (BrandPageMakerMixin as any).watch[
|
|
17
|
+
'containerStore.livePreviewUrl'
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const createContext = (
|
|
21
|
+
overrides: {
|
|
22
|
+
isUserAuthenticated?: boolean;
|
|
23
|
+
isPreviewModalVisible?: boolean;
|
|
24
|
+
containerStore?: { isPrePurchase: boolean; livePreviewUrl?: string };
|
|
25
|
+
} = {},
|
|
26
|
+
) => ({
|
|
27
|
+
isUserAuthenticated: true,
|
|
28
|
+
isPreviewModalVisible: false,
|
|
29
|
+
containerStore: { isPrePurchase: false, livePreviewUrl: undefined },
|
|
30
|
+
$emit: vi.fn(),
|
|
31
|
+
...overrides,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe('BrandPageMaker.onPreview', () => {
|
|
35
|
+
test('a signed-out customer is sent through Save Progress instead', () => {
|
|
36
|
+
const context = createContext({ isUserAuthenticated: false });
|
|
37
|
+
|
|
38
|
+
onPreview.call(context);
|
|
39
|
+
|
|
40
|
+
expect(context.$emit).toHaveBeenCalledWith(EVENTS.LivePreviewClicked);
|
|
41
|
+
expect(context.isPreviewModalVisible).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('post-purchase opens the preview, which saves through the maker store', () => {
|
|
45
|
+
const context = createContext();
|
|
46
|
+
|
|
47
|
+
onPreview.call(context);
|
|
48
|
+
|
|
49
|
+
expect(context.isPreviewModalVisible).toBe(true);
|
|
50
|
+
expect(context.$emit).toHaveBeenCalledWith(EVENTS.Preview);
|
|
51
|
+
expect(context.$emit).not.toHaveBeenCalledWith(EVENTS.LivePreviewClicked);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Opening here would mean waiting inside the modal on a host save it can't see the
|
|
55
|
+
// outcome of — which is how the loader used to hang forever (BP-5870).
|
|
56
|
+
test('pre-purchase asks the host to save and stays closed', () => {
|
|
57
|
+
const context = createContext({
|
|
58
|
+
containerStore: { isPrePurchase: true, livePreviewUrl: 'https://stale' },
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
onPreview.call(context);
|
|
62
|
+
|
|
63
|
+
expect(context.isPreviewModalVisible).toBe(false);
|
|
64
|
+
expect(context.$emit).toHaveBeenCalledWith(EVENTS.LivePreviewClicked);
|
|
65
|
+
expect(context.$emit).not.toHaveBeenCalledWith(EVENTS.Preview);
|
|
66
|
+
// A stale URL from an earlier preview must not open the frame on the next click.
|
|
67
|
+
expect(context.containerStore.livePreviewUrl).toBeUndefined();
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
describe('BrandPageMaker livePreviewUrl watcher', () => {
|
|
72
|
+
test('opens the preview once the host save hands back a URL', () => {
|
|
73
|
+
const context = createContext({
|
|
74
|
+
containerStore: { isPrePurchase: true, livePreviewUrl: undefined },
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
onLivePreviewUrlChanged.call(
|
|
78
|
+
context,
|
|
79
|
+
'https://brand.site/_p/request?token=x',
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
expect(context.isPreviewModalVisible).toBe(true);
|
|
83
|
+
expect(context.$emit).toHaveBeenCalledWith(EVENTS.Preview);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// A failed save or a customer sent to register never sets a URL, and the editor has
|
|
87
|
+
// already surfaced that — so nothing should open.
|
|
88
|
+
test('stays closed when the save produced no URL', () => {
|
|
89
|
+
const context = createContext({
|
|
90
|
+
containerStore: { isPrePurchase: true, livePreviewUrl: undefined },
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
onLivePreviewUrlChanged.call(context, undefined);
|
|
94
|
+
|
|
95
|
+
expect(context.isPreviewModalVisible).toBe(false);
|
|
96
|
+
expect(context.$emit).not.toHaveBeenCalledWith(EVENTS.Preview);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Post-purchase opens the modal itself, so the watcher must not double-open it.
|
|
100
|
+
test('ignores post-purchase, which opens the modal itself', () => {
|
|
101
|
+
const context = createContext({
|
|
102
|
+
containerStore: { isPrePurchase: false, livePreviewUrl: undefined },
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
onLivePreviewUrlChanged.call(
|
|
106
|
+
context,
|
|
107
|
+
'https://brand.site/_p/request?token=x',
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
expect(context.isPreviewModalVisible).toBe(false);
|
|
111
|
+
expect(context.$emit).not.toHaveBeenCalledWith(EVENTS.Preview);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
@back="onBackBrandPage"
|
|
16
16
|
@save="saveBrandPage('Navigation')"
|
|
17
17
|
@publish="saveAndPublishBrandPage(false)"
|
|
18
|
+
@preview="onPreview"
|
|
18
19
|
@create-team-cards="onCreateTeamCards"
|
|
19
20
|
/>
|
|
20
21
|
<slot name="editButtonHeader" />
|
|
@@ -148,6 +149,12 @@
|
|
|
148
149
|
@cancel="onChangeTemplateConfirmModalCancel"
|
|
149
150
|
/>
|
|
150
151
|
<!-- End template change confirm modal -->
|
|
152
|
+
|
|
153
|
+
<PreviewModalWithState
|
|
154
|
+
:visible="isPreviewModalVisible"
|
|
155
|
+
@publish="onPreviewPublish"
|
|
156
|
+
@close="onClosePreview"
|
|
157
|
+
/>
|
|
151
158
|
</div>
|
|
152
159
|
</template>
|
|
153
160
|
<script>
|
|
@@ -171,6 +178,7 @@ import AdminLogoSettings from '../admin-logo-settings/AdminLogoSettings.vue';
|
|
|
171
178
|
import AdminBackgroundSettings from '../admin-background-settings/AdminBackgroundSettings.vue';
|
|
172
179
|
import ConfirmModal from '@shared/confirm-modal/ConfirmModal.vue';
|
|
173
180
|
import ProductConfigModal from '@brand-page-maker/components/shop/ProductConfigModal.vue';
|
|
181
|
+
import PreviewModalWithState from '../preview-modal/PreviewModalWithState.vue';
|
|
174
182
|
import VideoPlayButton from '../video-play/VideoPlayButton.vue';
|
|
175
183
|
|
|
176
184
|
import { SIDE_BAR_TAB_NAMES } from '@brand-page-maker/constants';
|
|
@@ -205,6 +213,7 @@ export default {
|
|
|
205
213
|
SideBar,
|
|
206
214
|
StyleSettings,
|
|
207
215
|
ProductConfigModal,
|
|
216
|
+
PreviewModalWithState,
|
|
208
217
|
VideoPlayButton,
|
|
209
218
|
TemplatesSettings: BrandPageMakerTemplateSettings,
|
|
210
219
|
SparkleIcon,
|
|
@@ -215,8 +224,24 @@ export default {
|
|
|
215
224
|
type: Boolean,
|
|
216
225
|
default: false,
|
|
217
226
|
},
|
|
227
|
+
// Whether the current user is signed in. When false, clicking Preview asks
|
|
228
|
+
// the host to prompt sign-in first (the editor preview saves + mints an
|
|
229
|
+
// owner-gated token) instead of opening it. Defaults true so hosts that
|
|
230
|
+
// don't pass it keep the previous behaviour.
|
|
231
|
+
isUserAuthenticated: {
|
|
232
|
+
type: Boolean,
|
|
233
|
+
default: true,
|
|
234
|
+
},
|
|
218
235
|
},
|
|
219
|
-
emits: [
|
|
236
|
+
emits: [
|
|
237
|
+
'contactsupportclicked',
|
|
238
|
+
'initialised',
|
|
239
|
+
'save',
|
|
240
|
+
'publish',
|
|
241
|
+
'preview',
|
|
242
|
+
'livepreviewclicked',
|
|
243
|
+
'Back',
|
|
244
|
+
],
|
|
220
245
|
setup(props, context) {
|
|
221
246
|
const localisedRouteStore = useLocalisedRouteStore();
|
|
222
247
|
const brandPageMakerStore = useBrandPageMakerStore();
|