@rebilly/instruments 4.4.0 → 4.6.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 +14 -40
  4. package/dist/index.min.js +14 -40
  5. package/package.json +16 -5
  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 +420 -408
  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 +325 -289
  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 +149 -134
  33. package/src/functions/purchase.spec.js +59 -56
  34. package/src/functions/setup.js +53 -49
  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,152 +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;
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
+ }
26
+
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;
69
66
  }
70
67
 
71
68
  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;
103
- }
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;
79
+ } else {
80
+ data.items = mapItemsQuantities(state.options.items);
81
+ }
104
82
 
105
- export function handleApprovalUrl({fields, payload}) {
106
- if (payload.redirectUrl || !fields.transaction?.approvalUrl) {
107
- const { paymentMethodsUrl } = state.options._computed;
108
- const modelSafeFields = JSON.parse(JSON.stringify(fields));
83
+ if (state.data.couponIds && Array.isArray(state.data.couponIds)) {
84
+ data.couponIds = state.data.couponIds;
85
+ }
109
86
 
110
- const model = {};
111
- if (state.data.isPayment) {
112
- model.payment = modelSafeFields;
113
- } else {
114
- model.purchase = modelSafeFields;
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
+ });
115
97
  }
116
-
117
- state.data = new DataInstance({...fields});
118
-
119
- const name = 'rebilly-instruments-approval-url'
120
- mountModal({
121
- name,
122
- url: `${paymentMethodsUrl}?name=${name}`,
123
- model,
124
- close: (updatedPurchase) => {
125
- Events.purchaseCompleted.dispatch(updatedPurchase);
126
- }
98
+
99
+ const { fields } = await postPurchase({
100
+ state,
101
+ data,
127
102
  });
128
- } else if (fields.transaction?.approvalUrl) {
129
- window.location = fields.transaction?.approvalUrl
130
- }
103
+ return fields;
131
104
  }
132
105
 
133
- export async function purchase({ payload }) {
134
- Object.keys(payload).forEach(key => {
135
- if (payload[key] === null) {
136
- 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;
137
114
  }
138
- });
139
115
 
140
- try {
141
- let fields;
142
- if (state.data.isPayment) {
143
- fields = await makePayment({ state, payload });
144
- } else {
145
- fields = await makePurchase({ state, 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;
146
140
  }
141
+ }
147
142
 
148
- if (fields.transaction?.approvalUrl && fields.transaction?.result === 'unknown') {
149
- handleApprovalUrl({state, fields, payload});
150
- } else {
151
- Events.purchaseCompleted.dispatch(fields);
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;
152
172
  }
153
- return fields;
154
- } catch (error) {
155
- showError(error);
156
- return error;
157
- }
158
173
  }