@rebilly/instruments 4.5.0 → 4.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/.babelrc +24 -26
  2. package/CHANGELOG.md +14 -0
  3. package/dist/index.js +8 -8
  4. package/dist/index.min.js +8 -8
  5. package/package.json +14 -3
  6. package/project.json +9 -0
  7. package/rollup.config.mjs +21 -26
  8. package/src/data/options-schema/index.js +94 -78
  9. package/src/data/options-schema/schemas/options-schema.js +419 -411
  10. package/src/events/base-event.js +34 -34
  11. package/src/events/events.spec.js +6 -6
  12. package/src/events/index.js +5 -5
  13. package/src/functions/destroy.js +19 -19
  14. package/src/functions/destroy.spec.js +41 -41
  15. package/src/functions/mount/fetch-data.js +200 -193
  16. package/src/functions/mount/fetch-data.spec.js +287 -285
  17. package/src/functions/mount/get-lead-source-data.js +31 -31
  18. package/src/functions/mount/get-lead-source-data.spec.js +19 -19
  19. package/src/functions/mount/index.js +73 -65
  20. package/src/functions/mount/mount.spec.js +77 -66
  21. package/src/functions/mount/setup-element.js +23 -23
  22. package/src/functions/mount/setup-framepay-theme.js +86 -68
  23. package/src/functions/mount/setup-framepay.js +9 -5
  24. package/src/functions/mount/setup-i18n.js +15 -15
  25. package/src/functions/mount/setup-options.js +74 -74
  26. package/src/functions/mount/setup-options.spec.js +323 -287
  27. package/src/functions/mount/setup-storefront.js +15 -20
  28. package/src/functions/mount/setup-styles-vars.js +19 -22
  29. package/src/functions/mount/setup-user-flow.js +51 -47
  30. package/src/functions/on.js +5 -5
  31. package/src/functions/on.spec.js +60 -51
  32. package/src/functions/purchase.js +151 -146
  33. package/src/functions/purchase.spec.js +59 -56
  34. package/src/functions/setup.js +53 -53
  35. package/src/functions/setup.spec.js +88 -75
  36. package/src/functions/show.js +13 -14
  37. package/src/functions/show.spec.js +53 -53
  38. package/src/functions/update.js +30 -28
  39. package/src/functions/update.spec.js +94 -93
  40. package/src/i18n/en.json +32 -32
  41. package/src/i18n/es.json +29 -29
  42. package/src/i18n/i18n.spec.js +18 -18
  43. package/src/i18n/index.js +48 -48
  44. package/src/instance.js +36 -36
  45. package/src/instance.spec.js +29 -27
  46. package/src/loader/index.js +95 -70
  47. package/src/loader/loader.spec.js +63 -63
  48. package/src/state/iframes.js +21 -21
  49. package/src/state/index.js +56 -54
  50. package/src/storefront/account-and-website.js +10 -8
  51. package/src/storefront/account-and-website.spec.js +55 -55
  52. package/src/storefront/deposit-requests.js +6 -6
  53. package/src/storefront/fetch-plans-from-addons-bumpOffer.js +21 -19
  54. package/src/storefront/fetch-products-from-plans.js +52 -51
  55. package/src/storefront/fetch-products-from-plans.spec.js +90 -87
  56. package/src/storefront/index.js +56 -49
  57. package/src/storefront/invoices.js +15 -15
  58. package/src/storefront/invoices.spec.js +69 -65
  59. package/src/storefront/models/account-model.js +29 -32
  60. package/src/storefront/models/base-model.js +6 -9
  61. package/src/storefront/models/deposit-request-model.js +22 -13
  62. package/src/storefront/models/invoice-model.js +16 -16
  63. package/src/storefront/models/payment-metadata.js +4 -4
  64. package/src/storefront/models/plan-model.js +73 -64
  65. package/src/storefront/models/ready-to-pay-model.js +59 -59
  66. package/src/storefront/models/summary-model.js +43 -46
  67. package/src/storefront/models/transaction-model.js +11 -14
  68. package/src/storefront/payment-instruments.js +38 -35
  69. package/src/storefront/payment-instruments.spec.js +81 -62
  70. package/src/storefront/purchase.js +50 -44
  71. package/src/storefront/purchase.spec.js +40 -40
  72. package/src/storefront/ready-to-pay.js +75 -77
  73. package/src/storefront/ready-to-pay.spec.js +59 -54
  74. package/src/storefront/storefront.spec.js +9 -9
  75. package/src/storefront/summary.js +93 -67
  76. package/src/storefront/summary.spec.js +108 -106
  77. package/src/storefront/transactions.js +6 -6
  78. package/src/style/base/default-theme.js +928 -923
  79. package/src/style/base/theme.js +21 -21
  80. package/src/style/base/theme.spec.js +13 -13
  81. package/src/style/index.js +3 -3
  82. package/src/style/utils/border.js +40 -27
  83. package/src/style/utils/color-values.js +18 -18
  84. package/src/style/utils/minifyCss.js +6 -6
  85. package/src/utils/add-dom-element.js +14 -14
  86. package/src/utils/format-currency.js +6 -5
  87. package/src/utils/has-valid-css-selector.js +2 -2
  88. package/src/utils/index.js +6 -6
  89. package/src/utils/is-dom-element.js +1 -1
  90. package/src/utils/process-property-as-dom-element.js +22 -22
  91. package/src/utils/quantity.js +26 -28
  92. package/src/utils/sleep.js +3 -1
  93. package/src/views/amount-selector.js +37 -36
  94. package/src/views/common/iframe/base-iframe.js +53 -52
  95. package/src/views/common/iframe/events/change-iframe-src-handler.js +5 -5
  96. package/src/views/common/iframe/events/dispatch-event-handler.js +4 -4
  97. package/src/views/common/iframe/events/resize-component-handler.js +8 -8
  98. package/src/views/common/iframe/events/show-error-handler.js +2 -2
  99. package/src/views/common/iframe/events/stop-loader-handler.js +8 -8
  100. package/src/views/common/iframe/events/update-addons-handler.js +20 -13
  101. package/src/views/common/iframe/events/update-coupons-handler.js +9 -9
  102. package/src/views/common/iframe/events/update-items-handler.js +26 -22
  103. package/src/views/common/iframe/modal-iframe.js +67 -56
  104. package/src/views/common/iframe/view-iframe.js +11 -11
  105. package/src/views/common/render-utilities.js +2 -2
  106. package/src/views/confirmation.js +33 -30
  107. package/src/views/errors.js +89 -79
  108. package/src/views/form.js +41 -37
  109. package/src/views/method-selector/express-methods.js +46 -46
  110. package/src/views/method-selector/generate-digital-wallet.js +46 -45
  111. package/src/views/method-selector/generate-digital-wallet.spec.js +104 -102
  112. package/src/views/method-selector/generate-framepay-config.js +53 -51
  113. package/src/views/method-selector/generate-framepay-config.spec.js +197 -173
  114. package/src/views/method-selector/get-method-data.js +5 -6
  115. package/src/views/method-selector/get-payment-methods.js +18 -16
  116. package/src/views/method-selector/get-payment-methods.spec.js +29 -27
  117. package/src/views/method-selector/index.js +154 -139
  118. package/src/views/method-selector/method-selector.spec.js +13 -13
  119. package/src/views/method-selector/mount-bump-offer.js +65 -49
  120. package/src/views/method-selector/mount-express-methods.js +89 -85
  121. package/src/views/modal.js +74 -67
  122. package/src/views/result.js +14 -14
  123. package/src/views/summary.js +25 -26
  124. package/tests/async-utilities.js +13 -13
  125. package/tests/mocks/framepay-mock.js +9 -8
  126. package/tests/mocks/rebilly-api-mock.js +5 -3
  127. package/tests/mocks/rebilly-instruments-mock.js +121 -117
  128. package/tests/mocks/storefront-api-mock.js +55 -48
  129. package/tests/mocks/storefront-mock.js +10 -14
  130. package/tests/msw/server.js +6 -6
  131. package/tests/setup-test.js +14 -16
  132. package/vitest.config.js +14 -14
  133. package/.eslintrc.js +0 -34
  134. package/.prettierrc.js +0 -11
@@ -2,27 +2,22 @@ import Storefront from '../../storefront';
2
2
  import state from '../../state';
3
3
 
4
4
  export default () => {
5
- const {
6
- publishableKey,
7
- organizationId,
8
- apiMode,
9
- _dev
10
- } = state.options;
5
+ const { publishableKey, organizationId, apiMode, _dev } = state.options;
11
6
 
12
- const storefront = {
13
- organizationId,
14
- mode: apiMode || 'live'
15
- };
7
+ const storefront = {
8
+ organizationId,
9
+ mode: apiMode || 'live',
10
+ };
16
11
 
17
- if (publishableKey) {
18
- storefront.publishableKey = publishableKey;
19
- }
12
+ if (publishableKey) {
13
+ storefront.publishableKey = publishableKey;
14
+ }
20
15
 
21
- if (_dev) {
22
- storefront.liveUrl = _dev.liveUrl || 'https://api.rebilly.com';
23
- storefront.sandboxUrl =
24
- _dev.sandboxUrl || 'https://api-sandbox.rebilly.com';
25
- }
16
+ if (_dev) {
17
+ storefront.liveUrl = _dev.liveUrl || 'https://api.rebilly.com';
18
+ storefront.sandboxUrl =
19
+ _dev.sandboxUrl || 'https://api-sandbox.rebilly.com';
20
+ }
26
21
 
27
- return Storefront(storefront);
28
- }
22
+ return Storefront(storefront);
23
+ };
@@ -4,30 +4,27 @@ import { minifyCss } from '../../style/utils/minifyCss';
4
4
  import state from '../../state';
5
5
 
6
6
  export default () => {
7
- const {
8
- theme = {},
9
- css,
10
- } = state.options;
7
+ const { theme = {}, css } = state.options;
11
8
 
12
- // Adds base CSS vars stylesheet
13
- const styleVars = mainStyleVars(theme || {});
9
+ // Adds base CSS vars stylesheet
10
+ const styleVars = mainStyleVars(theme || {});
14
11
 
15
- addDOMElement({
16
- element: 'style',
17
- attributes: { type: 'text/css' },
18
- content: minifyCss(styleVars),
19
- target: 'head'
20
- });
21
-
22
- // Adds options CSS to override any styles
23
- if (css) {
24
12
  addDOMElement({
25
- element: 'style',
26
- attributes: { type: 'text/css' },
27
- content: minifyCss(css),
28
- target: 'head'
13
+ element: 'style',
14
+ attributes: { type: 'text/css' },
15
+ content: minifyCss(styleVars),
16
+ target: 'head',
29
17
  });
30
- }
31
18
 
32
- return styleVars;
33
- }
19
+ // Adds options CSS to override any styles
20
+ if (css) {
21
+ addDOMElement({
22
+ element: 'style',
23
+ attributes: { type: 'text/css' },
24
+ content: minifyCss(css),
25
+ target: 'head',
26
+ });
27
+ }
28
+
29
+ return styleVars;
30
+ };
@@ -3,54 +3,58 @@ import { show } from '../show';
3
3
  import { purchase } from '../purchase';
4
4
  import { setup } from '../setup';
5
5
 
6
- function showResult({state, payload}) {
7
- show({
8
- componentName: 'result',
9
- payload,
10
- state
11
- });
6
+ function showResult({ state, payload }) {
7
+ show({
8
+ componentName: 'result',
9
+ payload,
10
+ state,
11
+ });
12
12
  }
13
13
 
14
- export default ({state = {}}) => {
15
- if (state.options.features.autoConfirmation) {
16
- on({
17
- eventName: 'instrument-ready',
18
- callback: (payload) => {
19
- // Alternate flow for paypal.
20
- if (payload._raw?.method === 'paypal') {
21
- if (!state.data.isShippingRequired) {
22
- if (state.options.transactionType === 'setup') {
23
- setup({state, payload});
24
- } else {
25
- purchase({state, payload});
26
- }
27
- state.loader.startLoading({state, id: 'express-purchase', message: 'form.loaderMessages.processingPayment' });
28
- return;
29
- }
30
- }
31
- show({
32
- componentName: 'confirmation',
33
- payload,
34
- state
14
+ export default ({ state = {} }) => {
15
+ if (state.options.features.autoConfirmation) {
16
+ on({
17
+ eventName: 'instrument-ready',
18
+ callback: (payload) => {
19
+ // Alternate flow for paypal.
20
+ if (payload._raw?.method === 'paypal') {
21
+ if (!state.data.isShippingRequired) {
22
+ if (state.options.transactionType === 'setup') {
23
+ setup({ state, payload });
24
+ } else {
25
+ purchase({ state, payload });
26
+ }
27
+ state.loader.startLoading({
28
+ state,
29
+ id: 'express-purchase',
30
+ message: 'form.loaderMessages.processingPayment',
31
+ });
32
+ return;
33
+ }
34
+ }
35
+ show({
36
+ componentName: 'confirmation',
37
+ payload,
38
+ state,
39
+ });
40
+ },
35
41
  });
36
- }
37
- });
38
- }
42
+ }
39
43
 
40
- if (state.options.features.autoResult) {
41
- on({
42
- eventName: 'purchase-completed',
43
- callback: (payload) => {
44
- payload = JSON.parse(JSON.stringify(payload));
45
- showResult({state, payload});
46
- }
47
- });
48
- on({
49
- eventName: 'setup-completed',
50
- callback: (payload) => {
51
- payload = JSON.parse(JSON.stringify(payload));
52
- showResult({state, payload});
53
- }
54
- });
55
- }
56
- }
44
+ if (state.options.features.autoResult) {
45
+ on({
46
+ eventName: 'purchase-completed',
47
+ callback: (payload) => {
48
+ payload = JSON.parse(JSON.stringify(payload));
49
+ showResult({ state, payload });
50
+ },
51
+ });
52
+ on({
53
+ eventName: 'setup-completed',
54
+ callback: (payload) => {
55
+ payload = JSON.parse(JSON.stringify(payload));
56
+ showResult({ state, payload });
57
+ },
58
+ });
59
+ }
60
+ };
@@ -13,10 +13,10 @@ import Events, { publicEventNames } from '../events';
13
13
  * @param {OnParams} params
14
14
  */
15
15
  export function on({ eventName, callback }) {
16
- if (!publicEventNames.includes(eventName)) {
17
- throw new Error(`${eventName} is not a supported event`);
18
- }
16
+ if (!publicEventNames.includes(eventName)) {
17
+ throw new Error(`${eventName} is not a supported event`);
18
+ }
19
19
 
20
- const internalEventName = camelCase(eventName);
21
- Events[internalEventName].addEventListener(callback);
20
+ const internalEventName = camelCase(eventName);
21
+ Events[internalEventName].addEventListener(callback);
22
22
  }
@@ -5,62 +5,71 @@ import Events from '@/events';
5
5
  import iframes from '@/state/iframes';
6
6
 
7
7
  describe('RebillyInstruments on', () => {
8
- it('should register event listeners', async () => {
9
- const rebillyInstruments = await RenderMockRebillyInstruments();
10
- const publicEventNames = ['instrument-ready', 'purchase-completed'];
8
+ it('should register event listeners', async () => {
9
+ const rebillyInstruments = await RenderMockRebillyInstruments();
10
+ const publicEventNames = ['instrument-ready', 'purchase-completed'];
11
11
 
12
- await Promise.all(
13
- publicEventNames.map(async (eventName) => {
14
- const callback = vi.fn();
15
- rebillyInstruments.on(eventName, callback);
12
+ await Promise.all(
13
+ publicEventNames.map(async (eventName) => {
14
+ const callback = vi.fn();
15
+ rebillyInstruments.on(eventName, callback);
16
16
 
17
- const details = {
18
- test: 'data'
19
- };
20
- Events[camelCase(eventName)].dispatch(details);
17
+ const details = {
18
+ test: 'data',
19
+ };
20
+ Events[camelCase(eventName)].dispatch(details);
21
21
 
22
- expect(callback).toBeCalledTimes(1);
23
- expect(callback).toBeCalledWith(details);
24
- })
25
- );
26
- });
22
+ expect(callback).toBeCalledTimes(1);
23
+ expect(callback).toBeCalledWith(details);
24
+ }),
25
+ );
26
+ });
27
27
 
28
- it('should throw error for internal namespaced events', async () => {
29
- const callback = vi.fn();
30
- const instance = new RebillyInstrumentsInstance();
31
- const iframeMock = {
32
- component: {
33
- call: vi.fn()
34
- }
35
- };
36
- iframes.form = iframeMock;
28
+ it('should throw error for internal namespaced events', async () => {
29
+ const callback = vi.fn();
30
+ const instance = new RebillyInstrumentsInstance();
31
+ const iframeMock = {
32
+ component: {
33
+ call: vi.fn(),
34
+ },
35
+ };
36
+ iframes.form = iframeMock;
37
37
 
38
- let error;
39
- try {
40
- // rebilly-instruments-purchase-completed will be used internally but not available externally
41
- await instance.on('rebilly-instruments-purchase-completed', callback);
42
- } catch (e) {
43
- error = e;
44
- }
45
- expect(error).toEqual(new Error('rebilly-instruments-purchase-completed is not a supported event'));
46
- });
38
+ let error;
39
+ try {
40
+ // rebilly-instruments-purchase-completed will be used internally but not available externally
41
+ await instance.on(
42
+ 'rebilly-instruments-purchase-completed',
43
+ callback,
44
+ );
45
+ } catch (e) {
46
+ error = e;
47
+ }
48
+ expect(error).toEqual(
49
+ new Error(
50
+ 'rebilly-instruments-purchase-completed is not a supported event',
51
+ ),
52
+ );
53
+ });
47
54
 
48
- it('should throw error for a non defined event', async () => {
49
- const callback = vi.fn();
50
- const instance = new RebillyInstrumentsInstance();
51
- const iframeMock = {
52
- component: {
53
- call: vi.fn()
54
- }
55
- };
56
- iframes.form = iframeMock;
55
+ it('should throw error for a non defined event', async () => {
56
+ const callback = vi.fn();
57
+ const instance = new RebillyInstrumentsInstance();
58
+ const iframeMock = {
59
+ component: {
60
+ call: vi.fn(),
61
+ },
62
+ };
63
+ iframes.form = iframeMock;
57
64
 
58
- let error;
59
- try {
60
- await instance.on('not-an-event', callback);
61
- } catch (e) {
62
- error = e;
63
- }
64
- expect(error).toEqual(new Error('not-an-event is not a supported event'));
65
- });
65
+ let error;
66
+ try {
67
+ await instance.on('not-an-event', callback);
68
+ } catch (e) {
69
+ error = e;
70
+ }
71
+ expect(error).toEqual(
72
+ new Error('not-an-event is not a supported event'),
73
+ );
74
+ });
66
75
  });
@@ -7,162 +7,167 @@ import { showError } from '../views/errors';
7
7
  import { mapItemsQuantities } from '../utils/quantity';
8
8
 
9
9
  export async function makePayment({ payload }) {
10
- const {
11
- _raw: {
12
- id
13
- },
14
- isExistingInstrument
15
- } = payload;
16
- delete payload.isExistingInstrument;
17
- delete payload._raw;
18
-
19
- const data = {
20
- ...payload
21
- };
22
-
23
- if (isExistingInstrument) {
24
- data.paymentInstrumentId = id;
25
-
26
- } else {
27
- data.token = id;
28
- }
29
-
30
- if (state.options?.invoiceId) {
31
- data.invoiceId = state.options.invoiceId;
32
- }
33
-
34
- if (state.options?.transactionId) {
35
- data.transactionId = state.options.transactionId;
36
- }
37
-
38
- if (state.options?.money) {
39
- data.websiteId = state.options.websiteId;
40
- data.amount = state.options.money.amount;
41
- data.currency = state.options.money.currency;
42
- }
43
-
44
- if (state.options?.deposit) {
45
- data.websiteId = state.options.websiteId;
46
- data.amount = state.data.amountAndCurrency.amount;
47
- data.currency = state.data.amountAndCurrency.currency;
48
- }
49
-
50
- if (state.data?.couponIds && Array.isArray(state.data.couponIds)) {
51
- data.couponIds = state.data.couponIds
52
- }
53
-
54
- let { fields } = await postPayment({
55
- state,
56
- data
57
- });
58
-
59
- fields = {
60
- transaction: fields,
61
- token: fields.token || state.options.jwt
62
- };
63
-
64
- if (state.data.invoice) {
65
- fields.invoice = state.data.invoice;
66
- }
67
-
68
- return fields;
69
- }
10
+ const {
11
+ _raw: { id },
12
+ isExistingInstrument,
13
+ } = payload;
14
+ delete payload.isExistingInstrument;
15
+ delete payload._raw;
16
+
17
+ const data = {
18
+ ...payload,
19
+ };
20
+
21
+ if (isExistingInstrument) {
22
+ data.paymentInstrumentId = id;
23
+ } else {
24
+ data.token = id;
25
+ }
70
26
 
71
- export async function makePurchase({ payload }) {
72
- const data = {
73
- websiteId: state.options.websiteId,
74
- paymentInstruction: {
75
- token: payload._raw.id
76
- },
77
- ...payload
78
- };
79
-
80
- if (state.data.acceptBumpOffer) {
81
- data.items = state.options.bumpOffer;
82
- } else {
83
- data.items = mapItemsQuantities(state.options.items);
84
- }
85
-
86
- if (state.data.couponIds && Array.isArray(state.data.couponIds)) {
87
- data.couponIds = state.data.couponIds
88
- }
89
-
90
- if (state.options.addons && state.data.addons && Array.isArray(state.data.addons)) {
91
- state.options.addons.forEach(addon => {
92
- if (state.data.addons.includes(addon.planId)) {
93
- data.items.push(addon);
94
- }
95
- })
96
- }
97
-
98
- const { fields } = await postPurchase({
99
- state,
100
- data
101
- });
102
- return fields;
27
+ if (state.options?.invoiceId) {
28
+ data.invoiceId = state.options.invoiceId;
29
+ }
30
+
31
+ if (state.options?.transactionId) {
32
+ data.transactionId = state.options.transactionId;
33
+ }
34
+
35
+ if (state.options?.money) {
36
+ data.websiteId = state.options.websiteId;
37
+ data.amount = state.options.money.amount;
38
+ data.currency = state.options.money.currency;
39
+ }
40
+
41
+ if (state.options?.deposit) {
42
+ data.websiteId = state.options.websiteId;
43
+ data.amount = state.data.amountAndCurrency.amount;
44
+ data.currency = state.data.amountAndCurrency.currency;
45
+ }
46
+
47
+ if (state.data?.couponIds && Array.isArray(state.data.couponIds)) {
48
+ data.couponIds = state.data.couponIds;
49
+ }
50
+
51
+ let { fields } = await postPayment({
52
+ state,
53
+ data,
54
+ });
55
+
56
+ fields = {
57
+ transaction: fields,
58
+ token: fields.token || state.options.jwt,
59
+ };
60
+
61
+ if (state.data.invoice) {
62
+ fields.invoice = state.data.invoice;
63
+ }
64
+
65
+ return fields;
103
66
  }
104
67
 
105
- export function handleApprovalUrl({fields, payload}) {
106
- if (state.options.features.fullPageRedirect &&
107
- (payload.redirectUrl || fields.transaction?.approvalUrl)
108
- ) {
109
- window.location = payload.redirectUrl || fields.transaction?.approvalUrl;
110
- return;
111
- }
112
-
113
- if (payload.redirectUrl || !fields.transaction?.approvalUrl) {
114
- const { paymentMethodsUrl } = state.options._computed;
115
- const modelSafeFields = JSON.parse(JSON.stringify(fields));
116
-
117
- const model = {};
118
- if (state.data.isPayment) {
119
- model.payment = modelSafeFields;
68
+ export async function makePurchase({ payload }) {
69
+ const data = {
70
+ websiteId: state.options.websiteId,
71
+ paymentInstruction: {
72
+ token: payload._raw.id,
73
+ },
74
+ ...payload,
75
+ };
76
+
77
+ if (state.data.acceptBumpOffer) {
78
+ data.items = state.options.bumpOffer;
120
79
  } else {
121
- model.purchase = modelSafeFields;
80
+ data.items = mapItemsQuantities(state.options.items);
81
+ }
82
+
83
+ if (state.data.couponIds && Array.isArray(state.data.couponIds)) {
84
+ data.couponIds = state.data.couponIds;
122
85
  }
123
-
124
- state.data = new DataInstance({...fields});
125
-
126
- const name = 'rebilly-instruments-approval-url'
127
- mountModal({
128
- name,
129
- url: `${paymentMethodsUrl}?name=${name}`,
130
- model,
131
- close: (updatedPurchase) => {
132
- Events.purchaseCompleted.dispatch(updatedPurchase);
133
- }
86
+
87
+ if (
88
+ state.options.addons &&
89
+ state.data.addons &&
90
+ Array.isArray(state.data.addons)
91
+ ) {
92
+ state.options.addons.forEach((addon) => {
93
+ if (state.data.addons.includes(addon.planId)) {
94
+ data.items.push(addon);
95
+ }
96
+ });
97
+ }
98
+
99
+ const { fields } = await postPurchase({
100
+ state,
101
+ data,
134
102
  });
135
- } else if (fields.transaction?.approvalUrl) {
136
- window.location = fields.transaction?.approvalUrl
137
- }
103
+ return fields;
138
104
  }
139
105
 
140
- export async function purchase({ payload }) {
141
- Object.keys(payload).forEach(key => {
142
- if (payload[key] === null) {
143
- delete payload[key];
106
+ export function handleApprovalUrl({ fields, payload }) {
107
+ if (
108
+ state.options.features.fullPageRedirect &&
109
+ (payload.redirectUrl || fields.transaction?.approvalUrl)
110
+ ) {
111
+ window.location =
112
+ payload.redirectUrl || fields.transaction?.approvalUrl;
113
+ return;
144
114
  }
145
- });
146
115
 
147
- try {
148
- let fields;
149
- if (state.data.isPayment) {
150
- fields = await makePayment({ payload });
151
- } else {
152
- fields = await makePurchase({ payload });
116
+ if (payload.redirectUrl || !fields.transaction?.approvalUrl) {
117
+ const { paymentMethodsUrl } = state.options._computed;
118
+ const modelSafeFields = JSON.parse(JSON.stringify(fields));
119
+
120
+ const model = {};
121
+ if (state.data.isPayment) {
122
+ model.payment = modelSafeFields;
123
+ } else {
124
+ model.purchase = modelSafeFields;
125
+ }
126
+
127
+ state.data = new DataInstance({ ...fields });
128
+
129
+ const name = 'rebilly-instruments-approval-url';
130
+ mountModal({
131
+ name,
132
+ url: `${paymentMethodsUrl}?name=${name}`,
133
+ model,
134
+ close: (updatedPurchase) => {
135
+ Events.purchaseCompleted.dispatch(updatedPurchase);
136
+ },
137
+ });
138
+ } else if (fields.transaction?.approvalUrl) {
139
+ window.location = fields.transaction?.approvalUrl;
153
140
  }
154
- if (fields.transaction?.approvalUrl && fields.transaction?.result === 'unknown') {
155
- if (state.options.features.fullPageRedirect) {
156
- window.location = fields.transaction?.approvalUrl
157
- } else {
158
- handleApprovalUrl({fields, payload});
159
- }
160
- } else {
161
- Events.purchaseCompleted.dispatch(fields);
141
+ }
142
+
143
+ export async function purchase({ payload }) {
144
+ Object.keys(payload).forEach((key) => {
145
+ if (payload[key] === null) {
146
+ delete payload[key];
147
+ }
148
+ });
149
+
150
+ try {
151
+ let fields;
152
+ if (state.data.isPayment) {
153
+ fields = await makePayment({ payload });
154
+ } else {
155
+ fields = await makePurchase({ payload });
156
+ }
157
+ if (
158
+ fields.transaction?.approvalUrl &&
159
+ fields.transaction?.result === 'unknown'
160
+ ) {
161
+ if (state.options.features.fullPageRedirect) {
162
+ window.location = fields.transaction?.approvalUrl;
163
+ } else {
164
+ handleApprovalUrl({ fields, payload });
165
+ }
166
+ } else {
167
+ Events.purchaseCompleted.dispatch(fields);
168
+ }
169
+ } catch (error) {
170
+ showError(error);
171
+ return error;
162
172
  }
163
- return fields;
164
- } catch (error) {
165
- showError(error);
166
- return error;
167
- }
168
173
  }