@rebilly/instruments 3.12.3-beta.0 → 3.13.2-beta.0

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 (84) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +43 -66
  3. package/dist/index.min.js +43 -66
  4. package/package.json +3 -6
  5. package/src/functions/destroy.js +8 -2
  6. package/src/functions/mount/fetch-data.js +9 -2
  7. package/src/functions/mount/index.js +15 -10
  8. package/src/functions/mount/mount.spec.js +10 -11
  9. package/src/functions/mount/setup-framepay-theme.js +30 -72
  10. package/src/functions/mount/setup-options.js +2 -2
  11. package/src/functions/mount/{setup-styles.js → setup-styles-vars.js} +9 -7
  12. package/src/functions/purchase.js +2 -5
  13. package/src/functions/setup.js +3 -6
  14. package/src/functions/show.js +2 -2
  15. package/src/functions/show.spec.js +4 -4
  16. package/src/functions/update.spec.js +4 -3
  17. package/src/instance.js +4 -1
  18. package/src/loader/index.js +57 -33
  19. package/src/storefront/index.js +2 -5
  20. package/src/storefront/payment-instruments.js +7 -0
  21. package/src/style/base/__snapshots__/theme.spec.js.snap +136 -220
  22. package/src/style/base/default-theme.js +187 -14
  23. package/src/style/base/index.js +487 -79
  24. package/src/style/base/theme.js +3 -4
  25. package/src/style/base/theme.spec.js +2 -3
  26. package/src/style/index.js +4 -24
  27. package/src/style/utils/color-values.js +1 -1
  28. package/src/style/utils/minifyCss.js +14 -0
  29. package/src/views/common/iframe/base-iframe.js +3 -2
  30. package/src/views/common/iframe/event-listeners.js +12 -9
  31. package/src/views/common/iframe/method-iframe.js +3 -1
  32. package/src/views/common/iframe/modal-iframe.js +4 -2
  33. package/src/views/common/iframe/view-iframe.js +3 -1
  34. package/src/views/confirmation.js +12 -7
  35. package/src/views/errors.js +95 -0
  36. package/src/views/method-selector/express-methods.js +51 -0
  37. package/src/views/method-selector/generate-framepay-config.js +54 -0
  38. package/src/views/method-selector/generate-framepay-config.spec.js +195 -0
  39. package/src/views/method-selector/get-payment-methods.js +0 -1
  40. package/src/views/method-selector/index.js +45 -58
  41. package/src/views/method-selector/method-selector.spec.js +1 -1
  42. package/src/views/method-selector/mount-express-methods.js +66 -26
  43. package/src/views/modal.js +1 -1
  44. package/src/views/result.js +3 -3
  45. package/src/views/summary.js +24 -190
  46. package/tests/mocks/storefront-api-mock.js +48 -27
  47. package/src/style/browserslist.js +0 -1
  48. package/src/style/components/accordion.js +0 -140
  49. package/src/style/components/address.js +0 -55
  50. package/src/style/components/button.js +0 -117
  51. package/src/style/components/divider.js +0 -39
  52. package/src/style/components/forms/checkbox.js +0 -75
  53. package/src/style/components/forms/field.js +0 -56
  54. package/src/style/components/forms/form.js +0 -18
  55. package/src/style/components/forms/input.js +0 -77
  56. package/src/style/components/forms/label.js +0 -55
  57. package/src/style/components/forms/radio.js +0 -80
  58. package/src/style/components/forms/select.js +0 -86
  59. package/src/style/components/forms/validation.js +0 -72
  60. package/src/style/components/icons.js +0 -13
  61. package/src/style/components/index.js +0 -39
  62. package/src/style/components/loader.js +0 -41
  63. package/src/style/components/methods.js +0 -97
  64. package/src/style/components/overlay.js +0 -24
  65. package/src/style/helpers/index.js +0 -54
  66. package/src/style/payment-instruments/content.js +0 -8
  67. package/src/style/payment-instruments/index.js +0 -14
  68. package/src/style/payment-instruments/payment-card.js +0 -27
  69. package/src/style/payment-instruments/payment-instrument-list.js +0 -44
  70. package/src/style/payment-instruments/payment-instrument.js +0 -55
  71. package/src/style/utils/remove-empty-null.js +0 -10
  72. package/src/style/vendor/framepay.js +0 -28
  73. package/src/style/vendor/postmate.js +0 -18
  74. package/src/style/views/confirmation.js +0 -26
  75. package/src/style/views/index.js +0 -16
  76. package/src/style/views/method-selector.js +0 -11
  77. package/src/style/views/modal.js +0 -91
  78. package/src/style/views/result.js +0 -52
  79. package/src/style/views/summary.js +0 -118
  80. package/src/views/__snapshots__/summary.spec.js.snap +0 -246
  81. package/src/views/method-selector/express-methods/apple-pay.js +0 -92
  82. package/src/views/method-selector/express-methods/index.js +0 -25
  83. package/src/views/method-selector/mount-methods.js +0 -178
  84. package/src/views/summary.spec.js +0 -145
@@ -1,5 +1,6 @@
1
1
  import camelCase from 'lodash.camelcase';
2
2
  import Events from '../../../events';
3
+ import { showError } from '../../errors';
3
4
 
4
5
  export function dispatchRebillyInsturmentEventHandler(iframe) {
5
6
  iframe.component.on(`${iframe.name}-dispatch`, ({ event, detail }) => {
@@ -13,15 +14,13 @@ export function resizeComponentHandler(iframe) {
13
14
  });
14
15
  }
15
16
 
16
- export function stopLoaderHandler(iframe, data = { section: 'form' }) {
17
- const iframeLoader = iframe.container.querySelectorAll('.rebilly-instruments-loader.is-active');
18
-
19
- if (iframeLoader && iframeLoader.length) {
20
- iframeLoader.forEach(loader => loader.classList.remove('is-active'));
21
- }
22
-
23
- iframe.component.on(`${iframe.name}-stop-loading`, (id = null) => {
24
- data.loader?.stopLoading({ section: data.section, id: id || data.id });
17
+ export function stopLoaderHandler(iframe, data) {
18
+ iframe.component.on(`${iframe.name}-stop-loading`, (id) => {
19
+ let {section} = data;
20
+ if (!section) {
21
+ section = id.includes('summary') ? 'summary' : 'form';
22
+ }
23
+ data.loader?.stopLoading({ section, id });
25
24
  });
26
25
  }
27
26
 
@@ -41,3 +40,7 @@ export function displayOverlay(iframe) {
41
40
  }
42
41
  });
43
42
  }
43
+
44
+ export function showErrorHandler(iframe) {
45
+ iframe.component.on(`${iframe.name}-show-error`, showError);
46
+ }
@@ -3,7 +3,8 @@ import {
3
3
  dispatchRebillyInsturmentEventHandler,
4
4
  resizeComponentHandler,
5
5
  stopLoaderHandler,
6
- displayOverlay
6
+ displayOverlay,
7
+ showErrorHandler
7
8
  } from './event-listeners';
8
9
 
9
10
  export class MethodIframe extends BaseIframe {
@@ -19,5 +20,6 @@ export class MethodIframe extends BaseIframe {
19
20
  id
20
21
  });
21
22
  displayOverlay(this);
23
+ showErrorHandler(this);
22
24
  }
23
25
  }
@@ -3,7 +3,8 @@ import {
3
3
  dispatchRebillyInsturmentEventHandler,
4
4
  resizeComponentHandler,
5
5
  changeIframeSrcHandler,
6
- stopLoaderHandler
6
+ stopLoaderHandler,
7
+ showErrorHandler
7
8
  } from './event-listeners';
8
9
 
9
10
  export class ModalIframe extends BaseIframe {
@@ -18,8 +19,9 @@ export class ModalIframe extends BaseIframe {
18
19
  stopLoaderHandler(this, {
19
20
  loader,
20
21
  section: 'modal',
21
- id: 'modal-content'
22
+ id: this.name
22
23
  });
24
+ showErrorHandler(this);
23
25
 
24
26
  // Close modal via postmate
25
27
  this.component.on(`${this.name}-close`, (...args) => {
@@ -2,7 +2,8 @@ import BaseIframe from './base-iframe';
2
2
  import {
3
3
  dispatchRebillyInsturmentEventHandler,
4
4
  resizeComponentHandler,
5
- stopLoaderHandler
5
+ stopLoaderHandler,
6
+ showErrorHandler,
6
7
  } from './event-listeners';
7
8
 
8
9
  export class ViewIframe extends BaseIframe {
@@ -14,5 +15,6 @@ export class ViewIframe extends BaseIframe {
14
15
  dispatchRebillyInsturmentEventHandler(this);
15
16
  resizeComponentHandler(this);
16
17
  stopLoaderHandler(this, { loader });
18
+ showErrorHandler(this);
17
19
  }
18
20
  }
@@ -1,7 +1,6 @@
1
1
  import { purchase } from '../functions/purchase';
2
2
  import { setup } from '../functions/setup';
3
3
  import { ViewIframe } from './common/iframe';
4
- import { replaceContent } from './common/render-utilities';
5
4
  import { updateMethodSelector } from './method-selector';
6
5
  import { updateSummary } from './summary';
7
6
 
@@ -16,9 +15,14 @@ export async function mountConfirmation({ payload: instrument, state }) {
16
15
  updateSummary({ state, instrument });
17
16
  }
18
17
 
19
- replaceContent(state.form, baseConfirmationHTML);
18
+ const contentElement = state.form.querySelector('.rebilly-instruments-content');
19
+ contentElement.insertAdjacentHTML('afterend', baseConfirmationHTML);
20
20
 
21
- state.loader.startLoading({ id: 'confirmation' });
21
+ const methodSelectorElement = state.form.querySelector('.rebilly-instruments-method-selector');
22
+ methodSelectorElement.style.visibility = 'hidden';
23
+ methodSelectorElement.style.height = '0px';
24
+
25
+ state.loader.startLoading({ id: 'rebilly-instruments-confirmation' });
22
26
 
23
27
  const container = document.querySelector('.rebilly-instruments-confirmation');
24
28
 
@@ -27,7 +31,7 @@ export async function mountConfirmation({ payload: instrument, state }) {
27
31
  const model = {
28
32
  options: state.options,
29
33
  data: state.data.toPostmatesModel(),
30
- mainStyle: state.mainStyle,
34
+ mainStyleVars: state.mainStyleVars,
31
35
  instrument
32
36
  };
33
37
  const name = 'rebilly-instruments-confirmation';
@@ -50,7 +54,7 @@ export async function mountConfirmation({ payload: instrument, state }) {
50
54
  });
51
55
 
52
56
  iframe.component.on('choose-another-method', () => {
53
- state.iframeComponents = state.iframeComponents.filter((item) => {
57
+ state.iframeComponents.form = state.iframeComponents.form.filter((item) => {
54
58
  if (item.name === iframe.name) {
55
59
  item.destroy();
56
60
  return false;
@@ -60,8 +64,9 @@ export async function mountConfirmation({ payload: instrument, state }) {
60
64
  if (state.data.isPurchase) {
61
65
  updateSummary({ state });
62
66
  }
63
- updateMethodSelector({ state, mainStyle: state.mainStyle });
67
+ updateMethodSelector({ state, mainStyleVars: state.mainStyleVars });
68
+ state.form.querySelector('.rebilly-instruments-confirmation').remove();
64
69
  });
65
70
 
66
- state.iframeComponents.push(iframe);
71
+ state.iframeComponents.form.push(iframe);
67
72
  }
@@ -0,0 +1,95 @@
1
+ const errorTemplate = (error) => {
2
+ const title = 'Error';
3
+
4
+ function displayString(message = null) {
5
+ if (message === null) {
6
+ message = 'An unexpected error occurred';
7
+
8
+ if (typeof error === 'string') {
9
+ message = error;
10
+ }
11
+
12
+ if (error.error) {
13
+ message = error.error;
14
+ }
15
+
16
+ if (error.message) {
17
+ message = error.message;
18
+ }
19
+ }
20
+
21
+ return `<p class="rebilly-instruments-error-card-message">${message}</p>`;
22
+ }
23
+
24
+ function displayList() {
25
+ function displayDetail(detail) {
26
+ let detailMessage = detail;
27
+ if (detail['data-rebilly']) {
28
+ detailMessage = `"${detail['data-rebilly']}" ${detail.error}`
29
+ }
30
+ return detailMessage;
31
+ }
32
+
33
+ if (error.details.length > 1) {
34
+ return `<ul class="rebilly-instruments-error-card-details">
35
+ ${error.details.map(detail => `<li>${displayDetail(detail)}</li>`).join('')}
36
+ </ul>`
37
+ }
38
+
39
+ return displayString(displayDetail(error.details[0]));
40
+ }
41
+
42
+ return `<div class="rebilly-instruments-error-card">
43
+ <header class="rebilly-instruments-error-card-header">
44
+ <p class="rebilly-instruments-error-card-title">${title}</p>
45
+ <button class="rebilly-instruments-error-card-close-button">
46
+ <svg class="rebilly-instruments-icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
47
+ <path d="M12 10.5858l2.8284-2.8284c.3906-.3906 1.0237-.3906 1.4142 0 .3906.3905.3906 1.0236 0 1.4142L13.4142 12l2.8284 2.8284c.3906.3906.3906 1.0237 0 1.4142-.3905.3906-1.0236.3906-1.4142 0L12 13.4142l-2.8284 2.8284c-.3906.3906-1.0237.3906-1.4142 0-.3906-.3905-.3906-1.0236 0-1.4142L10.5858 12 7.7574 9.1716c-.3906-.3906-.3906-1.0237 0-1.4142.3905-.3906 1.0236-.3906 1.4142 0L12 10.5858z" fill-rule="nonzero"/>
48
+ </svg>
49
+ </button>
50
+ </header>
51
+ ${error.details ? displayList() : displayString()}
52
+ </div>`
53
+ };
54
+
55
+ export function clearError() {
56
+ const errorContainer = document.querySelector('#rebilly-instruments-error');
57
+ if (!errorContainer) return ;
58
+
59
+ errorContainer.innerHTML = '';
60
+ }
61
+
62
+ export function showError(error) {
63
+ const errorContainer = document.querySelector('#rebilly-instruments-error');
64
+ if (!errorContainer) return ;
65
+
66
+ errorContainer.innerHTML = errorTemplate(error);
67
+
68
+ const closeButton = document.querySelector('.rebilly-instruments-error-card-close-button');
69
+ closeButton.addEventListener('click', clearError);
70
+
71
+ function clickOutsideError(e) {
72
+ if (errorContainer.contains(e.target)) return;
73
+
74
+ window.removeEventListener('click', clickOutsideError, false);
75
+ clearError();
76
+ }
77
+
78
+ function windowBlur() {
79
+ setTimeout(() => {
80
+ if (document.activeElement.tagName === 'IFRAME') {
81
+ window.removeEventListener('click', windowBlur, false);
82
+ clearError();
83
+ }
84
+ });
85
+ }
86
+
87
+ window.addEventListener('click', clickOutsideError);
88
+ window.addEventListener('blur', windowBlur, { once: true });
89
+
90
+ errorContainer.scrollIntoView({behavior: 'smooth', block: 'end', inline: 'nearest'});
91
+ console.error('Rebilly Instruments Error', error);
92
+
93
+ // Must focus to ensure window blur event will trigger
94
+ window.focus();
95
+ }
@@ -0,0 +1,51 @@
1
+ export default function mountExpressMethod({
2
+ state,
3
+ id
4
+ }) {
5
+ const {Rebilly} = window;
6
+ const container = document.querySelector(`.rebilly-instruments-${id}-method`);
7
+
8
+ // Hack: The correct way to do this is to accept the options via the framepay package
9
+ // Will remove once these options are added to framepay
10
+ function updateApplePayStyling() {
11
+ const applePayButton = document.querySelector('#rebilly-apple-pay-button');
12
+ const {
13
+ applePayDisplayOptions: {
14
+ buttonHeight
15
+ }
16
+ } = state.options.digitalWallet.applePay;
17
+
18
+ applePayButton.style.margin = '0px';
19
+ applePayButton.style.width = '100%';
20
+ applePayButton.style.height = buttonHeight;
21
+ applePayButton.style.cursor = 'pointer';
22
+ }
23
+
24
+ function mountButton() {
25
+ if(!container.children.length) {
26
+ const rebillyMountFunction = {
27
+ 'google-pay': 'googlePay',
28
+ 'pay-pal-billing-agreement': 'paypal',
29
+ 'apple-pay': 'applePay'
30
+ }
31
+
32
+ if (rebillyMountFunction[id]) {
33
+ Rebilly[rebillyMountFunction[id]].mount(`.rebilly-instruments-${id}-method`);
34
+
35
+ if (id === 'apple-pay') {
36
+ updateApplePayStyling();
37
+ }
38
+ } else {
39
+ console.warn(`method '${id}' is not supported`);
40
+ }
41
+ }
42
+ }
43
+
44
+ Rebilly?.on('ready', () => {
45
+ mountButton();
46
+ });
47
+
48
+ Rebilly?.on('error', error => {
49
+ console.error(error)
50
+ });
51
+ }
@@ -0,0 +1,54 @@
1
+ import merge from 'lodash.merge';
2
+
3
+ export function generateFramepayConfig ({
4
+ state,
5
+ methodIds
6
+ } = {}) {
7
+ const {
8
+ options,
9
+ data
10
+ } = state;
11
+
12
+ const config = {
13
+ style: options.themeFramepay,
14
+ locale: options?.locale || 'auto',
15
+ organizationId: options.organizationId,
16
+ websiteId: options.websiteId,
17
+ methods: data.readyToPay,
18
+ };
19
+
20
+ if (methodIds.includes('pay-pal-billing-agreement')) {
21
+ config.transactionData = merge(
22
+ typeof config.transactionData === 'object' ? config.transactionData : {},
23
+ data.amountAndCurrency
24
+ );
25
+ config.paypal = options.paymentInstruments.paypal;
26
+ }
27
+
28
+ if (methodIds.includes('google-pay')) {
29
+ config.transactionData = merge(
30
+ typeof config.transactionData === 'object' ? config.transactionData : {},
31
+ options.digitalWallet.googlePay?.transactionData
32
+ );
33
+ config.googlePay = options.digitalWallet.googlePay.googlePayDisplayOptions;
34
+ }
35
+
36
+ if (methodIds.includes('apple-pay')) {
37
+ config.transactionData = merge(
38
+ typeof config.transactionData === 'object' ? config.transactionData : {},
39
+ options.digitalWallet.applePay?.transactionData
40
+ );
41
+ config.applePay = options.digitalWallet.applePay.applePayDisplayOptions;
42
+ }
43
+
44
+ if (options.publishableKey) {
45
+ config.publishableKey = options.publishableKey;
46
+ }
47
+
48
+ if (options.jwt) {
49
+ config.jwt = options.jwt;
50
+ config.sandbox = options.apiMode === 'sandbox';
51
+ }
52
+
53
+ return config;
54
+ }
@@ -0,0 +1,195 @@
1
+ import {generateFramepayConfig} from './generate-framepay-config';
2
+
3
+ describe('Generate FramePay Config', () => {
4
+ let state;
5
+
6
+ beforeEach(() => {
7
+ state = {
8
+ options: {
9
+ themeFramepay: {},
10
+ locale: 'en-CA',
11
+ organizationId: 'test-organization-id',
12
+ websiteId: 'test-website-id'
13
+ },
14
+ data: {
15
+ readyToPay: []
16
+ }
17
+ };
18
+ });
19
+
20
+ it('should generate default config', () => {
21
+ const config = generateFramepayConfig({
22
+ state,
23
+ methodIds: []
24
+ });
25
+
26
+ const {options, data} = state;
27
+
28
+ expect(config).toEqual(expect.objectContaining ({
29
+ style: options.themeFramepay,
30
+ locale: options.locale,
31
+ organizationId: options.organizationId,
32
+ websiteId: options.websiteId,
33
+ methods: data.readyToPay,
34
+ }))
35
+ });
36
+
37
+ it('should add publishableKey', () => {
38
+ state.options.publishableKey = 'test-publishable-key';
39
+
40
+ const config = generateFramepayConfig({
41
+ state,
42
+ methodIds: []
43
+ });
44
+
45
+ expect(config).toEqual(expect.objectContaining ({
46
+ publishableKey: state.options.publishableKey
47
+ }));
48
+ });
49
+
50
+ it('should add jwt', () => {
51
+ state.options.jwt = 'test-jwt';
52
+ state.options.apiMode = 'sandbox';
53
+
54
+ const config = generateFramepayConfig({
55
+ state,
56
+ methodIds: []
57
+ });
58
+
59
+ expect(config).toEqual(expect.objectContaining ({
60
+ jwt: state.options.jwt,
61
+ sandbox: true
62
+ }));
63
+ });
64
+
65
+ it('should add configurations for PayPal', () => {
66
+ state.data.amountAndCurrency = {
67
+ amount: 10,
68
+ currency: 'CAD'
69
+ };
70
+ state.options.paymentInstruments = {
71
+ paypal: {
72
+ test: 'key'
73
+ }
74
+ }
75
+
76
+ const config = generateFramepayConfig({
77
+ state,
78
+ methodIds: ['pay-pal-billing-agreement']
79
+ });
80
+
81
+ expect(config).toEqual(expect.objectContaining ({
82
+ transactionData: expect.objectContaining(
83
+ state.data.amountAndCurrency
84
+ ),
85
+ paypal: state.options.paymentInstruments.paypal
86
+ }));
87
+ });
88
+
89
+ it('should add configurations for Google Pay', () => {
90
+ state.options.digitalWallet = {
91
+ googlePay: {
92
+ transactionData: {
93
+ test: 'key'
94
+ },
95
+ googlePayDisplayOptions: {
96
+ test: 'key'
97
+ }
98
+ }
99
+ }
100
+
101
+ const config = generateFramepayConfig({
102
+ state,
103
+ methodIds: ['google-pay']
104
+ });
105
+
106
+ expect(config).toEqual(expect.objectContaining ({
107
+ transactionData: expect.objectContaining(
108
+ state.options.digitalWallet.googlePay.transactionData
109
+ ),
110
+ googlePay: state.options.digitalWallet.googlePay.googlePayDisplayOptions
111
+ }));
112
+ });
113
+
114
+ it('should add configurations for Apple Pay', () => {
115
+ state.options.digitalWallet = {
116
+ applePay: {
117
+ transactionData: {
118
+ test: 'key'
119
+ },
120
+ applePayDisplayOptions: {
121
+ test: 'key'
122
+ }
123
+ }
124
+ }
125
+
126
+ const config = generateFramepayConfig({
127
+ state,
128
+ methodIds: ['apple-pay']
129
+ });
130
+
131
+ expect(config).toEqual(expect.objectContaining ({
132
+ transactionData: expect.objectContaining(
133
+ state.options.digitalWallet.applePay.transactionData
134
+ ),
135
+ applePay: state.options.digitalWallet.applePay.applePayDisplayOptions
136
+ }));
137
+ });
138
+
139
+ it('should add all instrument methods together', () => {
140
+ state.data.amountAndCurrency = {
141
+ test: 'key'
142
+ };
143
+ state.options = {
144
+ paymentInstruments: {
145
+ paypal: {
146
+ test: 'key'
147
+ }
148
+ },
149
+ digitalWallet: {
150
+ googlePay: {
151
+ transactionData: {
152
+ test: 'key'
153
+ },
154
+ googlePayDisplayOptions: {
155
+ test: 'key'
156
+ }
157
+ },
158
+ applePay: {
159
+ transactionData: {
160
+ test: 'key'
161
+ },
162
+ applePayDisplayOptions: {
163
+ test: 'key'
164
+ }
165
+ }
166
+ }
167
+ }
168
+
169
+ const config = generateFramepayConfig({
170
+ state,
171
+ methodIds: ['pay-pal-billing-agreement', 'google-pay', 'apple-pay']
172
+ });
173
+
174
+ expect(config).toEqual(expect.objectContaining ({
175
+ transactionData: expect.objectContaining(
176
+ state.data.amountAndCurrency
177
+ ),
178
+ paypal: state.options.paymentInstruments.paypal
179
+ }));
180
+
181
+ expect(config).toEqual(expect.objectContaining ({
182
+ transactionData: expect.objectContaining(
183
+ state.options.digitalWallet.googlePay.transactionData
184
+ ),
185
+ googlePay: state.options.digitalWallet.googlePay.googlePayDisplayOptions
186
+ }));
187
+
188
+ expect(config).toEqual(expect.objectContaining ({
189
+ transactionData: expect.objectContaining(
190
+ state.options.digitalWallet.applePay.transactionData
191
+ ),
192
+ applePay: state.options.digitalWallet.applePay.applePayDisplayOptions
193
+ }));
194
+ });
195
+ });
@@ -9,7 +9,6 @@ const isExpressMethod = ({ method, feature }) => (
9
9
 
10
10
  const isSupportedMethod = ({ method }) => SUPPORTED_METHODS.includes(method);
11
11
 
12
- // TODO: just loader is used. We could simplify signature
13
12
  export function getPaymentMethods({ state }) {
14
13
  const result = {
15
14
  EXPRESS_METHODS: [],
@@ -1,13 +1,14 @@
1
1
  /* eslint-disable no-undef */
2
2
  import { collectData } from '@rebilly/risk-data-collector';
3
3
  import { getPaymentMethods } from './get-payment-methods';
4
+ import { fetchData } from '../../functions/mount/fetch-data';
5
+ import { ViewIframe } from '../common/iframe';
4
6
  import { mountExpressMethods } from './mount-express-methods';
5
7
  import { generateDigitalWallet } from './generate-digital-wallet';
6
- import { MountMethods } from './mount-methods';
7
- import { fetchData } from '../../functions/mount/fetch-data';
8
8
 
9
9
  export const baseMethodSelectorHTML = (compactExpressInstruments) => `
10
10
  <div class="rebilly-instruments-content">
11
+ <div id="rebilly-instruments-error"></div>
11
12
  <div class="rebilly-instruments-method-selector ${compactExpressInstruments ? 'has-express-compact' : ''}">
12
13
  <div class="rebilly-instruments-express-methods ${
13
14
  compactExpressInstruments ? 'is-compact' : ''
@@ -23,81 +24,67 @@ export const baseMethodSelectorHTML = (compactExpressInstruments) => `
23
24
  </div>
24
25
  `;
25
26
 
26
- export function mountMethodSelector({ state }) {
27
+ export async function mountMethodSelector({ state }) {
27
28
  const { EXPRESS_METHODS, METHODS } = getPaymentMethods({ state });
28
29
 
29
- state.form.innerHTML += baseMethodSelectorHTML(
30
- state.options.paymentInstruments.compactExpressInstruments && EXPRESS_METHODS.length
31
- );
32
-
33
- const EXPRESS_METHODS_CONTAINER = document.querySelector(
34
- '.rebilly-instruments-express-methods-container'
35
- );
36
- const METHODS_DIVIDER = document.querySelector(
37
- '.rebilly-instruments-divider'
38
- );
39
- METHODS_DIVIDER.style.display =
40
- METHODS.length && EXPRESS_METHODS.length ? 'block' : 'none';
41
- const METHODS_CONTAINER = document.querySelector(
42
- '.rebilly-instruments-methods'
43
- );
30
+ const methodSelectorElement = state.form.querySelector('.rebilly-instruments-method-selector');
31
+ if (methodSelectorElement) {
32
+ methodSelectorElement.style.visibility = 'visible';
33
+ methodSelectorElement.style.height = 'auto';
34
+ } else {
35
+ state.form.innerHTML += baseMethodSelectorHTML(
36
+ state.options.paymentInstruments.compactExpressInstruments && EXPRESS_METHODS.length
37
+ );
38
+ }
44
39
 
45
- state.options.digitalWallet = generateDigitalWallet({state, EXPRESS_METHODS});
40
+ const METHODS_CONTAINER = document.querySelector('.rebilly-instruments-methods');
41
+ const EXPRESS_METHODS_CONTAINER = document.querySelector('.rebilly-instruments-express-methods-container');
46
42
 
47
- if (METHODS.length) {
48
- MountMethods({
49
- state,
50
- METHODS_CONTAINER,
51
- METHODS
52
- });
43
+ if(EXPRESS_METHODS.length) {
44
+ if (!methodSelectorElement) {
45
+ state.options.digitalWallet = generateDigitalWallet({state, EXPRESS_METHODS});
46
+ mountExpressMethods({
47
+ state,
48
+ methods: EXPRESS_METHODS,
49
+ container: EXPRESS_METHODS_CONTAINER,
50
+ });
51
+ }
53
52
  } else {
54
- METHODS_CONTAINER.style.display = 'none';
53
+ EXPRESS_METHODS_CONTAINER.style.display = 'none';
54
+ document.querySelector('.rebilly-instruments-divider')
55
+ .style.display = 'none';
55
56
  }
56
57
 
57
- if (EXPRESS_METHODS.length) {
58
- mountExpressMethods({
59
- state,
60
- EXPRESS_METHODS,
61
- EXPRESS_METHODS_CONTAINER
58
+ if (METHODS.length) {
59
+ const model = {
60
+ options: state.options,
61
+ data: state.data.toPostmatesModel(),
62
+ mainStyleVars: state.mainStyleVars,
63
+ };
64
+ const { paymentMethodsUrl } = state.options._computed;
65
+
66
+ const iframe = await new ViewIframe({
67
+ name: 'rebilly-instruments-methods',
68
+ url: `${paymentMethodsUrl}`,
69
+ container: METHODS_CONTAINER,
70
+ model
62
71
  });
72
+ iframe.bindEventListeners({loader: state.loader});
73
+ state.iframeComponents.form.push(iframe);
63
74
  } else {
64
- EXPRESS_METHODS_CONTAINER.parentNode.style.display = 'none';
65
- }
66
-
67
- if (!METHODS.length && !EXPRESS_METHODS.length) {
68
- state.form.innerHTML = `
69
- <p data-rebilly-i18n="form.error.noPaymentMethods">
70
- No payment methods available for this transaction, please contact support.
71
- <p>
72
- `;
73
- state.form.style.minHeight = 'auto';
75
+ METHODS_CONTAINER.style.display = 'none';
74
76
  }
75
-
76
- state.translate.translateItems();
77
-
78
- state.loader.stopLoading({ id: 'initForm' });
79
77
  }
80
78
 
81
79
  export async function updateMethodSelector({ state }) {
82
- state.loader.startLoading({ id: 'initForm' });
83
- const { riskMetadata } = await collectData();
80
+ state.loader.startLoading({ id: 'rebilly-instruments-methods' });
84
81
 
82
+ const { riskMetadata } = await collectData();
85
83
  state.data = await fetchData({ state, riskMetadata });
86
84
 
87
85
  if (state.data.transaction && state.data.transaction?.type === 'setup') {
88
86
  state.options.transactionType = 'setup';
89
87
  }
90
88
 
91
- state.form
92
- .querySelectorAll(':not(.rebilly-instruments-confirmation)')
93
- .forEach((element) => {
94
- if (
95
- !element.classList.contains('rebilly-instruments-loader') &&
96
- !element.classList.contains('rebilly-instruments-loader-spinner')
97
- ) {
98
- element.remove();
99
- }
100
- });
101
-
102
89
  mountMethodSelector({ state });
103
90
  }