@rebilly/instruments 1.0.1-beta → 1.0.2-beta.10

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 (277) hide show
  1. package/.babelrc +23 -5
  2. package/.eslintrc.js +27 -0
  3. package/.prettierrc.js +11 -0
  4. package/CONTRIBUTING.md +4 -0
  5. package/README.md +361 -2
  6. package/dist/events/base-event.js +51 -37
  7. package/dist/events/events.spec.js +18 -0
  8. package/dist/events/index.js +11 -8
  9. package/dist/functions/destroy.js +27 -5
  10. package/dist/functions/destroy.spec.js +69 -0
  11. package/dist/functions/initialize.js +60 -41
  12. package/dist/functions/initialize.spec.js +13 -13
  13. package/dist/functions/mount/fetch-summary-data.js +46 -0
  14. package/dist/functions/mount/fetch-summary-data.spec.js +44 -0
  15. package/dist/functions/mount/index.js +346 -0
  16. package/dist/functions/mount/mount.spec.js +135 -0
  17. package/dist/functions/on.js +26 -18
  18. package/dist/functions/on.spec.js +45 -63
  19. package/dist/functions/purchase.js +41 -154
  20. package/dist/functions/purchase.spec.js +60 -76
  21. package/dist/functions/show.js +39 -43
  22. package/dist/functions/show.spec.js +57 -0
  23. package/dist/functions/update.js +60 -5
  24. package/dist/functions/update.spec.js +100 -0
  25. package/dist/i18n/en.json +19 -0
  26. package/dist/i18n/es.json +19 -0
  27. package/dist/i18n/i18n.spec.js +6 -23
  28. package/dist/i18n/index.js +44 -67
  29. package/dist/index.js +70 -71
  30. package/dist/index.spec.js +24 -44
  31. package/dist/loader/index.js +63 -62
  32. package/dist/loader/loader.spec.js +14 -11
  33. package/dist/storefront/index.js +28 -39
  34. package/dist/storefront/models/plan-model.js +37 -54
  35. package/dist/storefront/models/product-model.js +25 -36
  36. package/dist/storefront/models/ready-to-pay-model.js +38 -42
  37. package/dist/storefront/models/summary-model.js +72 -99
  38. package/dist/storefront/plans.js +37 -84
  39. package/dist/storefront/plans.spec.js +61 -151
  40. package/dist/storefront/products.js +35 -83
  41. package/dist/storefront/products.spec.js +60 -150
  42. package/dist/storefront/purchase.js +27 -64
  43. package/dist/storefront/purchase.spec.js +51 -87
  44. package/dist/storefront/ready-to-pay.js +45 -107
  45. package/dist/storefront/ready-to-pay.spec.js +72 -147
  46. package/dist/storefront/storefront.spec.js +6 -6
  47. package/dist/storefront/summary.js +37 -84
  48. package/dist/storefront/summary.spec.js +135 -240
  49. package/dist/style/base/__snapshots__/theme.spec.js.snap +52 -0
  50. package/dist/style/base/index.js +72 -0
  51. package/dist/style/base/theme.js +73 -0
  52. package/dist/style/base/theme.spec.js +30 -0
  53. package/dist/style/browserslist.js +8 -0
  54. package/dist/style/components/address.js +64 -0
  55. package/dist/style/components/button.js +61 -0
  56. package/dist/style/components/divider.js +48 -0
  57. package/dist/style/components/forms/checkbox.js +83 -0
  58. package/dist/style/components/forms/field.js +53 -0
  59. package/dist/style/components/forms/form.js +28 -0
  60. package/dist/style/components/forms/input.js +45 -0
  61. package/dist/style/components/forms/label.js +43 -0
  62. package/dist/style/components/forms/select.js +63 -0
  63. package/dist/style/components/forms/validation.js +34 -0
  64. package/dist/style/components/icons.js +22 -0
  65. package/dist/style/components/index.js +57 -0
  66. package/dist/style/components/loader.js +48 -0
  67. package/dist/style/components/methods.js +104 -0
  68. package/dist/style/components/overlay.js +33 -0
  69. package/dist/style/helpers/index.js +59 -0
  70. package/dist/style/index.js +48 -0
  71. package/dist/style/payment-instruments/content.js +17 -0
  72. package/dist/style/payment-instruments/index.js +20 -0
  73. package/dist/style/payment-instruments/payment-card.js +35 -0
  74. package/dist/style/utils/color-values.js +22 -0
  75. package/dist/style/vendor/framepay.js +34 -0
  76. package/dist/style/vendor/postmate.js +17 -0
  77. package/dist/style/views/confirmation.js +85 -0
  78. package/dist/style/views/index.js +29 -0
  79. package/dist/style/views/method-selector.js +20 -0
  80. package/dist/style/views/modal.js +93 -0
  81. package/dist/style/views/result.js +61 -0
  82. package/dist/style/views/summary.js +123 -0
  83. package/dist/utils/add-dom-element.js +12 -34
  84. package/dist/utils/format-currency.js +4 -4
  85. package/dist/utils/has-valid-css-selector.js +2 -2
  86. package/dist/utils/index.js +15 -31
  87. package/dist/utils/is-dom-element.js +1 -1
  88. package/dist/utils/process-property-as-dom-element.js +12 -17
  89. package/dist/utils/sleep.js +10 -0
  90. package/{src/components → dist/views}/__snapshots__/summary.spec.js.snap +7 -3
  91. package/dist/views/common/iframe/base-iframe.js +57 -0
  92. package/dist/views/common/iframe/event-listeners.js +50 -0
  93. package/dist/views/common/iframe/index.js +19 -0
  94. package/dist/views/common/iframe/method-iframe.js +33 -0
  95. package/dist/views/common/iframe/modal-iframe.js +38 -0
  96. package/dist/views/common/iframe/view-iframe.js +31 -0
  97. package/dist/views/common/render-utilities.js +11 -0
  98. package/dist/views/confirmation.js +82 -0
  99. package/dist/views/method-selector/__snapshots__/method-selector.spec.js.snap +3 -0
  100. package/dist/views/method-selector/express-methods/apple-pay.js +92 -0
  101. package/dist/views/method-selector/express-methods/google-pay.js +32 -0
  102. package/dist/views/method-selector/express-methods/paypal.js +19 -0
  103. package/dist/views/method-selector/generate-digital-wallet.js +59 -0
  104. package/dist/views/method-selector/generate-digital-wallet.spec.js +132 -0
  105. package/dist/views/method-selector/get-method-data.js +25 -0
  106. package/dist/views/method-selector/get-payment-methods.js +55 -0
  107. package/dist/views/method-selector/get-payment-methods.spec.js +44 -0
  108. package/dist/views/method-selector/index.js +133 -0
  109. package/dist/views/method-selector/method-selector.spec.js +139 -0
  110. package/dist/views/method-selector/mount-express-methods.js +69 -0
  111. package/dist/views/method-selector/mount-methods.js +78 -0
  112. package/dist/views/modal.js +83 -0
  113. package/dist/views/result.js +42 -0
  114. package/dist/views/summary.js +162 -0
  115. package/dist/views/summary.spec.js +148 -0
  116. package/package.json +12 -6
  117. package/src/events/base-event.js +35 -12
  118. package/src/events/events.spec.js +11 -0
  119. package/src/events/index.js +12 -6
  120. package/src/functions/destroy.js +22 -3
  121. package/src/functions/destroy.spec.js +63 -0
  122. package/src/functions/initialize.js +43 -20
  123. package/src/functions/initialize.spec.js +9 -7
  124. package/src/functions/mount/fetch-summary-data.js +29 -0
  125. package/src/functions/mount/fetch-summary-data.spec.js +41 -0
  126. package/src/functions/mount/index.js +312 -0
  127. package/src/functions/mount/mount.spec.js +171 -0
  128. package/src/functions/on.js +17 -14
  129. package/src/functions/on.spec.js +39 -29
  130. package/src/functions/purchase.js +24 -64
  131. package/src/functions/purchase.spec.js +19 -17
  132. package/src/functions/show.js +27 -7
  133. package/src/functions/show.spec.js +61 -0
  134. package/src/functions/update.js +50 -3
  135. package/src/functions/update.spec.js +107 -0
  136. package/src/i18n/i18n.spec.js +6 -4
  137. package/src/i18n/index.js +20 -12
  138. package/src/index.js +43 -49
  139. package/src/index.spec.js +11 -42
  140. package/src/loader/index.js +55 -39
  141. package/src/loader/loader.spec.js +30 -23
  142. package/src/storefront/index.js +9 -7
  143. package/src/storefront/models/plan-model.js +1 -1
  144. package/src/storefront/models/product-model.js +1 -1
  145. package/src/storefront/models/ready-to-pay-model.js +10 -4
  146. package/src/storefront/models/summary-model.js +8 -15
  147. package/src/storefront/plans.js +16 -12
  148. package/src/storefront/plans.spec.js +29 -37
  149. package/src/storefront/products.js +16 -12
  150. package/src/storefront/products.spec.js +28 -39
  151. package/src/storefront/purchase.js +8 -6
  152. package/src/storefront/purchase.spec.js +18 -17
  153. package/src/storefront/ready-to-pay.js +19 -13
  154. package/src/storefront/ready-to-pay.spec.js +41 -41
  155. package/src/storefront/storefront.spec.js +1 -1
  156. package/src/storefront/summary.js +14 -12
  157. package/src/storefront/summary.spec.js +37 -50
  158. package/src/style/base/__snapshots__/theme.spec.js.snap +52 -0
  159. package/src/style/base/index.js +63 -0
  160. package/src/style/base/theme.js +61 -0
  161. package/src/style/base/theme.spec.js +32 -0
  162. package/src/style/browserslist.js +1 -0
  163. package/src/style/components/address.js +55 -0
  164. package/src/style/components/button.js +54 -0
  165. package/src/style/components/divider.js +39 -0
  166. package/src/style/components/forms/checkbox.js +76 -0
  167. package/src/style/components/forms/field.js +44 -0
  168. package/src/style/components/forms/form.js +19 -0
  169. package/src/style/components/forms/input.js +36 -0
  170. package/src/style/components/forms/label.js +34 -0
  171. package/src/style/components/forms/select.js +54 -0
  172. package/src/style/components/forms/validation.js +25 -0
  173. package/src/style/components/icons.js +13 -0
  174. package/src/style/components/index.js +35 -0
  175. package/src/style/components/loader.js +41 -0
  176. package/src/style/components/methods.js +93 -0
  177. package/src/style/components/overlay.js +24 -0
  178. package/src/style/helpers/index.js +51 -0
  179. package/src/style/index.js +30 -0
  180. package/src/style/payment-instruments/content.js +8 -0
  181. package/src/style/payment-instruments/index.js +10 -0
  182. package/src/style/payment-instruments/payment-card.js +26 -0
  183. package/src/style/utils/color-values.js +9 -0
  184. package/src/style/vendor/framepay.js +25 -0
  185. package/src/style/vendor/postmate.js +8 -0
  186. package/src/style/views/confirmation.js +76 -0
  187. package/src/style/views/index.js +16 -0
  188. package/src/style/views/method-selector.js +11 -0
  189. package/src/style/views/modal.js +84 -0
  190. package/src/style/views/result.js +52 -0
  191. package/src/style/views/summary.js +114 -0
  192. package/src/utils/add-dom-element.js +12 -13
  193. package/src/utils/format-currency.js +4 -1
  194. package/src/utils/has-valid-css-selector.js +2 -2
  195. package/src/utils/index.js +2 -6
  196. package/src/utils/is-dom-element.js +1 -1
  197. package/src/utils/process-property-as-dom-element.js +27 -24
  198. package/src/utils/sleep.js +3 -0
  199. package/src/views/__snapshots__/summary.spec.js.snap +292 -0
  200. package/src/views/common/iframe/base-iframe.js +46 -0
  201. package/src/views/common/iframe/event-listeners.js +27 -0
  202. package/src/views/common/iframe/index.js +7 -0
  203. package/src/views/common/iframe/method-iframe.js +21 -0
  204. package/src/views/common/iframe/modal-iframe.js +27 -0
  205. package/src/views/common/iframe/view-iframe.js +18 -0
  206. package/src/views/common/render-utilities.js +4 -0
  207. package/src/views/confirmation.js +57 -0
  208. package/src/views/method-selector/__snapshots__/method-selector.spec.js.snap +3 -0
  209. package/src/views/method-selector/express-methods/apple-pay.js +78 -0
  210. package/src/views/method-selector/express-methods/google-pay.js +25 -0
  211. package/src/views/method-selector/express-methods/paypal.js +7 -0
  212. package/src/views/method-selector/generate-digital-wallet.js +44 -0
  213. package/src/views/method-selector/generate-digital-wallet.spec.js +131 -0
  214. package/src/{components/form → views/method-selector}/get-method-data.js +9 -5
  215. package/src/views/method-selector/get-payment-methods.js +40 -0
  216. package/src/views/method-selector/get-payment-methods.spec.js +40 -0
  217. package/src/views/method-selector/index.js +110 -0
  218. package/src/views/method-selector/method-selector.spec.js +146 -0
  219. package/src/views/method-selector/mount-express-methods.js +53 -0
  220. package/src/views/method-selector/mount-methods.js +71 -0
  221. package/src/views/modal.js +84 -0
  222. package/src/views/result.js +30 -0
  223. package/src/{components → views}/summary.js +90 -21
  224. package/src/views/summary.spec.js +170 -0
  225. package/tests/async-utilities.js +22 -0
  226. package/tests/mocks/rebilly-instruments-mock.js +105 -7
  227. package/dist/components/confirmation.js +0 -103
  228. package/dist/components/form/form.js +0 -110
  229. package/dist/components/form/form.spec.js +0 -135
  230. package/dist/components/form/get-method-data.js +0 -21
  231. package/dist/components/form/get-payment-methods.js +0 -42
  232. package/dist/components/form/method-selector.js +0 -61
  233. package/dist/components/form/mount-express-payment-methods.js +0 -102
  234. package/dist/components/form/process-digital-wallet-options.js +0 -20
  235. package/dist/components/form/zoid-helpers.js +0 -130
  236. package/dist/components/result.js +0 -66
  237. package/dist/components/summary.js +0 -60
  238. package/dist/components/summary.spec.js +0 -144
  239. package/dist/events/instrument-ready.js +0 -51
  240. package/dist/events/purchase-complete.js +0 -51
  241. package/dist/functions/mount.js +0 -311
  242. package/dist/functions/mount.spec.js +0 -203
  243. package/dist/styles/base-styles.js +0 -12
  244. package/dist/styles/flat-theme-object.js +0 -42
  245. package/dist/styles/framepay.js +0 -15
  246. package/dist/styles/main.js +0 -25
  247. package/dist/styles/payment-card.js +0 -12
  248. package/dist/styles/shade-tint-values-helper.js +0 -28
  249. package/dist/styles/style-variables.js +0 -43
  250. package/dist/utils/camel-case.js +0 -12
  251. package/dist/utils/kebab-case.js +0 -10
  252. package/dist/utils/un-kebab-case.js +0 -10
  253. package/src/components/confirmation.js +0 -77
  254. package/src/components/form/__snapshots__/form.spec.js.snap +0 -43
  255. package/src/components/form/form.js +0 -88
  256. package/src/components/form/form.spec.js +0 -109
  257. package/src/components/form/get-payment-methods.js +0 -32
  258. package/src/components/form/method-selector.js +0 -47
  259. package/src/components/form/mount-express-payment-methods.js +0 -84
  260. package/src/components/form/process-digital-wallet-options.js +0 -11
  261. package/src/components/form/zoid-helpers.js +0 -114
  262. package/src/components/result.js +0 -50
  263. package/src/components/summary.spec.js +0 -106
  264. package/src/events/instrument-ready.js +0 -11
  265. package/src/events/purchase-complete.js +0 -11
  266. package/src/functions/mount.js +0 -204
  267. package/src/functions/mount.spec.js +0 -172
  268. package/src/styles/base-styles.js +0 -741
  269. package/src/styles/flat-theme-object.js +0 -12
  270. package/src/styles/framepay.js +0 -30
  271. package/src/styles/main.js +0 -17
  272. package/src/styles/payment-card.js +0 -18
  273. package/src/styles/shade-tint-values-helper.js +0 -13
  274. package/src/styles/style-variables.js +0 -34
  275. package/src/utils/camel-case.js +0 -3
  276. package/src/utils/kebab-case.js +0 -3
  277. package/src/utils/un-kebab-case.js +0 -3
@@ -0,0 +1,57 @@
1
+ import { purchase } from '../functions/purchase';
2
+ import { ViewIframe } from './common/iframe';
3
+ import { replaceContent } from './common/render-utilities';
4
+ import { updateMethodSelector } from './method-selector';
5
+ import { updateSummary } from './summary';
6
+
7
+ export const baseConfirmationHTML =
8
+ '<div class="rebilly-instruments-confirmation"></div>';
9
+
10
+ export async function mountConfirmation({ instrument, mainStyle, state }) {
11
+ if (instrument.billingAddress && state.summary) {
12
+ updateSummary({ state, instrument });
13
+ }
14
+
15
+ replaceContent(state.form, baseConfirmationHTML);
16
+
17
+ state.loader.startLoading({ id: 'confirmation' });
18
+
19
+ const container = document.querySelector('.rebilly-instruments-confirmation');
20
+
21
+ const { paymentMethodsUrl } = state.options._computed;
22
+
23
+ const model = {
24
+ configs: state.configs,
25
+ options: state.options,
26
+ mainStyle,
27
+ instrument
28
+ };
29
+ const name = 'rebilly-instruments-confirmation';
30
+ const iframe = await new ViewIframe({
31
+ name,
32
+ url: `${paymentMethodsUrl}/confirmation`,
33
+ container,
34
+ model
35
+ });
36
+ iframe.bindEventListeners({
37
+ loader: state.loader
38
+ });
39
+
40
+ iframe.component.on(`${name}-confirm-purchase`, (confirmedInstrument) => {
41
+ purchase({ state, payload: confirmedInstrument });
42
+ });
43
+
44
+ iframe.component.on('choose-another-method', () => {
45
+ state.iframeComponents = state.iframeComponents.filter((item) => {
46
+ if (item.name === iframe.name) {
47
+ item.destroy();
48
+ return false;
49
+ }
50
+ return true;
51
+ });
52
+ updateSummary({ state });
53
+ updateMethodSelector({ state, mainStyle });
54
+ });
55
+
56
+ state.iframeComponents.push(iframe);
57
+ }
@@ -0,0 +1,3 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`Summary component should inject the proper HTML for express methods 1`] = `null`;
@@ -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.configs.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.configs.publishableKey,
45
+ organizationId: state.configs.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.configs.websiteId,
61
+ items: state.options.intent.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,25 @@
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
+ configs: state.configs,
10
+ options: state.options
11
+ };
12
+
13
+ const iframe = await new MethodIframe({
14
+ name: METHOD_ID,
15
+ url: `${paymentMethodsUrl}/${METHOD_ID}`,
16
+ container,
17
+ model
18
+ });
19
+
20
+ iframe.bindEventListeners({
21
+ loader: state.loader
22
+ });
23
+
24
+ state.iframeComponents.push(iframe);
25
+ }
@@ -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,44 @@
1
+ import { getMethodData } from './get-method-data';
2
+
3
+ export function generateDigitalWallet({ state, summary, EXPRESS_METHODS }) {
4
+ const output = {};
5
+
6
+ const { paymentInstruments } = state.options;
7
+
8
+ const transactionData = {
9
+ amount: summary.total,
10
+ currency: summary.currency,
11
+ countryCode: state.options.intent.countryCode,
12
+ label: state.configs.websiteId
13
+ }
14
+
15
+ EXPRESS_METHODS.forEach(method => {
16
+ const { METHOD_TYPE } = getMethodData(method);
17
+
18
+ if (method.feature?.name === 'Google Pay') {
19
+ output[METHOD_TYPE] = {
20
+ transactionData,
21
+ merchantConfig: {
22
+ merchantName: method.feature.merchantName,
23
+ merchantOrigin: method.feature.merchantOrigin
24
+ },
25
+ googlePayDisplayOptions: paymentInstruments.googlePay.displayOptions,
26
+ }
27
+ }
28
+
29
+ if (method.feature?.name === 'Apple Pay') {
30
+ output[METHOD_TYPE] = {
31
+ transactionData,
32
+ merchantConfig: {
33
+ merchantName: paymentInstruments.applePay.merchantConfig?.merchantName,
34
+ // Apple Pay code cannot run in an iframe, and the merchant origin must be
35
+ // registered as a merchant domain, so we can just send the current URL.
36
+ merchantOrigin: window.location.hostname,
37
+ },
38
+ applePayDisplayOptions: paymentInstruments.applePay.displayOptions
39
+ }
40
+ }
41
+ })
42
+
43
+ return output;
44
+ }
@@ -0,0 +1,131 @@
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
+
5
+ describe('generateDigitalWallet', () => {
6
+ class TestInstance {
7
+ constructor({ configs = {}, options = {} } = {}) {
8
+ this.configs = configs;
9
+ this.options = options;
10
+ }
11
+ }
12
+
13
+ const summary = new SummaryModel({
14
+ currency: 'USD',
15
+ total: 1,
16
+ });
17
+
18
+ const configs = {
19
+ websiteId: 'test-website-id'
20
+ };
21
+
22
+ const options = {
23
+ intent: {
24
+ countryCode: 'US',
25
+ },
26
+ paymentInstruments: {
27
+ googlePay: {
28
+ displayOptions: {
29
+ buttonColor: 'black',
30
+ buttonType: 'short',
31
+ buttonHeight: '44px'
32
+ }
33
+ },
34
+ applePay: {
35
+ displayOptions: {
36
+ buttonColor: 'black',
37
+ buttonType: 'buy',
38
+ buttonHeight: '44px'
39
+ },
40
+ merchantConfig: {
41
+ merchantName: 'Test Store Name',
42
+ },
43
+ }
44
+ }
45
+ };
46
+
47
+ it('should generate the correct digital wallet config for Google pay', () => {
48
+ const expressMethods = [
49
+ new ReadyToPayModel({
50
+ method: 'payment-card',
51
+ feature: {
52
+ name: 'Google Pay',
53
+ merchantName: 'google-pay-merchant-name',
54
+ merchantOrigin: 'google-pay-merchant-origin'
55
+ },
56
+ brands: ['Visa']
57
+ })
58
+ ];
59
+
60
+ const output = generateDigitalWallet({
61
+ state: new TestInstance({configs, options}),
62
+ EXPRESS_METHODS: expressMethods,
63
+ summary
64
+ });
65
+
66
+ const expectedOutput ={
67
+ googlePay: {
68
+ transactionData: {
69
+ amount: 1,
70
+ currency: 'USD',
71
+ countryCode: 'US',
72
+ label: 'test-website-id'
73
+ },
74
+ merchantConfig: {
75
+ merchantName: 'google-pay-merchant-name',
76
+ merchantOrigin: 'google-pay-merchant-origin'
77
+ },
78
+ googlePayDisplayOptions: {
79
+ buttonColor: 'black',
80
+ buttonType: 'short',
81
+ buttonHeight: '44px'
82
+ }
83
+ }
84
+ }
85
+
86
+ expect(output).toMatchObject(expectedOutput);
87
+ });
88
+
89
+ it('should generate the correct digital wallet config for Apple pay', () => {
90
+ delete window.location
91
+ window.location = new URL('https://rebilly-apple-pay-test-tunnel.ngrok.io/');
92
+
93
+ const expressMethods = [
94
+ new ReadyToPayModel({
95
+ method: 'payment-card',
96
+ feature: {
97
+ name: 'Apple Pay',
98
+ },
99
+ brands: ['Visa']
100
+ })
101
+ ];
102
+
103
+ const output = generateDigitalWallet({
104
+ state: new TestInstance({configs, options}),
105
+ EXPRESS_METHODS: expressMethods,
106
+ summary
107
+ });
108
+
109
+ const expectedOutput = {
110
+ applePay: {
111
+ transactionData: {
112
+ amount: 1,
113
+ currency: 'USD',
114
+ countryCode: 'US',
115
+ label: 'test-website-id'
116
+ },
117
+ merchantConfig: {
118
+ merchantName: 'Test Store Name',
119
+ merchantOrigin: 'rebilly-apple-pay-test-tunnel.ngrok.io'
120
+ },
121
+ applePayDisplayOptions: {
122
+ buttonColor: 'black',
123
+ buttonType: 'buy',
124
+ buttonHeight: '44px'
125
+ }
126
+ }
127
+ }
128
+
129
+ expect(output).toMatchObject(expectedOutput);
130
+ });
131
+ });
@@ -1,8 +1,12 @@
1
- import {kebabCase, camelCase} from '../../utils';
1
+ import kebabCase from 'lodash.kebabcase';
2
+ import camelCase from 'lodash.camelcase';
2
3
 
3
4
  export const getMethodData = (method) => {
4
5
  const METHOD_ID = kebabCase(method.feature?.name || method.method);
5
- const METHOD_TYPE = camelCase(method.feature?.name || method.method).replace('-', '');
6
-
7
- return {METHOD_ID, METHOD_TYPE}
8
- }
6
+ const METHOD_TYPE = camelCase(method.feature?.name || method.method).replace(
7
+ '-',
8
+ ''
9
+ );
10
+
11
+ return { METHOD_ID, METHOD_TYPE };
12
+ };
@@ -0,0 +1,40 @@
1
+ /* eslint-disable no-unused-expressions, arrow-body-style */
2
+ import { getMethodData } from './get-method-data';
3
+
4
+ const SUPPORTED_EXPRESS_METHODS = ['Google Pay', 'Apple Pay', 'paypal'];
5
+
6
+ const SUPPORTED_METHODS = ['payment-card'];
7
+
8
+ const isExpressMethod = ({ method, feature }) => {
9
+ return (
10
+ SUPPORTED_EXPRESS_METHODS.includes(method) ||
11
+ SUPPORTED_EXPRESS_METHODS.includes(feature?.name)
12
+ );
13
+ };
14
+
15
+ const isSupportedMethod = ({ method }) => {
16
+ return SUPPORTED_METHODS.includes(method);
17
+ };
18
+
19
+ // TODO: just loader is used. We could simplify signature
20
+ export function getPaymentMethods({ methods, state }) {
21
+ const result = {
22
+ EXPRESS_METHODS: [],
23
+ METHODS: []
24
+ };
25
+
26
+ methods.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
+ return result;
40
+ }
@@ -0,0 +1,40 @@
1
+ import { getPaymentMethods } from './get-payment-methods';
2
+ import ReadyToPayModel from '@/storefront/models/ready-to-pay-model';
3
+
4
+ class TestInstance {
5
+ constructor() {
6
+ this.loader = {
7
+ startLoading: jest.fn()
8
+ };
9
+ }
10
+ }
11
+
12
+ it('should only return the allowed methods', () => {
13
+ const instance = new TestInstance();
14
+ const methods = [
15
+ new ReadyToPayModel({
16
+ method: 'payment-card',
17
+ feature: {
18
+ name: 'Google Pay',
19
+ merchantName: 'google-pay-merchant-name',
20
+ merchantOrigin: 'google-pay-merchant-origin'
21
+ },
22
+ brands: ['Visa'],
23
+ filters: []
24
+ }),
25
+ new ReadyToPayModel({
26
+ method: 'bitcoin',
27
+ filters: []
28
+ }),
29
+ new ReadyToPayModel({
30
+ method: 'payment-card',
31
+ brands: ['Visa'],
32
+ filters: []
33
+ })
34
+ ];
35
+
36
+ const results = getPaymentMethods({ methods, state: instance });
37
+ expect(results.hasOwnProperty('EXPRESS_METHODS')).toEqual(true);
38
+ expect(results['EXPRESS_METHODS'].length).toEqual(1);
39
+ expect(results['METHODS'].length).toEqual(1);
40
+ });
@@ -0,0 +1,110 @@
1
+ /* eslint-disable no-undef */
2
+ import { collectData } from '@rebilly/risk-data-collector';
3
+ import { getPaymentMethods } from './get-payment-methods';
4
+ import { mountExpressMethods } from './mount-express-methods';
5
+ import { generateDigitalWallet } from './generate-digital-wallet';
6
+ import { MountMethods } from './mount-methods';
7
+ import { fetchSummaryData } from '../../functions/mount/fetch-summary-data';
8
+
9
+ export const baseMethodSelectorHTML = (compactExpressInstruments) => `
10
+ <div class="rebilly-instruments-content">
11
+ <div class="rebilly-instruments-method-selector">
12
+ <div class="rebilly-instruments-express-methods ${
13
+ compactExpressInstruments ? 'is-compact' : ''
14
+ }">
15
+ <span data-rebilly-i18n="form.expressCheckout" class="rebilly-instruments-express-methods-label">Express checkout</span>
16
+ <div class="rebilly-instruments-express-methods-container"></div>
17
+ </div>
18
+ <div class="rebilly-instruments-divider">
19
+ <span class="rebilly-instruments-divider-label" data-rebilly-i18n="form.or">Or</span>
20
+ </div>
21
+ <div class="rebilly-instruments-methods"></div>
22
+ </div>
23
+ </div>
24
+ `;
25
+
26
+ export function mountMethodSelector({ state, formOptions }) {
27
+ const { readyToPay, summary, plans, products, mainStyle } = formOptions;
28
+ const { EXPRESS_METHODS, METHODS } = getPaymentMethods({
29
+ methods: readyToPay,
30
+ state
31
+ });
32
+
33
+ state.form.innerHTML += baseMethodSelectorHTML(
34
+ state.options.paymentInstruments.compactExpressInstruments
35
+ );
36
+
37
+ const EXPRESS_METHODS_CONTAINER = document.querySelector(
38
+ '.rebilly-instruments-express-methods-container'
39
+ );
40
+ const METHODS_DIVIDER = document.querySelector(
41
+ '.rebilly-instruments-divider'
42
+ );
43
+ METHODS_DIVIDER.style.display =
44
+ METHODS.length && EXPRESS_METHODS.length ? 'block' : 'none';
45
+ const METHODS_CONTAINER = document.querySelector(
46
+ '.rebilly-instruments-methods'
47
+ );
48
+
49
+ state.configs.digitalWallet = generateDigitalWallet({state, summary, EXPRESS_METHODS});
50
+
51
+ if (METHODS.length) {
52
+ MountMethods({
53
+ state,
54
+ METHODS_CONTAINER,
55
+ METHODS,
56
+ mainStyle,
57
+ plans,
58
+ products
59
+ });
60
+ } else {
61
+ METHODS_CONTAINER.style.display = 'none';
62
+ }
63
+
64
+ if (EXPRESS_METHODS.length) {
65
+ mountExpressMethods({
66
+ state,
67
+ EXPRESS_METHODS,
68
+ EXPRESS_METHODS_CONTAINER
69
+ });
70
+ } else {
71
+ EXPRESS_METHODS_CONTAINER.parentNode.style.display = 'none';
72
+ }
73
+
74
+ state.translate.translateItems();
75
+
76
+ state.loader.stopLoading({ id: 'initForm' });
77
+ }
78
+
79
+ export async function updateMethodSelector({ state, mainStyle }) {
80
+ state.loader.startLoading({ id: 'initForm' });
81
+ const { riskMetadata } = await collectData();
82
+
83
+ const {
84
+ readyToPay,
85
+ summary: summaryData,
86
+ plans,
87
+ products
88
+ } = await fetchSummaryData({ state, riskMetadata });
89
+
90
+ const formOptions = {
91
+ summary: summaryData,
92
+ readyToPay,
93
+ plans,
94
+ products,
95
+ mainStyle
96
+ };
97
+
98
+ state.form
99
+ .querySelectorAll(':not(.rebilly-instruments-confirmation)')
100
+ .forEach((element) => {
101
+ if (
102
+ !element.classList.contains('rebilly-instruments-loader') &&
103
+ !element.classList.contains('rebilly-instruments-loader-spinner')
104
+ ) {
105
+ element.remove();
106
+ }
107
+ });
108
+
109
+ mountMethodSelector({ state, formOptions });
110
+ }