@rebilly/instruments 1.0.2-beta.1 → 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 (261) hide show
  1. package/.babelrc +13 -4
  2. package/.eslintrc.js +27 -0
  3. package/.prettierrc.js +11 -0
  4. package/CONTRIBUTING.md +4 -0
  5. package/README.md +350 -0
  6. package/dist/events/base-event.js +40 -11
  7. package/dist/events/events.spec.js +18 -0
  8. package/dist/events/index.js +10 -7
  9. package/dist/functions/destroy.js +27 -5
  10. package/dist/functions/destroy.spec.js +69 -0
  11. package/dist/functions/initialize.js +24 -20
  12. package/dist/functions/initialize.spec.js +4 -4
  13. package/dist/functions/mount/fetch-summary-data.js +26 -11
  14. package/dist/functions/mount/fetch-summary-data.spec.js +15 -16
  15. package/dist/functions/mount/index.js +168 -106
  16. package/dist/functions/mount/mount.spec.js +14 -36
  17. package/dist/functions/on.js +25 -17
  18. package/dist/functions/on.spec.js +36 -18
  19. package/dist/functions/purchase.js +33 -74
  20. package/dist/functions/purchase.spec.js +17 -14
  21. package/dist/functions/show.js +31 -8
  22. package/dist/functions/show.spec.js +42 -17
  23. package/dist/functions/update.js +60 -4
  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/index.js +5 -0
  28. package/dist/index.js +67 -55
  29. package/dist/index.spec.js +6 -10
  30. package/dist/loader/index.js +24 -4
  31. package/dist/loader/loader.spec.js +4 -4
  32. package/dist/storefront/models/ready-to-pay-model.js +7 -1
  33. package/dist/storefront/plans.js +9 -10
  34. package/dist/storefront/plans.spec.js +20 -20
  35. package/dist/storefront/products.js +9 -10
  36. package/dist/storefront/products.spec.js +20 -20
  37. package/dist/storefront/purchase.js +9 -8
  38. package/dist/storefront/purchase.spec.js +7 -4
  39. package/dist/storefront/ready-to-pay.js +12 -11
  40. package/dist/storefront/ready-to-pay.spec.js +24 -19
  41. package/dist/storefront/storefront.spec.js +1 -1
  42. package/dist/storefront/summary.js +11 -12
  43. package/dist/storefront/summary.spec.js +25 -24
  44. package/dist/style/base/__snapshots__/theme.spec.js.snap +52 -0
  45. package/dist/style/base/index.js +72 -0
  46. package/dist/style/base/theme.js +73 -0
  47. package/dist/style/base/theme.spec.js +30 -0
  48. package/dist/style/browserslist.js +8 -0
  49. package/dist/style/components/address.js +64 -0
  50. package/dist/style/components/button.js +61 -0
  51. package/dist/style/components/divider.js +48 -0
  52. package/dist/style/components/forms/checkbox.js +83 -0
  53. package/dist/style/components/forms/field.js +53 -0
  54. package/dist/style/components/forms/form.js +28 -0
  55. package/dist/style/components/forms/input.js +45 -0
  56. package/dist/style/components/forms/label.js +43 -0
  57. package/dist/style/components/forms/select.js +63 -0
  58. package/dist/style/components/forms/validation.js +34 -0
  59. package/dist/style/components/icons.js +22 -0
  60. package/dist/style/components/index.js +57 -0
  61. package/dist/style/components/loader.js +48 -0
  62. package/dist/style/components/methods.js +104 -0
  63. package/dist/style/components/overlay.js +33 -0
  64. package/dist/style/helpers/index.js +59 -0
  65. package/dist/style/index.js +48 -0
  66. package/dist/style/payment-instruments/content.js +17 -0
  67. package/dist/style/payment-instruments/index.js +20 -0
  68. package/dist/{styles → style/payment-instruments}/payment-card.js +14 -6
  69. package/dist/{styles/shade-tint-values-helper.js → style/utils/color-values.js} +5 -9
  70. package/dist/style/vendor/framepay.js +34 -0
  71. package/dist/style/vendor/postmate.js +17 -0
  72. package/dist/style/views/confirmation.js +85 -0
  73. package/dist/style/views/index.js +29 -0
  74. package/dist/style/views/method-selector.js +20 -0
  75. package/dist/style/views/modal.js +93 -0
  76. package/dist/style/views/result.js +61 -0
  77. package/dist/style/views/summary.js +123 -0
  78. package/dist/utils/format-currency.js +1 -0
  79. package/dist/utils/has-valid-css-selector.js +1 -1
  80. package/dist/utils/index.js +3 -19
  81. package/dist/utils/process-property-as-dom-element.js +0 -2
  82. package/dist/utils/sleep.js +10 -0
  83. package/{src/components → dist/views}/__snapshots__/summary.spec.js.snap +7 -3
  84. package/dist/views/common/iframe/base-iframe.js +57 -0
  85. package/dist/views/common/iframe/event-listeners.js +50 -0
  86. package/dist/views/common/iframe/index.js +19 -0
  87. package/dist/views/common/iframe/method-iframe.js +33 -0
  88. package/dist/views/common/iframe/modal-iframe.js +38 -0
  89. package/dist/views/common/iframe/view-iframe.js +31 -0
  90. package/dist/views/common/render-utilities.js +11 -0
  91. package/dist/views/confirmation.js +82 -0
  92. package/dist/views/method-selector/__snapshots__/method-selector.spec.js.snap +3 -0
  93. package/dist/views/method-selector/express-methods/apple-pay.js +92 -0
  94. package/dist/views/method-selector/express-methods/google-pay.js +32 -0
  95. package/dist/views/method-selector/express-methods/paypal.js +19 -0
  96. package/dist/views/method-selector/generate-digital-wallet.js +59 -0
  97. package/dist/views/method-selector/generate-digital-wallet.spec.js +132 -0
  98. package/dist/views/method-selector/get-method-data.js +25 -0
  99. package/dist/{components/form → views/method-selector}/get-payment-methods.js +22 -6
  100. package/dist/views/method-selector/get-payment-methods.spec.js +44 -0
  101. package/dist/views/method-selector/index.js +133 -0
  102. package/dist/views/method-selector/method-selector.spec.js +139 -0
  103. package/dist/views/method-selector/mount-express-methods.js +69 -0
  104. package/dist/views/method-selector/mount-methods.js +78 -0
  105. package/dist/views/modal.js +83 -0
  106. package/dist/views/result.js +42 -0
  107. package/dist/{components → views}/summary.js +36 -25
  108. package/dist/{components → views}/summary.spec.js +49 -22
  109. package/package.json +11 -5
  110. package/src/events/base-event.js +35 -12
  111. package/src/events/events.spec.js +11 -0
  112. package/src/events/index.js +12 -6
  113. package/src/functions/destroy.js +22 -3
  114. package/src/functions/destroy.spec.js +63 -0
  115. package/src/functions/initialize.js +23 -18
  116. package/src/functions/initialize.spec.js +9 -7
  117. package/src/functions/mount/fetch-summary-data.js +16 -13
  118. package/src/functions/mount/fetch-summary-data.spec.js +22 -27
  119. package/src/functions/mount/index.js +194 -133
  120. package/src/functions/mount/mount.spec.js +83 -84
  121. package/src/functions/on.js +17 -14
  122. package/src/functions/on.spec.js +39 -29
  123. package/src/functions/purchase.js +24 -64
  124. package/src/functions/purchase.spec.js +19 -17
  125. package/src/functions/show.js +26 -6
  126. package/src/functions/show.spec.js +41 -19
  127. package/src/functions/update.js +49 -3
  128. package/src/functions/update.spec.js +107 -0
  129. package/src/i18n/i18n.spec.js +6 -4
  130. package/src/i18n/index.js +19 -11
  131. package/src/index.js +42 -51
  132. package/src/index.spec.js +11 -20
  133. package/src/loader/index.js +55 -39
  134. package/src/loader/loader.spec.js +30 -23
  135. package/src/storefront/index.js +9 -7
  136. package/src/storefront/models/plan-model.js +1 -1
  137. package/src/storefront/models/product-model.js +1 -1
  138. package/src/storefront/models/ready-to-pay-model.js +10 -4
  139. package/src/storefront/models/summary-model.js +8 -15
  140. package/src/storefront/plans.js +16 -12
  141. package/src/storefront/plans.spec.js +29 -37
  142. package/src/storefront/products.js +16 -12
  143. package/src/storefront/products.spec.js +28 -39
  144. package/src/storefront/purchase.js +8 -6
  145. package/src/storefront/purchase.spec.js +18 -17
  146. package/src/storefront/ready-to-pay.js +19 -13
  147. package/src/storefront/ready-to-pay.spec.js +41 -41
  148. package/src/storefront/storefront.spec.js +1 -1
  149. package/src/storefront/summary.js +14 -12
  150. package/src/storefront/summary.spec.js +37 -50
  151. package/src/style/base/__snapshots__/theme.spec.js.snap +52 -0
  152. package/src/style/base/index.js +63 -0
  153. package/src/style/base/theme.js +61 -0
  154. package/src/style/base/theme.spec.js +32 -0
  155. package/src/style/browserslist.js +1 -0
  156. package/src/style/components/address.js +55 -0
  157. package/src/style/components/button.js +54 -0
  158. package/src/style/components/divider.js +39 -0
  159. package/src/style/components/forms/checkbox.js +76 -0
  160. package/src/style/components/forms/field.js +44 -0
  161. package/src/style/components/forms/form.js +19 -0
  162. package/src/style/components/forms/input.js +36 -0
  163. package/src/style/components/forms/label.js +34 -0
  164. package/src/style/components/forms/select.js +54 -0
  165. package/src/style/components/forms/validation.js +25 -0
  166. package/src/style/components/icons.js +13 -0
  167. package/src/style/components/index.js +35 -0
  168. package/src/style/components/loader.js +41 -0
  169. package/src/style/components/methods.js +93 -0
  170. package/src/style/components/overlay.js +24 -0
  171. package/src/style/helpers/index.js +51 -0
  172. package/src/style/index.js +30 -0
  173. package/src/style/payment-instruments/content.js +8 -0
  174. package/src/style/payment-instruments/index.js +10 -0
  175. package/src/style/payment-instruments/payment-card.js +26 -0
  176. package/src/style/utils/color-values.js +9 -0
  177. package/src/style/vendor/framepay.js +25 -0
  178. package/src/style/vendor/postmate.js +8 -0
  179. package/src/style/views/confirmation.js +76 -0
  180. package/src/style/views/index.js +16 -0
  181. package/src/style/views/method-selector.js +11 -0
  182. package/src/style/views/modal.js +84 -0
  183. package/src/style/views/result.js +52 -0
  184. package/src/style/views/summary.js +114 -0
  185. package/src/utils/add-dom-element.js +12 -13
  186. package/src/utils/format-currency.js +4 -1
  187. package/src/utils/has-valid-css-selector.js +2 -2
  188. package/src/utils/index.js +2 -6
  189. package/src/utils/is-dom-element.js +1 -1
  190. package/src/utils/process-property-as-dom-element.js +27 -24
  191. package/src/utils/sleep.js +3 -0
  192. package/src/views/__snapshots__/summary.spec.js.snap +292 -0
  193. package/src/views/common/iframe/base-iframe.js +46 -0
  194. package/src/views/common/iframe/event-listeners.js +27 -0
  195. package/src/views/common/iframe/index.js +7 -0
  196. package/src/views/common/iframe/method-iframe.js +21 -0
  197. package/src/views/common/iframe/modal-iframe.js +27 -0
  198. package/src/views/common/iframe/view-iframe.js +18 -0
  199. package/src/views/common/render-utilities.js +4 -0
  200. package/src/views/confirmation.js +57 -0
  201. package/src/views/method-selector/__snapshots__/method-selector.spec.js.snap +3 -0
  202. package/src/views/method-selector/express-methods/apple-pay.js +78 -0
  203. package/src/views/method-selector/express-methods/google-pay.js +25 -0
  204. package/src/views/method-selector/express-methods/paypal.js +7 -0
  205. package/src/views/method-selector/generate-digital-wallet.js +44 -0
  206. package/src/views/method-selector/generate-digital-wallet.spec.js +131 -0
  207. package/src/{components/form → views/method-selector}/get-method-data.js +9 -5
  208. package/src/views/method-selector/get-payment-methods.js +40 -0
  209. package/src/views/method-selector/get-payment-methods.spec.js +40 -0
  210. package/src/views/method-selector/index.js +110 -0
  211. package/src/views/method-selector/method-selector.spec.js +146 -0
  212. package/src/views/method-selector/mount-express-methods.js +53 -0
  213. package/src/views/method-selector/mount-methods.js +71 -0
  214. package/src/views/modal.js +84 -0
  215. package/src/views/result.js +30 -0
  216. package/src/{components → views}/summary.js +65 -33
  217. package/src/views/summary.spec.js +170 -0
  218. package/tests/async-utilities.js +22 -0
  219. package/tests/mocks/rebilly-instruments-mock.js +105 -7
  220. package/dist/components/confirmation.js +0 -113
  221. package/dist/components/form/form.js +0 -143
  222. package/dist/components/form/form.spec.js +0 -111
  223. package/dist/components/form/get-method-data.js +0 -21
  224. package/dist/components/form/method-selector.js +0 -60
  225. package/dist/components/form/mount-express-payment-methods.js +0 -102
  226. package/dist/components/form/process-digital-wallet-options.js +0 -24
  227. package/dist/components/form/zoid-helpers.js +0 -131
  228. package/dist/components/result.js +0 -68
  229. package/dist/events/instrument-ready.js +0 -24
  230. package/dist/events/purchase-complete.js +0 -24
  231. package/dist/styles/base-styles.js +0 -793
  232. package/dist/styles/flat-theme-object.js +0 -23
  233. package/dist/styles/framepay.js +0 -38
  234. package/dist/styles/main.js +0 -29
  235. package/dist/styles/style-variables.js +0 -44
  236. package/dist/utils/camel-case.js +0 -10
  237. package/dist/utils/kebab-case.js +0 -10
  238. package/dist/utils/un-kebab-case.js +0 -10
  239. package/src/components/confirmation.js +0 -81
  240. package/src/components/form/__snapshots__/form.spec.js.snap +0 -43
  241. package/src/components/form/form.js +0 -117
  242. package/src/components/form/form.spec.js +0 -109
  243. package/src/components/form/get-payment-methods.js +0 -32
  244. package/src/components/form/method-selector.js +0 -47
  245. package/src/components/form/mount-express-payment-methods.js +0 -84
  246. package/src/components/form/process-digital-wallet-options.js +0 -11
  247. package/src/components/form/zoid-helpers.js +0 -117
  248. package/src/components/result.js +0 -50
  249. package/src/components/summary.spec.js +0 -106
  250. package/src/events/instrument-ready.js +0 -11
  251. package/src/events/purchase-complete.js +0 -11
  252. package/src/styles/base-styles.js +0 -784
  253. package/src/styles/flat-theme-object.js +0 -12
  254. package/src/styles/framepay.js +0 -30
  255. package/src/styles/main.js +0 -17
  256. package/src/styles/payment-card.js +0 -18
  257. package/src/styles/shade-tint-values-helper.js +0 -13
  258. package/src/styles/style-variables.js +0 -34
  259. package/src/utils/camel-case.js +0 -3
  260. package/src/utils/kebab-case.js +0 -3
  261. package/src/utils/un-kebab-case.js +0 -3
@@ -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
+ }
@@ -0,0 +1,146 @@
1
+ import SummaryModel from '@/storefront/models/summary-model';
2
+ import ReadyToPayModel from '@/storefront/models/ready-to-pay-model';
3
+ import { Loader } from '../../loader';
4
+ import { Translate } from '../../i18n';
5
+ import { mountMethodSelector, updateMethodSelector } from './index';
6
+ import { avoidUnhandledPromises } from 'tests/async-utilities';
7
+ import { MockStorefront } from 'tests/mocks/storefront-mock';
8
+
9
+ describe('Summary component', () => {
10
+ let formElement;
11
+ beforeEach(() => {
12
+ formElement = document.createElement('div');
13
+ document.body.append(formElement);
14
+ });
15
+
16
+ class TestMountMethodSelectorInstance {
17
+ constructor({
18
+ configs = {},
19
+ options = {},
20
+ form = formElement,
21
+ loader = new Loader(),
22
+ translate = new Translate(),
23
+ zoidComponents = {}
24
+ } = {}) {
25
+ this.configs = configs;
26
+ this.options = options;
27
+ this.form = form;
28
+ this.loader = loader;
29
+ this.translate = translate;
30
+ this.zoidComponents = zoidComponents;
31
+ this.storefront = MockStorefront();
32
+ }
33
+ }
34
+
35
+ const options = {
36
+ intent: {
37
+ countryCode: 'US',
38
+ items: [
39
+ {
40
+ planId: 'my-awesome-product',
41
+ quantity: 1,
42
+ thumbnail: ''
43
+ },
44
+ {
45
+ planId: 'awesome-t-shirt',
46
+ quantity: 2,
47
+ thumbnail: ''
48
+ }
49
+ ]
50
+ },
51
+ paymentInstruments: {
52
+ googlePay: {
53
+ displayOptions: {
54
+ buttonColor: 'black',
55
+ buttonHeight: '44px',
56
+ buttonType: 'short'
57
+ }
58
+ },
59
+ compactExpressInstruments: true
60
+ },
61
+ _computed: {
62
+ paymentMethodsUrl: ''
63
+ }
64
+ };
65
+
66
+ const summaryData = new SummaryModel({
67
+ currency: 'USD',
68
+ lineItems: [
69
+ {
70
+ type: 'debit',
71
+ description: 'My Awesome Product',
72
+ unitPrice: 30,
73
+ quantity: 1,
74
+ price: 30,
75
+ productId: 'my-awesome-product',
76
+ planId: 'my-awesome-product'
77
+ },
78
+ {
79
+ type: 'debit',
80
+ description: 'Awesome T-Shirt',
81
+ unitPrice: 20,
82
+ quantity: 2,
83
+ price: 40,
84
+ productId: 'my-app',
85
+ planId: 'awesome-t-shirt'
86
+ }
87
+ ],
88
+ subtotalAmount: 70,
89
+ taxAmount: 0,
90
+ shippingAmount: 0,
91
+ discountsAmount: 0,
92
+ total: 70
93
+ });
94
+
95
+ const readyToPayData = [
96
+ new ReadyToPayModel({
97
+ method: 'payment-card',
98
+ feature: {
99
+ name: 'Google Pay',
100
+ merchantName: 'google-pay-merchant-name',
101
+ merchantOrigin: 'google-pay-merchant-origin'
102
+ },
103
+ brands: ['Visa'],
104
+ filters: []
105
+ })
106
+ ];
107
+
108
+ const configs = {
109
+ websiteId: 'test-website-id'
110
+ };
111
+
112
+ it('should inject the proper HTML for express methods', async () => {
113
+ const mountSummaryInstance = new TestMountMethodSelectorInstance({
114
+ configs,
115
+ options
116
+ });
117
+
118
+ mountSummaryInstance.loader.DOM.form = mountSummaryInstance.form;
119
+
120
+ mountMethodSelector({
121
+ state: mountSummaryInstance,
122
+ formOptions: {
123
+ summary: summaryData,
124
+ readyToPay: readyToPayData
125
+ }
126
+ });
127
+
128
+ const form = document.querySelector('.rebilly-instruments-form');
129
+ expect(form).toMatchSnapshot();
130
+ await avoidUnhandledPromises();
131
+ });
132
+
133
+ it('should allow updating method selector', async () => {
134
+ const state = new TestMountMethodSelectorInstance({
135
+ configs,
136
+ options
137
+ });
138
+
139
+ state.loader.DOM.form = state.form;
140
+
141
+ await updateMethodSelector({
142
+ state,
143
+ mainStyle: 'any main style'
144
+ });
145
+ });
146
+ });
@@ -0,0 +1,53 @@
1
+
2
+ import mountGooglePay from './express-methods/google-pay';
3
+ import mountApplePay from './express-methods/apple-pay';
4
+ import mountPaypal from './express-methods/paypal';
5
+ import { getMethodData } from './get-method-data';
6
+
7
+ export function mountExpressMethods({
8
+ state,
9
+ EXPRESS_METHODS,
10
+ EXPRESS_METHODS_CONTAINER
11
+ }) {
12
+ // A child div for each method must be created before mounting.
13
+ // Any DOM operation (innerHTML, append, etc) done on the parent div (EXPRESS_METHODS_CONTAINER) in between
14
+ // the two Postmate's instantiation (1 parent, 1 child) will cause the parent <-> child handshake to fail
15
+ EXPRESS_METHODS.forEach((expressMethod) => {
16
+ const { METHOD_ID } = getMethodData(expressMethod);
17
+
18
+ EXPRESS_METHODS_CONTAINER.innerHTML += `
19
+ <div class="rebilly-instruments-${METHOD_ID}-method"></div>
20
+ `;
21
+ });
22
+
23
+
24
+ EXPRESS_METHODS.forEach((expressMethod) => {
25
+ const { method, feature } = expressMethod;
26
+ const { METHOD_ID, METHOD_TYPE } = getMethodData(expressMethod);
27
+
28
+ if (feature?.name === 'Google Pay') {
29
+ mountGooglePay({
30
+ state,
31
+ METHOD_ID
32
+ });
33
+ }
34
+
35
+ if (feature?.name === 'Apple Pay') {
36
+ mountApplePay({
37
+ state,
38
+ METHOD_ID,
39
+ METHOD_TYPE,
40
+ EXPRESS_METHODS,
41
+ EXPRESS_METHODS_CONTAINER
42
+ });
43
+ }
44
+
45
+ if (method === 'paypal') {
46
+ mountPaypal({
47
+ state,
48
+ METHOD_ID,
49
+ METHOD_TYPE,
50
+ });
51
+ }
52
+ });
53
+ }
@@ -0,0 +1,71 @@
1
+ import camelCase from 'lodash.camelcase';
2
+ import { mountModal } from '../modal';
3
+ import { MethodIframe } from '../common/iframe';
4
+ import { getMethodData } from './get-method-data';
5
+
6
+ export function MountMethods({
7
+ state,
8
+ METHODS_CONTAINER,
9
+ METHODS,
10
+ mainStyle,
11
+ plans,
12
+ products
13
+ }) {
14
+ METHODS.forEach(async (method) => {
15
+ const { METHOD_ID: methodId, METHOD_TYPE: methodType } =
16
+ getMethodData(method);
17
+ const { paymentMethodsUrl } =
18
+ state.options._computed || 'https://www.example.com';
19
+
20
+ const selector = `rebilly-instruments-${methodId}`;
21
+ const isiFrame =
22
+ methodId === 'payment-card' &&
23
+ !state.options.paymentInstruments[methodType]?.popup;
24
+ const model = {
25
+ configs: state.configs,
26
+ options: state.options,
27
+ mainStyle,
28
+ method,
29
+ plans,
30
+ products
31
+ };
32
+
33
+ METHODS_CONTAINER.insertAdjacentHTML(
34
+ 'beforeend',
35
+ `<div id="${selector}" data-rebilly-instruments-type="${methodId}"></div>`
36
+ );
37
+ const container = document.querySelector(`#${selector}`);
38
+
39
+ if (isiFrame) {
40
+ const iframe = await new MethodIframe({
41
+ name: methodId,
42
+ url: `${paymentMethodsUrl}/${methodId}`,
43
+ container,
44
+ model
45
+ });
46
+ iframe.bindEventListeners({
47
+ loader: state.loader,
48
+ id: method.method
49
+ });
50
+ state.iframeComponents.push(iframe);
51
+ } else {
52
+ container.insertAdjacentHTML(
53
+ 'beforeend',
54
+ `<button class="${selector} rebilly-instruments-button" data-rebilly-i18n="paymentMethods.${
55
+ method.method
56
+ }">${camelCase(method.method)}</button>`
57
+ );
58
+ const paymentCardButton = document.querySelector(`.${selector}`);
59
+ paymentCardButton.addEventListener('click', async () => {
60
+ const iframe = await mountModal({
61
+ state,
62
+ name: methodId,
63
+ url: `${paymentMethodsUrl}/${methodId}`,
64
+ model
65
+ });
66
+ state.iframeComponents.push(iframe);
67
+ });
68
+ state.loader.stopLoading({ id: method.method });
69
+ }
70
+ });
71
+ }
@@ -0,0 +1,84 @@
1
+ import { ModalIframe } from './common/iframe';
2
+
3
+ const modalTemplate = (isRedirect, method) => `
4
+ <div class="rebilly-instruments-modal-overlay">
5
+ <div class="rebilly-instruments-modal-container ${
6
+ method ? `rebilly-instruments-${method}` : ''
7
+ } ${isRedirect ? 'is-redirect' : ''}">
8
+ <svg class="rebilly-instruments-modal-close" viewBox="0 0 30 30" xmlns="http://www.w3.org/2000/svg">
9
+ <path d="m15 13.5858 7.2929-7.293c.3905-.3904 1.0237-.3904 1.4142 0 .3905.3906.3905 1.0238 0 1.4143L16.4142 15l7.293 7.2929c.3904.3905.3904 1.0237 0 1.4142-.3906.3905-1.0238.3905-1.4143 0L15 16.4142l-7.2929 7.293c-.3905.3904-1.0237.3904-1.4142 0-.3905-.3906-.3905-1.0238 0-1.4143L13.5858 15l-7.293-7.2929c-.3904-.3905-.3904-1.0237 0-1.4142.3906-.3905 1.0238-.3905 1.4143 0L15 13.5858Z" fill-rule="nonzero"/>
10
+ </svg>
11
+ <div class="rebilly-instruments-modal-content"></div>
12
+ </div>
13
+ </div>
14
+ `;
15
+
16
+ export async function mountModal({
17
+ name = '',
18
+ url = '',
19
+ model = {},
20
+ classListArray = [],
21
+ close = () => {},
22
+ state = null
23
+ } = {}) {
24
+ const method = model?.method?.method;
25
+ const isRedirect = name === 'rebilly-instruments-approval-url';
26
+ state.form.insertAdjacentHTML('beforeend', modalTemplate(isRedirect, method));
27
+
28
+ const modalOverlay = document.querySelector(
29
+ '.rebilly-instruments-modal-overlay'
30
+ );
31
+ const modalContainer = document.querySelector(
32
+ '.rebilly-instruments-modal-container'
33
+ );
34
+ const closeButton = document.querySelector(
35
+ '.rebilly-instruments-modal-close'
36
+ );
37
+ const modalContent = document.querySelector(
38
+ '.rebilly-instruments-modal-content'
39
+ );
40
+
41
+ document.body.style.overflow = 'hidden';
42
+ setTimeout(() => {
43
+ modalOverlay.classList.add('is-visible');
44
+ modalContainer.classList.add('is-visible');
45
+ }, 240);
46
+ state.loader.addDOMElement({ section: 'modal', el: modalContent });
47
+ state.loader.startLoading({ section: 'modal', id: 'modal-content' });
48
+
49
+ const injectedModel = {
50
+ configs: state.configs,
51
+ options: state.options,
52
+ ...model
53
+ };
54
+
55
+ const iframe = await new ModalIframe({
56
+ name,
57
+ url,
58
+ model: injectedModel,
59
+ classListArray,
60
+ container: modalContent
61
+ });
62
+
63
+ const closeModal = (...args) => {
64
+ modalContainer.classList.remove('is-visible');
65
+ modalOverlay.classList.remove('is-visible');
66
+ setTimeout(() => {
67
+ document.body.style.overflow = 'auto';
68
+ modalOverlay.children.forEach((child) => child.remove());
69
+ modalOverlay.remove();
70
+ close(...args);
71
+ iframe.destroy();
72
+ }, 300);
73
+ };
74
+
75
+ iframe.bindEventListeners({
76
+ close: closeModal,
77
+ loader: state.loader
78
+ });
79
+
80
+ modalOverlay.addEventListener('click', closeModal);
81
+ closeButton.addEventListener('click', closeModal);
82
+
83
+ return iframe;
84
+ }
@@ -0,0 +1,30 @@
1
+ import { ViewIframe } from './common/iframe';
2
+ import { replaceContent } from './common/render-utilities';
3
+
4
+ export async function mountResult({ purchase, mainStyle, state }) {
5
+ const resultContainerClassName = 'rebilly-instruments-result';
6
+ replaceContent(state.form, `<div class="${resultContainerClassName}"></div>`);
7
+
8
+ state.loader.startLoading({ id: 'result' });
9
+
10
+ const container = document.querySelector(`.${resultContainerClassName}`);
11
+ const { paymentMethodsUrl } = state.options._computed;
12
+
13
+ const model = {
14
+ configs: state.configs,
15
+ options: state.options,
16
+ mainStyle,
17
+ purchase
18
+ };
19
+ const iframe = await new ViewIframe({
20
+ name: 'rebilly-instruments-result',
21
+ url: `${paymentMethodsUrl}/result`,
22
+ container,
23
+ model
24
+ });
25
+ iframe.bindEventListeners({
26
+ loader: state.loader
27
+ });
28
+
29
+ state.iframeComponents.push(iframe);
30
+ }
@@ -1,20 +1,27 @@
1
1
  import { collectData } from '@rebilly/risk-data-collector';
2
2
  import { formatCurrency } from '../utils';
3
- import { FetchSummaryData } from '../functions/mount/fetch-summary-data';
3
+ import { fetchSummaryData } from '../functions/mount/fetch-summary-data';
4
4
 
5
5
  export const baseSummaryHTML = `
6
- <div class="rebilly-instruments-summary-container">
6
+ <div class="rebilly-instruments-content">
7
7
  <div class="rebilly-instruments-summary-line-items"></div>
8
8
  <div class="rebilly-instruments-summary-breakdown"></div>
9
9
  </div>
10
10
  `;
11
11
 
12
- export function MountSummary({summary, plans, products} = {}) {
13
- this.summary.innerHTML += baseSummaryHTML;
14
- const itemsContainer = document.querySelector('.rebilly-instruments-summary-line-items');
15
- const summaryBreakdown = document.querySelector('.rebilly-instruments-summary-breakdown')
16
- const {intent: {items: optionItems}} = this.options;
17
- const hasThumbnails = optionItems.some(optionItem => optionItem.thumbnail);
12
+ export function mountSummary({ state, summaryOptions }) {
13
+ const { summary, plans, products } = summaryOptions;
14
+ state.summary.innerHTML += baseSummaryHTML;
15
+ const itemsContainer = document.querySelector(
16
+ '.rebilly-instruments-summary-line-items'
17
+ );
18
+ const summaryBreakdown = document.querySelector(
19
+ '.rebilly-instruments-summary-breakdown'
20
+ );
21
+ const {
22
+ intent: { items: optionItems }
23
+ } = state.options;
24
+ const hasThumbnails = optionItems?.some((optionItem) => optionItem.thumbnail);
18
25
 
19
26
  const {
20
27
  lineItems,
@@ -26,28 +33,47 @@ export function MountSummary({summary, plans, products} = {}) {
26
33
  total
27
34
  } = summary;
28
35
 
29
- lineItems.forEach(lineItem => {
30
- const {thumbnail} = optionItems.find(optionItem => optionItem.planId === lineItem.planId);
31
- const {name} = plans.find(plan => plan.id === lineItem.planId);
32
- const {description} = products.find(product => product.id === lineItem.productId);
36
+ lineItems.forEach((lineItem) => {
37
+ const { thumbnail } = optionItems.find(
38
+ (optionItem) => optionItem.planId === lineItem.planId
39
+ );
40
+ const { name } = plans.find((plan) => plan.id === lineItem.planId);
41
+ const { description } = products.find(
42
+ (product) => product.id === lineItem.productId
43
+ );
33
44
 
34
45
  itemsContainer.innerHTML += `
35
46
  <div class="rebilly-instruments-summary-line-item">
36
- ${hasThumbnails ? `
47
+ ${
48
+ hasThumbnails
49
+ ? `
37
50
  <figure class="rebilly-instruments-summary-line-item-figure">
38
51
  ${thumbnail ? `<img src="${thumbnail}" alt="${name}">` : ''}
39
52
  </figure>
40
- ` : ``}
53
+ `
54
+ : ''
55
+ }
41
56
  <div class="rebilly-instruments-summary-line-item-synopsis">
42
57
  <p class="rebilly-instruments-summary-line-item-synopsis-title">${name}</p>
43
- <p class="rebilly-instruments-summary-line-item-synopsis-description">${description}</p>
58
+ ${
59
+ description
60
+ ? `
61
+ <p class="rebilly-instruments-summary-line-item-synopsis-description">${description}</p>
62
+ `
63
+ : ''
64
+ }
44
65
  </div>
45
66
  <div class="rebilly-instruments-summary-line-item-price-breakdown">
46
- <p class="rebilly-instruments-summary-line-item-price-breakdown-quantity">${lineItem.quantity}</p>
67
+ <p class="rebilly-instruments-summary-line-item-price-breakdown-quantity">${
68
+ lineItem.quantity
69
+ }</p>
47
70
  <svg class="rebilly-instruments-icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
48
71
  <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"/>
49
72
  </svg>
50
- <p class="rebilly-instruments-summary-line-item-price-breakdown-unit-price">${formatCurrency(lineItem.unitPrice, currency)}</p>
73
+ <p class="rebilly-instruments-summary-line-item-price-breakdown-unit-price">${formatCurrency(
74
+ lineItem.unitPrice,
75
+ currency
76
+ )}</p>
51
77
  </div>
52
78
  </div>
53
79
  `;
@@ -78,19 +104,22 @@ export function MountSummary({summary, plans, products} = {}) {
78
104
  <div class="rebilly-instruments-summary-breakdown-total">
79
105
  <p data-rebilly-i18n="summary.total">Total</p>
80
106
  <p class="rebilly-instruments-summary-breakdown-total-amount">
81
- <span class="rebilly-instruments-summary-breakdown-total-amount-currency">${currency}</span>${formatCurrency(total, currency)}
107
+ <span class="rebilly-instruments-summary-breakdown-total-amount-currency">${currency}</span>${formatCurrency(
108
+ total,
109
+ currency
110
+ )}
82
111
  </p>
83
112
  </div>
84
113
  `;
85
-
86
- this.translate.translateItems();
87
114
 
88
- this.loader.stopLoading({section: 'summary', id: 'initSummary'});
89
- };
115
+ state.translate.translateItems();
116
+
117
+ state.loader.stopLoading({ section: 'summary', id: 'initSummary' });
118
+ }
90
119
 
91
- export async function UpdateSummary(instrument = null) {
92
- this.loader.startLoading({section: 'summary', id: 'initSummary'});
93
- const {riskMetadata} = await collectData();
120
+ export async function updateSummary({ state, instrument = null }) {
121
+ state.loader.startLoading({ section: 'summary', id: 'initSummary' });
122
+ const { riskMetadata } = await collectData();
94
123
 
95
124
  let summaryPayload;
96
125
 
@@ -105,20 +134,23 @@ export async function UpdateSummary(instrument = null) {
105
134
  summary: summaryData,
106
135
  plans,
107
136
  products
108
- } = await FetchSummaryData.call(this, {
137
+ } = await fetchSummaryData({
109
138
  riskMetadata,
110
- summaryPayload
139
+ summaryPayload,
140
+ state
111
141
  });
112
142
 
113
- this.summaryOptions = {
143
+ const summaryOptions = {
114
144
  summary: summaryData,
115
145
  readyToPay,
116
146
  plans,
117
- products,
147
+ products
118
148
  };
119
149
 
120
- const itemsContainer = document.querySelector('.rebilly-instruments-summary-container');
121
- itemsContainer.remove();
150
+ const itemsContainer = state.summary.querySelector(
151
+ '.rebilly-instruments-content'
152
+ );
153
+ itemsContainer?.remove();
122
154
 
123
- MountSummary.call(this, this.summaryOptions);
124
- }
155
+ mountSummary({ state, summaryOptions });
156
+ }