@rebilly/instruments 3.36.0 → 3.36.1

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 (34) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/index.js +15 -15
  3. package/dist/index.min.js +15 -15
  4. package/package.json +1 -1
  5. package/src/data/options-schema/schemas/options-schema.js +3 -7
  6. package/src/functions/mount/fetch-data.js +3 -15
  7. package/src/functions/mount/index.js +70 -4
  8. package/src/functions/mount/mount.spec.js +1 -6
  9. package/src/functions/mount/setup-options.js +6 -19
  10. package/src/functions/mount/setup-options.spec.js +3 -3
  11. package/src/functions/purchase.js +4 -10
  12. package/src/functions/show.js +4 -3
  13. package/src/functions/show.spec.js +2 -0
  14. package/src/i18n/en.json +0 -3
  15. package/src/i18n/es.json +0 -3
  16. package/src/storefront/ready-to-pay.js +0 -5
  17. package/src/storefront/summary.js +1 -1
  18. package/src/style/base/__snapshots__/theme.spec.js.snap +1 -1
  19. package/src/style/base/default-theme.js +1 -1
  20. package/src/views/common/iframe/base-iframe.js +1 -7
  21. package/src/views/confirmation.js +15 -14
  22. package/src/views/method-selector/__snapshots__/method-selector.spec.js.snap +59 -10
  23. package/src/views/method-selector/generate-digital-wallet.js +2 -2
  24. package/src/views/method-selector/generate-digital-wallet.spec.js +13 -2
  25. package/src/views/method-selector/get-payment-methods.js +5 -5
  26. package/src/views/method-selector/get-payment-methods.spec.js +3 -4
  27. package/src/views/method-selector/index.js +86 -151
  28. package/src/views/method-selector/method-selector.spec.js +1 -1
  29. package/src/views/result.js +18 -8
  30. package/src/views/summary.js +3 -11
  31. package/src/storefront/deposit-requests.js +0 -12
  32. package/src/storefront/models/deposit-request-model.js +0 -15
  33. package/src/views/amount-selector.js +0 -47
  34. package/src/views/form.js +0 -52
@@ -32,8 +32,7 @@ it('should only return the allowed methods', async () => {
32
32
  state.data.readyToPay = await fetchReadyToPay({});
33
33
 
34
34
  const results = getPaymentMethods();
35
-
36
- expect(results.hasOwnProperty('expressMethods')).toEqual(true);
37
- expect(results['expressMethods'].length).toEqual(1);
38
- expect(results['methods'].length).toEqual(1);
35
+ expect(results.hasOwnProperty('EXPRESS_METHODS')).toEqual(true);
36
+ expect(results['EXPRESS_METHODS'].length).toEqual(1);
37
+ expect(results['METHODS'].length).toEqual(1);
39
38
  });
@@ -4,193 +4,128 @@ import state from '../../state';
4
4
  import iframes from '../../state/iframes';
5
5
  import { getPaymentMethods } from './get-payment-methods';
6
6
  import { fetchData } from '../../functions/mount/fetch-data';
7
- import { mountForm } from '../form';
8
-
7
+ import { ViewIframe } from '../common/iframe';
8
+ import { purchase } from '../../functions/purchase';
9
+ import { setup } from '../../functions/setup';
9
10
  import { mountExpressMethods } from './mount-express-methods';
10
11
  import { mountBumpOffer } from './mount-bump-offer';
11
12
  import { generateDigitalWallet } from './generate-digital-wallet';
12
13
  import { updateSummary } from '../summary';
13
- import { mountAmountSelector } from '../amount-selector';
14
-
15
- function getElement(id, rootElement = state.form) {
16
- return rootElement.querySelector(`[data-rebilly-instruments="${id}"]`);
17
- }
18
14
 
19
- const bumpOfferElement = () => {
20
- const rootDiv = document.createElement('div');
21
- rootDiv.classList.add('rebilly-instruments-bump-offers');
22
- rootDiv.setAttribute('data-rebilly-instruments', 'bump-offer');
23
- return rootDiv;
24
- }
25
-
26
- const backToAmountElement = () => {
27
- const template = `
28
- <div class="rebilly-instruments-confirmation-go-back-link" style="display: inline-block;margin-bottom: var(--rebilly-spacingM);margin-left: calc(var(--rebilly-spacingXs) * -1);">
29
- <a
30
- class="rebilly-instruments-link has-icon-left"
31
- style="display: inline-flex;color: var(--rebilly-colorPrimary);cursor: pointer;"
32
- >
33
- <svg
34
- class="rebilly-instruments-icon"
35
- style="margin-right: var(--rebilly-spacingXs);fill: var(--rebilly-colorPrimary)"
36
- viewBox="0 0 24 24"
37
- xmlns="http://www.w3.org/2000/svg"
38
- >
39
- <path
40
- d="M6.2929 11.2929l5-5c.3905-.3905 1.0237-.3905 1.4142 0 .3905.3905.3905 1.0237 0 1.4142L9.4142 11H17c.5523 0 1 .4477 1 1s-.4477 1-1 1H9.4142l3.293 3.2929c.3904.3905.3904 1.0237 0 1.4142-.3906.3905-1.0238.3905-1.4143 0l-5-5A.9969.9969 0 016 12c0-.2761.112-.5261.2929-.7071z"
41
- fill-rule="nonzero"
42
- />
43
- </svg>
44
- <span data-rebilly-i18n="deposit.goBack"></span>
45
- </a>
15
+ export const baseMethodSelectorHTML = ({compactExpressInstruments, bumpOffer}) => `
16
+ <div class="rebilly-instruments-content">
17
+ <div id="rebilly-instruments-error"></div>
18
+ ${bumpOffer.length ? '<div data-rebilly-instruments="bump-offer" class="rebilly-instruments-bump-offers"></div>' : ''}
19
+ <div data-rebilly-instruments="express-method" class="rebilly-instruments-method-selector ${compactExpressInstruments ? 'has-express-compact' : ''}">
20
+ <div class="rebilly-instruments-express-methods ${
21
+ compactExpressInstruments ? 'is-compact' : ''
22
+ }">
23
+ <span data-rebilly-i18n="form.expressCheckout" class="rebilly-instruments-express-methods-label">Express checkout</span>
24
+ <div class="rebilly-instruments-express-methods-container"></div>
25
+ </div>
26
+ <div data-rebilly-instruments="divider" class="rebilly-instruments-divider">
27
+ <span class="rebilly-instruments-divider-label" data-rebilly-i18n="form.or">Or</span>
46
28
  </div>
47
- `;
48
- const rootDiv = document.createElement('div');
49
- rootDiv.setAttribute('data-rebilly-instruments', 'deposit-back');
50
- rootDiv.innerHTML += template;
51
-
52
- const link = rootDiv.querySelector('.rebilly-instruments-link');
53
- link.addEventListener('click', () => {
54
- hideExtraUI();
55
- mountAmountSelector();
56
- });
57
-
58
- return rootDiv;
59
- }
60
-
61
-
62
- const expressMethodsElement = ({
63
- expressMethods,
64
- }) => {
65
- const rootDiv = document.createElement('div');
66
- rootDiv.classList.add('rebilly-instruments-method-selector');
67
- rootDiv.setAttribute('data-rebilly-instruments', 'express-methods');
68
- rootDiv.innerHTML = `
69
- <div class="rebilly-instruments-express-methods ">
70
- <span data-rebilly-i18n="form.expressCheckout" class="rebilly-instruments-express-methods-label">Express checkout</span>
71
- <div class="rebilly-instruments-express-methods-container" data-rebilly-instruments="express-methods-container"></div>
72
- </div>
73
- <div data-rebilly-instruments="divider" class="rebilly-instruments-divider">
74
- <span class="rebilly-instruments-divider-label" data-rebilly-i18n="form.or">Or</span>
75
29
  </div>
76
- `;
77
- const expressMethodsContainer = getElement('express-methods-container', rootDiv);
78
-
79
- const useCompactExpressInstruments = state.options.paymentInstruments.compactExpressInstruments && expressMethods.length;
80
- if (useCompactExpressInstruments) {
81
- rootDiv.classList.add('has-express-compact');
82
- expressMethodsContainer.classList.add('is-compact')
83
- }
84
-
85
- return rootDiv;
86
- }
87
-
88
- export function hideExtraUI() {
89
- const { expressMethods } = getPaymentMethods();
90
-
91
- if (state.options?.deposit) {
92
- const linkElement = getElement('deposit-back');
93
- if (linkElement) {
94
- linkElement.style.height = '0px';
95
- linkElement.style.overflow = 'hidden';
96
- }
97
- }
98
-
99
- if (expressMethods.length) {
100
- const expressMethodsElement = getElement('express-methods');
101
- if (expressMethodsElement) {
102
- expressMethodsElement.style.height = '0px';
103
- expressMethodsElement.style.overflow = 'hidden';
104
- }
105
- }
106
-
107
- if (state.options?.bumpOffer?.length) {
108
- const bumpOfferElement = getElement('bump-offer');
109
- if (bumpOfferElement) {
110
- bumpOfferElement.style.height = '0px';
111
- bumpOfferElement.style.overflow = 'hidden';
112
- bumpOfferElement.style.marginBottom = '0px';
113
- }
114
- }
115
- }
30
+ <div data-rebilly-instruments="methods" class="rebilly-instruments-methods"></div>
31
+ </div>
32
+ `;
116
33
 
117
34
  export async function mountMethodSelector() {
118
- const contentEl = getElement('content');
119
- const formEl = getElement('form');
35
+ const { EXPRESS_METHODS, METHODS } = getPaymentMethods();
120
36
 
121
- const { expressMethods, methods } = getPaymentMethods();
122
-
123
- if (state.options?.deposit) {
124
- const existingDepositBackElement = getElement('deposit-back');
125
- if (existingDepositBackElement) {
126
- existingDepositBackElement.style.height = 'auto';
127
- } else {
128
- contentEl.insertBefore(backToAmountElement(), formEl);
129
- }
37
+ const methodSelectorElement = state.form.querySelector('.rebilly-instruments-method-selector');
38
+ if (methodSelectorElement) {
39
+ methodSelectorElement.style.visibility = 'visible';
40
+ methodSelectorElement.style.height = 'auto';
41
+ } else {
42
+ state.form.innerHTML += baseMethodSelectorHTML({
43
+ compactExpressInstruments: state.options.paymentInstruments.compactExpressInstruments && EXPRESS_METHODS.length,
44
+ bumpOffer: state.options.bumpOffer
45
+ });
130
46
  }
131
47
 
132
- if (expressMethods.length) {
133
- const existingExpressMethodElement = getElement('express-methods');
134
- if (existingExpressMethodElement) {
135
- existingExpressMethodElement.style.height = 'auto';
136
- } else {
137
- contentEl.insertBefore(expressMethodsElement({expressMethods}), formEl);
138
- state.options.digitalWallet = generateDigitalWallet({ expressMethods });
139
- const container = document.querySelector('[data-rebilly-instruments="express-methods-container"]');
140
- mountExpressMethods({
141
- methods: expressMethods,
142
- container,
143
- });
144
- }
145
- }
48
+ const BUMPOFFER_CONTAINER = document.querySelector('[data-rebilly-instruments="bump-offer"]');
49
+ const METHODS_CONTAINER = document.querySelector('[data-rebilly-instruments="methods"]');
50
+ const EXPRESS_METHODS_CONTAINER = document.querySelector('.rebilly-instruments-express-methods-container');
146
51
 
147
- if (state.options?.bumpOffer?.length) {
148
- const existingExpressMethodElement = getElement('bump-offer');
149
- if (existingExpressMethodElement) {
150
- existingExpressMethodElement.style.height = 'auto';
151
- existingExpressMethodElement.style.marginBottom = 'calc(var(--rebilly-spacingM) + var(--rebilly-fontSizeS))';
152
- } else {
153
- contentEl.insertBefore(bumpOfferElement(), formEl);
154
- const container = getElement('bump-offer');
155
- mountBumpOffer({
156
- container,
52
+ if(EXPRESS_METHODS.length) {
53
+ if (!methodSelectorElement) {
54
+ state.options.digitalWallet = generateDigitalWallet({ EXPRESS_METHODS });
55
+ mountExpressMethods({
56
+ methods: EXPRESS_METHODS,
57
+ container: EXPRESS_METHODS_CONTAINER,
157
58
  });
158
59
  }
60
+ } else {
61
+ EXPRESS_METHODS_CONTAINER.style.display = 'none';
62
+ document.querySelectorAll('[data-rebilly-instruments="divider"]')
63
+ .forEach(el => { el.style.display = 'none' });
159
64
  }
160
65
 
161
- if (methods.length) {
162
- const iframe = iframes.form;
163
- if (!iframe) {
164
- await mountForm();
165
- }
166
-
66
+ if (METHODS.length) {
167
67
  const modelSafeState = state.toModel();
168
68
  const model = {
169
69
  options: modelSafeState.options,
170
70
  data: modelSafeState.data,
171
71
  mainStyleVars: modelSafeState.mainStyleVars,
172
72
  };
73
+ const { paymentMethodsUrl } = state.options?._computed;
74
+
75
+ const name = 'rebilly-instruments-form';
76
+ const iframe = await new ViewIframe({
77
+ name,
78
+ url: `${paymentMethodsUrl}`,
79
+ container: METHODS_CONTAINER,
80
+ model
81
+ });
82
+ iframe.bindEventListeners({loader: state.loader});
173
83
 
174
- iframe?.component?.call('route', {
175
- name: 'method-switch'
84
+ iframe.component.on(`${name}-confirm-purchase`, (confirmedInstrument) => {
85
+ purchase({ payload: confirmedInstrument });
176
86
  });
177
87
 
178
- iframe?.component?.call('update', model);
88
+ iframe.component.on(`${name}-confirm-setup`, (confirmedInstrument) => {
89
+ setup({ payload: confirmedInstrument });
90
+ });
179
91
 
180
- iframe?.component?.on('choose-another-method', () => {
92
+ iframe.component.on('choose-another-method', () => {
93
+ document.querySelectorAll('[data-rebilly-instruments="express-method"]')
94
+ .forEach(el => {
95
+ el.style.height = 'auto';
96
+ });
97
+ document.querySelectorAll('[data-rebilly-instruments="bump-offer"]')
98
+ .forEach(el => {
99
+ el.style.height = 'auto';
100
+ el.style.marginBottom = 'calc(var(--rebilly-spacingM) + var(--rebilly-fontSizeS))';
101
+ });
102
+
103
+ iframe.component.call('route', {
104
+ name: 'method-switch'
105
+ });
106
+
181
107
  if (state.data.isPurchase) {
182
108
  updateSummary();
183
109
  }
184
- mountMethodSelector();
110
+
111
+ iframe.component.call('update', model);
185
112
  });
186
113
 
114
+ iframes.form = iframe;
187
115
  } else {
188
116
  state.loader.stopLoading({id: 'rebilly-instruments-form'});
189
- state.form.querySelector('[data-rebilly-instruments="form"]').style.display = 'none';
190
- document.querySelectorAll('[data-rebilly-instruments="divider"]').forEach(el => { el.style.display = 'none' });
117
+ METHODS_CONTAINER.style.display = 'none';
118
+ document.querySelectorAll('[data-rebilly-instruments="divider"]')
119
+ .forEach(el => { el.style.display = 'none' });
191
120
  }
192
121
 
193
- state.translate.translateItems();
122
+ if (state.options.bumpOffer.length) {
123
+ mountBumpOffer({
124
+ container: BUMPOFFER_CONTAINER,
125
+ });
126
+ } else if (BUMPOFFER_CONTAINER?.style) {
127
+ BUMPOFFER_CONTAINER.style.display = 'none';
128
+ }
194
129
  }
195
130
 
196
131
  export async function updateMethodSelector() {
@@ -11,7 +11,7 @@ describe('Methods Selector Component', () => {
11
11
  expect(form).toMatchSnapshot();
12
12
  });
13
13
 
14
- it ('should allow updating method selector', async () => {
14
+ it.only ('should allow updating method selector', async () => {
15
15
  await RenderMockRebillyInstruments();
16
16
  await updateMethodSelector({
17
17
  mainStyleVars: 'any main style'
@@ -1,13 +1,17 @@
1
+ import { ViewIframe } from './common/iframe';
2
+ import { replaceContent } from './common/render-utilities';
1
3
  import state from '../state';
2
4
  import iframes from '../state/iframes';
3
- import { mountForm } from './form';
4
5
 
5
6
  export async function mountResult({ payload }) {
6
- const iframe = iframes.form;
7
+ const resultContainerClassName = 'rebilly-instruments-result';
8
+ replaceContent(state.form, `<div class="${resultContainerClassName}"></div>`);
7
9
 
8
- if(!iframe) {
9
- await mountForm();
10
- }
10
+ state.loader.startLoading({ id: 'rebilly-instruments-result' });
11
+ state.loader.stopLoading({ id: 'express-purchase' });
12
+
13
+ const container = document.querySelector(`.${resultContainerClassName}`);
14
+ const { paymentMethodsUrl } = state.options._computed;
11
15
 
12
16
  const modelSafeState = state.toModel();
13
17
  const model = {
@@ -16,9 +20,15 @@ export async function mountResult({ payload }) {
16
20
  [state.options.transactionType]: payload
17
21
  };
18
22
 
19
- iframe?.component?.call('route', {
20
- name: 'result'
23
+ const iframe = await new ViewIframe({
24
+ name: 'rebilly-instruments-result',
25
+ url: `${paymentMethodsUrl}/result`,
26
+ container,
27
+ model
28
+ });
29
+ iframe.bindEventListeners({
30
+ loader: state.loader
21
31
  });
22
32
 
23
- iframe?.component?.call('update', model);
33
+ iframes.form = iframe;
24
34
  }
@@ -13,23 +13,15 @@ export async function mountSummary() {
13
13
  };
14
14
  const { paymentMethodsUrl } = state.options?._computed;
15
15
 
16
- const name = 'rebilly-instruments-summary'
17
16
  const iframe = await new ViewIframe({
18
- name,
19
- url: `${paymentMethodsUrl}?name=${name}`,
17
+ name: 'rebilly-instruments-summary',
18
+ url: `${paymentMethodsUrl}/summary`,
20
19
  container: state.summary,
21
- model,
22
- route: {
23
- name: 'summary'
24
- }
20
+ model
25
21
  });
26
22
  iframe.bindEventListeners({ loader: state.loader });
27
23
  iframes.summary = iframe;
28
24
  itemsUpdatedHandler(iframe);
29
-
30
- return {
31
- then: (callback) => callback()
32
- }
33
25
  }
34
26
 
35
27
  export async function updateSummary({ instrument } = {}) {
@@ -1,12 +0,0 @@
1
- import { Endpoint } from './index';
2
- import state from '../state';
3
- import DepositRequestModel from './models/deposit-request-model';
4
-
5
- export async function fetchDepositRequest({data = null}) {
6
- return Endpoint(async () => {
7
- state.storefront.setSessionToken(state.options.jwt);
8
- const {fields} = await state.storefront.cashierRequests.get(data);
9
-
10
- return new DepositRequestModel(fields);
11
- });
12
- }
@@ -1,15 +0,0 @@
1
- import BaseModel from './base-model';
2
- import merge from 'lodash.merge';
3
- export default class DepositRequestModel extends BaseModel {
4
- constructor(fields) {
5
- super(fields);
6
- this.amount = Array.isArray(fields.amount) ? fields.amount[0] : fields.amount;
7
- this.buttons = fields.buttons ?? [...fields.amounts];
8
- this.editable = typeof fields.editable === "boolean" ? fields.editable : Boolean(fields.customAmount);
9
- this.customAmount = merge({
10
- minimum: 1,
11
- maximum: 1000000000000,
12
- multipleOf: 1,
13
- }, (fields.customAmount || {}));
14
- }
15
- }
@@ -1,47 +0,0 @@
1
- import state from '../state';
2
- import iframes from '../state/iframes';
3
- import { mountMethodSelector } from './method-selector';
4
- import { fetchReadyToPay } from '../storefront/ready-to-pay';
5
-
6
- export async function mountAmountSelector() {
7
- if (state.data.money) {
8
- state.data.money.amount = null;
9
- state.data.money.currency = null;
10
- state.updateModel();
11
- }
12
-
13
- const iframe = iframes.form;
14
- if (!iframe) {
15
- await mountForm();
16
- }
17
-
18
- const modelSafeState = state.toModel();
19
- const model = {
20
- options: modelSafeState.options,
21
- data: modelSafeState.data,
22
- mainStyleVars: modelSafeState.mainStyleVars,
23
- };
24
-
25
- iframe.component?.call('route', {
26
- name: 'amount-selector'
27
- });
28
-
29
- iframe.component?.call('update', model);
30
-
31
- iframe?.component?.on('confirm-amount', async (data) => {
32
- const { amount, currency } = data;
33
- state.data.money = {
34
- amount,
35
- currency,
36
- };
37
-
38
- const readyToPayUpdated = await fetchReadyToPay({
39
- riskMetadata: state.data.riskMetadata
40
- });
41
-
42
- state.data.readyToPay = readyToPayUpdated;
43
-
44
- state.updateModel();
45
- mountMethodSelector();
46
- });
47
- }
package/src/views/form.js DELETED
@@ -1,52 +0,0 @@
1
- import state from '../state';
2
- import iframes from '../state/iframes';
3
- import { ViewIframe } from './common/iframe';
4
- import { mountMethodSelector } from './method-selector';
5
- import { mountAmountSelector } from './amount-selector';
6
-
7
- export const baseMethodSelectorHTML = () => `
8
- <div data-rebilly-instruments="content" class="rebilly-instruments-content">
9
- <div data-rebilly-instruments="content-error" id="rebilly-instruments-error"></div>
10
- <div data-rebilly-instruments="form"></div>
11
- </div>
12
- `;
13
-
14
- export async function mountForm() {
15
- state.form.innerHTML += baseMethodSelectorHTML();
16
- const container = document.querySelector('[data-rebilly-instruments="form"]');
17
- const { paymentMethodsUrl: url } = state.options?._computed;
18
- const name = 'rebilly-instruments-form';
19
-
20
- const modelSafeState = state.toModel();
21
- const model = {
22
- options: modelSafeState.options,
23
- data: modelSafeState.data,
24
- mainStyleVars: modelSafeState.mainStyleVars,
25
- };
26
-
27
- const args = {
28
- name,
29
- url: `${url}?name=${name}`,
30
- container,
31
- model,
32
- };
33
-
34
- const iframe = await new ViewIframe(args);
35
- iframe.bindEventListeners({loader: state.loader});
36
-
37
- iframes.form = iframe;
38
-
39
- state.loader.stopLoading({id: 'rebilly-instruments-form'});
40
-
41
- return {
42
- then: (callback) => callback()
43
- }
44
- }
45
-
46
- export function determineFirstView() {
47
- if (state.options?.deposit) {
48
- mountAmountSelector();
49
- } else {
50
- mountMethodSelector();
51
- }
52
- }