@rebilly/instruments 1.0.2-beta.9 → 3.0.0-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 (255) 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 +187 -0
  11. package/dist/functions/mount/fetch-data.spec.js +189 -0
  12. package/dist/functions/mount/index.js +164 -251
  13. package/dist/functions/mount/mount.spec.js +25 -124
  14. package/dist/functions/mount/setup-element.js +40 -0
  15. package/dist/functions/mount/setup-framepay-theme.js +95 -0
  16. package/dist/functions/mount/setup-framepay.js +46 -0
  17. package/dist/functions/mount/setup-i18n.js +33 -0
  18. package/dist/functions/mount/setup-options.js +99 -0
  19. package/dist/functions/mount/setup-options.spec.js +66 -0
  20. package/dist/functions/mount/setup-storefront.js +34 -0
  21. package/dist/functions/mount/setup-styles.js +43 -0
  22. package/dist/functions/on.js +13 -4
  23. package/dist/functions/on.spec.js +19 -5
  24. package/dist/functions/purchase.js +139 -22
  25. package/dist/functions/purchase.spec.js +23 -19
  26. package/dist/functions/setup.js +85 -0
  27. package/dist/functions/setup.spec.js +87 -0
  28. package/dist/functions/show.js +31 -14
  29. package/dist/functions/show.spec.js +47 -18
  30. package/dist/functions/update.js +53 -27
  31. package/dist/functions/update.spec.js +40 -21
  32. package/dist/i18n/en.json +5 -2
  33. package/dist/i18n/es.json +4 -1
  34. package/dist/index.js +67 -56
  35. package/dist/index.spec.js +7 -27
  36. package/dist/loader/index.js +4 -3
  37. package/dist/storefront/index.js +33 -0
  38. package/dist/storefront/invoices.js +27 -0
  39. package/dist/storefront/models/base-model.js +18 -0
  40. package/dist/storefront/models/invoice-model.js +14 -0
  41. package/dist/storefront/models/plan-model.js +4 -35
  42. package/dist/storefront/models/product-model.js +4 -23
  43. package/dist/storefront/models/summary-model.js +12 -25
  44. package/dist/storefront/models/transaction-model.js +31 -0
  45. package/dist/storefront/payment-instruments.js +47 -0
  46. package/dist/storefront/payment-instruments.spec.js +55 -0
  47. package/dist/storefront/plans.js +15 -24
  48. package/dist/storefront/plans.spec.js +17 -44
  49. package/dist/storefront/products.js +16 -20
  50. package/dist/storefront/products.spec.js +25 -49
  51. package/dist/storefront/purchase.js +28 -16
  52. package/dist/storefront/purchase.spec.js +4 -22
  53. package/dist/storefront/ready-to-pay.js +26 -22
  54. package/dist/storefront/ready-to-pay.spec.js +25 -54
  55. package/dist/storefront/storefront.spec.js +1 -1
  56. package/dist/storefront/summary.js +27 -24
  57. package/dist/storefront/summary.spec.js +44 -86
  58. package/dist/storefront/transactions.js +27 -0
  59. package/dist/style/base/__snapshots__/theme.spec.js.snap +188 -45
  60. package/dist/style/base/default-theme.js +699 -0
  61. package/dist/style/base/index.js +48 -16
  62. package/dist/style/base/theme.js +15 -48
  63. package/dist/style/base/theme.spec.js +4 -15
  64. package/dist/style/components/address.js +3 -3
  65. package/dist/style/components/button.js +32 -22
  66. package/dist/style/components/divider.js +9 -9
  67. package/dist/style/components/forms/checkbox.js +12 -9
  68. package/dist/style/components/forms/field.js +18 -6
  69. package/dist/style/components/forms/form.js +2 -2
  70. package/dist/style/components/forms/input.js +54 -13
  71. package/dist/style/components/forms/label.js +44 -18
  72. package/dist/style/components/forms/select.js +54 -22
  73. package/dist/style/components/forms/validation.js +53 -6
  74. package/dist/style/components/icons.js +4 -4
  75. package/dist/style/components/loader.js +5 -3
  76. package/dist/style/components/methods.js +52 -48
  77. package/dist/style/components/overlay.js +5 -5
  78. package/dist/style/helpers/index.js +46 -46
  79. package/dist/style/index.js +3 -1
  80. package/dist/style/payment-instruments/payment-card.js +4 -4
  81. package/dist/style/utils/border.js +47 -0
  82. package/dist/style/utils/color-values.js +37 -3
  83. package/dist/style/utils/remove-empty-null.js +20 -0
  84. package/dist/style/vendor/framepay.js +11 -8
  85. package/dist/style/vendor/postmate.js +2 -2
  86. package/dist/style/views/confirmation.js +13 -13
  87. package/dist/style/views/method-selector.js +3 -3
  88. package/dist/style/views/modal.js +8 -6
  89. package/dist/style/views/result.js +4 -4
  90. package/dist/style/views/summary.js +26 -22
  91. package/dist/utils/format-currency.js +4 -2
  92. package/dist/utils/has-valid-css-selector.js +1 -1
  93. package/dist/utils/process-property-as-dom-element.js +0 -2
  94. package/dist/views/__snapshots__/summary.spec.js.snap +72 -118
  95. package/dist/views/common/iframe/base-iframe.js +10 -2
  96. package/dist/views/common/iframe/modal-iframe.js +50 -4
  97. package/dist/views/confirmation.js +44 -20
  98. package/dist/views/method-selector/express-methods/apple-pay.js +92 -0
  99. package/dist/views/method-selector/express-methods/google-pay.js +31 -0
  100. package/dist/views/method-selector/express-methods/paypal.js +19 -0
  101. package/dist/views/method-selector/generate-digital-wallet.js +68 -0
  102. package/dist/views/method-selector/generate-digital-wallet.spec.js +135 -0
  103. package/dist/views/method-selector/get-payment-methods.js +27 -7
  104. package/dist/views/method-selector/get-payment-methods.spec.js +25 -26
  105. package/dist/views/method-selector/index.js +55 -86
  106. package/dist/views/method-selector/method-selector.spec.js +80 -69
  107. package/dist/views/method-selector/mount-express-methods.js +38 -62
  108. package/dist/views/method-selector/mount-methods.js +18 -18
  109. package/dist/views/modal.js +18 -12
  110. package/dist/views/result.js +13 -16
  111. package/dist/views/summary.js +176 -114
  112. package/dist/views/summary.spec.js +72 -76
  113. package/package.json +7 -4
  114. package/src/events/base-event.js +15 -17
  115. package/src/events/events.spec.js +6 -4
  116. package/src/events/index.js +6 -3
  117. package/src/functions/destroy.js +12 -13
  118. package/src/functions/destroy.spec.js +30 -31
  119. package/src/functions/mount/fetch-data.js +152 -0
  120. package/src/functions/mount/fetch-data.spec.js +238 -0
  121. package/src/functions/mount/index.js +131 -244
  122. package/src/functions/mount/mount.spec.js +35 -141
  123. package/src/functions/mount/setup-element.js +26 -0
  124. package/src/functions/mount/setup-framepay-theme.js +82 -0
  125. package/src/functions/mount/setup-framepay.js +41 -0
  126. package/src/functions/mount/setup-i18n.js +19 -0
  127. package/src/functions/mount/setup-options.js +103 -0
  128. package/src/functions/mount/setup-options.spec.js +60 -0
  129. package/src/functions/mount/setup-storefront.js +24 -0
  130. package/src/functions/mount/setup-styles.js +30 -0
  131. package/src/functions/on.js +13 -8
  132. package/src/functions/on.spec.js +30 -17
  133. package/src/functions/purchase.js +101 -19
  134. package/src/functions/purchase.spec.js +18 -18
  135. package/src/functions/setup.js +48 -0
  136. package/src/functions/setup.spec.js +98 -0
  137. package/src/functions/show.js +20 -10
  138. package/src/functions/show.spec.js +43 -22
  139. package/src/functions/update.js +50 -27
  140. package/src/functions/update.spec.js +57 -22
  141. package/src/i18n/en.json +5 -2
  142. package/src/i18n/es.json +4 -1
  143. package/src/i18n/i18n.spec.js +6 -4
  144. package/src/i18n/index.js +14 -11
  145. package/src/index.js +41 -52
  146. package/src/index.spec.js +8 -37
  147. package/src/loader/index.js +51 -47
  148. package/src/loader/loader.spec.js +26 -19
  149. package/src/storefront/index.js +37 -7
  150. package/src/storefront/invoices.js +11 -0
  151. package/src/storefront/models/base-model.js +10 -0
  152. package/src/storefront/models/invoice-model.js +3 -0
  153. package/src/storefront/models/plan-model.js +3 -35
  154. package/src/storefront/models/product-model.js +3 -23
  155. package/src/storefront/models/ready-to-pay-model.js +3 -3
  156. package/src/storefront/models/summary-model.js +15 -29
  157. package/src/storefront/models/transaction-model.js +19 -0
  158. package/src/storefront/payment-instruments.js +30 -0
  159. package/src/storefront/payment-instruments.spec.js +69 -0
  160. package/src/storefront/plans.js +16 -23
  161. package/src/storefront/plans.spec.js +25 -54
  162. package/src/storefront/products.js +18 -22
  163. package/src/storefront/products.spec.js +23 -54
  164. package/src/storefront/purchase.js +14 -14
  165. package/src/storefront/purchase.spec.js +17 -29
  166. package/src/storefront/ready-to-pay.js +26 -23
  167. package/src/storefront/ready-to-pay.spec.js +41 -71
  168. package/src/storefront/storefront.spec.js +1 -1
  169. package/src/storefront/summary.js +26 -22
  170. package/src/storefront/summary.spec.js +60 -109
  171. package/src/storefront/transactions.js +11 -0
  172. package/src/style/base/__snapshots__/theme.spec.js.snap +188 -45
  173. package/src/style/base/default-theme.js +674 -0
  174. package/src/style/base/index.js +48 -16
  175. package/src/style/base/theme.js +20 -48
  176. package/src/style/base/theme.spec.js +5 -15
  177. package/src/style/browserslist.js +1 -3
  178. package/src/style/components/address.js +3 -3
  179. package/src/style/components/button.js +32 -22
  180. package/src/style/components/divider.js +9 -9
  181. package/src/style/components/forms/checkbox.js +11 -9
  182. package/src/style/components/forms/field.js +18 -6
  183. package/src/style/components/forms/form.js +2 -2
  184. package/src/style/components/forms/input.js +54 -13
  185. package/src/style/components/forms/label.js +44 -18
  186. package/src/style/components/forms/select.js +54 -22
  187. package/src/style/components/forms/validation.js +53 -6
  188. package/src/style/components/icons.js +4 -4
  189. package/src/style/components/index.js +1 -1
  190. package/src/style/components/loader.js +4 -3
  191. package/src/style/components/methods.js +52 -48
  192. package/src/style/components/overlay.js +5 -5
  193. package/src/style/helpers/index.js +46 -46
  194. package/src/style/index.js +4 -2
  195. package/src/style/payment-instruments/payment-card.js +4 -4
  196. package/src/style/utils/border.js +34 -0
  197. package/src/style/utils/color-values.js +30 -4
  198. package/src/style/utils/remove-empty-null.js +10 -0
  199. package/src/style/vendor/framepay.js +12 -9
  200. package/src/style/vendor/postmate.js +3 -3
  201. package/src/style/views/confirmation.js +13 -13
  202. package/src/style/views/index.js +1 -1
  203. package/src/style/views/method-selector.js +3 -3
  204. package/src/style/views/modal.js +9 -7
  205. package/src/style/views/result.js +4 -4
  206. package/src/style/views/summary.js +26 -22
  207. package/src/utils/add-dom-element.js +12 -13
  208. package/src/utils/format-currency.js +6 -2
  209. package/src/utils/has-valid-css-selector.js +2 -2
  210. package/src/utils/is-dom-element.js +1 -1
  211. package/src/utils/process-property-as-dom-element.js +27 -24
  212. package/src/utils/sleep.js +1 -1
  213. package/src/views/__snapshots__/summary.spec.js.snap +72 -118
  214. package/src/views/common/iframe/base-iframe.js +12 -4
  215. package/src/views/common/iframe/event-listeners.js +6 -6
  216. package/src/views/common/iframe/index.js +1 -1
  217. package/src/views/common/iframe/method-iframe.js +3 -6
  218. package/src/views/common/iframe/modal-iframe.js +48 -6
  219. package/src/views/common/iframe/view-iframe.js +3 -5
  220. package/src/views/common/render-utilities.js +3 -3
  221. package/src/views/confirmation.js +34 -25
  222. package/src/views/method-selector/express-methods/apple-pay.js +78 -0
  223. package/src/views/method-selector/express-methods/google-pay.js +24 -0
  224. package/src/views/method-selector/express-methods/paypal.js +7 -0
  225. package/src/views/method-selector/generate-digital-wallet.js +51 -0
  226. package/src/views/method-selector/generate-digital-wallet.spec.js +135 -0
  227. package/src/views/method-selector/get-method-data.js +7 -4
  228. package/src/views/method-selector/get-payment-methods.js +38 -31
  229. package/src/views/method-selector/get-payment-methods.spec.js +26 -33
  230. package/src/views/method-selector/index.js +70 -99
  231. package/src/views/method-selector/method-selector.spec.js +88 -78
  232. package/src/views/method-selector/mount-express-methods.js +36 -60
  233. package/src/views/method-selector/mount-methods.js +32 -21
  234. package/src/views/modal.js +36 -22
  235. package/src/views/result.js +12 -15
  236. package/src/views/summary.js +175 -101
  237. package/src/views/summary.spec.js +99 -74
  238. package/tests/async-utilities.js +22 -0
  239. package/tests/mocks/rebilly-instruments-mock.js +89 -77
  240. package/tests/mocks/storefront-api-mock.js +8 -0
  241. package/tests/mocks/storefront-mock.js +17 -0
  242. package/dist/events/purchase-completed.js +0 -24
  243. package/dist/functions/initialize.js +0 -82
  244. package/dist/functions/initialize.spec.js +0 -34
  245. package/dist/functions/mount/fetch-summary-data.js +0 -31
  246. package/dist/functions/mount/fetch-summary-data.spec.js +0 -45
  247. package/dist/views/method-selector/process-digital-wallet-options.js +0 -35
  248. package/dist/views/method-selector/process-digital-wallet-options.spec.js +0 -80
  249. package/src/events/purchase-completed.js +0 -11
  250. package/src/functions/initialize.js +0 -74
  251. package/src/functions/initialize.spec.js +0 -38
  252. package/src/functions/mount/fetch-summary-data.js +0 -26
  253. package/src/functions/mount/fetch-summary-data.spec.js +0 -46
  254. package/src/views/method-selector/process-digital-wallet-options.js +0 -16
  255. package/src/views/method-selector/process-digital-wallet-options.spec.js +0 -94
package/src/index.js CHANGED
@@ -1,30 +1,17 @@
1
- import { Initialize } from './functions/initialize';
2
- import { Mount } from './functions/mount';
3
- import { Purchase } from './functions/purchase';
4
- import { Show } from './functions/show';
5
- import { On } from './functions/on';
6
- import { Update } from './functions/update';
7
- import { Destroy } from './functions/destroy';
8
-
9
- import { FetchReadyToPay } from './storefront/ready-to-pay';
10
- import { FetchSummary } from './storefront/summary';
11
- import { FetchPlans } from './storefront/plans';
12
- import { FetchProducts } from './storefront/products';
13
- import { PostPurchase } from './storefront/purchase';
14
-
15
- import { MountSummary, UpdateSummary } from './views/summary';
16
- import { MountMethodSelector, UpdateMethodSelector } from './views/method-selector';
17
- import { MountConfirmation } from './views/confirmation';
18
- import { MountResult } from './views/result';
19
- import { MountModal } from './views/modal';
20
-
1
+ import { mount } from './functions/mount';
2
+ import { purchase } from './functions/purchase';
3
+ import { setup } from './functions/setup';
4
+ import { on } from './functions/on';
5
+ import { update } from './functions/update';
6
+ import { destroy } from './functions/destroy';
21
7
  import { Loader } from './loader';
22
8
  import { Translate } from './i18n';
9
+ import { show } from './functions/show';
23
10
 
24
- export class RebillyInstrumentsInstance {
11
+ export class InstrumentsState {
25
12
  constructor() {
26
- this.configs = null;
27
13
  this.options = null;
14
+ this.data = {};
28
15
  this.mountingPoints = null;
29
16
  this.storefront = null;
30
17
  this.form = null;
@@ -33,41 +20,43 @@ export class RebillyInstrumentsInstance {
33
20
  this.translate = new Translate();
34
21
  this.iframeComponents = [];
35
22
  this.hasMounted = false;
23
+ }
24
+ }
25
+
26
+ export class RebillyInstrumentsInstance {
27
+ constructor() {
28
+ this.state = new InstrumentsState();
29
+ // TODO: mountConfirmation, mountResult have different contract shape when they look similar
30
+ // TODO: review test coverage of UpdateSummary and UpdateMethodSelector as no tests were broken
31
+ // when commenting them
32
+ }
36
33
 
37
- const functionsMap = {
38
- // "Private" functions
39
- _fetchReadyToPay: FetchReadyToPay,
40
- _fetchSummary: FetchSummary,
41
- _fetchPlans: FetchPlans,
42
- _fetchProducts: FetchProducts,
43
- _postPurchase: PostPurchase,
34
+ async mount(options) {
35
+ await mount({ state: this.state, ...options });
36
+ }
44
37
 
45
- _mountSummary: MountSummary,
46
- _mountMethodSelector: MountMethodSelector,
47
- _mountConfirmation: MountConfirmation,
48
- _mountResult: MountResult,
49
- _mountModal: MountModal,
38
+ async destroy() {
39
+ await destroy({ state: this.state });
40
+ }
50
41
 
51
- _updateSummary: UpdateSummary,
52
- _updateSelector: UpdateMethodSelector,
42
+ async update(newOptions) {
43
+ await update({state: this.state, newOptions});
44
+ }
53
45
 
54
- // Public Functions
55
- initialize: Initialize,
56
- mount: Mount,
57
- destroy: Destroy,
58
- update: Update,
59
- purchase: Purchase,
60
- show: Show,
61
- on: On,
62
- };
46
+ async purchase(payload) {
47
+ await purchase({ state: this.state, payload });
48
+ }
49
+
50
+ async setup(payload) {
51
+ await setup({ state: this.state, payload });
52
+ }
53
+
54
+ async show(componentName, payload) {
55
+ await show({ state: this.state, componentName, payload });
56
+ }
63
57
 
64
- // eslint-disable-next-line no-restricted-syntax
65
- for (const local of Object.keys(functionsMap)) {
66
- // eslint-disable-next-line func-names
67
- this[local] = function(...args) {
68
- return functionsMap[local].apply(this, args);
69
- }
70
- }
58
+ on(eventName, callback) {
59
+ on({ state: this.state, eventName, callback });
71
60
  }
72
61
  }
73
62
 
package/src/index.spec.js CHANGED
@@ -1,14 +1,9 @@
1
- import RebillyInstruments, {RebillyInstrumentsInstance} from './index';
1
+ import RebillyInstruments, { RebillyInstrumentsInstance } from './index';
2
+ import { avoidUnhandledPromises } from 'tests/async-utilities';
2
3
 
3
4
  describe('RebillyInstruments instance', () => {
4
5
  let rebillyInstruments;
5
6
 
6
- function setupInstance(config = {
7
- test: 'value'
8
- }) {
9
- rebillyInstruments.initialize(config);
10
- }
11
-
12
7
  beforeEach(() => {
13
8
  rebillyInstruments = RebillyInstruments;
14
9
  });
@@ -17,48 +12,24 @@ describe('RebillyInstruments instance', () => {
17
12
  expect(RebillyInstruments).toBeInstanceOf(RebillyInstrumentsInstance);
18
13
  });
19
14
 
20
- it('should be initializable', () => {
21
- jest.spyOn(rebillyInstruments, 'initialize');
22
-
23
- const config = {
24
- test: 'value'
25
- };
26
- rebillyInstruments.initialize(config);
27
-
28
- expect(rebillyInstruments.initialize).toHaveBeenCalledTimes(1);
29
- expect(rebillyInstruments.initialize).toHaveBeenCalledWith(config);
30
- });
31
-
32
- it('should be mountable', () => {
15
+ it('should be mountable', async () => {
33
16
  jest.spyOn(rebillyInstruments, 'mount');
34
17
 
35
- document.body.innerHTML =
36
- `
18
+ document.body.innerHTML = `
37
19
  <div class="form-selector"></div>
38
20
  <div class="summary-selector"></div>
39
21
  `;
40
22
 
41
23
  const options = {
42
24
  form: '.form-selector',
43
- test: 'value'
25
+ summary: '.summary-selector',
26
+ items: []
44
27
  };
45
28
 
46
- setupInstance();
47
- rebillyInstruments.mount(options);
29
+ await rebillyInstruments.mount(options);
48
30
 
49
31
  expect(rebillyInstruments.mount).toHaveBeenCalledTimes(1);
50
32
  expect(rebillyInstruments.mount).toHaveBeenCalledWith(options);
51
- });
52
-
53
- it('should be able to trigger a purchase', () => {
54
- jest.spyOn(rebillyInstruments, 'purchase');
55
-
56
- const instrument = {};
57
-
58
- setupInstance();
59
- rebillyInstruments.purchase(instrument);
60
-
61
- expect(rebillyInstruments.purchase).toHaveBeenCalledTimes(1);
33
+ await avoidUnhandledPromises();
62
34
  });
63
35
  });
64
-
@@ -1,66 +1,70 @@
1
1
  import isDOMElement from '../utils/is-dom-element';
2
2
 
3
3
  export class Loader {
4
- constructor() {
5
- this.summary = [];
6
- this.form = [];
7
- this.modal = [];
8
- this.DOM = {
9
- loading: `
4
+ constructor() {
5
+ this.summary = [];
6
+ this.form = [];
7
+ this.modal = [];
8
+ this.DOM = {
9
+ loading: `
10
10
  <div class="rebilly-instruments-loader is-active">
11
11
  <div class="rebilly-instruments-loader-spinner"></div>
12
12
  </div>
13
13
  `
14
- };
15
- }
16
-
17
- addDOMElement({section = 'form', el = null} = {}) {
18
- const minHeight = '200px';
14
+ };
15
+ }
19
16
 
20
- if (isDOMElement(el)) {
21
- el.style.position = 'relative';
22
- el.style.minHeight = minHeight;
17
+ addDOMElement({ section = 'form', el = null } = {}) {
18
+ if (isDOMElement(el)) {
19
+ el.style.position = 'relative';
23
20
 
24
- this.DOM[section] = el;
25
- }
21
+ this.DOM[section] = el;
26
22
  }
23
+ }
27
24
 
28
- startLoading({section = 'form', id = ''} = {}) {
29
- this[section].push(id);
25
+ startLoading({ section = 'form', id = '' } = {}) {
26
+ const minHeight = '200px';
27
+ this[section].push(id);
30
28
 
31
- if (this.DOM?.[section]) {
32
- if (!this.DOM[section].querySelector('.rebilly-instruments-loader')) {
33
- this.DOM[section].innerHTML = this.DOM.loading;
34
- } else {
35
- this.DOM[section].querySelector('.rebilly-instruments-loader')
36
- .classList.add('is-active');
37
- }
38
- }
29
+ if (this.DOM?.[section]) {
30
+ if (!this.DOM[section].querySelector('.rebilly-instruments-loader')) {
31
+ this.DOM[section].innerHTML = this.DOM.loading;
32
+ } else {
33
+ this.DOM[section]
34
+ .querySelector('.rebilly-instruments-loader')
35
+ .classList.add('is-active');
36
+ }
37
+ this.DOM[section].style.minHeight = minHeight;
39
38
  }
39
+ }
40
40
 
41
- stopLoading({section = 'form', id = ''} = {}) {
42
- const idIndex = this[section].indexOf(id);
41
+ stopLoading({ section = 'form', id = '' } = {}) {
42
+ const idIndex = this[section].indexOf(id);
43
43
 
44
- if (idIndex !== -1) {
45
- this[section].splice(idIndex, 1);
46
- }
47
-
48
- if (!this[section].length
49
- && this.DOM[section].querySelector('.rebilly-instruments-loader')) {
50
- this.DOM[section].querySelector('.rebilly-instruments-loader')
51
- .classList.remove('is-active');
52
- }
44
+ if (idIndex !== -1) {
45
+ this[section].splice(idIndex, 1);
53
46
  }
54
47
 
55
- clearAll() {
56
- this.form.forEach(id => {
57
- this.stopLoading({id})
58
- });
59
- this.summary.forEach(id => {
60
- this.stopLoading({section: 'summary', id})
61
- });
62
- this.modal.forEach(id => {
63
- this.stopLoading({section: 'modal', id})
64
- });
48
+ if (
49
+ !this[section].length &&
50
+ this.DOM[section].querySelector('.rebilly-instruments-loader')
51
+ ) {
52
+ this.DOM[section]
53
+ .querySelector('.rebilly-instruments-loader')
54
+ .classList.remove('is-active');
55
+ this.DOM[section].style.minHeight = '';
65
56
  }
57
+ }
58
+
59
+ clearAll() {
60
+ this.form.forEach((id) => {
61
+ this.stopLoading({ id });
62
+ });
63
+ this.summary.forEach((id) => {
64
+ this.stopLoading({ section: 'summary', id });
65
+ });
66
+ this.modal.forEach((id) => {
67
+ this.stopLoading({ section: 'modal', id });
68
+ });
69
+ }
66
70
  }
@@ -1,5 +1,5 @@
1
1
  import { Loader } from './index';
2
-
2
+
3
3
  describe('Loader Class', () => {
4
4
  let loader;
5
5
 
@@ -11,56 +11,63 @@ describe('Loader Class', () => {
11
11
  <div class="summary-selector"></div>
12
12
  `;
13
13
 
14
- loader.addDOMElement({el: document.querySelector('.form-selector')});
15
- loader.addDOMElement({section: 'summary', el: document.querySelector('.summary-selector')});
16
- })
14
+ loader.addDOMElement({ el: document.querySelector('.form-selector') });
15
+ loader.addDOMElement({
16
+ section: 'summary',
17
+ el: document.querySelector('.summary-selector')
18
+ });
19
+ });
17
20
 
18
21
  it('manage state of loading ids', () => {
19
- loader.startLoading({id: 'loadForm'});
20
- loader.startLoading({id: 'updateForm'});
22
+ loader.startLoading({ id: 'loadForm' });
23
+ loader.startLoading({ id: 'updateForm' });
21
24
 
22
25
  // Start loading state
23
- loader.startLoading({section: 'summary', id: 'loadSummary'});
24
- loader.startLoading({section: 'summary', id: 'updateSummary'});
26
+ loader.startLoading({ section: 'summary', id: 'loadSummary' });
27
+ loader.startLoading({ section: 'summary', id: 'updateSummary' });
25
28
 
26
29
  // Stop one loading state
27
- loader.stopLoading({id: 'loadForm'});
30
+ loader.stopLoading({ id: 'loadForm' });
28
31
 
29
32
  expect(loader.form.length).toEqual(1);
30
33
  expect(loader.summary.length).toEqual(2);
31
34
  });
32
35
 
33
36
  it('adds the loader HTML on element and removes the active class when stoped', () => {
34
- loader.startLoading({id: 'loadForm'});
37
+ loader.startLoading({ id: 'loadForm' });
35
38
 
36
39
  expect(loader.DOM.form.innerHTML).toMatch('rebilly-instruments-loader');
37
40
  expect(
38
- loader.DOM.form.querySelector('.rebilly-instruments-loader')
41
+ loader.DOM.form
42
+ .querySelector('.rebilly-instruments-loader')
39
43
  .classList.contains('is-active')
40
44
  ).toEqual(true);
41
45
 
42
- loader.stopLoading({id: 'loadForm'});
46
+ loader.stopLoading({ id: 'loadForm' });
43
47
 
44
48
  expect(
45
- loader.DOM.form.querySelector('.rebilly-instruments-loader')
49
+ loader.DOM.form
50
+ .querySelector('.rebilly-instruments-loader')
46
51
  .classList.contains('is-active')
47
52
  ).toEqual(false);
48
53
  });
49
54
 
50
55
  it('keeps loading when there are Ids on the element array', () => {
51
- loader.startLoading({id: 'loadForm'});
52
- loader.startLoading({id: 'updateForm'});
56
+ loader.startLoading({ id: 'loadForm' });
57
+ loader.startLoading({ id: 'updateForm' });
53
58
 
54
59
  expect(loader.DOM.form.innerHTML).toMatch('rebilly-instruments-loader');
55
60
  expect(
56
- loader.DOM.form.querySelector('.rebilly-instruments-loader')
61
+ loader.DOM.form
62
+ .querySelector('.rebilly-instruments-loader')
57
63
  .classList.contains('is-active')
58
64
  ).toEqual(true);
59
65
 
60
- loader.stopLoading({id: 'loadForm'});
61
-
66
+ loader.stopLoading({ id: 'loadForm' });
67
+
62
68
  expect(
63
- loader.DOM.form.querySelector('.rebilly-instruments-loader')
69
+ loader.DOM.form
70
+ .querySelector('.rebilly-instruments-loader')
64
71
  .classList.contains('is-active')
65
72
  ).toEqual(true);
66
73
  });
@@ -1,7 +1,35 @@
1
- import {RebillyStorefrontAPI} from 'rebilly-js-sdk';
1
+ import { RebillyStorefrontAPI } from 'rebilly-js-sdk';
2
+
3
+ export function validateStateForStorefront({state}) {
4
+ if (!state.storefront) {
5
+ throw new Error('Could not access rebilly-js-sdk instance');
6
+ }
7
+
8
+ if (!state.options) {
9
+ throw new Error(
10
+ 'Could not use Rebilly Instruments mount options to fetch Rebilly data'
11
+ );
12
+ }
13
+ }
14
+
15
+ export async function Endpoint({
16
+ state
17
+ } = {}, callback) {
18
+ try {
19
+ validateStateForStorefront({state});
20
+ return await callback();
21
+ } catch(error) {
22
+ // TODO: standard error handling for all endpoints
23
+ // console.error(error);
24
+ if(error.status === 422) {
25
+ error.details.forEach(e => console.error(e));
26
+ }
27
+ throw error;
28
+ }
29
+ }
2
30
 
3
31
  export class StorefrontInstance {
4
- constructor ({
32
+ constructor({
5
33
  publishableKey = null,
6
34
  organizationId = null,
7
35
  mode = 'live',
@@ -17,15 +45,17 @@ export class StorefrontInstance {
17
45
  const api = RebillyStorefrontAPI({
18
46
  organizationId,
19
47
  sandbox: mode === 'sandbox',
20
- timeout: Number.isNaN(parseInt(timeout, 10)) ? 10000 : parseInt(timeout, 10),
21
- urls,
48
+ timeout: Number.isNaN(parseInt(timeout, 10))
49
+ ? 10000
50
+ : parseInt(timeout, 10),
51
+ urls
22
52
  });
23
-
53
+
24
54
  api.setPublishableKey(publishableKey);
25
-
55
+
26
56
  this.api = api;
27
57
  return this.api;
28
58
  }
29
59
  }
30
60
 
31
- export default (config = {}) => new StorefrontInstance(config)
61
+ export default (config = {}) => new StorefrontInstance(config);
@@ -0,0 +1,11 @@
1
+ import InvoiceModel from './models/invoice-model';
2
+ import { Endpoint } from './index';
3
+
4
+ export async function fetchInvoice({ data = null, state = null }) {
5
+ return Endpoint({state}, async () => {
6
+ state.storefront.setSessionToken(state.options.customerJwt);
7
+ const {fields} = await state.storefront.invoices.get(data);
8
+
9
+ return new InvoiceModel(fields);
10
+ });
11
+ }
@@ -0,0 +1,10 @@
1
+ export default class BaseModel {
2
+ constructor({
3
+ ...fields
4
+ } = {}) {
5
+ Object.entries(fields)
6
+ .forEach(([key, value]) => {
7
+ this[key] = value;
8
+ })
9
+ }
10
+ }
@@ -0,0 +1,3 @@
1
+ import BaseModel from './base-model';
2
+
3
+ export default class InvoiceModel extends BaseModel {}
@@ -1,35 +1,3 @@
1
- export default class PlanModel {
2
- constructor({
3
- id = '',
4
- name = '',
5
- productId = '',
6
- productOptions = {},
7
- currency = '',
8
- currencySign = '',
9
- pricing = {},
10
- recurringInterval = {},
11
- trial = null,
12
- isTrialOnly = false,
13
- setup = null,
14
- customFields = {},
15
- createdTime = '',
16
- updatedTime = '',
17
- invoiceTimeShift = {},
18
- } = {}) {
19
- this.id = id;
20
- this.name = name;
21
- this.productId = productId;
22
- this.productOptions = productOptions;
23
- this.currency = currency;
24
- this.currencySign = currencySign;
25
- this.pricing = pricing;
26
- this.recurringInterval = recurringInterval;
27
- this.trial = trial;
28
- this.isTrialOnly = isTrialOnly;
29
- this.setup = setup;
30
- this.customFields = customFields;
31
- this.createdTime = createdTime;
32
- this.updatedTime = updatedTime;
33
- this.invoiceTimeShift = invoiceTimeShift;
34
- }
35
- }
1
+ import BaseModel from './base-model';
2
+
3
+ export default class PlanModel extends BaseModel {}
@@ -1,23 +1,3 @@
1
- export default class ProductModel {
2
- constructor({
3
- id = '',
4
- name = '',
5
- unitLabel = '',
6
- description = {},
7
- requiresShipping = false,
8
- options = [],
9
- customFields = {},
10
- createdTime = '',
11
- updatedTime = '',
12
- } = {}) {
13
- this.id = id;
14
- this.name = name;
15
- this.unitLabel = unitLabel;
16
- this.description = description;
17
- this.requiresShipping = requiresShipping;
18
- this.options = options;
19
- this.customFields = customFields;
20
- this.createdTime = createdTime;
21
- this.updatedTime = updatedTime;
22
- }
23
- }
1
+ import BaseModel from './base-model';
2
+
3
+ export default class ProductModel extends BaseModel {}
@@ -6,7 +6,7 @@ export class ReadyToPayFeatureModel {
6
6
  merchantOrigin = '',
7
7
  // Plaid fields
8
8
  linkToken = '',
9
- expirationTime = '',
9
+ expirationTime = ''
10
10
  } = {}) {
11
11
  this.name = name;
12
12
  this.merchantName = merchantName;
@@ -22,7 +22,7 @@ export default class ReadyToPayModel {
22
22
  method = '',
23
23
  feature = null,
24
24
  brands = [],
25
- filters = [],
25
+ filters = []
26
26
  } = {}) {
27
27
  this.index = index;
28
28
  this.method = method;
@@ -30,4 +30,4 @@ export default class ReadyToPayModel {
30
30
  this.brands = brands;
31
31
  this.filters = filters;
32
32
  }
33
- }
33
+ }
@@ -1,42 +1,28 @@
1
- export class SummaryLineItemModel{
1
+ import BaseModel from './base-model';
2
+
3
+ export class SummaryLineItemModel extends BaseModel {
2
4
  constructor({
3
- type = '',
4
- description = '',
5
5
  unitPrice = 0.0,
6
6
  quantity = 0,
7
7
  price = 0.0,
8
- planId = '',
9
- productId = ''
8
+ ...fields
10
9
  } = {}) {
11
- this.type = type;
12
- this.description = description;
10
+ super(fields);
13
11
  this.unitPrice = unitPrice;
14
12
  this.quantity = quantity;
15
13
  this.price = price;
16
- this.planId = planId;
17
- this.productId = productId;
18
14
  }
19
15
  }
20
16
 
21
- export class SummaryTaxModel {
22
- constructor({
23
- amount = '',
24
- description = ''
25
- } = {}) {
26
- this.amount = amount;
27
- this.description = description;
28
- }
29
- }
17
+ export class SummaryTaxModel extends BaseModel {}
30
18
 
31
- export class SummaryDiscountModel {
19
+ export class SummaryDiscountModel extends BaseModel {
32
20
  constructor({
33
- couponId = '',
34
21
  amount = 0,
35
- description = ''
36
- } = {}) {
37
- this.couponId = couponId;
22
+ ...fields
23
+ }) {
24
+ super(fields);
38
25
  this.amount = amount;
39
- this.description = description;
40
26
  }
41
27
  }
42
28
 
@@ -53,13 +39,13 @@ export default class SummaryModel {
53
39
  total = 0.0
54
40
  } = {}) {
55
41
  function map(array) {
56
- const list = (Array.isArray(array) ? array : []);
42
+ const list = Array.isArray(array) ? array : [];
57
43
  return {
58
44
  // eslint-disable-next-line new-cap
59
- to: (instance) => list.map(item => new instance(item))
60
- }
45
+ to: (instance) => list.map((item) => new instance(item))
46
+ };
61
47
  }
62
-
48
+
63
49
  this.currency = currency;
64
50
  this.lineItems = map(lineItems).to(SummaryLineItemModel);
65
51
  this.taxes = map(taxes).to(SummaryTaxModel);
@@ -70,4 +56,4 @@ export default class SummaryModel {
70
56
  this.discountsAmount = discountsAmount;
71
57
  this.total = total;
72
58
  }
73
- }
59
+ }
@@ -0,0 +1,19 @@
1
+ import BaseModel from './base-model';
2
+
3
+ export default class TransactionModel extends BaseModel {
4
+ constructor({
5
+ invoiceIds = [],
6
+ ...fields
7
+ }) {
8
+ super(fields);
9
+ this.invoiceIds = invoiceIds || [];
10
+ }
11
+
12
+ get invoiceId () {
13
+ return this.invoiceIds[0] || null;
14
+ }
15
+
16
+ get hasInvoice () {
17
+ return !!this.invoiceId;
18
+ }
19
+ }