@designcrowd/library.brand-page 5.17.2 → 5.17.4
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-DVbX019x.js → CreatedOnBrandCrowd-de-de-C_NzyXvG.js} +3 -3
- package/lib/src/{CreatedOnBrandCrowd-en-us-U7ZUILmi.js → CreatedOnBrandCrowd-en-us-DSmpdByg.js} +3 -3
- package/lib/src/{CreatedOnBrandCrowd-es-es-D97zjmv_.js → CreatedOnBrandCrowd-es-es-4O9ttd4y.js} +3 -3
- package/lib/src/{CreatedOnBrandCrowd-fr-fr-BuOAG7-D.js → CreatedOnBrandCrowd-fr-ca-DDr8rQHb.js} +3 -3
- package/lib/src/{CreatedOnBrandCrowd-fr-ca-BuOAG7-D.js → CreatedOnBrandCrowd-fr-fr-DDr8rQHb.js} +3 -3
- package/lib/src/{CreatedOnBrandCrowd-pt-pt-DMTRsNBz.js → CreatedOnBrandCrowd-pt-br-BUTVQ17i.js} +3 -3
- package/lib/src/{CreatedOnBrandCrowd-pt-br-DMTRsNBz.js → CreatedOnBrandCrowd-pt-pt-BUTVQ17i.js} +3 -3
- package/lib/src/{CreatedOnDcom-de-de-B_jbp2ga.js → CreatedOnDcom-de-de-thkGl7gg.js} +3 -3
- package/lib/src/{CreatedOnDcom-en-us-DQQQhn-z.js → CreatedOnDcom-en-us-DOgnHkVR.js} +3 -3
- package/lib/src/{CreatedOnDcom-es-es-q3MzWO6e.js → CreatedOnDcom-es-es-NyEB16vO.js} +3 -3
- package/lib/src/{CreatedOnDcom-fr-ca-Bep30mu7.js → CreatedOnDcom-fr-ca-Cd6WjWcu.js} +3 -3
- package/lib/src/{CreatedOnDcom-fr-fr-DTF8Zzzc.js → CreatedOnDcom-fr-fr-CDKX35U7.js} +3 -3
- package/lib/src/{CreatedOnDcom-pt-br-ByR1GU2L.js → CreatedOnDcom-pt-br-PbJzyRNp.js} +3 -3
- package/lib/src/{CreatedOnDcom-pt-pt-A0L4zTr0.js → CreatedOnDcom-pt-pt-tja7jglY.js} +3 -3
- package/lib/src/brand-page/clients/brand-page.client.d.ts +2 -1
- package/lib/src/brand-page/clients/brand-page.client.js +1 -0
- package/lib/src/brand-page/models/payment.model.d.ts +42 -0
- package/lib/src/brand-page/models/payment.model.js +9 -0
- package/lib/src/brand-page/utils/view-model.util.js +1 -0
- package/lib/src/brand-page/view-models.d.ts +1 -0
- package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +1 -1
- package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +1 -0
- package/lib/src/brand-page-maker/composables/useEventTracker.d.ts +2 -0
- package/lib/src/brand-page-maker/composables/useEventTracker.js +6 -0
- package/lib/src/brand-page-maker/constants/config-settings-constant.d.ts +1 -0
- package/lib/src/brand-page-maker/constants/config-settings-constant.js +7 -0
- package/lib/src/brand-page-maker/models/content-settings.js +1 -0
- package/lib/src/brand-page-maker/validators/section-button.validator.js +4 -1
- package/lib/src/bundled-translations-D5A4swr0.js +173 -0
- package/lib/src/bundled-translations.de-DE-Bq6H28Hz.js +173 -0
- package/lib/src/bundled-translations.es-ES-Bo-UGy51.js +173 -0
- package/lib/src/bundled-translations.fr-CA-7GXawEcN.js +173 -0
- package/lib/src/bundled-translations.fr-FR-DzVwt2U-.js +173 -0
- package/lib/src/bundled-translations.pt-BR-DSZZ-i-B.js +173 -0
- package/lib/src/bundled-translations.pt-PT-SNbEX0GM.js +173 -0
- package/lib/src/bundles/bundled-translations.de-DE.json +965 -1
- package/lib/src/bundles/bundled-translations.es-ES.json +965 -1
- package/lib/src/bundles/bundled-translations.fr-CA.json +965 -1
- package/lib/src/bundles/bundled-translations.fr-FR.json +965 -1
- package/lib/src/bundles/bundled-translations.json +965 -1
- package/lib/src/bundles/bundled-translations.pt-BR.json +965 -1
- package/lib/src/bundles/bundled-translations.pt-PT.json +965 -1
- package/lib/src/composables/useTranslate.d.ts +7 -1
- package/lib/src/composables/useTranslate.js +9 -1
- package/lib/src/css/library.brand-page-brandCrowd.min.css +76 -55
- package/lib/src/css/library.brand-page-brandPage.min.css +77 -57
- package/lib/src/css/library.brand-page-designCom.min.css +76 -55
- package/lib/src/css/library.brand-page-preview.min.css +76 -55
- package/lib/src/index.mjs +88 -87
- package/lib/src/{lib-CvEpWvWA.js → lib-DL-13itP.js} +24124 -23832
- package/lib/src/mockServiceWorker.js +1 -1
- package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts +1 -0
- package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +1 -0
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.d.ts +1 -0
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.js +14 -0
- package/lib/src/shared/content-settings/components/payment-config-field/payment-toggle-field/PaymentToggleField.mixin.d.ts +13 -1
- package/lib/src/shared/content-settings/components/payment-config-field/payment-toggle-field/PaymentToggleField.mixin.js +10 -0
- package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.d.ts +2 -1
- package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +1 -0
- package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +1 -0
- package/lib/src/shared/side-bar/components/SideBarTabButton.mixin.d.ts +1 -0
- package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +1 -0
- package/lib/src/shared/template-settings/components/TemplatesSettings.mixin.d.ts +2 -1
- package/package.json +1 -1
- package/src/brand-page/clients/brand-page.client.ts +3 -0
- package/src/brand-page/components/about-section/AboutSection.vue +7 -1
- package/src/brand-page/components/payment/RequestPaymentStripe.vue +381 -44
- package/src/brand-page/components/shop/PaymentModal.vue +7 -1
- package/src/brand-page/components/shop/PaymentShippingAddress.vue +297 -0
- package/src/brand-page/components/shop/Shop.vue +1 -0
- package/src/brand-page/components/shop/i18n/countries.de-DE.json +240 -0
- package/src/brand-page/components/shop/i18n/countries.es-ES.json +240 -0
- package/src/brand-page/components/shop/i18n/countries.fr-CA.json +240 -0
- package/src/brand-page/components/shop/i18n/countries.fr-FR.json +240 -0
- package/src/brand-page/components/shop/i18n/countries.json +240 -0
- package/src/brand-page/components/shop/i18n/countries.pt-BR.json +240 -0
- package/src/brand-page/components/shop/i18n/countries.pt-PT.json +240 -0
- package/src/brand-page/components/shop/i18n/payment-shipping-address.de-DE.json +18 -0
- package/src/brand-page/components/shop/i18n/payment-shipping-address.es-ES.json +18 -0
- package/src/brand-page/components/shop/i18n/payment-shipping-address.fr-CA.json +18 -0
- package/src/brand-page/components/shop/i18n/payment-shipping-address.fr-FR.json +18 -0
- package/src/brand-page/components/shop/i18n/payment-shipping-address.json +18 -0
- package/src/brand-page/components/shop/i18n/payment-shipping-address.pt-BR.json +18 -0
- package/src/brand-page/components/shop/i18n/payment-shipping-address.pt-PT.json +18 -0
- package/src/brand-page/models/payment.model.ts +24 -0
- package/src/brand-page/utils/view-model.util.ts +1 -0
- package/src/brand-page/view-models.ts +1 -0
- package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.vue +1 -1
- package/src/brand-page-maker/composables/useEventTracker.ts +6 -0
- package/src/brand-page-maker/constants/config-settings-constant.ts +8 -0
- package/src/brand-page-maker/models/content-settings.ts +1 -0
- package/src/brand-page-maker/validators/section-button.validator.ts +5 -1
- package/src/bundles/bundled-translations.de-DE.json +965 -1
- package/src/bundles/bundled-translations.es-ES.json +965 -1
- package/src/bundles/bundled-translations.fr-CA.json +965 -1
- package/src/bundles/bundled-translations.fr-FR.json +965 -1
- package/src/bundles/bundled-translations.json +965 -1
- package/src/bundles/bundled-translations.pt-BR.json +965 -1
- package/src/bundles/bundled-translations.pt-PT.json +965 -1
- package/src/composables/useTranslate.ts +15 -0
- package/src/shared/content-settings/components/content-settings/i18n/content-settings.de-DE.json +3 -1
- package/src/shared/content-settings/components/content-settings/i18n/content-settings.es-ES.json +3 -1
- package/src/shared/content-settings/components/content-settings/i18n/content-settings.fr-CA.json +3 -1
- package/src/shared/content-settings/components/content-settings/i18n/content-settings.fr-FR.json +3 -1
- package/src/shared/content-settings/components/content-settings/i18n/content-settings.json +3 -1
- package/src/shared/content-settings/components/content-settings/i18n/content-settings.pt-BR.json +3 -1
- package/src/shared/content-settings/components/content-settings/i18n/content-settings.pt-PT.json +3 -1
- package/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.ts +17 -0
- package/src/shared/content-settings/components/payment-config-field/payment-toggle-field/PaymentToggleField.mixin.ts +12 -0
- package/src/shared/content-settings/components/payment-config-field/payment-toggle-field/PaymentToggleField.vue +9 -1
- package/lib/src/brand-page/components/payment/RequestPaymentStripe.mixin.d.ts +0 -106
- package/lib/src/brand-page/components/payment/RequestPaymentStripe.mixin.js +0 -253
- package/lib/src/bundled-translations-B6qZE8LU.js +0 -169
- package/lib/src/bundled-translations.de-DE-CsU6YsZb.js +0 -169
- package/lib/src/bundled-translations.es-ES-unPBdcJx.js +0 -169
- package/lib/src/bundled-translations.fr-CA-Dpa2wEtC.js +0 -169
- package/lib/src/bundled-translations.fr-FR-BPloaUjN.js +0 -169
- package/lib/src/bundled-translations.pt-BR-CFRGdaDO.js +0 -169
- package/lib/src/bundled-translations.pt-PT-BHVYCE0K.js +0 -169
- package/src/brand-page/components/payment/RequestPaymentStripe.mixin.ts +0 -364
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div data-component="request-payment-stripe" :style="containerStyle">
|
|
3
|
-
<div class="tw-relative tw-my-2
|
|
3
|
+
<div class="tw-relative tw-my-2">
|
|
4
4
|
<button
|
|
5
|
-
class="tw-bg-transparent tw-border-none tw-
|
|
5
|
+
class="tw-bg-transparent tw-border-none tw-absolute tw-left-0 tw-top-1/2 -tw-translate-y-1/2 hover:tw-cursor-pointer"
|
|
6
6
|
@click="onBackClick"
|
|
7
7
|
>
|
|
8
8
|
<Icon name="chevron-left" size="sm" :style="arrowStyle" />
|
|
9
9
|
</button>
|
|
10
|
-
<div
|
|
10
|
+
<div class="tw-w-full tw-flex tw-justify-center">
|
|
11
11
|
<span class="tw-text-center">
|
|
12
12
|
{{ currencySymbol }}{{ amount }} ({{ currencyCode }})
|
|
13
13
|
{{
|
|
14
|
-
productName
|
|
14
|
+
!isShop && productName
|
|
15
15
|
? requestPaymentStripeTr('forProduct', {
|
|
16
16
|
PRODUCT_NAME: productName,
|
|
17
17
|
})
|
|
@@ -27,14 +27,35 @@
|
|
|
27
27
|
<Loader />
|
|
28
28
|
</div>
|
|
29
29
|
<div v-show="isInitialised">
|
|
30
|
+
<PaymentShippingAddress
|
|
31
|
+
v-if="props.isShippingEnabled"
|
|
32
|
+
v-model="shippingDetails"
|
|
33
|
+
@validation-change="onShippingValidationChange"
|
|
34
|
+
/>
|
|
35
|
+
<p class="tw-font-bold tw-mt-2">
|
|
36
|
+
{{ requestPaymentStripeTr('emailAddress') }}
|
|
37
|
+
</p>
|
|
38
|
+
<!-- Start Email Address -->
|
|
39
|
+
<TextInput
|
|
40
|
+
v-model="emailAddress"
|
|
41
|
+
class="tw-mt-3 tw-mb-2"
|
|
42
|
+
:placeholder="requestPaymentStripeTr('emailAddressPlaceholder')"
|
|
43
|
+
:error="Boolean(emailAddressError)"
|
|
44
|
+
@blur="onEmailAddressEvent"
|
|
45
|
+
@input="onEmailAddressEvent"
|
|
46
|
+
/>
|
|
47
|
+
<p v-if="emailAddressError" class="form-error">
|
|
48
|
+
{{ emailAddressError.message }}
|
|
49
|
+
</p>
|
|
50
|
+
<!-- End Email Address -->
|
|
30
51
|
<p class="tw-font-bold">{{ requestPaymentStripeTr('cardNumber') }}</p>
|
|
31
52
|
<!-- Start Card Number -->
|
|
32
53
|
<div
|
|
33
|
-
ref="
|
|
34
|
-
class="tw-border tw-border-solid tw-
|
|
54
|
+
ref="cardNumberRef"
|
|
55
|
+
class="tw-w-full tw-border tw-border-solid tw-rounded tw-px-4 tw-py-3 tw-text-base tw-bg-white tw-mt-3 tw-mb-2"
|
|
35
56
|
:class="{
|
|
36
57
|
'tw-border-error-500': cardNumberElementError,
|
|
37
|
-
'tw-border-grayscale-
|
|
58
|
+
'tw-border-grayscale-300': !cardNumberElementError,
|
|
38
59
|
}"
|
|
39
60
|
/>
|
|
40
61
|
<div v-if="cardNumberElementError" class="form-error tw-pb-2">
|
|
@@ -45,19 +66,19 @@
|
|
|
45
66
|
<!-- Start Card CVC Expiry -->
|
|
46
67
|
<div class="tw-flex tw-flex-row tw-mt-3">
|
|
47
68
|
<div
|
|
48
|
-
ref="
|
|
49
|
-
class="tw-border tw-border-solid tw-
|
|
69
|
+
ref="cardExpiryRef"
|
|
70
|
+
class="tw-border tw-border-solid tw-rounded tw-px-4 tw-py-3 tw-text-base tw-bg-white tw-grow tw-mb-3"
|
|
50
71
|
:class="{
|
|
51
72
|
'tw-border-error-500': cardExpiryElementError,
|
|
52
|
-
'tw-border-grayscale-
|
|
73
|
+
'tw-border-grayscale-300': !cardExpiryElementError,
|
|
53
74
|
}"
|
|
54
75
|
/>
|
|
55
76
|
<div
|
|
56
|
-
ref="
|
|
57
|
-
class="tw-border tw-border-solid tw-
|
|
77
|
+
ref="cardCvcRef"
|
|
78
|
+
class="tw-border tw-border-solid tw-rounded tw-px-4 tw-py-3 tw-text-base tw-bg-white tw-grow tw-mb-3 tw-ml-2 tw-w-1/4"
|
|
58
79
|
:class="{
|
|
59
80
|
'tw-border-error-500': cardCvcElementError,
|
|
60
|
-
'tw-border-grayscale-
|
|
81
|
+
'tw-border-grayscale-300': !cardCvcElementError,
|
|
61
82
|
}"
|
|
62
83
|
/>
|
|
63
84
|
</div>
|
|
@@ -69,21 +90,6 @@
|
|
|
69
90
|
</div>
|
|
70
91
|
<!-- End Card CVC Expiry -->
|
|
71
92
|
|
|
72
|
-
<p class="tw-font-bold">{{ requestPaymentStripeTr('emailAddress') }}</p>
|
|
73
|
-
<!-- Start Email Address -->
|
|
74
|
-
<TextInput
|
|
75
|
-
v-model="emailAddress"
|
|
76
|
-
class="tw-mt-3 tw-mb-2"
|
|
77
|
-
:placeholder="requestPaymentStripeTr('emailAddressPlaceholder')"
|
|
78
|
-
:error="Boolean(emailAddressError)"
|
|
79
|
-
@blur="onEmailAddressEvent"
|
|
80
|
-
@input="onEmailAddressEvent"
|
|
81
|
-
/>
|
|
82
|
-
<p v-if="emailAddressError" class="form-error">
|
|
83
|
-
{{ emailAddressError.message }}
|
|
84
|
-
</p>
|
|
85
|
-
<!-- End Email Address -->
|
|
86
|
-
|
|
87
93
|
<!-- Start Error Message -->
|
|
88
94
|
<p v-if="submitError" class="form-error tw-mt-2">
|
|
89
95
|
{{ submitError.message }}
|
|
@@ -134,28 +140,359 @@
|
|
|
134
140
|
</div>
|
|
135
141
|
</div>
|
|
136
142
|
</template>
|
|
137
|
-
<script>
|
|
143
|
+
<script setup lang="ts">
|
|
144
|
+
import type { StyleValue } from 'vue';
|
|
145
|
+
import { computed, onMounted, ref } from 'vue';
|
|
138
146
|
import { Icon, TextInput, Loader } from '@designcrowd/fe-shared-lib';
|
|
147
|
+
import validator from 'validator';
|
|
139
148
|
import IconStripe from '../icon/IconStripe.vue';
|
|
140
|
-
import
|
|
141
|
-
import {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
149
|
+
import PaymentShippingAddress from '../shop/PaymentShippingAddress.vue';
|
|
150
|
+
import { debug, debugError } from '../../../utils/debug.util';
|
|
151
|
+
import * as constants from '../../constants';
|
|
152
|
+
import type {
|
|
153
|
+
BrandPagePaymentConfig,
|
|
154
|
+
ButtonStyles,
|
|
155
|
+
CheckoutInformation,
|
|
156
|
+
CreateCartResult,
|
|
157
|
+
StripePaymentIntent,
|
|
158
|
+
StripeShippingDetails,
|
|
159
|
+
} from '../../models';
|
|
160
|
+
import { requestPaymentStripeTr } from '../../../composables/useTranslate';
|
|
161
|
+
import brandPageClient from '../../clients/brand-page.client';
|
|
162
|
+
|
|
163
|
+
declare global {
|
|
164
|
+
interface Window {
|
|
165
|
+
Stripe?: stripe.StripeStatic;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const STRIPE_SCRIPT_URL = 'https://js.stripe.com/v3/';
|
|
170
|
+
const SCRIPT_TAG_NAME = 'SCRIPT';
|
|
171
|
+
|
|
172
|
+
interface Props {
|
|
173
|
+
cart: CreateCartResult<StripePaymentIntent>;
|
|
174
|
+
checkoutInformation: CheckoutInformation;
|
|
175
|
+
buttonStyles: ButtonStyles;
|
|
176
|
+
paymentConfig: BrandPagePaymentConfig;
|
|
177
|
+
stripePublishableKey: string;
|
|
178
|
+
productName?: string;
|
|
179
|
+
isShop?: boolean;
|
|
180
|
+
isShippingEnabled: boolean;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
184
|
+
productName: undefined,
|
|
185
|
+
isShop: false,
|
|
186
|
+
isShippingEnabled: false,
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
const emit = defineEmits<{
|
|
190
|
+
(e: 'go-to-payment-option-selection'): void;
|
|
191
|
+
(e: 'success', payload: { result: unknown }): void;
|
|
192
|
+
}>();
|
|
193
|
+
|
|
194
|
+
const cardNumberRef = ref<HTMLElement | null>(null);
|
|
195
|
+
const cardExpiryRef = ref<HTMLElement | null>(null);
|
|
196
|
+
const cardCvcRef = ref<HTMLElement | null>(null);
|
|
197
|
+
|
|
198
|
+
const cardCvcElement = ref<stripe.elements.Element | undefined>(undefined);
|
|
199
|
+
const cardCvcElementError = ref<stripe.Error | undefined>(undefined);
|
|
200
|
+
const cardExpiryElement = ref<stripe.elements.Element | undefined>(undefined);
|
|
201
|
+
const cardExpiryElementError = ref<stripe.Error | undefined>(undefined);
|
|
202
|
+
const cardNumberElement = ref<stripe.elements.Element | undefined>(undefined);
|
|
203
|
+
const cardNumberElementError = ref<stripe.Error | undefined>(undefined);
|
|
204
|
+
const emailAddress = ref<string | undefined>(undefined);
|
|
205
|
+
const emailAddressError = ref<Error | undefined>(undefined);
|
|
206
|
+
const isBusy = ref(false);
|
|
207
|
+
const isCardCvcValid = ref(false);
|
|
208
|
+
const isCardExpiryValid = ref(false);
|
|
209
|
+
const isCardNumberValid = ref(false);
|
|
210
|
+
const isInitialised = ref(false);
|
|
211
|
+
const stripeInstance = ref<stripe.Stripe | undefined>(undefined);
|
|
212
|
+
const submitButtonMessage = ref('Pay');
|
|
213
|
+
const submitError = ref<Error | stripe.Error | undefined>(undefined);
|
|
214
|
+
|
|
215
|
+
const shippingDetails = ref<StripeShippingDetails>({
|
|
216
|
+
name: '',
|
|
217
|
+
line1: '',
|
|
218
|
+
line2: '',
|
|
219
|
+
city: '',
|
|
220
|
+
state: '',
|
|
221
|
+
postalCode: '',
|
|
222
|
+
country: '',
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
const isShippingValid = ref(false);
|
|
226
|
+
|
|
227
|
+
const amount = computed((): string => {
|
|
228
|
+
return (props.cart.totalAmount / 100).toFixed(2) || '';
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
const currencyCode = computed((): string => {
|
|
232
|
+
return props.paymentConfig?.defaultCurrency || '';
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
const currencySymbol = computed((): string => {
|
|
236
|
+
return props.paymentConfig?.defaultCurrencySymbol || '$';
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
const isStripeElementFormComplete = computed((): boolean => {
|
|
240
|
+
return (
|
|
241
|
+
isCardCvcValid.value && isCardExpiryValid.value && isCardNumberValid.value
|
|
242
|
+
);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
const isSubmitButtonEnabled = computed((): boolean => {
|
|
246
|
+
return (
|
|
247
|
+
isInitialised.value &&
|
|
248
|
+
isStripeElementFormComplete.value &&
|
|
249
|
+
Boolean(emailAddress.value) &&
|
|
250
|
+
!emailAddressError.value &&
|
|
251
|
+
!isBusy.value &&
|
|
252
|
+
(props.isShippingEnabled ? isShippingValid.value : true)
|
|
253
|
+
);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
const arrowStyle = computed((): StyleValue => {
|
|
257
|
+
return {
|
|
258
|
+
color: props.buttonStyles.style?.color,
|
|
259
|
+
} as StyleValue;
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
const payButtonStyle = computed((): StyleValue => {
|
|
263
|
+
if (!props.buttonStyles || !props.buttonStyles.style) {
|
|
264
|
+
return { ...props.buttonStyles } as StyleValue;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return {
|
|
268
|
+
...props.buttonStyles.style,
|
|
269
|
+
color: props.buttonStyles.style.backgroundColor,
|
|
270
|
+
backgroundColor: props.buttonStyles.style.color,
|
|
271
|
+
} as StyleValue;
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
const containerStyle = computed((): StyleValue => {
|
|
275
|
+
const buttonStyle = { ...props.buttonStyles?.style };
|
|
276
|
+
|
|
277
|
+
return {
|
|
278
|
+
color: buttonStyle.color,
|
|
279
|
+
} as StyleValue;
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
const initialiseStripeScript = (): void => {
|
|
283
|
+
debug('initialiseStripeScript: start');
|
|
284
|
+
|
|
285
|
+
const stripeScript = Array.from(document.head.children).find(
|
|
286
|
+
(child): child is HTMLScriptElement => {
|
|
287
|
+
return (
|
|
288
|
+
child.tagName.toUpperCase() === SCRIPT_TAG_NAME &&
|
|
289
|
+
child.hasAttribute('src') &&
|
|
290
|
+
child.getAttribute('src') === STRIPE_SCRIPT_URL
|
|
291
|
+
);
|
|
292
|
+
},
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
if (stripeScript) {
|
|
296
|
+
debug('initialiseStripeScript: script exists');
|
|
297
|
+
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const scriptElement = document.createElement(
|
|
302
|
+
SCRIPT_TAG_NAME,
|
|
303
|
+
) as HTMLScriptElement;
|
|
304
|
+
|
|
305
|
+
scriptElement.setAttribute('src', STRIPE_SCRIPT_URL);
|
|
306
|
+
scriptElement.setAttribute('async', '');
|
|
307
|
+
scriptElement.setAttribute('defer', '');
|
|
308
|
+
|
|
309
|
+
document.head.appendChild(scriptElement);
|
|
310
|
+
|
|
311
|
+
debug('initialiseStripeScript: script injected');
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
const initStripeElements = (): void => {
|
|
315
|
+
if (!props.stripePublishableKey) {
|
|
316
|
+
debugError('initStripeElements: stripe publishable key undefined');
|
|
317
|
+
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (typeof window.Stripe !== 'function') {
|
|
322
|
+
setTimeout(() => {
|
|
323
|
+
debug('initStripeElements: waiting for stripe script');
|
|
324
|
+
initStripeElements();
|
|
325
|
+
}, 250);
|
|
326
|
+
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
debug('initStripeElements: start');
|
|
331
|
+
|
|
332
|
+
try {
|
|
333
|
+
stripeInstance.value = window.Stripe(props.stripePublishableKey, {
|
|
334
|
+
stripeAccount: props.cart.paymentProviderExternalId,
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
const stripeElements = stripeInstance.value.elements();
|
|
338
|
+
|
|
339
|
+
cardNumberElement.value = stripeElements.create('cardNumber', {
|
|
340
|
+
style: constants.stripeDefaultStyle,
|
|
341
|
+
placeholder: 'Credit Card Number',
|
|
342
|
+
});
|
|
343
|
+
if (cardNumberRef.value) {
|
|
344
|
+
cardNumberElement.value.mount(cardNumberRef.value);
|
|
345
|
+
}
|
|
346
|
+
cardNumberElement.value.addEventListener('change', onStripeElementChange);
|
|
347
|
+
|
|
348
|
+
cardExpiryElement.value = stripeElements.create('cardExpiry', {
|
|
349
|
+
style: constants.stripeDefaultStyle,
|
|
350
|
+
placeholder: 'Expiry',
|
|
351
|
+
});
|
|
352
|
+
if (cardExpiryRef.value) {
|
|
353
|
+
cardExpiryElement.value.mount(cardExpiryRef.value);
|
|
354
|
+
}
|
|
355
|
+
cardExpiryElement.value.addEventListener('change', onStripeElementChange);
|
|
356
|
+
|
|
357
|
+
cardCvcElement.value = stripeElements.create('cardCvc', {
|
|
358
|
+
style: constants.stripeDefaultStyle,
|
|
359
|
+
placeholder: 'CVV',
|
|
360
|
+
});
|
|
361
|
+
if (cardCvcRef.value) {
|
|
362
|
+
cardCvcElement.value.mount(cardCvcRef.value);
|
|
363
|
+
}
|
|
364
|
+
cardCvcElement.value.addEventListener('change', onStripeElementChange);
|
|
365
|
+
|
|
366
|
+
isInitialised.value = true;
|
|
367
|
+
} catch (err) {
|
|
368
|
+
console.error(err);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
debug('initStripeElements: end');
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
const onBackClick = (): void => {
|
|
375
|
+
emit('go-to-payment-option-selection');
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
const onEmailAddressEvent = (): void => {
|
|
379
|
+
validateEmailAddress();
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
const onStripeElementChange = (
|
|
383
|
+
response?: stripe.elements.ElementChangeResponse,
|
|
384
|
+
): void => {
|
|
385
|
+
if (!response) {
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
switch (response.elementType) {
|
|
390
|
+
case 'cardCvc':
|
|
391
|
+
isCardCvcValid.value = response.complete;
|
|
392
|
+
cardCvcElementError.value = response.error;
|
|
393
|
+
break;
|
|
394
|
+
case 'cardExpiry':
|
|
395
|
+
isCardExpiryValid.value = response.complete;
|
|
396
|
+
cardExpiryElementError.value = response.error;
|
|
397
|
+
break;
|
|
398
|
+
case 'cardNumber':
|
|
399
|
+
isCardNumberValid.value = response.complete;
|
|
400
|
+
cardNumberElementError.value = response.error;
|
|
401
|
+
break;
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
const onSubmitPaymentClick = async (): Promise<void> => {
|
|
406
|
+
if (
|
|
407
|
+
!cardNumberElement.value ||
|
|
408
|
+
!isSubmitButtonEnabled.value ||
|
|
409
|
+
!stripeInstance.value ||
|
|
410
|
+
!props.stripePublishableKey ||
|
|
411
|
+
!emailAddress.value
|
|
412
|
+
) {
|
|
413
|
+
debugError('onSubmitPaymentClick: invalid operation');
|
|
414
|
+
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
isBusy.value = true;
|
|
419
|
+
|
|
420
|
+
try {
|
|
421
|
+
const paymentIntentResponse =
|
|
422
|
+
await brandPageClient.createStripePaymentIntent({
|
|
423
|
+
cartId: props.cart.cartId,
|
|
424
|
+
customerEmail: emailAddress.value,
|
|
425
|
+
customerRequestDetails:
|
|
426
|
+
props.checkoutInformation.customerRequestDetails,
|
|
427
|
+
customerMessage: props.checkoutInformation.customerMessage,
|
|
428
|
+
shippingDetails:
|
|
429
|
+
props.isShop && props.isShippingEnabled
|
|
430
|
+
? shippingDetails.value
|
|
431
|
+
: undefined,
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
if (!paymentIntentResponse) {
|
|
435
|
+
submitError.value = new Error(
|
|
436
|
+
'Unable to create payment intent. Please try again.',
|
|
437
|
+
);
|
|
438
|
+
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const confirmCardPaymentResult =
|
|
443
|
+
await stripeInstance.value.confirmCardPayment(
|
|
444
|
+
paymentIntentResponse.paymentIntent.client_secret,
|
|
445
|
+
{
|
|
446
|
+
payment_method: {
|
|
447
|
+
card: cardNumberElement.value,
|
|
448
|
+
},
|
|
449
|
+
},
|
|
450
|
+
);
|
|
451
|
+
|
|
452
|
+
if (confirmCardPaymentResult.error) {
|
|
453
|
+
debugError(confirmCardPaymentResult.error);
|
|
454
|
+
submitError.value = confirmCardPaymentResult.error;
|
|
455
|
+
} else {
|
|
456
|
+
debug('onSubmitPaymentClick: payment intent success');
|
|
457
|
+
emit('success', { result: confirmCardPaymentResult });
|
|
458
|
+
}
|
|
459
|
+
} finally {
|
|
460
|
+
isBusy.value = false;
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
|
|
464
|
+
const validateEmailAddress = (): void => {
|
|
465
|
+
if (!emailAddress.value) {
|
|
466
|
+
emailAddressError.value = new Error(
|
|
467
|
+
requestPaymentStripeTr('invalidEmailMessage'),
|
|
468
|
+
);
|
|
469
|
+
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
if (!validator.isEmail(emailAddress.value)) {
|
|
474
|
+
emailAddressError.value = new Error(
|
|
475
|
+
requestPaymentStripeTr('invalidEmailMessage'),
|
|
476
|
+
);
|
|
477
|
+
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
emailAddressError.value = undefined;
|
|
154
482
|
};
|
|
483
|
+
|
|
484
|
+
const onShippingValidationChange = (isValid: boolean): void => {
|
|
485
|
+
isShippingValid.value = isValid;
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
onMounted(() => {
|
|
489
|
+
initialiseStripeScript();
|
|
490
|
+
initStripeElements();
|
|
491
|
+
});
|
|
155
492
|
</script>
|
|
156
493
|
<style scoped>
|
|
157
494
|
.form-error {
|
|
158
|
-
@apply tw-text-
|
|
495
|
+
@apply tw-text-xs;
|
|
159
496
|
color: #f21b3f;
|
|
160
497
|
}
|
|
161
498
|
</style>
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
:stripe-publishable-key="context.stripePublishableKey!"
|
|
36
36
|
:product-name="productName"
|
|
37
37
|
:is-shop="true"
|
|
38
|
+
:is-shipping-enabled="props.isShippingEnabled"
|
|
38
39
|
@go-to-payment-option-selection="onGoToCartSelection"
|
|
39
40
|
@success="onRequestPaymentStripeSuccess"
|
|
40
41
|
/>
|
|
@@ -114,7 +115,7 @@
|
|
|
114
115
|
<script setup lang="ts">
|
|
115
116
|
import { Modal, Button, Loader } from '@designcrowd/fe-shared-lib';
|
|
116
117
|
import { useCartStore } from '@shared/ecommerce-settings/store/cart-settings-store';
|
|
117
|
-
import { computed, reactive, onMounted } from 'vue';
|
|
118
|
+
import { computed, reactive, ref, onMounted } from 'vue';
|
|
118
119
|
import IconStripe from '../icon/IconStripe.vue';
|
|
119
120
|
import RequestPaymentStripe from '../payment/RequestPaymentStripe.vue';
|
|
120
121
|
import TextWrapper from '../text-wrapper/TextWrapper.vue';
|
|
@@ -127,6 +128,7 @@ import type {
|
|
|
127
128
|
BrandPagePaymentConfig,
|
|
128
129
|
TextStyleDeclaration,
|
|
129
130
|
StripePaymentIntent,
|
|
131
|
+
StripeShippingDetails,
|
|
130
132
|
} from '@brand-page/models';
|
|
131
133
|
import { paymentProviders } from '@brand-page/constants';
|
|
132
134
|
import raygunUtil from '@brand-page/utils/raygun.util';
|
|
@@ -150,10 +152,12 @@ interface Props {
|
|
|
150
152
|
shopPaymentConfig: BrandPagePaymentConfig;
|
|
151
153
|
descriptionStyle: TextStyleDeclaration | undefined;
|
|
152
154
|
successMessage: string;
|
|
155
|
+
isShippingEnabled: boolean;
|
|
153
156
|
}
|
|
154
157
|
|
|
155
158
|
const props = withDefaults(defineProps<Props>(), {
|
|
156
159
|
isVisible: true,
|
|
160
|
+
isShippingEnabled: false,
|
|
157
161
|
});
|
|
158
162
|
|
|
159
163
|
const uniformDescriptionStyle = computed<TextStyleDeclaration>(() => ({
|
|
@@ -169,6 +173,8 @@ const data = reactive({
|
|
|
169
173
|
state: 'creating-cart' as State,
|
|
170
174
|
});
|
|
171
175
|
|
|
176
|
+
const customerEmail = ref('');
|
|
177
|
+
|
|
172
178
|
const emit = defineEmits(['on-close', 'on-back']);
|
|
173
179
|
|
|
174
180
|
const onClose = () => {
|