@designcrowd/library.brand-page 5.16.42 → 5.16.43-ast-ai
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-2yOEYkJj.js → CreatedOnBrandCrowd-de-de-B-Oc1A1o.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-en-us-C3ZcstVb.js → CreatedOnBrandCrowd-en-us-D5C-8hdn.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-es-es-CUVbeolm.js → CreatedOnBrandCrowd-es-es-58ZSy8Zn.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-fr-CWrEm5XF.js → CreatedOnBrandCrowd-fr-ca-Csqkn-I_.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-ca-CWrEm5XF.js → CreatedOnBrandCrowd-fr-fr-Csqkn-I_.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-pt-5WAjD7l3.js → CreatedOnBrandCrowd-pt-br-ILKVUj-T.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-br-5WAjD7l3.js → CreatedOnBrandCrowd-pt-pt-ILKVUj-T.js} +1 -1
- package/lib/src/{CreatedOnDcom-de-de-B4b3caW2.js → CreatedOnDcom-de-de-B5x4Crpb.js} +1 -1
- package/lib/src/{CreatedOnDcom-en-us-DaLELZyT.js → CreatedOnDcom-en-us-DtufP1lJ.js} +1 -1
- package/lib/src/{CreatedOnDcom-es-es-p5JZJPXb.js → CreatedOnDcom-es-es-DJ0sw5dx.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-ca-DcaNqreO.js → CreatedOnDcom-fr-ca-DrMbvOz7.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-fr-DKzy6dez.js → CreatedOnDcom-fr-fr-B2EKyBz8.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-br-DXK8qDlO.js → CreatedOnDcom-pt-br-SdOffbzb.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-pt-ChGL1q2P.js → CreatedOnDcom-pt-pt-3khFhgHk.js} +1 -1
- package/lib/src/brand-page/__fixtures__/brand-page-sample-data.js +2 -0
- package/lib/src/brand-page/clients/brand-page.client.d.ts +2 -2
- package/lib/src/brand-page/clients/brand-page.client.js +4 -2
- package/lib/src/brand-page/components/contact-form/ContactForm.mixin.d.ts +10 -1
- package/lib/src/brand-page/components/contact-form/ContactForm.mixin.js +18 -2
- package/lib/src/brand-page/components/image-gallery/ImageGallery.stories.js +2 -1
- package/lib/src/brand-page/components/images-section/ImagesSection.stories.js +2 -1
- package/lib/src/brand-page/components/mailing-list/MailingList.mixin.d.ts +8 -0
- package/lib/src/brand-page/components/mailing-list/MailingList.mixin.js +22 -7
- package/lib/src/brand-page/components/page/Page.mixin.d.ts +3 -1
- package/lib/src/brand-page/components/page/Page.mixin.js +13 -4
- package/lib/src/brand-page/components/payment/__fixtures__/request-payment.d.ts +1 -0
- package/lib/src/brand-page/components/payment/__fixtures__/support-me.d.ts +1 -0
- package/lib/src/brand-page/components/profile/Profile.stories.js +2 -1
- package/lib/src/brand-page/composables/recaptcha.composable.d.ts +23 -0
- package/lib/src/brand-page/composables/recaptcha.composable.js +109 -0
- package/lib/src/brand-page/constants/misc.constants.d.ts +3 -0
- package/lib/src/brand-page/constants/misc.constants.js +4 -0
- package/lib/src/brand-page/models/brand-page-context.model.d.ts +2 -0
- package/lib/src/brand-page/utils/index.d.ts +1 -0
- package/lib/src/brand-page/utils/index.js +1 -0
- package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +3 -0
- package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +7 -1
- package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.js +15 -0
- package/lib/src/brand-page-maker/components/preview/Preview.mixin.js +1 -0
- package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.js +1 -0
- package/lib/src/bundled-translations-CaJjdBEL.js +169 -0
- package/lib/src/bundled-translations.de-DE-1O8nqesB.js +169 -0
- package/lib/src/bundled-translations.es-ES-DpzOLKxV.js +169 -0
- package/lib/src/bundled-translations.fr-CA-D4lvna7W.js +169 -0
- package/lib/src/bundled-translations.fr-FR-rn7Qlrcy.js +169 -0
- package/lib/src/bundled-translations.pt-BR-Cuinfm5y.js +169 -0
- package/lib/src/bundled-translations.pt-PT-BWcxkaQn.js +169 -0
- package/lib/src/bundles/bundled-translations.de-DE.json +1 -1
- package/lib/src/bundles/bundled-translations.es-ES.json +1 -1
- package/lib/src/bundles/bundled-translations.fr-CA.json +1 -1
- package/lib/src/bundles/bundled-translations.fr-FR.json +2 -2
- package/lib/src/bundles/bundled-translations.json +1 -1
- package/lib/src/bundles/bundled-translations.pt-BR.json +2 -2
- package/lib/src/bundles/bundled-translations.pt-PT.json +2 -2
- package/lib/src/css/library.brand-page-brandCrowd.min.css +51 -51
- package/lib/src/css/library.brand-page-brandPage.min.css +51 -51
- package/lib/src/css/library.brand-page-designCom.min.css +51 -51
- package/lib/src/css/library.brand-page-preview.min.css +51 -51
- package/lib/src/index.d.ts +3 -1
- package/lib/src/index.mjs +116 -111
- package/lib/src/{lib-hXQaBPKF.js → lib-Cr89CnhI.js} +17648 -17488
- package/lib/src/lib.js +2 -1
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.d.ts +3 -0
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.js +1 -0
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.d.ts +3 -0
- package/lib/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.js +1 -0
- package/lib/src/shared/content-settings/components/radio-field/RadioField.mixin.js +1 -0
- package/lib/src/shared/side-bar/components/SideBar.mixin.d.ts +3 -0
- package/lib/src/shared/side-bar/components/SideBarTabButton.mixin.d.ts +3 -0
- package/lib/src/shared/side-bar/store/side-bar-store.d.ts +4 -0
- package/lib/src/shared/side-bar/store/side-bar-store.js +4 -1
- package/package.json +5 -4
- package/src/brand-page/__fixtures__/brand-page-sample-data.ts +2 -0
- package/src/brand-page/clients/brand-page.client.ts +5 -0
- package/src/brand-page/components/about-section/AboutSection.vue.test.ts +1 -0
- package/src/brand-page/components/contact-form/ContactForm.mixin.ts +23 -0
- package/src/brand-page/components/contact-form/ContactForm.vue +5 -0
- package/src/brand-page/components/image/Image.test.ts +1 -0
- package/src/brand-page/components/image-gallery/ImageGallery.stories.ts +2 -1
- package/src/brand-page/components/image-gallery/ImageGallery.test.ts +1 -0
- package/src/brand-page/components/images-section/ImagesSection.stories.ts +2 -1
- package/src/brand-page/components/mailing-list/MailingList.mixin.ts +32 -12
- package/src/brand-page/components/page/Page.mixin.ts +15 -4
- package/src/brand-page/components/page/Page.vue +1 -0
- package/src/brand-page/components/profile/Profile.stories.ts +2 -1
- package/src/brand-page/components/save-contact/SaveContactWidget.vue +9 -4
- package/src/brand-page/components/save-contact/i18n/save-contact.de-DE.json +1 -1
- package/src/brand-page/components/save-contact/i18n/save-contact.es-ES.json +1 -1
- package/src/brand-page/components/save-contact/i18n/save-contact.fr-CA.json +1 -1
- package/src/brand-page/components/save-contact/i18n/save-contact.fr-FR.json +2 -2
- package/src/brand-page/components/save-contact/i18n/save-contact.pt-BR.json +2 -2
- package/src/brand-page/components/save-contact/i18n/save-contact.pt-PT.json +2 -2
- package/src/brand-page/components/social-links/SocialLinks.vue.test.ts +1 -0
- package/src/brand-page/components/text-wrapper/TextWrapper.vue +1 -1
- package/src/brand-page/composables/recaptcha.composable.ts +159 -0
- package/src/brand-page/constants/misc.constants.ts +5 -0
- package/src/brand-page/models/brand-page-context.model.ts +2 -0
- package/src/brand-page/utils/index.ts +1 -0
- package/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.ts +19 -0
- package/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.vue +1 -0
- package/src/brand-page-maker/components/brandpage-settings/BrandPageSettings.vue +50 -1
- package/src/brand-page-maker/components/preview/Preview.mixin.ts +1 -0
- package/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.ts +1 -0
- package/src/bundles/bundled-translations.de-DE.json +1 -1
- package/src/bundles/bundled-translations.es-ES.json +1 -1
- package/src/bundles/bundled-translations.fr-CA.json +1 -1
- package/src/bundles/bundled-translations.fr-FR.json +2 -2
- package/src/bundles/bundled-translations.json +1 -1
- package/src/bundles/bundled-translations.pt-BR.json +2 -2
- package/src/bundles/bundled-translations.pt-PT.json +2 -2
- package/src/lib.ts +6 -0
- package/src/shared/common/i18n/common.json +1 -1
- package/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.ts +1 -0
- package/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.ts +1 -0
- package/src/shared/content-settings/components/generate-ai-button/GenerateAiButton.vue +1 -1
- package/src/shared/content-settings/components/radio-field/RadioField.mixin.ts +1 -0
- package/src/shared/side-bar/store/side-bar-store.ts +6 -1
- package/lib/src/bundled-translations-m0LLDrVj.js +0 -169
- package/lib/src/bundled-translations.de-DE-CTyBT5RM.js +0 -169
- package/lib/src/bundled-translations.es-ES-62eLb3OR.js +0 -169
- package/lib/src/bundled-translations.fr-CA-38Mskv1H.js +0 -169
- package/lib/src/bundled-translations.fr-FR-Ct8Ky13V.js +0 -169
- package/lib/src/bundled-translations.pt-BR-smqmYHq1.js +0 -169
- package/lib/src/bundled-translations.pt-PT-DjM0Ggh1.js +0 -169
|
@@ -97,6 +97,7 @@ export const context = {
|
|
|
97
97
|
mediaSizes: MEDIA_SIZES.sizeThumb,
|
|
98
98
|
},
|
|
99
99
|
isCapturingPreview: false,
|
|
100
|
+
recaptchaSiteKey: undefined,
|
|
100
101
|
};
|
|
101
102
|
export const BScontext = {
|
|
102
103
|
isTemplate: false,
|
|
@@ -119,6 +120,7 @@ export const BScontext = {
|
|
|
119
120
|
mediaSizes: MEDIA_SIZES.sizeThumb,
|
|
120
121
|
},
|
|
121
122
|
isCapturingPreview: false,
|
|
123
|
+
recaptchaSiteKey: undefined,
|
|
122
124
|
};
|
|
123
125
|
export const logoTheme = {
|
|
124
126
|
logoTextColor: {
|
|
@@ -16,8 +16,8 @@ export interface CartForShopRequest {
|
|
|
16
16
|
unitPrice: number;
|
|
17
17
|
}
|
|
18
18
|
declare const _default: {
|
|
19
|
-
addMailSubscriber: (brandPageToken: string, email: string, name?: string | undefined) => Promise<FormResult>;
|
|
20
|
-
submitContactForm: (brandPageToken: string, contentBlockId: string, values: ContactFormField[]) => Promise<FormResult>;
|
|
19
|
+
addMailSubscriber: (brandPageToken: string, email: string, name?: string | undefined, recaptchaToken?: string | undefined) => Promise<FormResult>;
|
|
20
|
+
submitContactForm: (brandPageToken: string, contentBlockId: string, values: ContactFormField[], recaptchaToken?: string | undefined) => Promise<FormResult>;
|
|
21
21
|
getPaymentConfigStatusByPaymentConfigId: (paymentConfigId: string) => Promise<string>;
|
|
22
22
|
getStoreProductsByBrandPageToken: (brandPageToken: string) => Promise<string>;
|
|
23
23
|
createBrandPageCart: (request: {
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
import * as constants from '../constants';
|
|
3
3
|
import * as csrfUtil from '../utils/csrf.util';
|
|
4
|
-
const addMailSubscriber = async (brandPageToken, email, name) => {
|
|
4
|
+
const addMailSubscriber = async (brandPageToken, email, name, recaptchaToken) => {
|
|
5
5
|
try {
|
|
6
6
|
const csrfToken = csrfUtil.getCsrfTokenFromMetaHeader();
|
|
7
7
|
await axios.post(`/api/mailing-lists/${brandPageToken}`, {
|
|
8
8
|
email,
|
|
9
9
|
name,
|
|
10
|
+
recaptchaToken,
|
|
10
11
|
}, {
|
|
11
12
|
headers: {
|
|
12
13
|
'Content-Type': 'application/json',
|
|
@@ -28,12 +29,13 @@ const addMailSubscriber = async (brandPageToken, email, name) => {
|
|
|
28
29
|
};
|
|
29
30
|
}
|
|
30
31
|
};
|
|
31
|
-
const submitContactForm = async (brandPageToken, contentBlockId, values) => {
|
|
32
|
+
const submitContactForm = async (brandPageToken, contentBlockId, values, recaptchaToken) => {
|
|
32
33
|
try {
|
|
33
34
|
const csrfToken = csrfUtil.getCsrfTokenFromMetaHeader();
|
|
34
35
|
const formBody = {
|
|
35
36
|
contentBlockId,
|
|
36
37
|
fields: values,
|
|
38
|
+
recaptchaToken,
|
|
37
39
|
};
|
|
38
40
|
await axios.post(`/api/contact/${brandPageToken}`, formBody, {
|
|
39
41
|
headers: {
|
|
@@ -28,7 +28,16 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
28
28
|
required: false;
|
|
29
29
|
default: undefined;
|
|
30
30
|
};
|
|
31
|
-
}>, {
|
|
31
|
+
}>, {
|
|
32
|
+
recaptcha: {
|
|
33
|
+
isReady: import("vue").ComputedRef<boolean>;
|
|
34
|
+
initialise: (config: import("../../composables/recaptcha.composable").ReCaptchaConfig) => Promise<void>;
|
|
35
|
+
executeAsync: (action: string) => Promise<string | undefined>;
|
|
36
|
+
error: import("vue").ComputedRef<string | undefined>;
|
|
37
|
+
isLoading: import("vue").ComputedRef<boolean>;
|
|
38
|
+
siteKey: import("vue").ComputedRef<string>;
|
|
39
|
+
};
|
|
40
|
+
}, {
|
|
32
41
|
values: FieldValue[];
|
|
33
42
|
hasSubmitted: boolean;
|
|
34
43
|
isSubmitting: boolean;
|
|
@@ -3,8 +3,9 @@ import { FORM_FIELD_TYPES } from '../../models';
|
|
|
3
3
|
import { getEmailValidationError, getMessageValidationError, getNameValidationError, getPhoneValidationError, } from '../../utils';
|
|
4
4
|
import brandPageClient from '../../clients/brand-page.client';
|
|
5
5
|
import { isEmail } from '../../../utils/validator.util';
|
|
6
|
-
import { ALIGN_CARD_CENTER, ALIGN_CARD_CENTER_IMAGE, ALIGN_CENTERED, ALIGN_LEFT_FULL_IMAGE, ALIGN_RIGHT_FULL_IMAGE, DISPLAY_STYLE_COLLAPSED, TEXT_ONLY, } from '../../constants';
|
|
6
|
+
import { ALIGN_CARD_CENTER, ALIGN_CARD_CENTER_IMAGE, ALIGN_CENTERED, ALIGN_LEFT_FULL_IMAGE, ALIGN_RIGHT_FULL_IMAGE, DISPLAY_STYLE_COLLAPSED, RECAPTCHA_ACTION_CONTACT_FORM, TEXT_ONLY, } from '../../constants';
|
|
7
7
|
import { getRenderText } from '../../utils';
|
|
8
|
+
import { useReCaptcha } from '../../composables/recaptcha.composable';
|
|
8
9
|
export default defineComponent({
|
|
9
10
|
props: {
|
|
10
11
|
context: {
|
|
@@ -29,6 +30,12 @@ export default defineComponent({
|
|
|
29
30
|
default: undefined,
|
|
30
31
|
},
|
|
31
32
|
},
|
|
33
|
+
setup() {
|
|
34
|
+
const recaptcha = useReCaptcha();
|
|
35
|
+
return {
|
|
36
|
+
recaptcha,
|
|
37
|
+
};
|
|
38
|
+
},
|
|
32
39
|
data: () => ({
|
|
33
40
|
values: [],
|
|
34
41
|
hasSubmitted: false,
|
|
@@ -136,6 +143,11 @@ export default defineComponent({
|
|
|
136
143
|
field: f,
|
|
137
144
|
}));
|
|
138
145
|
},
|
|
146
|
+
mounted() {
|
|
147
|
+
if (this.context?.recaptchaSiteKey && !this.isPreview && this.recaptcha) {
|
|
148
|
+
this.recaptcha.initialise({ siteKey: this.context.recaptchaSiteKey });
|
|
149
|
+
}
|
|
150
|
+
},
|
|
139
151
|
methods: {
|
|
140
152
|
async submitContactForm() {
|
|
141
153
|
this.validateFormValues();
|
|
@@ -152,12 +164,16 @@ export default defineComponent({
|
|
|
152
164
|
let result;
|
|
153
165
|
this.isSubmitting = true;
|
|
154
166
|
try {
|
|
167
|
+
let recaptchaToken;
|
|
168
|
+
if (this.context?.recaptchaSiteKey && this.recaptcha?.isReady?.value) {
|
|
169
|
+
recaptchaToken = await this.recaptcha.executeAsync(RECAPTCHA_ACTION_CONTACT_FORM);
|
|
170
|
+
}
|
|
155
171
|
result = await brandPageClient.submitContactForm(this.context.brandPageToken, this.viewModel.id, this.values.map((v) => ({
|
|
156
172
|
id: v.field.id,
|
|
157
173
|
name: v.field.name,
|
|
158
174
|
type: v.field.type,
|
|
159
175
|
value: v.value,
|
|
160
|
-
})));
|
|
176
|
+
})), recaptchaToken);
|
|
161
177
|
}
|
|
162
178
|
finally {
|
|
163
179
|
this.isSubmitting = false;
|
|
@@ -21,6 +21,14 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
21
21
|
};
|
|
22
22
|
}>, {
|
|
23
23
|
mailingListTr: (key: any, valuesToInterpolate?: {}) => any;
|
|
24
|
+
recaptcha: {
|
|
25
|
+
isReady: import("vue").ComputedRef<boolean>;
|
|
26
|
+
initialise: (config: import("../../composables/recaptcha.composable").ReCaptchaConfig) => Promise<void>;
|
|
27
|
+
executeAsync: (action: string) => Promise<string | undefined>;
|
|
28
|
+
error: import("vue").ComputedRef<string | undefined>;
|
|
29
|
+
isLoading: import("vue").ComputedRef<boolean>;
|
|
30
|
+
siteKey: import("vue").ComputedRef<string>;
|
|
31
|
+
};
|
|
24
32
|
}, {
|
|
25
33
|
email: string;
|
|
26
34
|
emailError: string | undefined;
|
|
@@ -2,6 +2,8 @@ import { defineComponent } from 'vue';
|
|
|
2
2
|
import brandPageClient from '../../clients/brand-page.client';
|
|
3
3
|
import { getEmailValidationError } from '../../utils';
|
|
4
4
|
import { contentSettingsTr, mailingListTr, } from '../../../composables/useTranslate';
|
|
5
|
+
import { useReCaptcha } from '../../composables/recaptcha.composable';
|
|
6
|
+
import { RECAPTCHA_ACTION_MAILING_LIST } from '../../constants';
|
|
5
7
|
const MAX_NAME_LENGTH = 200;
|
|
6
8
|
export default defineComponent({
|
|
7
9
|
props: {
|
|
@@ -24,8 +26,10 @@ export default defineComponent({
|
|
|
24
26
|
},
|
|
25
27
|
},
|
|
26
28
|
setup() {
|
|
29
|
+
const recaptcha = useReCaptcha();
|
|
27
30
|
return {
|
|
28
31
|
mailingListTr,
|
|
32
|
+
recaptcha,
|
|
29
33
|
};
|
|
30
34
|
},
|
|
31
35
|
data() {
|
|
@@ -42,6 +46,9 @@ export default defineComponent({
|
|
|
42
46
|
},
|
|
43
47
|
mounted() {
|
|
44
48
|
this.show = true;
|
|
49
|
+
if (this.context?.recaptchaSiteKey && !this.isPreview && this.recaptcha) {
|
|
50
|
+
this.recaptcha.initialise({ siteKey: this.context.recaptchaSiteKey });
|
|
51
|
+
}
|
|
45
52
|
},
|
|
46
53
|
computed: {
|
|
47
54
|
hasNameError() {
|
|
@@ -107,14 +114,22 @@ export default defineComponent({
|
|
|
107
114
|
return;
|
|
108
115
|
}
|
|
109
116
|
this.isSubmitting = true;
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
117
|
+
try {
|
|
118
|
+
let recaptchaToken;
|
|
119
|
+
if (this.context?.recaptchaSiteKey && this.recaptcha?.isReady?.value) {
|
|
120
|
+
recaptchaToken = await this.recaptcha.executeAsync(RECAPTCHA_ACTION_MAILING_LIST);
|
|
121
|
+
}
|
|
122
|
+
const result = await brandPageClient.addMailSubscriber(this.brandPageToken, this.email, this.name === '' ? undefined : this.name, recaptchaToken);
|
|
123
|
+
if (!result.success) {
|
|
124
|
+
this.submitError = result.errMessage;
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
this.submitError = undefined;
|
|
128
|
+
this.hasSubscribed = result.success;
|
|
129
|
+
}
|
|
130
|
+
finally {
|
|
131
|
+
this.isSubmitting = false;
|
|
115
132
|
}
|
|
116
|
-
this.submitError = undefined;
|
|
117
|
-
this.hasSubscribed = result.success;
|
|
118
133
|
},
|
|
119
134
|
validateName() {
|
|
120
135
|
if (this.name.trim() === '') {
|
|
@@ -88,7 +88,8 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
88
88
|
scrollToLastContent(): void;
|
|
89
89
|
onPageHeaderContainerClick(): void;
|
|
90
90
|
onPageFooterContainerClick(): void;
|
|
91
|
-
|
|
91
|
+
onSaveContactWidgetClick(): void;
|
|
92
|
+
}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("on-logo-click" | "on-set-preview-styles" | "on-scroll-to-element" | "page-header-container-click" | "page-footer-container-click" | "save-contact-widget-click")[], "on-logo-click" | "on-set-preview-styles" | "on-scroll-to-element" | "page-header-container-click" | "page-footer-container-click" | "save-contact-widget-click", import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
92
93
|
context: {
|
|
93
94
|
type: PropType<BrandPageContext>;
|
|
94
95
|
required: true;
|
|
@@ -138,6 +139,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
138
139
|
"onOn-scroll-to-element"?: ((...args: any[]) => any) | undefined;
|
|
139
140
|
"onPage-header-container-click"?: ((...args: any[]) => any) | undefined;
|
|
140
141
|
"onPage-footer-container-click"?: ((...args: any[]) => any) | undefined;
|
|
142
|
+
"onSave-contact-widget-click"?: ((...args: any[]) => any) | undefined;
|
|
141
143
|
}>, {
|
|
142
144
|
viewport: ViewportsType;
|
|
143
145
|
isMobileDevice: boolean;
|
|
@@ -55,6 +55,7 @@ export default defineComponent({
|
|
|
55
55
|
'on-scroll-to-element',
|
|
56
56
|
'page-header-container-click',
|
|
57
57
|
'page-footer-container-click',
|
|
58
|
+
'save-contact-widget-click',
|
|
58
59
|
],
|
|
59
60
|
setup(props) {
|
|
60
61
|
return {
|
|
@@ -266,10 +267,12 @@ export default defineComponent({
|
|
|
266
267
|
},
|
|
267
268
|
shouldShowSaveContactWidget() {
|
|
268
269
|
try {
|
|
269
|
-
if (this.context.isPreview
|
|
270
|
-
this.context.options?.enableSaveContact === false ||
|
|
271
|
-
!this.context.isBrandContact
|
|
272
|
-
|
|
270
|
+
if ((!this.context.isPreview &&
|
|
271
|
+
this.context.options?.enableSaveContact === false) ||
|
|
272
|
+
!this.context.isBrandContact) {
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
if (this.viewModel.saveContactSettings?.isSavingEnabled === false) {
|
|
273
276
|
return false;
|
|
274
277
|
}
|
|
275
278
|
const brandPageData = { pages: this.context?.pages || [] };
|
|
@@ -355,5 +358,11 @@ export default defineComponent({
|
|
|
355
358
|
}
|
|
356
359
|
this.$emit('page-footer-container-click');
|
|
357
360
|
},
|
|
361
|
+
onSaveContactWidgetClick() {
|
|
362
|
+
if (!this.context.isPreview) {
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
this.$emit('save-contact-widget-click');
|
|
366
|
+
},
|
|
358
367
|
},
|
|
359
368
|
});
|
|
@@ -12,6 +12,7 @@ export declare const context: {
|
|
|
12
12
|
pages?: import("../../../view-models").PageViewModel[] | undefined;
|
|
13
13
|
currentPageSlug?: string | undefined;
|
|
14
14
|
runtimeEnvironment: string;
|
|
15
|
+
recaptchaSiteKey: string | undefined;
|
|
15
16
|
pageTitle: string;
|
|
16
17
|
customDomain: string | undefined;
|
|
17
18
|
brandPageType: "default" | "brandSite" | "brandContact";
|
|
@@ -12,6 +12,7 @@ export declare const context: {
|
|
|
12
12
|
pages?: import("../../../view-models").PageViewModel[] | undefined;
|
|
13
13
|
currentPageSlug?: string | undefined;
|
|
14
14
|
runtimeEnvironment: string;
|
|
15
|
+
recaptchaSiteKey: string | undefined;
|
|
15
16
|
pageTitle: string;
|
|
16
17
|
customDomain: string | undefined;
|
|
17
18
|
brandPageType: "default" | "brandSite" | "brandContact";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
declare global {
|
|
2
|
+
interface Window {
|
|
3
|
+
grecaptcha: {
|
|
4
|
+
enterprise: {
|
|
5
|
+
ready: (callback: () => void) => void;
|
|
6
|
+
execute: (siteKey: string, options: {
|
|
7
|
+
action: string;
|
|
8
|
+
}) => Promise<string>;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export interface ReCaptchaConfig {
|
|
14
|
+
siteKey: string;
|
|
15
|
+
}
|
|
16
|
+
export declare const useReCaptcha: () => {
|
|
17
|
+
isReady: import("vue").ComputedRef<boolean>;
|
|
18
|
+
initialise: (config: ReCaptchaConfig) => Promise<void>;
|
|
19
|
+
executeAsync: (action: string) => Promise<string | undefined>;
|
|
20
|
+
error: import("vue").ComputedRef<string | undefined>;
|
|
21
|
+
isLoading: import("vue").ComputedRef<boolean>;
|
|
22
|
+
siteKey: import("vue").ComputedRef<string>;
|
|
23
|
+
};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { reactive, computed } from 'vue';
|
|
2
|
+
const store = reactive({
|
|
3
|
+
isLoaded: false,
|
|
4
|
+
isLoading: false,
|
|
5
|
+
siteKey: '',
|
|
6
|
+
error: undefined,
|
|
7
|
+
});
|
|
8
|
+
const SCRIPT_ID = 'recaptcha-enterprise-script';
|
|
9
|
+
const isBrowser = () => {
|
|
10
|
+
return typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
11
|
+
};
|
|
12
|
+
const loadScript = (siteKey) => {
|
|
13
|
+
return new Promise((resolve, reject) => {
|
|
14
|
+
if (!isBrowser()) {
|
|
15
|
+
reject(new Error('reCAPTCHA can only be loaded in browser environment'));
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
// Check if script already exists
|
|
19
|
+
const existingScript = document.getElementById(SCRIPT_ID);
|
|
20
|
+
if (existingScript) {
|
|
21
|
+
resolve();
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const script = document.createElement('script');
|
|
25
|
+
script.id = SCRIPT_ID;
|
|
26
|
+
script.src = `https://www.google.com/recaptcha/enterprise.js?render=${siteKey}`;
|
|
27
|
+
script.async = true;
|
|
28
|
+
script.defer = true;
|
|
29
|
+
script.onload = () => {
|
|
30
|
+
resolve();
|
|
31
|
+
};
|
|
32
|
+
script.onerror = () => {
|
|
33
|
+
reject(new Error('Failed to load reCAPTCHA script'));
|
|
34
|
+
};
|
|
35
|
+
document.head.appendChild(script);
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
export const useReCaptcha = () => {
|
|
39
|
+
const isReady = computed(() => store.isLoaded && !store.isLoading);
|
|
40
|
+
/**
|
|
41
|
+
* Initialize reCAPTCHA with the site key.
|
|
42
|
+
* Should be called once when the component mounts.
|
|
43
|
+
*/
|
|
44
|
+
const initialise = async (config) => {
|
|
45
|
+
if (!isBrowser()) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (store.isLoaded || store.isLoading) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (!config.siteKey) {
|
|
52
|
+
store.error = 'reCAPTCHA site key is required';
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
store.siteKey = config.siteKey;
|
|
56
|
+
store.isLoading = true;
|
|
57
|
+
store.error = undefined;
|
|
58
|
+
try {
|
|
59
|
+
await loadScript(config.siteKey);
|
|
60
|
+
store.isLoaded = true;
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
store.error =
|
|
64
|
+
err instanceof Error ? err.message : 'Failed to load reCAPTCHA';
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
store.isLoading = false;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Execute reCAPTCHA and get a token for the specified action.
|
|
72
|
+
* @param action - The action name for reCAPTCHA (e.g., 'CONTACT_FORM_SUBMIT')
|
|
73
|
+
* @returns Promise<string | undefined> - The reCAPTCHA token or undefined if failed
|
|
74
|
+
*/
|
|
75
|
+
const executeAsync = async (action) => {
|
|
76
|
+
if (!isBrowser()) {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
if (!store.isLoaded || !store.siteKey) {
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
return await new Promise((resolve, reject) => {
|
|
84
|
+
window.grecaptcha.enterprise.ready(async () => {
|
|
85
|
+
try {
|
|
86
|
+
const token = await window.grecaptcha.enterprise.execute(store.siteKey, { action });
|
|
87
|
+
resolve(token);
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
reject(err);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
store.error =
|
|
97
|
+
err instanceof Error ? err.message : 'Failed to execute reCAPTCHA';
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
return {
|
|
102
|
+
isReady,
|
|
103
|
+
initialise,
|
|
104
|
+
executeAsync,
|
|
105
|
+
error: computed(() => store.error),
|
|
106
|
+
isLoading: computed(() => store.isLoading),
|
|
107
|
+
siteKey: computed(() => store.siteKey),
|
|
108
|
+
};
|
|
109
|
+
};
|
|
@@ -51,6 +51,9 @@ export declare const STATUS_CODE_CONFLICT = 409;
|
|
|
51
51
|
export declare const MESSAGE_ADD_MAIL_SUBSCRIBER_CONFLICT: () => any;
|
|
52
52
|
export declare const MESSAGE_ADD_MAIL_SUBSCRIBER_FAILED: () => any;
|
|
53
53
|
export declare const MESSAGE_CONTACT_MESSAGE_FAILED: () => any;
|
|
54
|
+
export declare const RECAPTCHA_ACTION_MAILING_LIST = "MAILING_LIST_SUBSCRIBE";
|
|
55
|
+
export declare const RECAPTCHA_ACTION_CONTACT_FORM = "CONTACT_FORM_SUBMIT";
|
|
56
|
+
export declare const RECAPTCHA_MIN_SCORE = 0.5;
|
|
54
57
|
export declare const stripeDefaultStyle: {
|
|
55
58
|
readonly base: {
|
|
56
59
|
readonly color: "#7d8284";
|
|
@@ -61,6 +61,10 @@ export const STATUS_CODE_CONFLICT = 409;
|
|
|
61
61
|
export const MESSAGE_ADD_MAIL_SUBSCRIBER_CONFLICT = () => errorTr('alreadySubscribedError');
|
|
62
62
|
export const MESSAGE_ADD_MAIL_SUBSCRIBER_FAILED = () => errorTr('mailingListError');
|
|
63
63
|
export const MESSAGE_CONTACT_MESSAGE_FAILED = () => errorTr('contactMessageError');
|
|
64
|
+
// reCAPTCHA constants
|
|
65
|
+
export const RECAPTCHA_ACTION_MAILING_LIST = 'MAILING_LIST_SUBSCRIBE';
|
|
66
|
+
export const RECAPTCHA_ACTION_CONTACT_FORM = 'CONTACT_FORM_SUBMIT';
|
|
67
|
+
export const RECAPTCHA_MIN_SCORE = 0.5;
|
|
64
68
|
export const stripeDefaultStyle = {
|
|
65
69
|
base: {
|
|
66
70
|
color: '#7d8284',
|
|
@@ -59,6 +59,8 @@ export interface BrandPageContext {
|
|
|
59
59
|
currentPageSlug?: string;
|
|
60
60
|
runtimeEnvironment: string;
|
|
61
61
|
stripePublishableKey: string | undefined;
|
|
62
|
+
/** reCAPTCHA Enterprise site key for spam protection */
|
|
63
|
+
recaptchaSiteKey: string | undefined;
|
|
62
64
|
pageTitle: string;
|
|
63
65
|
customDomain: string | undefined;
|
|
64
66
|
brandPageType: BrandPageType;
|
|
@@ -8,6 +8,7 @@ export * from './image.util';
|
|
|
8
8
|
export * from './font-loader.util';
|
|
9
9
|
export * from './aspect-ratio.util';
|
|
10
10
|
export * from './context.util';
|
|
11
|
+
export * from './color.util';
|
|
11
12
|
export * from './personalisation.util';
|
|
12
13
|
export * from './migration.util';
|
|
13
14
|
export * from '../../utils/validator.util';
|
|
@@ -8,6 +8,7 @@ export * from './image.util';
|
|
|
8
8
|
export * from './font-loader.util';
|
|
9
9
|
export * from './aspect-ratio.util';
|
|
10
10
|
export * from './context.util';
|
|
11
|
+
export * from './color.util';
|
|
11
12
|
export * from './personalisation.util';
|
|
12
13
|
export * from './migration.util';
|
|
13
14
|
export * from '../../utils/validator.util';
|
|
@@ -196,6 +196,9 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
196
196
|
isVisible: boolean;
|
|
197
197
|
}): void;
|
|
198
198
|
setSelectedTabName(payload: import("../../../lib").SetSelectedTabNamePayload): void;
|
|
199
|
+
setSelectedSettingsSection(payload: {
|
|
200
|
+
sectionName?: string | undefined;
|
|
201
|
+
}): void;
|
|
199
202
|
}>;
|
|
200
203
|
userStore: import("pinia").Store<"brandPageMakerUser", import("../../stores").UserState, {}, {
|
|
201
204
|
setUserState(payload: {
|