@designcrowd/library.brand-page 5.17.3 → 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.
Files changed (113) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-yFg0wq_8.js → CreatedOnBrandCrowd-de-de-C_NzyXvG.js} +1 -1
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-D4sUyR-U.js → CreatedOnBrandCrowd-en-us-DSmpdByg.js} +1 -1
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-CjXHshc0.js → CreatedOnBrandCrowd-es-es-4O9ttd4y.js} +1 -1
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-CtsyncLl.js → CreatedOnBrandCrowd-fr-ca-DDr8rQHb.js} +1 -1
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-CtsyncLl.js → CreatedOnBrandCrowd-fr-fr-DDr8rQHb.js} +1 -1
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-D8Z-gS4q.js → CreatedOnBrandCrowd-pt-br-BUTVQ17i.js} +1 -1
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-D8Z-gS4q.js → CreatedOnBrandCrowd-pt-pt-BUTVQ17i.js} +1 -1
  8. package/lib/src/{CreatedOnDcom-de-de-k7a8-Akd.js → CreatedOnDcom-de-de-thkGl7gg.js} +1 -1
  9. package/lib/src/{CreatedOnDcom-en-us-Bh5mbVcr.js → CreatedOnDcom-en-us-DOgnHkVR.js} +1 -1
  10. package/lib/src/{CreatedOnDcom-es-es-DkEBWtQn.js → CreatedOnDcom-es-es-NyEB16vO.js} +1 -1
  11. package/lib/src/{CreatedOnDcom-fr-ca-DcarvQ1r.js → CreatedOnDcom-fr-ca-Cd6WjWcu.js} +1 -1
  12. package/lib/src/{CreatedOnDcom-fr-fr-Cbe-yOPu.js → CreatedOnDcom-fr-fr-CDKX35U7.js} +1 -1
  13. package/lib/src/{CreatedOnDcom-pt-br-DlWu_Kwc.js → CreatedOnDcom-pt-br-PbJzyRNp.js} +1 -1
  14. package/lib/src/{CreatedOnDcom-pt-pt-DZp9RWfH.js → CreatedOnDcom-pt-pt-tja7jglY.js} +1 -1
  15. package/lib/src/brand-page/clients/brand-page.client.d.ts +2 -1
  16. package/lib/src/brand-page/clients/brand-page.client.js +1 -0
  17. package/lib/src/brand-page/models/payment.model.d.ts +42 -0
  18. package/lib/src/brand-page/models/payment.model.js +9 -0
  19. package/lib/src/brand-page/utils/view-model.util.js +1 -0
  20. package/lib/src/brand-page/view-models.d.ts +1 -0
  21. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +1 -1
  22. package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +1 -0
  23. package/lib/src/brand-page-maker/composables/useEventTracker.d.ts +2 -0
  24. package/lib/src/brand-page-maker/composables/useEventTracker.js +6 -0
  25. package/lib/src/brand-page-maker/constants/config-settings-constant.d.ts +1 -0
  26. package/lib/src/brand-page-maker/constants/config-settings-constant.js +7 -0
  27. package/lib/src/brand-page-maker/models/content-settings.js +1 -0
  28. package/lib/src/bundled-translations-D5A4swr0.js +173 -0
  29. package/lib/src/bundled-translations.de-DE-Bq6H28Hz.js +173 -0
  30. package/lib/src/bundled-translations.es-ES-Bo-UGy51.js +173 -0
  31. package/lib/src/bundled-translations.fr-CA-7GXawEcN.js +173 -0
  32. package/lib/src/bundled-translations.fr-FR-DzVwt2U-.js +173 -0
  33. package/lib/src/bundled-translations.pt-BR-DSZZ-i-B.js +173 -0
  34. package/lib/src/bundled-translations.pt-PT-SNbEX0GM.js +173 -0
  35. package/lib/src/bundles/bundled-translations.de-DE.json +965 -1
  36. package/lib/src/bundles/bundled-translations.es-ES.json +965 -1
  37. package/lib/src/bundles/bundled-translations.fr-CA.json +965 -1
  38. package/lib/src/bundles/bundled-translations.fr-FR.json +965 -1
  39. package/lib/src/bundles/bundled-translations.json +965 -1
  40. package/lib/src/bundles/bundled-translations.pt-BR.json +965 -1
  41. package/lib/src/bundles/bundled-translations.pt-PT.json +965 -1
  42. package/lib/src/composables/useTranslate.d.ts +7 -1
  43. package/lib/src/composables/useTranslate.js +9 -1
  44. package/lib/src/css/library.brand-page-brandCrowd.min.css +33 -14
  45. package/lib/src/css/library.brand-page-brandPage.min.css +33 -14
  46. package/lib/src/css/library.brand-page-designCom.min.css +33 -14
  47. package/lib/src/css/library.brand-page-preview.min.css +33 -14
  48. package/lib/src/index.mjs +88 -87
  49. package/lib/src/{lib-DOfGX3z2.js → lib-DL-13itP.js} +21136 -20938
  50. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts +1 -0
  51. package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +1 -0
  52. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.d.ts +1 -0
  53. package/lib/src/shared/content-settings/components/payment-config-field/payment-toggle-field/PaymentToggleField.mixin.d.ts +13 -1
  54. package/lib/src/shared/content-settings/components/payment-config-field/payment-toggle-field/PaymentToggleField.mixin.js +10 -0
  55. package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.d.ts +2 -1
  56. package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +1 -0
  57. package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +1 -0
  58. package/lib/src/shared/side-bar/components/SideBarTabButton.mixin.d.ts +1 -0
  59. package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +1 -0
  60. package/lib/src/shared/template-settings/components/TemplatesSettings.mixin.d.ts +2 -1
  61. package/package.json +1 -1
  62. package/src/brand-page/clients/brand-page.client.ts +3 -0
  63. package/src/brand-page/components/payment/RequestPaymentStripe.vue +381 -44
  64. package/src/brand-page/components/shop/PaymentModal.vue +7 -1
  65. package/src/brand-page/components/shop/PaymentShippingAddress.vue +297 -0
  66. package/src/brand-page/components/shop/Shop.vue +1 -0
  67. package/src/brand-page/components/shop/i18n/countries.de-DE.json +240 -0
  68. package/src/brand-page/components/shop/i18n/countries.es-ES.json +240 -0
  69. package/src/brand-page/components/shop/i18n/countries.fr-CA.json +240 -0
  70. package/src/brand-page/components/shop/i18n/countries.fr-FR.json +240 -0
  71. package/src/brand-page/components/shop/i18n/countries.json +240 -0
  72. package/src/brand-page/components/shop/i18n/countries.pt-BR.json +240 -0
  73. package/src/brand-page/components/shop/i18n/countries.pt-PT.json +240 -0
  74. package/src/brand-page/components/shop/i18n/payment-shipping-address.de-DE.json +18 -0
  75. package/src/brand-page/components/shop/i18n/payment-shipping-address.es-ES.json +18 -0
  76. package/src/brand-page/components/shop/i18n/payment-shipping-address.fr-CA.json +18 -0
  77. package/src/brand-page/components/shop/i18n/payment-shipping-address.fr-FR.json +18 -0
  78. package/src/brand-page/components/shop/i18n/payment-shipping-address.json +18 -0
  79. package/src/brand-page/components/shop/i18n/payment-shipping-address.pt-BR.json +18 -0
  80. package/src/brand-page/components/shop/i18n/payment-shipping-address.pt-PT.json +18 -0
  81. package/src/brand-page/models/payment.model.ts +24 -0
  82. package/src/brand-page/utils/view-model.util.ts +1 -0
  83. package/src/brand-page/view-models.ts +1 -0
  84. package/src/brand-page-maker/composables/useEventTracker.ts +6 -0
  85. package/src/brand-page-maker/constants/config-settings-constant.ts +8 -0
  86. package/src/brand-page-maker/models/content-settings.ts +1 -0
  87. package/src/bundles/bundled-translations.de-DE.json +965 -1
  88. package/src/bundles/bundled-translations.es-ES.json +965 -1
  89. package/src/bundles/bundled-translations.fr-CA.json +965 -1
  90. package/src/bundles/bundled-translations.fr-FR.json +965 -1
  91. package/src/bundles/bundled-translations.json +965 -1
  92. package/src/bundles/bundled-translations.pt-BR.json +965 -1
  93. package/src/bundles/bundled-translations.pt-PT.json +965 -1
  94. package/src/composables/useTranslate.ts +15 -0
  95. package/src/shared/content-settings/components/content-settings/i18n/content-settings.de-DE.json +3 -1
  96. package/src/shared/content-settings/components/content-settings/i18n/content-settings.es-ES.json +3 -1
  97. package/src/shared/content-settings/components/content-settings/i18n/content-settings.fr-CA.json +3 -1
  98. package/src/shared/content-settings/components/content-settings/i18n/content-settings.fr-FR.json +3 -1
  99. package/src/shared/content-settings/components/content-settings/i18n/content-settings.json +3 -1
  100. package/src/shared/content-settings/components/content-settings/i18n/content-settings.pt-BR.json +3 -1
  101. package/src/shared/content-settings/components/content-settings/i18n/content-settings.pt-PT.json +3 -1
  102. package/src/shared/content-settings/components/payment-config-field/payment-toggle-field/PaymentToggleField.mixin.ts +12 -0
  103. package/src/shared/content-settings/components/payment-config-field/payment-toggle-field/PaymentToggleField.vue +9 -1
  104. package/lib/src/brand-page/components/payment/RequestPaymentStripe.mixin.d.ts +0 -106
  105. package/lib/src/brand-page/components/payment/RequestPaymentStripe.mixin.js +0 -253
  106. package/lib/src/bundled-translations-B6qZE8LU.js +0 -169
  107. package/lib/src/bundled-translations.de-DE-CsU6YsZb.js +0 -169
  108. package/lib/src/bundled-translations.es-ES-unPBdcJx.js +0 -169
  109. package/lib/src/bundled-translations.fr-CA-Dpa2wEtC.js +0 -169
  110. package/lib/src/bundled-translations.fr-FR-BPloaUjN.js +0 -169
  111. package/lib/src/bundled-translations.pt-BR-CFRGdaDO.js +0 -169
  112. package/lib/src/bundled-translations.pt-PT-BHVYCE0K.js +0 -169
  113. package/src/brand-page/components/payment/RequestPaymentStripe.mixin.ts +0 -364
@@ -783,6 +783,7 @@ declare const _default: import("vue").DefineComponent<{}, {
783
783
  toggleLogoBackground(): Promise<any>;
784
784
  }>;
785
785
  eventTracker: {
786
+ sendShippingToggleEvent: (isEnabled: boolean) => void;
786
787
  sendSaveContactEvent: () => void;
787
788
  sendStartForFreeEvent: () => void;
788
789
  sendFooterLinkClickEvent: (linkType: "watermark_logo" | "create_your_website") => void;
@@ -731,6 +731,7 @@ declare const _default: import("vue").DefineComponent<{}, {
731
731
  toggleShouldPlayVideo(): void;
732
732
  }>;
733
733
  bpEventTracker: {
734
+ sendShippingToggleEvent: (isEnabled: boolean) => void;
734
735
  sendSaveContactEvent: () => void;
735
736
  sendStartForFreeEvent: () => void;
736
737
  sendFooterLinkClickEvent: (linkType: "watermark_logo" | "create_your_website") => void;
@@ -475,6 +475,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
475
475
  clearAiTextEditContext(): void;
476
476
  }>;
477
477
  eventTracker: {
478
+ sendShippingToggleEvent: (isEnabled: boolean) => void;
478
479
  sendSaveContactEvent: () => void;
479
480
  sendStartForFreeEvent: () => void;
480
481
  sendFooterLinkClickEvent: (linkType: "watermark_logo" | "create_your_website") => void;
@@ -21,6 +21,11 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
21
21
  type: PropType<RequestPaymentConfig>;
22
22
  required: true;
23
23
  };
24
+ placeholder: {
25
+ type: StringConstructor;
26
+ required: false;
27
+ default: string;
28
+ };
24
29
  }>, {}, {}, {
25
30
  toggleState: {
26
31
  get(): boolean;
@@ -47,7 +52,14 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
47
52
  type: PropType<RequestPaymentConfig>;
48
53
  required: true;
49
54
  };
55
+ placeholder: {
56
+ type: StringConstructor;
57
+ required: false;
58
+ default: string;
59
+ };
50
60
  }>> & Readonly<{
51
61
  "onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
52
- }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
62
+ }>, {
63
+ placeholder: string;
64
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
53
65
  export default _default;
@@ -1,4 +1,5 @@
1
1
  import { defineComponent } from 'vue';
2
+ import { useEventTracker } from '../../../../../brand-page-maker/composables/useEventTracker';
2
3
  export default defineComponent({
3
4
  props: {
4
5
  id: {
@@ -21,6 +22,11 @@ export default defineComponent({
21
22
  type: Object,
22
23
  required: true,
23
24
  },
25
+ placeholder: {
26
+ type: String,
27
+ required: false,
28
+ default: '',
29
+ },
24
30
  },
25
31
  emits: ['update:modelValue'],
26
32
  computed: {
@@ -38,6 +44,10 @@ export default defineComponent({
38
44
  name: this.name,
39
45
  value,
40
46
  };
47
+ if (this.settingsName === 'isShippingEnabled') {
48
+ const eventTracker = useEventTracker();
49
+ eventTracker.sendShippingToggleEvent(newVal);
50
+ }
41
51
  this.$emit('update:modelValue', payload);
42
52
  },
43
53
  },
@@ -208,7 +208,7 @@ declare const _default: import("vue").DefineComponent<{}, {
208
208
  searchTerm: string | undefined;
209
209
  }): void;
210
210
  _setSelectedTab({ tabName }: {
211
- tabName: "all" | "AI" | "categories";
211
+ tabName: "AI" | "all" | "categories";
212
212
  }): void;
213
213
  _setSelectedCategory({ categoryName, }: {
214
214
  categoryName: string | undefined;
@@ -242,6 +242,7 @@ declare const _default: import("vue").DefineComponent<{}, {
242
242
  setupLogoChangeWatcher(): void;
243
243
  }>;
244
244
  eventTracker: {
245
+ sendShippingToggleEvent: (isEnabled: boolean) => void;
245
246
  sendSaveContactEvent: () => void;
246
247
  sendStartForFreeEvent: () => void;
247
248
  sendFooterLinkClickEvent: (linkType: "watermark_logo" | "create_your_website") => void;
@@ -4725,6 +4725,7 @@ declare const _default: import("vue").DefineComponent<{}, {
4725
4725
  onDraggingStart: () => void;
4726
4726
  onDraggingEnd: (ev?: any, routeId?: string, previousParentRouteId?: string) => void;
4727
4727
  eventTracker: {
4728
+ sendShippingToggleEvent: (isEnabled: boolean) => void;
4728
4729
  sendSaveContactEvent: () => void;
4729
4730
  sendStartForFreeEvent: () => void;
4730
4731
  sendFooterLinkClickEvent: (linkType: "watermark_logo" | "create_your_website") => void;
@@ -431,6 +431,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
431
431
  }): Promise<void>;
432
432
  }>;
433
433
  eventTracker: {
434
+ sendShippingToggleEvent: (isEnabled: boolean) => void;
434
435
  sendSaveContactEvent: () => void;
435
436
  sendStartForFreeEvent: () => void;
436
437
  sendFooterLinkClickEvent: (linkType: "watermark_logo" | "create_your_website") => void;
@@ -18,6 +18,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
18
18
  }>;
19
19
  isDesignCom: import("vue").ComputedRef<boolean>;
20
20
  eventTracker: {
21
+ sendShippingToggleEvent: (isEnabled: boolean) => void;
21
22
  sendSaveContactEvent: () => void;
22
23
  sendStartForFreeEvent: () => void;
23
24
  sendFooterLinkClickEvent: (linkType: "watermark_logo" | "create_your_website") => void;
@@ -876,6 +876,7 @@ declare const _default: import("vue").DefineComponent<{}, {
876
876
  removeBackgroundVideo(): void;
877
877
  }>;
878
878
  eventTracker: {
879
+ sendShippingToggleEvent: (isEnabled: boolean) => void;
879
880
  sendSaveContactEvent: () => void;
880
881
  sendStartForFreeEvent: () => void;
881
882
  sendFooterLinkClickEvent: (linkType: "watermark_logo" | "create_your_website") => void;
@@ -489,7 +489,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
489
489
  searchTerm: string | undefined;
490
490
  }): void;
491
491
  _setSelectedTab({ tabName }: {
492
- tabName: "all" | "AI" | "categories";
492
+ tabName: "AI" | "all" | "categories";
493
493
  }): void;
494
494
  _setSelectedCategory({ categoryName, }: {
495
495
  categoryName: string | undefined;
@@ -562,6 +562,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
562
562
  }>;
563
563
  isDesignCom: import("vue").ComputedRef<boolean>;
564
564
  eventTracker: {
565
+ sendShippingToggleEvent: (isEnabled: boolean) => void;
565
566
  sendSaveContactEvent: () => void;
566
567
  sendStartForFreeEvent: () => void;
567
568
  sendFooterLinkClickEvent: (linkType: "watermark_logo" | "create_your_website") => void;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@designcrowd/library.brand-page",
3
3
  "description": "A collection of Maker/Designer applications",
4
- "version": "5.17.3",
4
+ "version": "5.17.4",
5
5
  "author": "Design.com Eng",
6
6
  "license": "UNLICENSED",
7
7
  "type": "module",
@@ -3,6 +3,7 @@ import * as constants from '../constants';
3
3
  import type {
4
4
  CreateCartResult,
5
5
  CreateStripePaymentIntentResponse,
6
+ StripeShippingDetails,
6
7
  } from '../models';
7
8
  import * as csrfUtil from '../utils/csrf.util';
8
9
 
@@ -171,6 +172,7 @@ const createStripePaymentIntent = async (request: {
171
172
  customerEmail: string;
172
173
  customerRequestDetails?: string;
173
174
  customerMessage?: string;
175
+ shippingDetails?: StripeShippingDetails;
174
176
  }): Promise<CreateStripePaymentIntentResponse | null> => {
175
177
  const csrfToken = csrfUtil.getCsrfTokenFromMetaHeader();
176
178
 
@@ -181,6 +183,7 @@ const createStripePaymentIntent = async (request: {
181
183
  customerEmail: request.customerEmail,
182
184
  customerRequestDetails: request.customerRequestDetails,
183
185
  customerMessage: request.customerMessage,
186
+ shipping: request.shippingDetails,
184
187
  },
185
188
  {
186
189
  headers: {
@@ -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 tw-justify-center">
3
+ <div class="tw-relative tw-my-2">
4
4
  <button
5
- class="tw-bg-transparent tw-border-none tw-top-0 tw-left-0 hover:tw-cursor-pointer"
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 v-if="!isShop" class="tw-w-full tw-flex tw-justify-center">
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="cardNumber"
34
- class="tw-border tw-border-solid tw-mb-2 tw-px-4 tw-py-1 tw-mt-3 tw-rounded tw-bg-white"
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-500': !cardNumberElementError,
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="cardExpiry"
49
- class="tw-border tw-border-solid tw-border-grayscale-500 tw-grow tw-mb-3 tw-px-4 tw-py-1 tw-rounded tw-bg-white"
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-500': !cardExpiryElementError,
73
+ 'tw-border-grayscale-300': !cardExpiryElementError,
53
74
  }"
54
75
  />
55
76
  <div
56
- ref="cardCvc"
57
- class="tw-border tw-border-solid tw-border-grayscale-500 tw-grow tw-mb-3 tw-ml-2 tw-px-4 tw-py-1 tw-rounded tw-w-1/4 tw-bg-white"
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-500': !cardCvcElementError,
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 CheckoutStripeMixin from './RequestPaymentStripe.mixin.ts';
141
- import { requestPaymentStripeTr } from '@src/composables/useTranslate';
142
-
143
- export default {
144
- components: {
145
- Icon,
146
- IconStripe,
147
- TextInput,
148
- Loader,
149
- },
150
- mixins: [CheckoutStripeMixin],
151
- methods: {
152
- requestPaymentStripeTr,
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-sm;
495
+ @apply tw-text-xs;
159
496
  color: #f21b3f;
160
497
  }
161
498
  </style>