@rebilly/instruments 1.0.2-beta.8 → 2.1.1-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 (211) hide show
  1. package/.babelrc +13 -4
  2. package/.eslintrc.js +3 -0
  3. package/.prettierrc.js +11 -0
  4. package/README.md +15 -314
  5. package/dist/events/base-event.js +6 -9
  6. package/dist/events/events.spec.js +4 -4
  7. package/dist/events/index.js +2 -1
  8. package/dist/functions/destroy.js +12 -14
  9. package/dist/functions/destroy.spec.js +3 -3
  10. package/dist/functions/mount/fetch-data.js +183 -0
  11. package/dist/functions/mount/fetch-data.spec.js +189 -0
  12. package/dist/functions/mount/index.js +158 -251
  13. package/dist/functions/mount/mount.spec.js +24 -121
  14. package/dist/functions/mount/setup-element.js +40 -0
  15. package/dist/functions/mount/setup-framepay.js +46 -0
  16. package/dist/functions/mount/setup-i18n.js +33 -0
  17. package/dist/functions/mount/setup-options.js +96 -0
  18. package/dist/functions/mount/setup-options.spec.js +66 -0
  19. package/dist/functions/mount/setup-storefront.js +34 -0
  20. package/dist/functions/mount/setup-styles.js +43 -0
  21. package/dist/functions/on.js +13 -4
  22. package/dist/functions/on.spec.js +19 -5
  23. package/dist/functions/purchase.js +139 -22
  24. package/dist/functions/purchase.spec.js +23 -19
  25. package/dist/functions/setup.js +85 -0
  26. package/dist/functions/setup.spec.js +87 -0
  27. package/dist/functions/show.js +31 -14
  28. package/dist/functions/show.spec.js +47 -18
  29. package/dist/functions/update.js +53 -27
  30. package/dist/functions/update.spec.js +40 -21
  31. package/dist/i18n/en.json +4 -1
  32. package/dist/i18n/es.json +4 -1
  33. package/dist/index.js +67 -56
  34. package/dist/index.spec.js +7 -27
  35. package/dist/loader/index.js +4 -3
  36. package/dist/storefront/index.js +33 -0
  37. package/dist/storefront/invoices.js +27 -0
  38. package/dist/storefront/models/base-model.js +18 -0
  39. package/dist/storefront/models/invoice-model.js +14 -0
  40. package/dist/storefront/models/plan-model.js +4 -35
  41. package/dist/storefront/models/product-model.js +4 -23
  42. package/dist/storefront/models/summary-model.js +12 -25
  43. package/dist/storefront/models/transaction-model.js +31 -0
  44. package/dist/storefront/payment-instruments.js +47 -0
  45. package/dist/storefront/payment-instruments.spec.js +55 -0
  46. package/dist/storefront/plans.js +15 -24
  47. package/dist/storefront/plans.spec.js +17 -44
  48. package/dist/storefront/products.js +16 -20
  49. package/dist/storefront/products.spec.js +25 -49
  50. package/dist/storefront/purchase.js +28 -16
  51. package/dist/storefront/purchase.spec.js +4 -22
  52. package/dist/storefront/ready-to-pay.js +26 -22
  53. package/dist/storefront/ready-to-pay.spec.js +25 -54
  54. package/dist/storefront/storefront.spec.js +1 -1
  55. package/dist/storefront/summary.js +27 -24
  56. package/dist/storefront/summary.spec.js +44 -86
  57. package/dist/storefront/transactions.js +27 -0
  58. package/dist/style/base/theme.js +3 -3
  59. package/dist/style/components/methods.js +43 -42
  60. package/dist/style/utils/color-values.js +1 -3
  61. package/dist/style/views/confirmation.js +0 -4
  62. package/dist/style/views/method-selector.js +1 -1
  63. package/dist/style/views/modal.js +3 -1
  64. package/dist/style/views/summary.js +5 -1
  65. package/dist/utils/format-currency.js +4 -2
  66. package/dist/utils/has-valid-css-selector.js +1 -1
  67. package/dist/utils/process-property-as-dom-element.js +0 -2
  68. package/dist/views/__snapshots__/summary.spec.js.snap +103 -113
  69. package/dist/views/common/iframe/base-iframe.js +10 -2
  70. package/dist/views/common/iframe/modal-iframe.js +44 -3
  71. package/dist/views/confirmation.js +44 -20
  72. package/dist/views/method-selector/express-methods/apple-pay.js +92 -0
  73. package/dist/views/method-selector/express-methods/google-pay.js +31 -0
  74. package/dist/views/method-selector/express-methods/paypal.js +19 -0
  75. package/dist/views/method-selector/generate-digital-wallet.js +68 -0
  76. package/dist/views/method-selector/generate-digital-wallet.spec.js +135 -0
  77. package/dist/views/method-selector/get-payment-methods.js +28 -8
  78. package/dist/views/method-selector/get-payment-methods.spec.js +25 -26
  79. package/dist/views/method-selector/index.js +55 -86
  80. package/dist/views/method-selector/method-selector.spec.js +80 -69
  81. package/dist/views/method-selector/mount-express-methods.js +38 -62
  82. package/dist/views/method-selector/mount-methods.js +18 -18
  83. package/dist/views/modal.js +21 -15
  84. package/dist/views/result.js +13 -16
  85. package/dist/views/summary.js +170 -114
  86. package/dist/views/summary.spec.js +72 -76
  87. package/package.json +5 -4
  88. package/src/events/base-event.js +15 -17
  89. package/src/events/events.spec.js +6 -4
  90. package/src/events/index.js +6 -3
  91. package/src/functions/destroy.js +12 -13
  92. package/src/functions/destroy.spec.js +30 -31
  93. package/src/functions/mount/fetch-data.js +148 -0
  94. package/src/functions/mount/fetch-data.spec.js +238 -0
  95. package/src/functions/mount/index.js +129 -244
  96. package/src/functions/mount/mount.spec.js +35 -139
  97. package/src/functions/mount/setup-element.js +26 -0
  98. package/src/functions/mount/setup-framepay.js +41 -0
  99. package/src/functions/mount/setup-i18n.js +19 -0
  100. package/src/functions/mount/setup-options.js +100 -0
  101. package/src/functions/mount/setup-options.spec.js +60 -0
  102. package/src/functions/mount/setup-storefront.js +24 -0
  103. package/src/functions/mount/setup-styles.js +30 -0
  104. package/src/functions/on.js +13 -8
  105. package/src/functions/on.spec.js +30 -17
  106. package/src/functions/purchase.js +101 -19
  107. package/src/functions/purchase.spec.js +18 -18
  108. package/src/functions/setup.js +48 -0
  109. package/src/functions/setup.spec.js +98 -0
  110. package/src/functions/show.js +20 -10
  111. package/src/functions/show.spec.js +43 -22
  112. package/src/functions/update.js +50 -27
  113. package/src/functions/update.spec.js +57 -22
  114. package/src/i18n/en.json +4 -1
  115. package/src/i18n/es.json +4 -1
  116. package/src/i18n/i18n.spec.js +6 -4
  117. package/src/i18n/index.js +14 -11
  118. package/src/index.js +41 -52
  119. package/src/index.spec.js +8 -37
  120. package/src/loader/index.js +51 -47
  121. package/src/loader/loader.spec.js +26 -19
  122. package/src/storefront/index.js +37 -7
  123. package/src/storefront/invoices.js +11 -0
  124. package/src/storefront/models/base-model.js +10 -0
  125. package/src/storefront/models/invoice-model.js +3 -0
  126. package/src/storefront/models/plan-model.js +3 -35
  127. package/src/storefront/models/product-model.js +3 -23
  128. package/src/storefront/models/ready-to-pay-model.js +3 -3
  129. package/src/storefront/models/summary-model.js +15 -29
  130. package/src/storefront/models/transaction-model.js +19 -0
  131. package/src/storefront/payment-instruments.js +30 -0
  132. package/src/storefront/payment-instruments.spec.js +69 -0
  133. package/src/storefront/plans.js +16 -23
  134. package/src/storefront/plans.spec.js +25 -54
  135. package/src/storefront/products.js +18 -22
  136. package/src/storefront/products.spec.js +23 -54
  137. package/src/storefront/purchase.js +14 -14
  138. package/src/storefront/purchase.spec.js +17 -29
  139. package/src/storefront/ready-to-pay.js +26 -23
  140. package/src/storefront/ready-to-pay.spec.js +41 -71
  141. package/src/storefront/storefront.spec.js +1 -1
  142. package/src/storefront/summary.js +26 -22
  143. package/src/storefront/summary.spec.js +60 -109
  144. package/src/storefront/transactions.js +11 -0
  145. package/src/style/base/theme.js +10 -8
  146. package/src/style/base/theme.spec.js +4 -2
  147. package/src/style/browserslist.js +1 -3
  148. package/src/style/components/button.js +3 -1
  149. package/src/style/components/forms/checkbox.js +3 -1
  150. package/src/style/components/index.js +1 -1
  151. package/src/style/components/loader.js +3 -1
  152. package/src/style/components/methods.js +43 -42
  153. package/src/style/helpers/index.js +1 -1
  154. package/src/style/index.js +2 -1
  155. package/src/style/utils/color-values.js +4 -4
  156. package/src/style/vendor/framepay.js +1 -1
  157. package/src/style/vendor/postmate.js +1 -1
  158. package/src/style/views/confirmation.js +0 -4
  159. package/src/style/views/index.js +1 -1
  160. package/src/style/views/method-selector.js +1 -1
  161. package/src/style/views/modal.js +4 -2
  162. package/src/style/views/summary.js +5 -1
  163. package/src/utils/add-dom-element.js +12 -13
  164. package/src/utils/format-currency.js +6 -2
  165. package/src/utils/has-valid-css-selector.js +2 -2
  166. package/src/utils/is-dom-element.js +1 -1
  167. package/src/utils/process-property-as-dom-element.js +27 -24
  168. package/src/utils/sleep.js +1 -1
  169. package/src/views/__snapshots__/summary.spec.js.snap +103 -113
  170. package/src/views/common/iframe/base-iframe.js +12 -4
  171. package/src/views/common/iframe/event-listeners.js +6 -6
  172. package/src/views/common/iframe/index.js +1 -1
  173. package/src/views/common/iframe/method-iframe.js +3 -6
  174. package/src/views/common/iframe/modal-iframe.js +42 -6
  175. package/src/views/common/iframe/view-iframe.js +3 -5
  176. package/src/views/common/render-utilities.js +3 -3
  177. package/src/views/confirmation.js +34 -25
  178. package/src/views/method-selector/express-methods/apple-pay.js +78 -0
  179. package/src/views/method-selector/express-methods/google-pay.js +24 -0
  180. package/src/views/method-selector/express-methods/paypal.js +7 -0
  181. package/src/views/method-selector/generate-digital-wallet.js +51 -0
  182. package/src/views/method-selector/generate-digital-wallet.spec.js +135 -0
  183. package/src/views/method-selector/get-method-data.js +7 -4
  184. package/src/views/method-selector/get-payment-methods.js +38 -29
  185. package/src/views/method-selector/get-payment-methods.spec.js +26 -33
  186. package/src/views/method-selector/index.js +70 -99
  187. package/src/views/method-selector/method-selector.spec.js +88 -78
  188. package/src/views/method-selector/mount-express-methods.js +36 -60
  189. package/src/views/method-selector/mount-methods.js +32 -21
  190. package/src/views/modal.js +37 -23
  191. package/src/views/result.js +12 -15
  192. package/src/views/summary.js +169 -101
  193. package/src/views/summary.spec.js +99 -74
  194. package/tests/async-utilities.js +22 -0
  195. package/tests/mocks/rebilly-instruments-mock.js +89 -77
  196. package/tests/mocks/storefront-api-mock.js +8 -0
  197. package/tests/mocks/storefront-mock.js +17 -0
  198. package/dist/events/purchase-completed.js +0 -24
  199. package/dist/functions/initialize.js +0 -82
  200. package/dist/functions/initialize.spec.js +0 -34
  201. package/dist/functions/mount/fetch-summary-data.js +0 -31
  202. package/dist/functions/mount/fetch-summary-data.spec.js +0 -45
  203. package/dist/views/method-selector/process-digital-wallet-options.js +0 -35
  204. package/dist/views/method-selector/process-digital-wallet-options.spec.js +0 -80
  205. package/src/events/purchase-completed.js +0 -11
  206. package/src/functions/initialize.js +0 -74
  207. package/src/functions/initialize.spec.js +0 -38
  208. package/src/functions/mount/fetch-summary-data.js +0 -26
  209. package/src/functions/mount/fetch-summary-data.spec.js +0 -46
  210. package/src/views/method-selector/process-digital-wallet-options.js +0 -16
  211. package/src/views/method-selector/process-digital-wallet-options.spec.js +0 -94
@@ -1,4 +1,4 @@
1
1
  export function replaceContent(form, newContent) {
2
- const contentElement = form.querySelector('.rebilly-instruments-content');
3
- contentElement.innerHTML = newContent;
4
- }
2
+ const contentElement = form.querySelector('.rebilly-instruments-content');
3
+ contentElement.innerHTML = newContent;
4
+ }
@@ -1,29 +1,32 @@
1
+ import { purchase } from '../functions/purchase';
2
+ import { setup } from '../functions/setup';
1
3
  import { ViewIframe } from './common/iframe';
2
4
  import { replaceContent } from './common/render-utilities';
5
+ import { updateMethodSelector } from './method-selector';
6
+ import { updateSummary } from './summary';
3
7
 
4
- export const baseConfirmationHTML = '<div class="rebilly-instruments-confirmation"></div>';
8
+ export const baseConfirmationHTML =
9
+ '<div class="rebilly-instruments-confirmation"></div>';
5
10
 
6
- export async function MountConfirmation({
7
- instrument,
8
- mainStyle
9
- }) {
10
- if(instrument.billingAddress && this.summary) {
11
- this._updateSummary.call(this, instrument);
11
+ export async function mountConfirmation({ payload: instrument, state }) {
12
+ if (
13
+ (instrument.billingAddress && state.summary) &&
14
+ state.data.isPurchase
15
+ ) {
16
+ updateSummary({ state, instrument });
12
17
  }
13
18
 
14
- replaceContent(this.form, baseConfirmationHTML);
15
-
16
- this.loader.startLoading({id: 'confirmation'});
17
-
19
+ replaceContent(state.form, baseConfirmationHTML);
20
+
21
+ state.loader.startLoading({ id: 'confirmation' });
18
22
 
19
23
  const container = document.querySelector('.rebilly-instruments-confirmation');
20
-
21
- const {paymentMethodsUrl} = this.options._computed;
24
+
25
+ const { paymentMethodsUrl } = state.options._computed;
22
26
 
23
27
  const model = {
24
- configs: this.configs,
25
- options: this.options,
26
- mainStyle,
28
+ options: state.options,
29
+ mainStyle: state.mainStyle,
27
30
  instrument
28
31
  };
29
32
  const name = 'rebilly-instruments-confirmation';
@@ -34,24 +37,30 @@ export async function MountConfirmation({
34
37
  model
35
38
  });
36
39
  iframe.bindEventListeners({
37
- loader: this.loader,
40
+ loader: state.loader
38
41
  });
39
42
 
40
43
  iframe.component.on(`${name}-confirm-purchase`, (confirmedInstrument) => {
41
- this.purchase(confirmedInstrument);
44
+ purchase({ state, payload: confirmedInstrument });
45
+ });
46
+
47
+ iframe.component.on(`${name}-confirm-setup`, (confirmedInstrument) => {
48
+ setup({ state, payload: confirmedInstrument });
42
49
  });
43
50
 
44
51
  iframe.component.on('choose-another-method', () => {
45
- this.iframeComponents = this.iframeComponents.filter(item => {
46
- if(item.name === iframe.name) {
47
- item.component.destroy();
52
+ state.iframeComponents = state.iframeComponents.filter((item) => {
53
+ if (item.name === iframe.name) {
54
+ item.destroy();
48
55
  return false;
49
56
  }
50
57
  return true;
51
58
  });
52
- this._updateSummary.call(this);
53
- this._updateSelector.call(this, {mainStyle});
59
+ if (state.data.isPurchase) {
60
+ updateSummary({ state });
61
+ }
62
+ updateMethodSelector({ state, mainStyle: state.mainStyle });
54
63
  });
55
64
 
56
- this.iframeComponents.push(iframe);
57
- }
65
+ state.iframeComponents.push(iframe);
66
+ }
@@ -0,0 +1,78 @@
1
+ import Events from '../../../events';
2
+
3
+ const browserIsSafari = () => window.ApplePaySession;
4
+
5
+ export default function mountApplePay({
6
+ state,
7
+ METHOD_ID,
8
+ METHOD_TYPE,
9
+ EXPRESS_METHODS,
10
+ EXPRESS_METHODS_CONTAINER
11
+ }) {
12
+ const container = document.querySelector(`.rebilly-instruments-${METHOD_ID}-method`);
13
+ const digitalWallet = state.options.digitalWallet.applePay;
14
+
15
+ function mountApplePayButton() {
16
+ if(!container.children.length) {
17
+ Rebilly.applePay.mount(`.rebilly-instruments-${METHOD_ID}-method`);
18
+ }
19
+ state.loader.stopLoading({ id: `${METHOD_TYPE}-express` });
20
+ }
21
+
22
+ // Hack: The correct way to do this is to accept the options via the framepay package
23
+ // Will remove once these options are added to framepay
24
+ function updateBtnStyling() {
25
+ const applePayButton = document.querySelector('#rebilly-apple-pay-button');
26
+ applePayButton.style.margin = '0px';
27
+ applePayButton.style.width = '100%';
28
+ applePayButton.style.height = digitalWallet.applePayDisplayOptions.buttonHeight;
29
+ }
30
+
31
+ if(!browserIsSafari()) {
32
+ if(EXPRESS_METHODS.length === 1) {
33
+ EXPRESS_METHODS_CONTAINER.parentNode.style.display = 'none';
34
+ }
35
+ state.loader.stopLoading({ id: `${METHOD_TYPE}-express` });
36
+ container.style.display = 'none';
37
+ return;
38
+ }
39
+
40
+ container.style.height = digitalWallet.applePayDisplayOptions.buttonHeight;
41
+
42
+ if (!Rebilly.initialized) {
43
+ Rebilly.initialize({
44
+ publishableKey: state.options.publishableKey,
45
+ organizationId: state.options.organizationId,
46
+ digitalWallet
47
+ });
48
+ } else {
49
+ mountApplePayButton();
50
+ updateBtnStyling();
51
+ }
52
+
53
+ Rebilly.on('ready', () => {
54
+ mountApplePayButton();
55
+ updateBtnStyling();
56
+ });
57
+
58
+ Rebilly.on('token-ready', (token) => {
59
+ const instrumentReadyPayload = {
60
+ websiteId: state.options.websiteId,
61
+ items: state.options.items,
62
+ paymentInstruction: {
63
+ token: token.id,
64
+ },
65
+ billingAddress: token.billingAddress,
66
+ _raw: token
67
+ }
68
+ if (!token.shippingAddress) {
69
+ instrumentReadyPayload.deliveryAddress = token.shippingAddress;
70
+ }
71
+
72
+ Events.instrumentReady.dispatch(instrumentReadyPayload);
73
+ });
74
+
75
+ Rebilly.on('error', error => {
76
+ console.error(error)
77
+ });
78
+ }
@@ -0,0 +1,24 @@
1
+ import { MethodIframe } from '../../common/iframe';
2
+
3
+ export default async function mountGooglePay({ state, METHOD_ID }) {
4
+ const container = document.querySelector(`.rebilly-instruments-${METHOD_ID}-method`);
5
+
6
+ const { paymentMethodsUrl } = state.options._computed;
7
+
8
+ const model = {
9
+ options: state.options
10
+ };
11
+
12
+ const iframe = await new MethodIframe({
13
+ name: METHOD_ID,
14
+ url: `${paymentMethodsUrl}/${METHOD_ID}`,
15
+ container,
16
+ model
17
+ });
18
+
19
+ iframe.bindEventListeners({
20
+ loader: state.loader
21
+ });
22
+
23
+ state.iframeComponents.push(iframe);
24
+ }
@@ -0,0 +1,7 @@
1
+
2
+ export default async function mountPaypal({ state, METHOD_ID, METHOD_TYPE }) {
3
+ console.log('PayPal - work in progress');
4
+ const container = document.querySelector(`.rebilly-instruments-${METHOD_ID}-method`);
5
+ container.style.display = 'none';
6
+ state.loader.stopLoading({ id: `${METHOD_TYPE}-express` });
7
+ }
@@ -0,0 +1,51 @@
1
+ import { getMethodData } from './get-method-data';
2
+
3
+ export function generateDigitalWallet({ state, EXPRESS_METHODS }) {
4
+ const output = {};
5
+
6
+ const { paymentInstruments } = state.options;
7
+
8
+ const transactionData = {
9
+ countryCode: state.options.countryCode,
10
+ label: state.options.websiteId
11
+ }
12
+
13
+ if (state.data?.amountAndCurrency) {
14
+ const {
15
+ amount,
16
+ currency
17
+ } = state.data.amountAndCurrency;
18
+ transactionData.amount = amount;
19
+ transactionData.currency = currency;
20
+ }
21
+
22
+ EXPRESS_METHODS.forEach(method => {
23
+ const { METHOD_TYPE } = getMethodData(method);
24
+
25
+ if (method.feature?.name === 'Google Pay') {
26
+ output[METHOD_TYPE] = {
27
+ transactionData,
28
+ merchantConfig: {
29
+ merchantName: method.feature.merchantName,
30
+ merchantOrigin: method.feature.merchantOrigin
31
+ },
32
+ googlePayDisplayOptions: paymentInstruments.googlePay.displayOptions,
33
+ }
34
+ }
35
+
36
+ if (method.feature?.name === 'Apple Pay') {
37
+ output[METHOD_TYPE] = {
38
+ transactionData,
39
+ merchantConfig: {
40
+ merchantName: paymentInstruments.applePay?.merchantConfig?.merchantName,
41
+ // Apple Pay code cannot run in an iframe, and the merchant origin must be
42
+ // registered as a merchant domain, so we can just send the current URL.
43
+ merchantOrigin: window.location.hostname,
44
+ },
45
+ applePayDisplayOptions: paymentInstruments.applePay.displayOptions
46
+ }
47
+ }
48
+ })
49
+
50
+ return output;
51
+ }
@@ -0,0 +1,135 @@
1
+ import { generateDigitalWallet } from './generate-digital-wallet';
2
+ import ReadyToPayModel from '@/storefront/models/ready-to-pay-model';
3
+ import SummaryModel from '@/storefront/models/summary-model';
4
+ import { DataInstance } from '../../functions/mount/fetch-data';
5
+
6
+ describe('generateDigitalWallet', () => {
7
+ class TestInstance {
8
+ constructor({ options = {} } = {}) {
9
+ this.options = options;
10
+ this.data = new DataInstance({
11
+ state: {
12
+ options
13
+ },
14
+ previewPurchase: {
15
+ total: 1,
16
+ currency: 'USD'
17
+ }
18
+ });
19
+ }
20
+ }
21
+
22
+ const summary = new SummaryModel({
23
+ currency: 'USD',
24
+ total: 1,
25
+ });
26
+
27
+ const options = {
28
+ websiteId: 'test-website-id',
29
+ countryCode: 'US',
30
+ paymentInstruments: {
31
+ googlePay: {
32
+ displayOptions: {
33
+ buttonColor: 'black',
34
+ buttonType: 'short',
35
+ buttonHeight: '44px'
36
+ }
37
+ },
38
+ applePay: {
39
+ displayOptions: {
40
+ buttonColor: 'black',
41
+ buttonType: 'buy',
42
+ buttonHeight: '44px'
43
+ },
44
+ merchantConfig: {
45
+ merchantName: 'Test Store Name',
46
+ },
47
+ }
48
+ }
49
+ };
50
+
51
+ it('should generate the correct digital wallet config for Google pay', () => {
52
+ const expressMethods = [
53
+ new ReadyToPayModel({
54
+ method: 'payment-card',
55
+ feature: {
56
+ name: 'Google Pay',
57
+ merchantName: 'google-pay-merchant-name',
58
+ merchantOrigin: 'google-pay-merchant-origin'
59
+ },
60
+ brands: ['Visa']
61
+ })
62
+ ];
63
+
64
+ const output = generateDigitalWallet({
65
+ state: new TestInstance({options}),
66
+ EXPRESS_METHODS: expressMethods,
67
+ summary
68
+ });
69
+
70
+ const expectedOutput ={
71
+ googlePay: {
72
+ transactionData: {
73
+ amount: 1,
74
+ currency: 'USD',
75
+ countryCode: 'US',
76
+ label: 'test-website-id'
77
+ },
78
+ merchantConfig: {
79
+ merchantName: 'google-pay-merchant-name',
80
+ merchantOrigin: 'google-pay-merchant-origin'
81
+ },
82
+ googlePayDisplayOptions: {
83
+ buttonColor: 'black',
84
+ buttonType: 'short',
85
+ buttonHeight: '44px'
86
+ }
87
+ }
88
+ }
89
+
90
+ expect(output).toMatchObject(expectedOutput);
91
+ });
92
+
93
+ it('should generate the correct digital wallet config for Apple pay', () => {
94
+ delete window.location
95
+ window.location = new URL('https://rebilly-apple-pay-test-tunnel.ngrok.io/');
96
+
97
+ const expressMethods = [
98
+ new ReadyToPayModel({
99
+ method: 'payment-card',
100
+ feature: {
101
+ name: 'Apple Pay',
102
+ },
103
+ brands: ['Visa']
104
+ })
105
+ ];
106
+
107
+ const output = generateDigitalWallet({
108
+ state: new TestInstance({options}),
109
+ EXPRESS_METHODS: expressMethods,
110
+ summary
111
+ });
112
+
113
+ const expectedOutput = {
114
+ applePay: {
115
+ transactionData: {
116
+ amount: 1,
117
+ currency: 'USD',
118
+ countryCode: 'US',
119
+ label: 'test-website-id'
120
+ },
121
+ merchantConfig: {
122
+ merchantName: 'Test Store Name',
123
+ merchantOrigin: 'rebilly-apple-pay-test-tunnel.ngrok.io'
124
+ },
125
+ applePayDisplayOptions: {
126
+ buttonColor: 'black',
127
+ buttonType: 'buy',
128
+ buttonHeight: '44px'
129
+ }
130
+ }
131
+ }
132
+
133
+ expect(output).toMatchObject(expectedOutput);
134
+ });
135
+ });
@@ -3,7 +3,10 @@ import camelCase from 'lodash.camelcase';
3
3
 
4
4
  export const getMethodData = (method) => {
5
5
  const METHOD_ID = kebabCase(method.feature?.name || method.method);
6
- const METHOD_TYPE = camelCase(method.feature?.name || method.method).replace('-', '');
7
-
8
- return {METHOD_ID, METHOD_TYPE}
9
- }
6
+ const METHOD_TYPE = camelCase(method.feature?.name || method.method).replace(
7
+ '-',
8
+ ''
9
+ );
10
+
11
+ return { METHOD_ID, METHOD_TYPE };
12
+ };
@@ -1,36 +1,45 @@
1
1
  /* eslint-disable no-unused-expressions, arrow-body-style */
2
- const SUPPORTED_EXPRESS_METHODS = [
3
- 'Google Pay'
4
- ];
2
+ import { getMethodData } from './get-method-data';
3
+
4
+ const SUPPORTED_EXPRESS_METHODS = ['Google Pay', 'Apple Pay', 'paypal'];
5
5
 
6
6
  const SUPPORTED_METHODS = ['payment-card'];
7
7
 
8
- const isExpressMethod = ({method, feature}) => {
9
- return SUPPORTED_EXPRESS_METHODS.includes(method)
10
- || SUPPORTED_EXPRESS_METHODS.includes(feature?.name);
11
- }
8
+ const isExpressMethod = ({ method, feature }) => {
9
+ return (
10
+ SUPPORTED_EXPRESS_METHODS.includes(method) ||
11
+ SUPPORTED_EXPRESS_METHODS.includes(feature?.name)
12
+ );
13
+ };
12
14
 
13
- const isSupportedMethod = ({method}) => {
15
+ const isSupportedMethod = ({ method }) => {
14
16
  return SUPPORTED_METHODS.includes(method);
15
- }
17
+ };
18
+
19
+ // TODO: just loader is used. We could simplify signature
20
+ export function getPaymentMethods({ state }) {
21
+ const result = {
22
+ EXPRESS_METHODS: [],
23
+ METHODS: []
24
+ };
16
25
 
17
- export function getPaymentMethods (methods) {
18
- const result = {
19
- EXPRESS_METHODS: [],
20
- METHODS: [],
21
- };
22
-
23
- methods.forEach(method => {
24
- if (isExpressMethod(method)) {
25
- // Add loader entry per express method
26
- this.loader.startLoading({id: `${method.method}-express`});
27
- result.EXPRESS_METHODS.push(method)
28
- } else if (isSupportedMethod(method)) {
29
- // Add loader entry per method
30
- this.loader.startLoading({id: method.method});
31
- result.METHODS.push(method);
32
- }
33
- })
34
-
35
- return result;
36
- }
26
+ state.data.readyToPay.forEach((method) => {
27
+ if (isExpressMethod(method)) {
28
+ const { METHOD_TYPE } = getMethodData(method);
29
+ // Add loader entry per express method
30
+ state.loader.startLoading({ id: `${METHOD_TYPE}-express` });
31
+ result.EXPRESS_METHODS.push(method);
32
+ } else if (isSupportedMethod(method)) {
33
+ // Add loader entry per method
34
+ state.loader.startLoading({ id: method.method });
35
+ result.METHODS.push(method);
36
+ }
37
+ });
38
+
39
+ if (!window.ApplePaySession) {
40
+ result.EXPRESS_METHODS = result.EXPRESS_METHODS.filter(method => method?.feature?.name !== 'Apple Pay');
41
+ state.loader.stopLoading({ id: 'applePay-express' });
42
+ }
43
+
44
+ return result;
45
+ }
@@ -4,46 +4,39 @@ import ReadyToPayModel from '@/storefront/models/ready-to-pay-model';
4
4
  class TestInstance {
5
5
  constructor() {
6
6
  this.loader = {
7
- startLoading: jest.fn()
7
+ startLoading: jest.fn(),
8
+ stopLoading: jest.fn()
8
9
  };
9
- }
10
-
11
- _getPaymentMethods() {
12
- return getPaymentMethods.apply(this, arguments);
10
+ this.data = {
11
+ readyToPay: [
12
+ new ReadyToPayModel({
13
+ method: 'payment-card',
14
+ feature: {
15
+ name: 'Google Pay',
16
+ merchantName: 'google-pay-merchant-name',
17
+ merchantOrigin: 'google-pay-merchant-origin'
18
+ },
19
+ brands: ['Visa'],
20
+ filters: []
21
+ }),
22
+ new ReadyToPayModel({
23
+ method: 'bitcoin',
24
+ filters: []
25
+ }),
26
+ new ReadyToPayModel({
27
+ method: 'payment-card',
28
+ brands: ['Visa'],
29
+ filters: []
30
+ })
31
+ ]
32
+ }
13
33
  }
14
34
  }
15
35
 
16
36
  it('should only return the allowed methods', () => {
17
37
  const instance = new TestInstance();
18
- const methods = [
19
- new ReadyToPayModel(
20
- {
21
- method: 'payment-card',
22
- feature: {
23
- name: 'Google Pay',
24
- merchantName: 'google-pay-merchant-name',
25
- merchantOrigin: 'google-pay-merchant-origin'
26
- },
27
- brands: ['Visa'],
28
- filters: []
29
- }
30
- ),
31
- new ReadyToPayModel(
32
- {
33
- method: 'bitcoin',
34
- filters: []
35
- },
36
- ),
37
- new ReadyToPayModel(
38
- {
39
- method: 'payment-card',
40
- brands: ['Visa'],
41
- filters: []
42
- }
43
- )
44
- ];
45
38
 
46
- const results = instance._getPaymentMethods(methods);
39
+ const results = getPaymentMethods({ state: instance });
47
40
  expect(results.hasOwnProperty('EXPRESS_METHODS')).toEqual(true);
48
41
  expect(results['EXPRESS_METHODS'].length).toEqual(1);
49
42
  expect(results['METHODS'].length).toEqual(1);