@designcrowd/library.brand-page 6.0.21 → 6.0.23-ast-remove
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-C52IyXZu.js → CreatedOnBrandCrowd-de-de-C2IaS_Mb.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-en-us-DhTy_dEV.js → CreatedOnBrandCrowd-en-us-AtykytDu.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-es-es-BJelIAQ4.js → CreatedOnBrandCrowd-es-es-CBzMnp_n.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-fr-DwJohy0T.js → CreatedOnBrandCrowd-fr-ca-Cz7WzWc3.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-ca-DwJohy0T.js → CreatedOnBrandCrowd-fr-fr-Cz7WzWc3.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-pt-CMzKbxdG.js → CreatedOnBrandCrowd-pt-br-DE3vjPyC.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-br-CMzKbxdG.js → CreatedOnBrandCrowd-pt-pt-DE3vjPyC.js} +1 -1
- package/lib/src/{CreatedOnDcom-de-de-DAy1GHrw.js → CreatedOnDcom-de-de-DlcGgBF6.js} +1 -1
- package/lib/src/{CreatedOnDcom-en-us-CgBDAkJN.js → CreatedOnDcom-en-us-D5jdeN_E.js} +1 -1
- package/lib/src/{CreatedOnDcom-es-es-Ds9d5rem.js → CreatedOnDcom-es-es-BBB7ZE8B.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-ca-CZL0BQ-u.js → CreatedOnDcom-fr-ca-odHmWYoP.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-fr-BVYh5Wvo.js → CreatedOnDcom-fr-fr-DKr11T_P.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-br-1hsWNXfq.js → CreatedOnDcom-pt-br-s8blQRF7.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-pt-DvM0N-3M.js → CreatedOnDcom-pt-pt-Dga4RM96.js} +1 -1
- package/lib/src/brand-page/components/collapsible/Collapsible.mixin.d.ts +11 -0
- package/lib/src/brand-page/components/collapsible/Collapsible.mixin.js +13 -1
- package/lib/src/brand-page/components/contact-form/ContactForm.mixin.d.ts +1 -0
- package/lib/src/brand-page/components/contact-form/ContactForm.mixin.js +12 -3
- package/lib/src/brand-page/components/mailing-list/MailingList.mixin.js +5 -0
- package/lib/src/brand-page/components/payment/Payment.mixin.js +5 -0
- package/lib/src/brand-page/models/index.d.ts +1 -1
- package/lib/src/brand-page/models/index.js +0 -3
- package/lib/src/brand-page/models/payment.model.d.ts +2 -0
- package/lib/src/brand-page/utils/button.util.d.ts +5 -0
- package/lib/src/brand-page/utils/button.util.js +13 -0
- package/lib/src/brand-page/utils/migration/migration-19.d.ts +2 -0
- package/lib/src/brand-page/utils/migration/migration-19.js +41 -0
- package/lib/src/brand-page/utils/migration.util.js +11 -0
- package/lib/src/brand-page/utils/view-model.util.js +1 -0
- package/lib/src/brand-page-maker/assessors/contact-form-visibility.assessor.d.ts +1 -0
- package/lib/src/brand-page-maker/assessors/contact-form-visibility.assessor.js +16 -7
- package/lib/src/brand-page-maker/constants/config-settings-constant.js +40 -3
- package/lib/src/brand-page-maker/default-getters/contact-form-card-color.default-getter.d.ts +8 -0
- package/lib/src/brand-page-maker/default-getters/contact-form-card-color.default-getter.js +16 -0
- package/lib/src/brand-page-maker/default-getters/index.d.ts +1 -0
- package/lib/src/brand-page-maker/default-getters/index.js +1 -0
- package/lib/src/brand-page-maker/models/button-styles-config.js +15 -3
- package/lib/src/brand-page-maker/models/content-settings-configs.d.ts +2 -1
- package/lib/src/brand-page-maker/models/content-settings.js +15 -3
- package/lib/src/brand-page-maker/stores/ai-checkpoint/ai-checkpoint-store.d.ts +0 -6
- package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +0 -2
- package/lib/src/css/library.brand-page-brandCrowd.min.css +96 -68
- package/lib/src/css/library.brand-page-brandPage.min.css +96 -68
- package/lib/src/css/library.brand-page-designCom.min.css +96 -68
- package/lib/src/css/library.brand-page-preview.min.css +96 -68
- package/lib/src/index.mjs +1 -1
- package/lib/src/{lib-CK2FPBv5.js → lib-aLiBOhnh.js} +18776 -18430
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.js +5 -0
- package/lib/src/shared/content-settings/models.d.ts +1 -0
- package/lib/src/shared/content-settings/store/content-settings-store.js +3 -0
- package/lib/src/shared/template-settings/store/template-settings-store.js +4 -4
- package/package.json +2 -2
- package/src/brand-page/components/button/ButtonStyleWrapper.vue +112 -44
- package/src/brand-page/components/button/ButtonStyleWrapper.vue.test.ts +167 -0
- package/src/brand-page/components/collapsible/Collapsible.mixin.ts +14 -1
- package/src/brand-page/components/contact-form/ContactForm.mixin.test.ts +18 -0
- package/src/brand-page/components/contact-form/ContactForm.mixin.ts +15 -3
- package/src/brand-page/components/contact-form/ContactForm.vue +97 -36
- package/src/brand-page/components/mailing-list/MailingList.mixin.ts +6 -0
- package/src/brand-page/components/mailing-list/MailingList.vue +18 -10
- package/src/brand-page/components/payment/Payment.mixin.ts +6 -0
- package/src/brand-page/components/payment/Payment.vue +43 -24
- package/src/brand-page/components/payment/RequestPaymentStripe.vue +26 -22
- package/src/brand-page/components/shop/PaymentModal.vue +3 -3
- package/src/brand-page/components/shop/Shop.vue +17 -8
- package/src/brand-page/components/shop/Shop.vue.test.ts +209 -0
- package/src/brand-page/models/index.ts +1 -4
- package/src/brand-page/models/payment.model.ts +2 -0
- package/src/brand-page/utils/__snapshots__/migration.util.test.ts.snap +3 -6
- package/src/brand-page/utils/__snapshots__/migration2.util.test.ts.snap +0 -1
- package/src/brand-page/utils/__snapshots__/model.util.test.ts.snap +0 -2
- package/src/brand-page/utils/button.util.ts +17 -0
- package/src/brand-page/utils/migration/migration-19.test.ts +172 -0
- package/src/brand-page/utils/migration/migration-19.ts +65 -0
- package/src/brand-page/utils/migration.util.ts +12 -0
- package/src/brand-page/utils/view-model.util.ts +1 -0
- package/src/brand-page-maker/assessors/contact-form-visibility.assessor.ts +34 -26
- package/src/brand-page-maker/constants/config-settings-constant.ts +43 -2
- package/src/brand-page-maker/default-getters/contact-form-card-color.default-getter.ts +23 -0
- package/src/brand-page-maker/default-getters/index.ts +1 -0
- package/src/brand-page-maker/models/button-styles-config.ts +15 -3
- package/src/brand-page-maker/models/content-settings-configs.ts +4 -1
- package/src/brand-page-maker/models/content-settings.ts +16 -3
- package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +0 -2
- package/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.ts +6 -0
- package/src/shared/content-settings/models.ts +3 -0
- package/src/shared/content-settings/store/content-settings-store.ts +3 -0
- package/src/shared/style-settings/components/StyleSettings.vue +1 -0
- package/src/shared/template-settings/store/template-settings-store.ts +6 -4
- package/lib/src/metadata-builder/builders/reorder-pages-builder.d.ts +0 -13
- package/lib/src/metadata-builder/builders/reorder-pages-builder.js +0 -49
- package/src/metadata-builder/builders/reorder-pages-builder.ts +0 -80
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { vi } from 'vitest';
|
|
2
|
+
import { shallowMount } from '@vue/test-utils';
|
|
3
|
+
import Shop from './Shop.vue';
|
|
4
|
+
import PaymentModal from './PaymentModal.vue';
|
|
5
|
+
import { createPinia, setActivePinia } from 'pinia';
|
|
6
|
+
import {
|
|
7
|
+
BRAND_PAGE_TYPES,
|
|
8
|
+
ButtonStyles,
|
|
9
|
+
MEDIA_SIZES,
|
|
10
|
+
type BrandPageContext,
|
|
11
|
+
} from '@brand-page/models';
|
|
12
|
+
import type { ShopViewModel } from '@brand-page/view-models';
|
|
13
|
+
|
|
14
|
+
vi.mock('../../clients/brand-page.client', () => ({
|
|
15
|
+
default: {
|
|
16
|
+
getPaymentConfigStatusByPaymentConfigId: vi.fn(),
|
|
17
|
+
createBrandPageCart: vi.fn(),
|
|
18
|
+
},
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
vi.mock('@brand-page/utils/raygun.util', () => ({
|
|
22
|
+
default: { safeSendRaygunError: vi.fn() },
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
const createContext = (): BrandPageContext => ({
|
|
26
|
+
brandPageSlug: 'test',
|
|
27
|
+
brandPageToken: '',
|
|
28
|
+
isMobile: false,
|
|
29
|
+
isPreview: true,
|
|
30
|
+
isProduction: false,
|
|
31
|
+
isServerRender: false,
|
|
32
|
+
options: { mediaSizes: MEDIA_SIZES.sizeThumb },
|
|
33
|
+
isTemplate: false,
|
|
34
|
+
isDesignCom: false,
|
|
35
|
+
pageTitle: 'Test',
|
|
36
|
+
runtimeEnvironment: '',
|
|
37
|
+
stripePublishableKey: undefined,
|
|
38
|
+
customDomain: undefined,
|
|
39
|
+
brandPageType: BRAND_PAGE_TYPES.brandSite,
|
|
40
|
+
isBrandPage: false,
|
|
41
|
+
isBrandPageOrIsBrandContact: false,
|
|
42
|
+
isBrandSite: true,
|
|
43
|
+
isBrandContact: false,
|
|
44
|
+
pages: [],
|
|
45
|
+
isCapturingPreview: false,
|
|
46
|
+
recaptchaSiteKey: undefined,
|
|
47
|
+
nav: { navItems: [] },
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const PRODUCT = {
|
|
51
|
+
id: '1',
|
|
52
|
+
name: 'Test',
|
|
53
|
+
price: 1,
|
|
54
|
+
description: '',
|
|
55
|
+
imageUrl: '',
|
|
56
|
+
} as any;
|
|
57
|
+
|
|
58
|
+
const createViewModel = (
|
|
59
|
+
overrides: Partial<ShopViewModel> = {},
|
|
60
|
+
): ShopViewModel =>
|
|
61
|
+
({
|
|
62
|
+
id: '1',
|
|
63
|
+
type: 'shop-section',
|
|
64
|
+
role: 'shop-section',
|
|
65
|
+
title: 'Shop',
|
|
66
|
+
description: '',
|
|
67
|
+
successMessage: 'Thanks!',
|
|
68
|
+
products: [],
|
|
69
|
+
displayStyle: 'text',
|
|
70
|
+
aspectRatio: '1:1',
|
|
71
|
+
fillColor: {},
|
|
72
|
+
defaultBorderColor: {},
|
|
73
|
+
itemTextStyle: {},
|
|
74
|
+
backgroundStyle: {},
|
|
75
|
+
buttonStyles: new ButtonStyles(),
|
|
76
|
+
isFullWidth: true,
|
|
77
|
+
isShippingEnabled: false,
|
|
78
|
+
shopPaymentConfig: {
|
|
79
|
+
paymentConfig: {},
|
|
80
|
+
paymentOptionDisplayType: 'text',
|
|
81
|
+
paymentOptionImageType: 'none',
|
|
82
|
+
isCustomerRequestDetailsEnabled: false,
|
|
83
|
+
isShippingEnabled: false,
|
|
84
|
+
},
|
|
85
|
+
...overrides,
|
|
86
|
+
}) as ShopViewModel;
|
|
87
|
+
|
|
88
|
+
const mountShop = (viewModel: ShopViewModel) =>
|
|
89
|
+
shallowMount(Shop, {
|
|
90
|
+
props: {
|
|
91
|
+
context: createContext(),
|
|
92
|
+
viewModel,
|
|
93
|
+
contentIndex: 0,
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
describe('Shop', () => {
|
|
98
|
+
beforeEach(() => {
|
|
99
|
+
setActivePinia(createPinia());
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe('buttonStyles defensive access', () => {
|
|
103
|
+
it('does not throw when buttonStyles has no style property', () => {
|
|
104
|
+
const vm = createViewModel({
|
|
105
|
+
buttonStyles: { selectedButtonStyleId: 'BUTTON_STYLE_1' } as any,
|
|
106
|
+
products: [PRODUCT],
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
expect(() => mountShop(vm)).not.toThrow();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('does not throw when buttonStyles is undefined', () => {
|
|
113
|
+
const vm = createViewModel({
|
|
114
|
+
buttonStyles: undefined as any,
|
|
115
|
+
products: [PRODUCT],
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
expect(() => mountShop(vm)).not.toThrow();
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('renders correctly with fully populated buttonStyles', () => {
|
|
122
|
+
const vm = createViewModel({
|
|
123
|
+
buttonStyles: new ButtonStyles({
|
|
124
|
+
selectedButtonStyleId: 'BUTTON_STYLE_1',
|
|
125
|
+
style: {
|
|
126
|
+
color: 'rgb(255, 0, 0)',
|
|
127
|
+
backgroundColor: 'rgb(0, 0, 255)',
|
|
128
|
+
},
|
|
129
|
+
}),
|
|
130
|
+
products: [PRODUCT],
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
const wrapper = mountShop(vm);
|
|
134
|
+
|
|
135
|
+
expect(
|
|
136
|
+
wrapper.find('[data-component="button-style-wrapper"]').exists() ||
|
|
137
|
+
wrapper.findComponent({ name: 'ButtonStyleWrapper' }).exists(),
|
|
138
|
+
).toBe(true);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
describe('PaymentModal', () => {
|
|
144
|
+
beforeEach(() => {
|
|
145
|
+
setActivePinia(createPinia());
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const mountPaymentModal = (buttonStyle: any) =>
|
|
149
|
+
shallowMount(PaymentModal, {
|
|
150
|
+
props: {
|
|
151
|
+
context: createContext(),
|
|
152
|
+
isVisible: true,
|
|
153
|
+
buttonStyle,
|
|
154
|
+
shopPaymentConfig: { paymentConfig: {} } as any,
|
|
155
|
+
descriptionStyle: undefined,
|
|
156
|
+
successMessage: 'Thanks!',
|
|
157
|
+
isShippingEnabled: false,
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('does not throw when given a ButtonStyles instance', () => {
|
|
162
|
+
const buttonStyles = new ButtonStyles({
|
|
163
|
+
selectedButtonStyleId: 'BUTTON_STYLE_1',
|
|
164
|
+
style: { color: 'rgb(255, 0, 0)', backgroundColor: 'rgb(0, 0, 255)' },
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
expect(() => mountPaymentModal(buttonStyles)).not.toThrow();
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it('receives a ButtonStyles with .style (not flat CSS)', () => {
|
|
171
|
+
const buttonStyles = new ButtonStyles({
|
|
172
|
+
selectedButtonStyleId: 'BUTTON_STYLE_1',
|
|
173
|
+
style: { color: 'rgb(255, 0, 0)', backgroundColor: 'rgb(0, 0, 255)' },
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
const wrapper = mountPaymentModal(buttonStyles);
|
|
177
|
+
const prop = wrapper.props('buttonStyle');
|
|
178
|
+
|
|
179
|
+
expect(prop).toHaveProperty('style');
|
|
180
|
+
expect(prop).toHaveProperty('selectedButtonStyleId');
|
|
181
|
+
expect(prop.style.color).toBe('rgb(255, 0, 0)');
|
|
182
|
+
expect(prop.style.backgroundColor).toBe('rgb(0, 0, 255)');
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it('passes buttonStyles through to RequestPaymentStripe', () => {
|
|
186
|
+
const buttonStyles = new ButtonStyles({
|
|
187
|
+
selectedButtonStyleId: 'BUTTON_STYLE_1',
|
|
188
|
+
style: { color: 'rgb(255, 0, 0)', backgroundColor: 'rgb(0, 0, 255)' },
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
const wrapper = mountPaymentModal(buttonStyles);
|
|
192
|
+
const stripe = wrapper.findComponent({
|
|
193
|
+
name: 'RequestPaymentStripe',
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
if (stripe.exists()) {
|
|
197
|
+
const stripeProp = stripe.props('buttonStyles');
|
|
198
|
+
|
|
199
|
+
expect(stripeProp).toHaveProperty('style');
|
|
200
|
+
expect(stripeProp.style.color).toBe('rgb(255, 0, 0)');
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('would fail with a flat CSS object — .style is undefined', () => {
|
|
205
|
+
const flatCss = { color: 'rgb(255,0,0)', backgroundColor: 'rgb(0,0,255)' };
|
|
206
|
+
|
|
207
|
+
expect((flatCss as any).style).toBeUndefined();
|
|
208
|
+
});
|
|
209
|
+
});
|
|
@@ -331,6 +331,7 @@ export interface MailingListContent extends Content {
|
|
|
331
331
|
buttonText: string;
|
|
332
332
|
titleStyle: TextStyleDeclaration;
|
|
333
333
|
buttonTextStyle: TextStyleDeclaration;
|
|
334
|
+
backgroundStyle?: BrandPageCssStyle;
|
|
334
335
|
}
|
|
335
336
|
|
|
336
337
|
export const FORM_FIELD_TYPES = {
|
|
@@ -946,10 +947,6 @@ export class BrandPageModel {
|
|
|
946
947
|
// Model version
|
|
947
948
|
v: number;
|
|
948
949
|
|
|
949
|
-
// AI personalisation key persisted with the draft so previews survive login/checkout-back/
|
|
950
|
-
// refresh - content is retrieved by this token (user-agnostic), not regenerated (bp-5742).
|
|
951
|
-
userPromptContentKey?: string;
|
|
952
|
-
|
|
953
950
|
styles: PageStyles;
|
|
954
951
|
|
|
955
952
|
/** @deprecated */
|
|
@@ -147,6 +147,7 @@ export interface RequestPaymentContent extends Content {
|
|
|
147
147
|
descriptionStyle?: TextStyleDeclaration;
|
|
148
148
|
itemTextStyle: TextStyleDeclaration;
|
|
149
149
|
buttonTextStyle?: TextStyleDeclaration;
|
|
150
|
+
backgroundStyle?: BrandPageCssStyle;
|
|
150
151
|
}
|
|
151
152
|
|
|
152
153
|
export interface ShopContentConfig extends PaymentConfig {
|
|
@@ -191,6 +192,7 @@ export interface SupportMeContent extends Content {
|
|
|
191
192
|
descriptionStyle: TextStyleDeclaration;
|
|
192
193
|
buttonTextStyle: TextStyleDeclaration;
|
|
193
194
|
itemTextStyle: TextStyleDeclaration;
|
|
195
|
+
backgroundStyle?: BrandPageCssStyle;
|
|
194
196
|
}
|
|
195
197
|
|
|
196
198
|
export interface CreateStripePaymentIntentResponse {
|
|
@@ -462,8 +462,7 @@ exports[`migration.util > Banner Contents - text Align and Font Family should no
|
|
|
462
462
|
},
|
|
463
463
|
},
|
|
464
464
|
},
|
|
465
|
-
"
|
|
466
|
-
"v": 18,
|
|
465
|
+
"v": 19,
|
|
467
466
|
},
|
|
468
467
|
"useOldLogoRenderSize": true,
|
|
469
468
|
}
|
|
@@ -915,8 +914,7 @@ exports[`migration.util > migrateBrandPageModel should return brand page model w
|
|
|
915
914
|
},
|
|
916
915
|
},
|
|
917
916
|
},
|
|
918
|
-
"
|
|
919
|
-
"v": 18,
|
|
917
|
+
"v": 19,
|
|
920
918
|
},
|
|
921
919
|
"useOldLogoRenderSize": true,
|
|
922
920
|
}
|
|
@@ -1375,8 +1373,7 @@ exports[`migration.util > migrateBrandPageModel should return brand page model w
|
|
|
1375
1373
|
},
|
|
1376
1374
|
},
|
|
1377
1375
|
},
|
|
1378
|
-
"
|
|
1379
|
-
"v": 18,
|
|
1376
|
+
"v": 19,
|
|
1380
1377
|
},
|
|
1381
1378
|
"useOldLogoRenderSize": true,
|
|
1382
1379
|
}
|
|
@@ -37,3 +37,20 @@ export const getBoxShadowValue = (buttonStyles: ButtonStyles): string => {
|
|
|
37
37
|
|
|
38
38
|
return boxShadowValue;
|
|
39
39
|
};
|
|
40
|
+
|
|
41
|
+
// The "decorative" button styles — brushstroke / arrow / torn-paper — whose visual
|
|
42
|
+
// is drawn by ButtonStyleWrapper rather than plain CSS. Their banner-like SVG
|
|
43
|
+
// decoration needs the button to be reasonably wide to render legibly, so narrow
|
|
44
|
+
// (w-fit) hosts should widen when one of these is active (BP-5800).
|
|
45
|
+
export const BUTTON_STYLE_BRUSHSTROKE = 'BUTTON_STYLE_19';
|
|
46
|
+
export const BUTTON_STYLE_ARROW = 'BUTTON_STYLE_20';
|
|
47
|
+
export const BUTTON_STYLE_PAPER = 'BUTTON_STYLE_21';
|
|
48
|
+
|
|
49
|
+
export const DECORATIVE_BUTTON_STYLE_IDS = [
|
|
50
|
+
BUTTON_STYLE_BRUSHSTROKE,
|
|
51
|
+
BUTTON_STYLE_ARROW,
|
|
52
|
+
BUTTON_STYLE_PAPER,
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
export const isDecorativeButtonStyle = (styleId?: string): boolean =>
|
|
56
|
+
!!styleId && DECORATIVE_BUTTON_STYLE_IDS.includes(styleId);
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { describe, test, expect } from 'vitest';
|
|
2
|
+
import { migration19 } from './migration-19';
|
|
3
|
+
import type { MigrationData } from '../migration.util';
|
|
4
|
+
import { BRAND_PAGE_TYPES } from '../../models';
|
|
5
|
+
|
|
6
|
+
const BUTTON_FILL = 'rgb(255, 222, 89)';
|
|
7
|
+
const USER_CARD = 'rgb(1, 2, 3)';
|
|
8
|
+
|
|
9
|
+
const createMigrationData = (brandPageModel: any): MigrationData => ({
|
|
10
|
+
brandPageModel,
|
|
11
|
+
useOldLogoRenderSize: false,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const modelWith = (
|
|
15
|
+
contents: any[],
|
|
16
|
+
buttonFill: string | undefined = BUTTON_FILL,
|
|
17
|
+
brandPageType: string = BRAND_PAGE_TYPES.default,
|
|
18
|
+
) => ({
|
|
19
|
+
brandPageType,
|
|
20
|
+
styles: { buttonStyles: { style: { backgroundColor: buttonFill } } },
|
|
21
|
+
pages: [{ contents }],
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe('migration19', () => {
|
|
25
|
+
test('seeds backgroundColor from the button fill for each container-backed block when unset', async () => {
|
|
26
|
+
const model = modelWith([
|
|
27
|
+
{ type: 'mailing-list' },
|
|
28
|
+
{ type: 'request-payment' },
|
|
29
|
+
{ type: 'support-me' },
|
|
30
|
+
]);
|
|
31
|
+
|
|
32
|
+
const result = await migration19(createMigrationData(model));
|
|
33
|
+
|
|
34
|
+
(result.brandPageModel as any).pages[0].contents.forEach((c: any) => {
|
|
35
|
+
expect(c.backgroundStyle.backgroundColor).toBe(BUTTON_FILL);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('does not override a backgroundColor that is already set', async () => {
|
|
40
|
+
const model = modelWith([
|
|
41
|
+
{
|
|
42
|
+
type: 'mailing-list',
|
|
43
|
+
backgroundStyle: { backgroundColor: 'rgb(1, 2, 3)' },
|
|
44
|
+
},
|
|
45
|
+
]);
|
|
46
|
+
|
|
47
|
+
const result = await migration19(createMigrationData(model));
|
|
48
|
+
|
|
49
|
+
expect(
|
|
50
|
+
(result.brandPageModel as any).pages[0].contents[0].backgroundStyle
|
|
51
|
+
.backgroundColor,
|
|
52
|
+
).toBe('rgb(1, 2, 3)');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('seeds contact-form via cardStyle (not backgroundStyle) so its container colour is detached from the button', async () => {
|
|
56
|
+
const model = modelWith([{ type: 'contact-form' }]);
|
|
57
|
+
|
|
58
|
+
const result = await migration19(createMigrationData(model));
|
|
59
|
+
|
|
60
|
+
const block = (result.brandPageModel as any).pages[0].contents[0];
|
|
61
|
+
|
|
62
|
+
expect(block.backgroundStyle).toBeUndefined();
|
|
63
|
+
expect(block.cardStyle.backgroundColor).toBe(BUTTON_FILL);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test('still seeds mailing-list on brand-site (button-fill container on every type)', async () => {
|
|
67
|
+
const model = modelWith(
|
|
68
|
+
[{ type: 'mailing-list' }],
|
|
69
|
+
BUTTON_FILL,
|
|
70
|
+
BRAND_PAGE_TYPES.brandSite,
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
const result = await migration19(createMigrationData(model));
|
|
74
|
+
|
|
75
|
+
expect(
|
|
76
|
+
(result.brandPageModel as any).pages[0].contents[0].backgroundStyle
|
|
77
|
+
.backgroundColor,
|
|
78
|
+
).toBe(BUTTON_FILL);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('leaves out-of-scope content types untouched', async () => {
|
|
82
|
+
const model = modelWith([{ type: 'banner-section' }, { type: 'text' }]);
|
|
83
|
+
|
|
84
|
+
const result = await migration19(createMigrationData(model));
|
|
85
|
+
|
|
86
|
+
(result.brandPageModel as any).pages[0].contents.forEach((c: any) => {
|
|
87
|
+
expect(c.backgroundStyle).toBeUndefined();
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test('is a no-op when the button fill colour is undefined', async () => {
|
|
92
|
+
const model = {
|
|
93
|
+
styles: { buttonStyles: { style: {} } },
|
|
94
|
+
pages: [{ contents: [{ type: 'mailing-list' }] }],
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const result = await migration19(createMigrationData(model));
|
|
98
|
+
|
|
99
|
+
expect(
|
|
100
|
+
(result.brandPageModel as any).pages[0].contents[0].backgroundStyle,
|
|
101
|
+
).toBeUndefined();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('preserves other backgroundStyle keys when seeding', async () => {
|
|
105
|
+
const model = modelWith([
|
|
106
|
+
{ type: 'mailing-list', backgroundStyle: { opacity: '0.5' } },
|
|
107
|
+
]);
|
|
108
|
+
|
|
109
|
+
const result = await migration19(createMigrationData(model));
|
|
110
|
+
|
|
111
|
+
const bg = (result.brandPageModel as any).pages[0].contents[0]
|
|
112
|
+
.backgroundStyle;
|
|
113
|
+
|
|
114
|
+
expect(bg.backgroundColor).toBe(BUTTON_FILL);
|
|
115
|
+
expect(bg.opacity).toBe('0.5');
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('seeds contact-form cardStyle from the button fill on brand-contact', async () => {
|
|
119
|
+
const model = modelWith(
|
|
120
|
+
[{ type: 'contact-form' }],
|
|
121
|
+
BUTTON_FILL,
|
|
122
|
+
BRAND_PAGE_TYPES.brandContact,
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const result = await migration19(createMigrationData(model));
|
|
126
|
+
|
|
127
|
+
expect(
|
|
128
|
+
(result.brandPageModel as any).pages[0].contents[0].cardStyle
|
|
129
|
+
.backgroundColor,
|
|
130
|
+
).toBe(BUTTON_FILL);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test('is idempotent — does NOT overwrite a contact-form cardStyle colour that is already set', async () => {
|
|
134
|
+
const model = modelWith([
|
|
135
|
+
{ type: 'contact-form', cardStyle: { backgroundColor: USER_CARD } },
|
|
136
|
+
]);
|
|
137
|
+
|
|
138
|
+
const result = await migration19(createMigrationData(model));
|
|
139
|
+
|
|
140
|
+
expect(
|
|
141
|
+
(result.brandPageModel as any).pages[0].contents[0].cardStyle
|
|
142
|
+
.backgroundColor,
|
|
143
|
+
).toBe(USER_CARD);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test('preserves other cardStyle keys while seeding the contact-form colour', async () => {
|
|
147
|
+
const model = modelWith([
|
|
148
|
+
{ type: 'contact-form', cardStyle: { borderRadius: '8px' } },
|
|
149
|
+
]);
|
|
150
|
+
|
|
151
|
+
const result = await migration19(createMigrationData(model));
|
|
152
|
+
|
|
153
|
+
const card = (result.brandPageModel as any).pages[0].contents[0].cardStyle;
|
|
154
|
+
|
|
155
|
+
expect(card.backgroundColor).toBe(BUTTON_FILL);
|
|
156
|
+
expect(card.borderRadius).toBe('8px');
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
test('does NOT touch contact forms on brand-site (keeps its own layout/card behaviour)', async () => {
|
|
160
|
+
const model = modelWith(
|
|
161
|
+
[{ type: 'contact-form' }],
|
|
162
|
+
BUTTON_FILL,
|
|
163
|
+
BRAND_PAGE_TYPES.brandSite,
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
const result = await migration19(createMigrationData(model));
|
|
167
|
+
|
|
168
|
+
expect(
|
|
169
|
+
(result.brandPageModel as any).pages[0].contents[0].cardStyle,
|
|
170
|
+
).toBeUndefined();
|
|
171
|
+
});
|
|
172
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { MigrationData } from '../migration.util';
|
|
2
|
+
import { BRAND_PAGE_TYPES } from '../../models';
|
|
3
|
+
|
|
4
|
+
const CONTAINER_BACKGROUND_TYPES = new Set<string>([
|
|
5
|
+
'mailing-list',
|
|
6
|
+
'request-payment',
|
|
7
|
+
'support-me',
|
|
8
|
+
]);
|
|
9
|
+
|
|
10
|
+
type WithBackgroundStyle = {
|
|
11
|
+
backgroundStyle?: { backgroundColor?: string };
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
type WithCardStyle = {
|
|
15
|
+
cardStyle?: { backgroundColor?: string };
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const migration19 = async (
|
|
19
|
+
migrationResult: MigrationData,
|
|
20
|
+
): Promise<MigrationData> => {
|
|
21
|
+
const { brandPageModel } = migrationResult;
|
|
22
|
+
|
|
23
|
+
const buttonFill =
|
|
24
|
+
brandPageModel.styles?.buttonStyles?.style?.backgroundColor;
|
|
25
|
+
|
|
26
|
+
if (buttonFill === undefined) {
|
|
27
|
+
return migrationResult;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const isBrandSite =
|
|
31
|
+
brandPageModel.brandPageType === BRAND_PAGE_TYPES.brandSite;
|
|
32
|
+
|
|
33
|
+
brandPageModel.pages.forEach((page) => {
|
|
34
|
+
page.contents.forEach((content) => {
|
|
35
|
+
// Container-backed blocks: seed their own backgroundStyle on every type.
|
|
36
|
+
if (CONTAINER_BACKGROUND_TYPES.has(content.type)) {
|
|
37
|
+
const block = content as WithBackgroundStyle;
|
|
38
|
+
|
|
39
|
+
if (block.backgroundStyle?.backgroundColor === undefined) {
|
|
40
|
+
block.backgroundStyle = {
|
|
41
|
+
...block.backgroundStyle,
|
|
42
|
+
backgroundColor: buttonFill,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Contact form: colour moves to cardStyle — skip on brand-site, which
|
|
50
|
+
// keeps its own layout/card behaviour.
|
|
51
|
+
if (content.type === 'contact-form' && !isBrandSite) {
|
|
52
|
+
const block = content as WithCardStyle;
|
|
53
|
+
|
|
54
|
+
if (block.cardStyle?.backgroundColor === undefined) {
|
|
55
|
+
block.cardStyle = {
|
|
56
|
+
...block.cardStyle,
|
|
57
|
+
backgroundColor: buttonFill,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
return migrationResult;
|
|
65
|
+
};
|
|
@@ -21,6 +21,7 @@ import { migration15 } from './migration/migration-15';
|
|
|
21
21
|
import { migration16 } from './migration/migration-16';
|
|
22
22
|
import { migration17 } from './migration/migration-17';
|
|
23
23
|
import { migration18 } from './migration/migration-18';
|
|
24
|
+
import { migration19 } from './migration/migration-19';
|
|
24
25
|
|
|
25
26
|
export interface MigrationData {
|
|
26
27
|
brandPageModel: BrandPageModel;
|
|
@@ -167,6 +168,17 @@ const MIGRATION_TABLE = [
|
|
|
167
168
|
description:
|
|
168
169
|
'BP-5603: backfill stable item ids on all nested items (gallery/section/testimonial/text items, section + footer social links) — the item id is now non-nullable',
|
|
169
170
|
},
|
|
171
|
+
{
|
|
172
|
+
version: 19,
|
|
173
|
+
migrateFn: migration19,
|
|
174
|
+
// runAlways: re-apply on every load so already-published sites pick up the seed
|
|
175
|
+
// without a version bump. Idempotent — only seeds a colour when unset, so a user
|
|
176
|
+
// colour is never clobbered. Single pass over the model seeds both container types
|
|
177
|
+
// and the contact form.
|
|
178
|
+
runAlways: true,
|
|
179
|
+
description:
|
|
180
|
+
'BP-5800: seed the button fill colour as each block’s own container colour so it is independent of the site button (existing sites render unchanged) — backgroundStyle for mailing-list, request-payment and support-me (all types); cardStyle for the BP/BC contact form (skipped on brand-site)',
|
|
181
|
+
},
|
|
170
182
|
] as MigrationTableItem[];
|
|
171
183
|
|
|
172
184
|
export const GetLatestModelVersion = () =>
|
|
@@ -11,50 +11,58 @@ import {
|
|
|
11
11
|
|
|
12
12
|
export const contactCardDisplayTypeVisibilityAssessor: VisibilityAssessor<
|
|
13
13
|
ContactFormContent | undefined
|
|
14
|
+
> = (content, context) => {
|
|
15
|
+
return Boolean(
|
|
16
|
+
content?.layoutStyle &&
|
|
17
|
+
[
|
|
18
|
+
ALIGN_CARD_CENTER_IMAGE,
|
|
19
|
+
ALIGN_CARD_CENTER,
|
|
20
|
+
ALIGN_LEFT_FULL_IMAGE,
|
|
21
|
+
ALIGN_RIGHT_FULL_IMAGE,
|
|
22
|
+
].includes(content?.layoutStyle) &&
|
|
23
|
+
context?.isBrandSite,
|
|
24
|
+
);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// Card colour picker: on brand-page/brand-contact it's the collapsible container
|
|
28
|
+
// colour (shown for every layout); on brand-site it's the card in card layouts.
|
|
29
|
+
export const contactCardColorVisibilityAssessor: VisibilityAssessor<
|
|
30
|
+
ContactFormContent | undefined
|
|
14
31
|
> = (content, context) => {
|
|
15
32
|
return (
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
[
|
|
19
|
-
ALIGN_CARD_CENTER_IMAGE,
|
|
20
|
-
ALIGN_CARD_CENTER,
|
|
21
|
-
ALIGN_LEFT_FULL_IMAGE,
|
|
22
|
-
ALIGN_RIGHT_FULL_IMAGE,
|
|
23
|
-
].includes(content?.layoutStyle),
|
|
24
|
-
) && context!.isBrandSite
|
|
33
|
+
!context?.isBrandSite ||
|
|
34
|
+
contactCardDisplayTypeVisibilityAssessor(content, context)
|
|
25
35
|
);
|
|
26
36
|
};
|
|
27
37
|
|
|
28
38
|
export const displayTypeVisibilityAssessor: VisibilityAssessor<
|
|
29
39
|
ContactFormContent | undefined
|
|
30
40
|
> = (content, context) => {
|
|
31
|
-
return Boolean(content?.layoutStyle === '' || context
|
|
41
|
+
return Boolean(content?.layoutStyle === '' || context?.isBrandPage);
|
|
32
42
|
};
|
|
33
43
|
|
|
34
44
|
export const imageUrlVisibilityAssessor: VisibilityAssessor<
|
|
35
45
|
ContactFormContent | undefined
|
|
36
46
|
> = (content, context) => {
|
|
37
|
-
return (
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
) && context!.isBrandSite
|
|
47
|
+
return Boolean(
|
|
48
|
+
content?.layoutStyle &&
|
|
49
|
+
[
|
|
50
|
+
ALIGN_CARD_CENTER_IMAGE,
|
|
51
|
+
ALIGN_LEFT_FULL_IMAGE,
|
|
52
|
+
ALIGN_RIGHT_FULL_IMAGE,
|
|
53
|
+
].includes(content?.layoutStyle) &&
|
|
54
|
+
context?.isBrandSite,
|
|
46
55
|
);
|
|
47
56
|
};
|
|
48
57
|
|
|
49
58
|
export const contactBackgroundDisplayTypeVisibilityAssessor: VisibilityAssessor<
|
|
50
59
|
ContactFormContent | undefined
|
|
51
60
|
> = (content, context) => {
|
|
52
|
-
return (
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
) && context!.isBrandSite
|
|
61
|
+
return Boolean(
|
|
62
|
+
content?.layoutStyle &&
|
|
63
|
+
[ALIGN_CARD_CENTER, ALIGN_CENTERED, TEXT_ONLY].includes(
|
|
64
|
+
content?.layoutStyle,
|
|
65
|
+
) &&
|
|
66
|
+
context?.isBrandSite,
|
|
59
67
|
);
|
|
60
68
|
};
|