@rebilly/instruments 4.4.0 → 4.6.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 (134) hide show
  1. package/.babelrc +24 -26
  2. package/CHANGELOG.md +14 -0
  3. package/dist/index.js +14 -40
  4. package/dist/index.min.js +14 -40
  5. package/package.json +16 -5
  6. package/project.json +9 -0
  7. package/rollup.config.mjs +21 -26
  8. package/src/data/options-schema/index.js +94 -78
  9. package/src/data/options-schema/schemas/options-schema.js +420 -408
  10. package/src/events/base-event.js +34 -34
  11. package/src/events/events.spec.js +6 -6
  12. package/src/events/index.js +5 -5
  13. package/src/functions/destroy.js +19 -19
  14. package/src/functions/destroy.spec.js +41 -41
  15. package/src/functions/mount/fetch-data.js +200 -193
  16. package/src/functions/mount/fetch-data.spec.js +287 -285
  17. package/src/functions/mount/get-lead-source-data.js +31 -31
  18. package/src/functions/mount/get-lead-source-data.spec.js +19 -19
  19. package/src/functions/mount/index.js +73 -65
  20. package/src/functions/mount/mount.spec.js +77 -66
  21. package/src/functions/mount/setup-element.js +23 -23
  22. package/src/functions/mount/setup-framepay-theme.js +86 -68
  23. package/src/functions/mount/setup-framepay.js +9 -5
  24. package/src/functions/mount/setup-i18n.js +15 -15
  25. package/src/functions/mount/setup-options.js +74 -74
  26. package/src/functions/mount/setup-options.spec.js +325 -289
  27. package/src/functions/mount/setup-storefront.js +15 -20
  28. package/src/functions/mount/setup-styles-vars.js +19 -22
  29. package/src/functions/mount/setup-user-flow.js +51 -47
  30. package/src/functions/on.js +5 -5
  31. package/src/functions/on.spec.js +60 -51
  32. package/src/functions/purchase.js +149 -134
  33. package/src/functions/purchase.spec.js +59 -56
  34. package/src/functions/setup.js +53 -49
  35. package/src/functions/setup.spec.js +88 -75
  36. package/src/functions/show.js +13 -14
  37. package/src/functions/show.spec.js +53 -53
  38. package/src/functions/update.js +30 -28
  39. package/src/functions/update.spec.js +94 -93
  40. package/src/i18n/en.json +32 -32
  41. package/src/i18n/es.json +29 -29
  42. package/src/i18n/i18n.spec.js +18 -18
  43. package/src/i18n/index.js +48 -48
  44. package/src/instance.js +36 -36
  45. package/src/instance.spec.js +29 -27
  46. package/src/loader/index.js +95 -70
  47. package/src/loader/loader.spec.js +63 -63
  48. package/src/state/iframes.js +21 -21
  49. package/src/state/index.js +56 -54
  50. package/src/storefront/account-and-website.js +10 -8
  51. package/src/storefront/account-and-website.spec.js +55 -55
  52. package/src/storefront/deposit-requests.js +6 -6
  53. package/src/storefront/fetch-plans-from-addons-bumpOffer.js +21 -19
  54. package/src/storefront/fetch-products-from-plans.js +52 -51
  55. package/src/storefront/fetch-products-from-plans.spec.js +90 -87
  56. package/src/storefront/index.js +56 -49
  57. package/src/storefront/invoices.js +15 -15
  58. package/src/storefront/invoices.spec.js +69 -65
  59. package/src/storefront/models/account-model.js +29 -32
  60. package/src/storefront/models/base-model.js +6 -9
  61. package/src/storefront/models/deposit-request-model.js +22 -13
  62. package/src/storefront/models/invoice-model.js +16 -16
  63. package/src/storefront/models/payment-metadata.js +4 -4
  64. package/src/storefront/models/plan-model.js +73 -64
  65. package/src/storefront/models/ready-to-pay-model.js +59 -59
  66. package/src/storefront/models/summary-model.js +43 -46
  67. package/src/storefront/models/transaction-model.js +11 -14
  68. package/src/storefront/payment-instruments.js +38 -35
  69. package/src/storefront/payment-instruments.spec.js +81 -62
  70. package/src/storefront/purchase.js +50 -44
  71. package/src/storefront/purchase.spec.js +40 -40
  72. package/src/storefront/ready-to-pay.js +75 -77
  73. package/src/storefront/ready-to-pay.spec.js +59 -54
  74. package/src/storefront/storefront.spec.js +9 -9
  75. package/src/storefront/summary.js +93 -67
  76. package/src/storefront/summary.spec.js +108 -106
  77. package/src/storefront/transactions.js +6 -6
  78. package/src/style/base/default-theme.js +928 -923
  79. package/src/style/base/theme.js +21 -21
  80. package/src/style/base/theme.spec.js +13 -13
  81. package/src/style/index.js +3 -3
  82. package/src/style/utils/border.js +40 -27
  83. package/src/style/utils/color-values.js +18 -18
  84. package/src/style/utils/minifyCss.js +6 -6
  85. package/src/utils/add-dom-element.js +14 -14
  86. package/src/utils/format-currency.js +6 -5
  87. package/src/utils/has-valid-css-selector.js +2 -2
  88. package/src/utils/index.js +6 -6
  89. package/src/utils/is-dom-element.js +1 -1
  90. package/src/utils/process-property-as-dom-element.js +22 -22
  91. package/src/utils/quantity.js +26 -28
  92. package/src/utils/sleep.js +3 -1
  93. package/src/views/amount-selector.js +37 -36
  94. package/src/views/common/iframe/base-iframe.js +53 -52
  95. package/src/views/common/iframe/events/change-iframe-src-handler.js +5 -5
  96. package/src/views/common/iframe/events/dispatch-event-handler.js +4 -4
  97. package/src/views/common/iframe/events/resize-component-handler.js +8 -8
  98. package/src/views/common/iframe/events/show-error-handler.js +2 -2
  99. package/src/views/common/iframe/events/stop-loader-handler.js +8 -8
  100. package/src/views/common/iframe/events/update-addons-handler.js +20 -13
  101. package/src/views/common/iframe/events/update-coupons-handler.js +9 -9
  102. package/src/views/common/iframe/events/update-items-handler.js +26 -22
  103. package/src/views/common/iframe/modal-iframe.js +67 -56
  104. package/src/views/common/iframe/view-iframe.js +11 -11
  105. package/src/views/common/render-utilities.js +2 -2
  106. package/src/views/confirmation.js +33 -30
  107. package/src/views/errors.js +89 -79
  108. package/src/views/form.js +41 -37
  109. package/src/views/method-selector/express-methods.js +46 -46
  110. package/src/views/method-selector/generate-digital-wallet.js +46 -45
  111. package/src/views/method-selector/generate-digital-wallet.spec.js +104 -102
  112. package/src/views/method-selector/generate-framepay-config.js +53 -51
  113. package/src/views/method-selector/generate-framepay-config.spec.js +197 -173
  114. package/src/views/method-selector/get-method-data.js +5 -6
  115. package/src/views/method-selector/get-payment-methods.js +18 -16
  116. package/src/views/method-selector/get-payment-methods.spec.js +29 -27
  117. package/src/views/method-selector/index.js +154 -139
  118. package/src/views/method-selector/method-selector.spec.js +13 -13
  119. package/src/views/method-selector/mount-bump-offer.js +65 -49
  120. package/src/views/method-selector/mount-express-methods.js +89 -85
  121. package/src/views/modal.js +74 -67
  122. package/src/views/result.js +14 -14
  123. package/src/views/summary.js +25 -26
  124. package/tests/async-utilities.js +13 -13
  125. package/tests/mocks/framepay-mock.js +9 -8
  126. package/tests/mocks/rebilly-api-mock.js +5 -3
  127. package/tests/mocks/rebilly-instruments-mock.js +121 -117
  128. package/tests/mocks/storefront-api-mock.js +55 -48
  129. package/tests/mocks/storefront-mock.js +10 -14
  130. package/tests/msw/server.js +6 -6
  131. package/tests/setup-test.js +14 -16
  132. package/vitest.config.js +14 -14
  133. package/.eslintrc.js +0 -34
  134. package/.prettierrc.js +0 -11
@@ -1,45 +1,47 @@
1
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
- }
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
+ }
32
11
 
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>`
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>`;
37
22
  }
38
23
 
39
- return displayString(displayDetail(error.details[0]));
40
- }
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
36
+ .map((detail) => `<li>${displayDetail(detail)}</li>`)
37
+ .join('')}
38
+ </ul>`;
39
+ }
40
+
41
+ return displayString(displayDetail(error.details[0]));
42
+ }
41
43
 
42
- return `<div class="rebilly-instruments-error-card">
44
+ return `<div class="rebilly-instruments-error-card">
43
45
  <header class="rebilly-instruments-error-card-header">
44
46
  <p class="rebilly-instruments-error-card-title">${title}</p>
45
47
  <button class="rebilly-instruments-error-card-close-button">
@@ -49,57 +51,65 @@ const errorTemplate = (error) => {
49
51
  </button>
50
52
  </header>
51
53
  ${error.details ? displayList() : displayString()}
52
- </div>`
54
+ </div>`;
53
55
  };
54
56
 
55
57
  export function clearError() {
56
- const errorContainer = document.querySelector('#rebilly-instruments-error');
57
- if (!errorContainer) return ;
58
+ const errorContainer = document.querySelector('#rebilly-instruments-error');
59
+ if (!errorContainer) return;
58
60
 
59
- errorContainer.innerHTML = '';
61
+ errorContainer.innerHTML = '';
60
62
  }
61
63
 
62
64
  export function showError(error, isCloseable = true) {
63
- if (!error) return;
64
- const errorContainer = document.querySelector('#rebilly-instruments-error');
65
- if (!errorContainer) return ;
66
-
67
- errorContainer.innerHTML = errorTemplate(error);
65
+ if (!error) return;
66
+ const errorContainer = document.querySelector('#rebilly-instruments-error');
67
+ if (!errorContainer) return;
68
68
 
69
- function clickOutsideError(e) {
70
- if (errorContainer.contains(e.target)) return;
69
+ errorContainer.innerHTML = errorTemplate(error);
71
70
 
72
- window.removeEventListener('click', clickOutsideError, false);
73
- clearError();
74
- }
71
+ function clickOutsideError(e) {
72
+ if (errorContainer.contains(e.target)) return;
75
73
 
76
- function windowBlur() {
77
- setTimeout(() => {
78
- if (document.activeElement.tagName === 'IFRAME') {
79
- window.removeEventListener('click', windowBlur, false);
74
+ window.removeEventListener('click', clickOutsideError, false);
80
75
  clearError();
81
- }
82
- });
83
- }
84
-
85
- const closeButton = document.querySelector('.rebilly-instruments-error-card-close-button');
86
-
87
- if(isCloseable) {
88
- closeButton.addEventListener('click', clearError);
89
-
90
- window.addEventListener('click', clickOutsideError);
91
- window.addEventListener('blur', windowBlur, { once: true });
92
- } else {
93
- const errorBox = document.querySelector('.rebilly-instruments-error-card');
94
- errorBox.classList.add('not-closeable');
95
- closeButton.remove();
96
- }
97
-
98
- if(errorContainer.scrollIntoView){
99
- errorContainer.scrollIntoView({behavior: 'smooth', block: 'end', inline: 'nearest'});
100
- }
101
- console.error('Rebilly Instruments Error', error);
102
-
103
- // Must focus to ensure window blur event will trigger
104
- window.focus();
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
+ const closeButton = document.querySelector(
88
+ '.rebilly-instruments-error-card-close-button',
89
+ );
90
+
91
+ if (isCloseable) {
92
+ closeButton.addEventListener('click', clearError);
93
+
94
+ window.addEventListener('click', clickOutsideError);
95
+ window.addEventListener('blur', windowBlur, { once: true });
96
+ } else {
97
+ const errorBox = document.querySelector(
98
+ '.rebilly-instruments-error-card',
99
+ );
100
+ errorBox.classList.add('not-closeable');
101
+ closeButton.remove();
102
+ }
103
+
104
+ if (errorContainer.scrollIntoView) {
105
+ errorContainer.scrollIntoView({
106
+ behavior: 'smooth',
107
+ block: 'end',
108
+ inline: 'nearest',
109
+ });
110
+ }
111
+ console.error('Rebilly Instruments Error', error);
112
+
113
+ // Must focus to ensure window blur event will trigger
114
+ window.focus();
105
115
  }
package/src/views/form.js CHANGED
@@ -12,46 +12,50 @@ export const baseMethodSelectorHTML = () => `
12
12
  `;
13
13
 
14
14
  export async function mountForm() {
15
- state.form.innerHTML += baseMethodSelectorHTML();
16
- const container = document.querySelector('[data-rebilly-instruments="form"]');
17
- const { paymentMethodsUrl: url } = state.options?._computed;
18
- const name = 'rebilly-instruments-form';
19
-
20
- const modelSafeState = state.toModel();
21
- const model = {
22
- options: modelSafeState.options,
23
- data: modelSafeState.data,
24
- mainStyleVars: modelSafeState.mainStyleVars,
25
- };
26
-
27
- const args = {
28
- name,
29
- url: `${url}?name=${name}`,
30
- container,
31
- model,
32
- };
33
-
34
- const iframe = await new ViewIframe(args);
35
- iframe.bindEventListeners({loader: state.loader});
36
-
37
- iframes.form = iframe;
38
-
39
- state.loader.stopLoading({id: 'rebilly-instruments-form'});
40
-
41
- return {
42
- then: (callback) => callback()
43
- }
15
+ state.form.innerHTML += baseMethodSelectorHTML();
16
+ const container = document.querySelector(
17
+ '[data-rebilly-instruments="form"]',
18
+ );
19
+ const { paymentMethodsUrl: url } = state?.options?._computed || {};
20
+ const name = 'rebilly-instruments-form';
21
+
22
+ const modelSafeState = state.toModel();
23
+ const model = {
24
+ options: modelSafeState.options,
25
+ data: modelSafeState.data,
26
+ mainStyleVars: modelSafeState.mainStyleVars,
27
+ };
28
+
29
+ const args = {
30
+ name,
31
+ url: `${url}?name=${name}`,
32
+ container,
33
+ model,
34
+ };
35
+
36
+ const iframe = await new ViewIframe(args);
37
+ iframe.bindEventListeners({ loader: state.loader });
38
+
39
+ iframes.form = iframe;
40
+
41
+ state.loader.stopLoading({ id: 'rebilly-instruments-form' });
42
+
43
+ return {
44
+ then: (callback) => callback(),
45
+ };
44
46
  }
45
47
 
46
48
  export function determineFirstView() {
47
- if (state.options?.deposit) {
48
- mountAmountSelector();
49
- } else {
50
- mountMethodSelector();
51
- }
49
+ if (state.options?.deposit) {
50
+ mountAmountSelector();
51
+ } else {
52
+ mountMethodSelector();
53
+ }
52
54
  }
53
55
 
54
56
  export function removeForm() {
55
- const container = document.querySelector('[data-rebilly-instruments="form"]');
56
- container.remove();
57
- }
57
+ const container = document.querySelector(
58
+ '[data-rebilly-instruments="form"]',
59
+ );
60
+ container.remove();
61
+ }
@@ -1,52 +1,52 @@
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`);
1
+ export default function mountExpressMethod({ state, id }) {
2
+ const { Rebilly } = window;
3
+ const container = document.querySelector(
4
+ `.rebilly-instruments-${id}-method`,
5
+ );
6
+
7
+ // Hack: The correct way to do this is to accept the options via the framepay package
8
+ // Will remove once these options are added to framepay
9
+ function updateApplePayStyling() {
10
+ const applePayButton = document.querySelector(
11
+ '#rebilly-apple-pay-button',
12
+ );
13
+ const {
14
+ applePayDisplayOptions: { buttonHeight },
15
+ } = state.options.digitalWallet.applePay;
16
+
17
+ applePayButton.style.margin = '0px';
18
+ applePayButton.style.width = '100%';
19
+ applePayButton.style.height = buttonHeight;
20
+ applePayButton.style.cursor = 'pointer';
21
+ }
34
22
 
35
- if (id === 'apple-pay') {
36
- updateApplePayStyling();
23
+ function mountButton() {
24
+ if (!container.children.length) {
25
+ const rebillyMountFunction = {
26
+ 'google-pay': 'googlePay',
27
+ 'pay-pal-billing-agreement': 'paypal',
28
+ 'apple-pay': 'applePay',
29
+ };
30
+
31
+ if (rebillyMountFunction[id]) {
32
+ Rebilly[rebillyMountFunction[id]].mount(
33
+ `.rebilly-instruments-${id}-method`,
34
+ );
35
+
36
+ if (id === 'apple-pay') {
37
+ updateApplePayStyling();
38
+ }
39
+ } else {
40
+ console.warn(`method '${id}' is not supported`);
41
+ }
37
42
  }
38
-
39
- } else {
40
- console.warn(`method '${id}' is not supported`);
41
- }
42
43
  }
43
- }
44
44
 
45
- Rebilly?.on('ready', () => {
46
- mountButton();
47
- });
45
+ Rebilly?.on('ready', () => {
46
+ mountButton();
47
+ });
48
48
 
49
- Rebilly?.on('error', error => {
50
- console.error(error)
51
- });
49
+ Rebilly?.on('error', (error) => {
50
+ console.error(error);
51
+ });
52
52
  }
@@ -2,51 +2,52 @@ import state from '../../state';
2
2
  import { getMethodData } from './get-method-data';
3
3
 
4
4
  export function generateDigitalWallet({ expressMethods = [] }) {
5
- const output = {};
6
-
7
- const { paymentInstruments } = state.options;
8
-
9
- const transactionData = {
10
- countryCode: state.options.countryCode,
11
- label: state.options.websiteId
12
- }
13
-
14
- if (state.data?.amountAndCurrency) {
15
- const {
16
- amount,
17
- currency
18
- } = state.data.amountAndCurrency;
19
- transactionData.amount = amount;
20
- transactionData.currency = currency;
21
- }
22
-
23
- expressMethods.forEach(method => {
24
- const { METHOD_TYPE } = getMethodData(method);
25
-
26
- if (method.feature?.name === 'Google Pay') {
27
- output[METHOD_TYPE] = {
28
- transactionData,
29
- merchantConfig: {
30
- merchantName: method.feature.merchantName,
31
- merchantOrigin: method.feature.merchantOrigin
32
- },
33
- googlePayDisplayOptions: paymentInstruments.googlePay.displayOptions,
34
- }
35
- }
5
+ const output = {};
6
+
7
+ const { paymentInstruments } = state.options;
8
+
9
+ const transactionData = {
10
+ countryCode: state.options.countryCode,
11
+ label: state.options.websiteId,
12
+ };
36
13
 
37
- if (method.feature?.name === 'Apple Pay') {
38
- output[METHOD_TYPE] = {
39
- transactionData,
40
- merchantConfig: {
41
- merchantName: paymentInstruments.applePay?.merchantConfig?.merchantName,
42
- // Apple Pay code cannot run in an iframe, and the merchant origin must be
43
- // registered as a merchant domain, so we can just send the current URL.
44
- merchantOrigin: window.location.hostname,
45
- },
46
- applePayDisplayOptions: paymentInstruments.applePay.displayOptions
47
- }
14
+ if (state.data?.amountAndCurrency) {
15
+ const { amount, currency } = state.data.amountAndCurrency;
16
+ transactionData.amount = amount;
17
+ transactionData.currency = currency;
48
18
  }
49
- });
50
19
 
51
- return output;
52
- }
20
+ expressMethods.forEach((method) => {
21
+ const { METHOD_TYPE } = getMethodData(method);
22
+
23
+ if (method.feature?.name === 'Google Pay') {
24
+ output[METHOD_TYPE] = {
25
+ transactionData,
26
+ merchantConfig: {
27
+ merchantName: method.feature.merchantName,
28
+ merchantOrigin: method.feature.merchantOrigin,
29
+ },
30
+ googlePayDisplayOptions:
31
+ paymentInstruments.googlePay.displayOptions,
32
+ };
33
+ }
34
+
35
+ if (method.feature?.name === 'Apple Pay') {
36
+ output[METHOD_TYPE] = {
37
+ transactionData,
38
+ merchantConfig: {
39
+ merchantName:
40
+ paymentInstruments.applePay?.merchantConfig
41
+ ?.merchantName,
42
+ // Apple Pay code cannot run in an iframe, and the merchant origin must be
43
+ // registered as a merchant domain, so we can just send the current URL.
44
+ merchantOrigin: window.location.hostname,
45
+ },
46
+ applePayDisplayOptions:
47
+ paymentInstruments.applePay.displayOptions,
48
+ };
49
+ }
50
+ });
51
+
52
+ return output;
53
+ }