@rebilly/instruments 3.13.2-beta.0 → 3.13.4-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.
- package/README.md +1 -1
- package/dist/index.js +66 -43
- package/dist/index.min.js +66 -43
- package/package.json +6 -3
- package/src/functions/destroy.js +2 -8
- package/src/functions/mount/fetch-data.js +2 -9
- package/src/functions/mount/index.js +10 -15
- package/src/functions/mount/mount.spec.js +11 -10
- package/src/functions/mount/setup-framepay-theme.js +72 -30
- package/src/functions/mount/setup-options.js +2 -2
- package/src/functions/mount/{setup-styles-vars.js → setup-styles.js} +7 -9
- package/src/functions/purchase.js +5 -2
- package/src/functions/setup.js +6 -3
- package/src/functions/show.js +2 -2
- package/src/functions/show.spec.js +4 -4
- package/src/functions/update.spec.js +3 -4
- package/src/instance.js +1 -4
- package/src/loader/index.js +33 -57
- package/src/storefront/index.js +5 -2
- package/src/storefront/payment-instruments.js +0 -7
- package/src/style/base/__snapshots__/theme.spec.js.snap +220 -136
- package/src/style/base/default-theme.js +14 -187
- package/src/style/base/index.js +79 -487
- package/src/style/base/theme.js +4 -3
- package/src/style/base/theme.spec.js +3 -2
- package/src/style/browserslist.js +1 -0
- package/src/style/components/accordion.js +140 -0
- package/src/style/components/address.js +55 -0
- package/src/style/components/button.js +117 -0
- package/src/style/components/divider.js +39 -0
- package/src/style/components/forms/checkbox.js +75 -0
- package/src/style/components/forms/field.js +56 -0
- package/src/style/components/forms/form.js +18 -0
- package/src/style/components/forms/input.js +77 -0
- package/src/style/components/forms/label.js +55 -0
- package/src/style/components/forms/radio.js +80 -0
- package/src/style/components/forms/select.js +86 -0
- package/src/style/components/forms/validation.js +72 -0
- package/src/style/components/icons.js +13 -0
- package/src/style/components/index.js +39 -0
- package/src/style/components/loader.js +41 -0
- package/src/style/components/methods.js +97 -0
- package/src/style/components/overlay.js +24 -0
- package/src/style/helpers/index.js +54 -0
- package/src/style/index.js +24 -4
- package/src/style/payment-instruments/content.js +8 -0
- package/src/style/payment-instruments/index.js +14 -0
- package/src/style/payment-instruments/payment-card.js +27 -0
- package/src/style/payment-instruments/payment-instrument-list.js +44 -0
- package/src/style/payment-instruments/payment-instrument.js +55 -0
- package/src/style/utils/color-values.js +1 -1
- package/src/style/utils/remove-empty-null.js +10 -0
- package/src/style/vendor/framepay.js +28 -0
- package/src/style/vendor/postmate.js +18 -0
- package/src/style/views/confirmation.js +26 -0
- package/src/style/views/index.js +16 -0
- package/src/style/views/method-selector.js +11 -0
- package/src/style/views/modal.js +91 -0
- package/src/style/views/result.js +52 -0
- package/src/style/views/summary.js +118 -0
- package/src/views/__snapshots__/summary.spec.js.snap +246 -0
- package/src/views/common/iframe/base-iframe.js +2 -3
- package/src/views/common/iframe/event-listeners.js +9 -12
- package/src/views/common/iframe/method-iframe.js +1 -3
- package/src/views/common/iframe/modal-iframe.js +2 -4
- package/src/views/common/iframe/view-iframe.js +1 -3
- package/src/views/confirmation.js +7 -12
- package/src/views/method-selector/express-methods/apple-pay.js +92 -0
- package/src/views/method-selector/express-methods/index.js +25 -0
- package/src/views/method-selector/get-payment-methods.js +1 -0
- package/src/views/method-selector/index.js +58 -45
- package/src/views/method-selector/method-selector.spec.js +1 -1
- package/src/views/method-selector/mount-express-methods.js +26 -66
- package/src/views/method-selector/mount-methods.js +178 -0
- package/src/views/modal.js +1 -1
- package/src/views/result.js +3 -3
- package/src/views/summary.js +190 -24
- package/src/views/summary.spec.js +145 -0
- package/tests/mocks/storefront-api-mock.js +27 -48
- package/src/style/utils/minifyCss.js +0 -14
- package/src/views/errors.js +0 -95
- package/src/views/method-selector/express-methods.js +0 -51
- package/src/views/method-selector/generate-framepay-config.js +0 -54
- package/src/views/method-selector/generate-framepay-config.spec.js +0 -195
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rebilly/instruments",
|
|
3
|
-
"version": "3.13.
|
|
3
|
+
"version": "3.13.4-beta.0",
|
|
4
4
|
"author": "Rebilly",
|
|
5
|
-
"license": "MIT",
|
|
6
5
|
"main": "dist/index.js",
|
|
7
6
|
"unpkg": "dist/index.min.js",
|
|
7
|
+
"license": "MIT",
|
|
8
8
|
"scripts": {
|
|
9
9
|
"build": "yarn rollup -c --environment NODE_ENV:production",
|
|
10
10
|
"dev": "yarn rollup -c --watch --environment NODE_ENV:development",
|
|
@@ -16,13 +16,16 @@
|
|
|
16
16
|
"@babel/core": "^7.14.6",
|
|
17
17
|
"@babel/preset-env": "^7.14.7",
|
|
18
18
|
"@rebilly/risk-data-collector": "^2.3.0",
|
|
19
|
+
"autoprefixer": "^10.3.4",
|
|
20
|
+
"css": "^3.0.0",
|
|
19
21
|
"jwt-decode": "^3.1.2",
|
|
20
22
|
"lodash.camelcase": "^4.3.0",
|
|
21
23
|
"lodash.isequal": "^4.5.0",
|
|
22
24
|
"lodash.kebabcase": "^4.1.1",
|
|
23
25
|
"lodash.merge": "^4.6.2",
|
|
24
26
|
"popostmate": "^1.6.4",
|
|
25
|
-
"
|
|
27
|
+
"postcss": "^8.4.5",
|
|
28
|
+
"rebilly-js-sdk": "^44.4.0",
|
|
26
29
|
"values.js": "^2.0.0"
|
|
27
30
|
},
|
|
28
31
|
"devDependencies": {
|
package/src/functions/destroy.js
CHANGED
|
@@ -6,19 +6,13 @@ export async function destroy({ state }) {
|
|
|
6
6
|
// wait to allow for cancellation to catch any pending api requests
|
|
7
7
|
const sleepMilliseconds = 1000;
|
|
8
8
|
await sleep(sleepMilliseconds);
|
|
9
|
-
[
|
|
10
|
-
...(state.iframeComponents?.form || []),
|
|
11
|
-
...(state.iframeComponents?.summary || [])
|
|
12
|
-
].forEach((iframe) => {
|
|
9
|
+
[...(state.iframeComponents || {})].forEach((iframe) => {
|
|
13
10
|
iframe.destroy();
|
|
14
11
|
});
|
|
15
12
|
|
|
16
13
|
registeredListeners.removeAll(document);
|
|
17
14
|
|
|
18
|
-
state.iframeComponents =
|
|
19
|
-
summary: [],
|
|
20
|
-
form: [],
|
|
21
|
-
};
|
|
15
|
+
state.iframeComponents = [];
|
|
22
16
|
state.hasMounted = false;
|
|
23
17
|
|
|
24
18
|
state.summary.textContent = '';
|
|
@@ -6,7 +6,6 @@ import { fetchSummary } from '../../storefront/summary';
|
|
|
6
6
|
import { fetchInvoice as FetchInvoice } from '../../storefront/invoices';
|
|
7
7
|
import { fetchTransaction as FetchTransaction } from '../../storefront/transactions';
|
|
8
8
|
import { fetchAccount as FetchAccount } from '../../storefront/account';
|
|
9
|
-
import { fetchPaymentInstrument as FetchInstruments } from '../../storefront/payment-instruments';
|
|
10
9
|
|
|
11
10
|
export class DataInstance {
|
|
12
11
|
constructor({
|
|
@@ -109,13 +108,11 @@ export async function fetchData({
|
|
|
109
108
|
// Dependency injectable functions
|
|
110
109
|
fetchInvoice = FetchInvoice,
|
|
111
110
|
fetchTransaction = FetchTransaction,
|
|
112
|
-
fetchAccount = FetchAccount
|
|
113
|
-
fetchInstruments = FetchInstruments
|
|
111
|
+
fetchAccount = FetchAccount
|
|
114
112
|
}) {
|
|
115
113
|
try {
|
|
116
114
|
let transaction = null;
|
|
117
115
|
let account = null;
|
|
118
|
-
let availableInstruments = null;
|
|
119
116
|
if (state.options?.transactionId) {
|
|
120
117
|
transaction = await fetchTransaction({data: {
|
|
121
118
|
id: state.options.transactionId
|
|
@@ -137,10 +134,7 @@ export async function fetchData({
|
|
|
137
134
|
}
|
|
138
135
|
|
|
139
136
|
if (state.options?.jwt) {
|
|
140
|
-
|
|
141
|
-
fetchAccount({state}),
|
|
142
|
-
fetchInstruments({state})
|
|
143
|
-
]);
|
|
137
|
+
account = await fetchAccount({state});
|
|
144
138
|
}
|
|
145
139
|
|
|
146
140
|
state.data = new DataInstance({
|
|
@@ -149,7 +143,6 @@ export async function fetchData({
|
|
|
149
143
|
transaction,
|
|
150
144
|
riskMetadata,
|
|
151
145
|
account,
|
|
152
|
-
availableInstruments,
|
|
153
146
|
});
|
|
154
147
|
|
|
155
148
|
const [readyToPay, previewPurchase] = await Promise.all([
|
|
@@ -7,11 +7,10 @@ import setupElement from './setup-element';
|
|
|
7
7
|
import setupStorefront from './setup-storefront';
|
|
8
8
|
import setupOptions from './setup-options';
|
|
9
9
|
import setupFramepayInstance from './setup-framepay';
|
|
10
|
-
import
|
|
10
|
+
import setupStyles from './setup-styles';
|
|
11
11
|
import setupI18n from './setup-i18n';
|
|
12
12
|
import setupFramepayTheme from './setup-framepay-theme';
|
|
13
13
|
import setupUserFlow from './setup-user-flow';
|
|
14
|
-
import { showError } from '../../views/errors';
|
|
15
14
|
|
|
16
15
|
/**
|
|
17
16
|
* @typedef {object} Item
|
|
@@ -88,26 +87,23 @@ export async function mount({
|
|
|
88
87
|
// Setup DOM
|
|
89
88
|
state.form = setupElement({ element: 'form', options });
|
|
90
89
|
state.summary = setupElement({ element: 'summary', options });
|
|
91
|
-
// hardcode max-width to not break UX
|
|
92
|
-
// PayPal button cannot exceed 750px;
|
|
93
|
-
state.form.style.maxWidth = '750px';
|
|
94
|
-
state.summary.style.maxWidth = '750px';
|
|
95
|
-
|
|
96
|
-
// Setup state
|
|
97
|
-
state.options = setupOptions({ options });
|
|
98
|
-
state.storefront = setupStorefront({ options });
|
|
99
|
-
state.mainStyleVars = setupStylesVars({ options });
|
|
100
|
-
state.options.themeFramepay = setupFramepayTheme({ state, options });
|
|
101
90
|
|
|
102
91
|
// Setup loader
|
|
103
92
|
state.loader.addDOMElement({ el: state.form });
|
|
104
93
|
state.loader.addDOMElement({ section: 'summary', el: state.summary });
|
|
105
|
-
state.loader.startLoading({
|
|
106
|
-
state.loader.startLoading({
|
|
94
|
+
state.loader.startLoading({ section: 'summary', id: 'initSummary' });
|
|
95
|
+
state.loader.startLoading({ id: 'initForm' });
|
|
107
96
|
|
|
97
|
+
// Setup state
|
|
98
|
+
state.options = setupOptions({ options });
|
|
99
|
+
state.storefront = setupStorefront({ options });
|
|
100
|
+
|
|
101
|
+
state.mainStyle = await setupStyles({ options });
|
|
102
|
+
|
|
108
103
|
state.data = await fetchData({ state });
|
|
109
104
|
Events.dataReady.dispatch(state.data);
|
|
110
105
|
|
|
106
|
+
state.options.themeFramepay = await setupFramepayTheme({ state, options });
|
|
111
107
|
state.i18n = setupI18n({ state });
|
|
112
108
|
|
|
113
109
|
await setupFramepay(state);
|
|
@@ -132,7 +128,6 @@ export async function mount({
|
|
|
132
128
|
state.i18n({state});
|
|
133
129
|
state.hasMounted = true;
|
|
134
130
|
} catch (error) {
|
|
135
|
-
showError(error);
|
|
136
131
|
throw error;
|
|
137
132
|
}
|
|
138
133
|
|
|
@@ -29,22 +29,23 @@ describe('RebillyInstruments instance', () => {
|
|
|
29
29
|
};
|
|
30
30
|
await RenderMockRebillyInstruments(options);
|
|
31
31
|
|
|
32
|
-
await new Promise((resolve) => {
|
|
33
|
-
setTimeout(() => {
|
|
34
|
-
resolve();
|
|
35
|
-
}, 100);
|
|
36
|
-
})
|
|
37
|
-
|
|
38
32
|
// Mounts form and summary
|
|
39
33
|
const summarySelector = document.querySelector('.summary-selector');
|
|
40
|
-
expect(summarySelector.innerHTML).
|
|
34
|
+
expect(summarySelector.innerHTML).toMatch('My Product');
|
|
41
35
|
|
|
42
36
|
// Theme config overrides initial styles
|
|
43
|
-
const
|
|
37
|
+
const SUMMARY_CONTAINER = summarySelector.querySelector(
|
|
38
|
+
'.rebilly-instruments-content'
|
|
39
|
+
);
|
|
40
|
+
expect(getComputedStyle(SUMMARY_CONTAINER).getPropertyValue('--rebilly-colorBackground')).toEqual(
|
|
41
|
+
'#000'
|
|
42
|
+
);
|
|
44
43
|
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
// CSS config property overrides initial styles
|
|
45
|
+
const LINE_ITEM_TITLE = document.querySelector(
|
|
46
|
+
'.rebilly-instruments-summary-line-item-synopsis-title'
|
|
47
47
|
);
|
|
48
|
+
expect(getComputedStyle(LINE_ITEM_TITLE).color).toEqual('rgb(0, 68, 212)');
|
|
48
49
|
|
|
49
50
|
// Mounts default FramePay script
|
|
50
51
|
const SCRIPTS = [...document.querySelectorAll('head script')];
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import css from 'css';
|
|
2
|
+
import camelCase from 'lodash.camelcase';
|
|
3
|
+
|
|
1
4
|
function processCSS(rawCss) {
|
|
2
5
|
const cssMap = {};
|
|
3
6
|
[...rawCss.matchAll(/(--rebilly.*(?=:))[:\s](.*(?=;))/g)]
|
|
@@ -23,62 +26,101 @@ function processCSS(rawCss) {
|
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
function replaceCssVars(rawCss) {
|
|
26
|
-
const CssVarsObj = {}
|
|
27
29
|
processCSS(rawCss).forEach(([key, value]) => {
|
|
28
|
-
|
|
30
|
+
rawCss = rawCss.split(`var(${key})`).join(value);
|
|
29
31
|
});
|
|
30
|
-
|
|
32
|
+
|
|
33
|
+
return rawCss;
|
|
31
34
|
}
|
|
32
35
|
|
|
33
|
-
const getStyleProps = (
|
|
36
|
+
const getStyleProps = (ast, selector) => {
|
|
37
|
+
const { rules } = ast.stylesheet;
|
|
34
38
|
const output = {
|
|
35
|
-
color:
|
|
36
|
-
fontFamily:
|
|
37
|
-
fontSize:
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
background:
|
|
41
|
-
|
|
39
|
+
color: null,
|
|
40
|
+
fontFamily: null,
|
|
41
|
+
fontSize: null,
|
|
42
|
+
lineHeight: null,
|
|
43
|
+
fontWeight: null,
|
|
44
|
+
background: null
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
for(let i = 0; i < rules.length; i += 1) {
|
|
48
|
+
const rule = rules[i];
|
|
49
|
+
|
|
50
|
+
if(rule.type === 'rule' && rule.selectors.includes(selector)) {
|
|
51
|
+
rule.declarations.forEach(decl => {
|
|
52
|
+
const propName = camelCase(decl.property);
|
|
53
|
+
if(typeof output[propName] !== 'undefined') {
|
|
54
|
+
output[propName] = decl.value;
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
}
|
|
42
58
|
}
|
|
43
59
|
return output;
|
|
44
60
|
}
|
|
45
61
|
|
|
46
|
-
export default ({
|
|
62
|
+
export default async ({
|
|
47
63
|
state,
|
|
48
64
|
options = {}
|
|
49
65
|
}) => {
|
|
50
66
|
const fullCss = `
|
|
51
|
-
${state.
|
|
67
|
+
${state.mainStyle}
|
|
52
68
|
${options.css || ''}
|
|
53
69
|
`;
|
|
54
70
|
|
|
55
|
-
const
|
|
71
|
+
const resolvedCss = replaceCssVars(fullCss);
|
|
72
|
+
const cssAst = css.parse(resolvedCss);
|
|
73
|
+
|
|
74
|
+
const cssSelectors = {
|
|
75
|
+
input: {
|
|
76
|
+
base: '.rebilly-instruments-form-field-input',
|
|
77
|
+
baseHover: '.rebilly-instruments-form-field-input:hover',
|
|
78
|
+
baseFocus: '.rebilly-instruments-form-field-input:focus',
|
|
79
|
+
basePlaceholder: '.rebilly-instruments-form-field-input::placeholder',
|
|
80
|
+
baseSelection: '.rebilly-instruments-form-field-input::selection',
|
|
81
|
+
|
|
82
|
+
invalid: '.rebilly-instruments-form-field.is-error .rebilly-instruments-form-field-input',
|
|
83
|
+
invalidHover: '.rebilly-instruments-form-field.is-error .rebilly-instruments-form-field-input:hover',
|
|
84
|
+
invalidFocus: '.rebilly-instruments-form-field.is-error .rebilly-instruments-form-field-input:focus',
|
|
85
|
+
invalidPlaceholder: '.rebilly-instruments-form-field.is-error .rebilly-instruments-form-field-input::placeholder',
|
|
86
|
+
invalidSelection: '.rebilly-instruments-form-field.is-error .rebilly-instruments-form-field-input::selection'
|
|
87
|
+
},
|
|
88
|
+
button: {
|
|
89
|
+
base: '.rebilly-instruments-button.rebilly-instruments-button-secondary',
|
|
90
|
+
baseHover: '.rebilly-instruments-button.rebilly-instruments-button-secondary:not([disabled]):hover',
|
|
91
|
+
baseFocus: '.rebilly-instruments-button.rebilly-instruments-button-secondary:not([disabled]):active',
|
|
92
|
+
|
|
93
|
+
active: '.rebilly-instruments-button',
|
|
94
|
+
activeHover: '.rebilly-instruments-button:not([disabled]):hover',
|
|
95
|
+
activeFocus: '.rebilly-instruments-button:not([disabled]):active',
|
|
96
|
+
}
|
|
97
|
+
}
|
|
56
98
|
|
|
57
99
|
const framepayStyle = {
|
|
58
100
|
base: {
|
|
59
|
-
...getStyleProps(
|
|
60
|
-
':hover': getStyleProps(
|
|
61
|
-
':focus': getStyleProps(
|
|
62
|
-
'::placeholder': getStyleProps(
|
|
63
|
-
'::selection': getStyleProps(
|
|
101
|
+
...getStyleProps(cssAst, cssSelectors.input.base),
|
|
102
|
+
':hover': getStyleProps(cssAst, cssSelectors.input.baseHover),
|
|
103
|
+
':focus': getStyleProps(cssAst, cssSelectors.input.baseFocus),
|
|
104
|
+
'::placeholder': getStyleProps(cssAst, cssSelectors.input.basePlaceholder),
|
|
105
|
+
'::selection': getStyleProps(cssAst, cssSelectors.input.baseSelection),
|
|
64
106
|
},
|
|
65
107
|
invalid: {
|
|
66
|
-
...getStyleProps(
|
|
67
|
-
':hover': getStyleProps(
|
|
68
|
-
':focus': getStyleProps(
|
|
69
|
-
'::placeholder': getStyleProps(
|
|
70
|
-
'::selection': getStyleProps(
|
|
108
|
+
...getStyleProps(cssAst, cssSelectors.input.invalid),
|
|
109
|
+
':hover': getStyleProps(cssAst, cssSelectors.input.invalidHover),
|
|
110
|
+
':focus': getStyleProps(cssAst, cssSelectors.input.invalidFocus),
|
|
111
|
+
'::placeholder': getStyleProps(cssAst, cssSelectors.input.invalidPlaceholder),
|
|
112
|
+
'::selection': getStyleProps(cssAst, cssSelectors.input.invalidSelection),
|
|
71
113
|
},
|
|
72
114
|
buttons: {
|
|
73
115
|
base: {
|
|
74
|
-
...getStyleProps(
|
|
75
|
-
':hover': getStyleProps(
|
|
76
|
-
':focus': getStyleProps(
|
|
116
|
+
...getStyleProps(cssAst, cssSelectors.button.base),
|
|
117
|
+
':hover': getStyleProps(cssAst, cssSelectors.button.baseHover),
|
|
118
|
+
':focus': getStyleProps(cssAst, cssSelectors.button.baseFocus),
|
|
77
119
|
},
|
|
78
120
|
active: {
|
|
79
|
-
...getStyleProps(
|
|
80
|
-
':hover': getStyleProps(
|
|
81
|
-
':focus': getStyleProps(
|
|
121
|
+
...getStyleProps(cssAst, cssSelectors.button.active),
|
|
122
|
+
':hover': getStyleProps(cssAst, cssSelectors.button.activeHover),
|
|
123
|
+
':focus': getStyleProps(cssAst, cssSelectors.button.activeFocus),
|
|
82
124
|
}
|
|
83
125
|
}
|
|
84
126
|
}
|
|
@@ -5,7 +5,7 @@ export const defaults = {
|
|
|
5
5
|
countryCode: 'US',
|
|
6
6
|
locale: 'auto',
|
|
7
7
|
theme: {
|
|
8
|
-
labels: '
|
|
8
|
+
labels: 'floating'
|
|
9
9
|
},
|
|
10
10
|
paymentInstruments: {
|
|
11
11
|
address: {
|
|
@@ -15,7 +15,7 @@ export const defaults = {
|
|
|
15
15
|
show: [],
|
|
16
16
|
require: []
|
|
17
17
|
},
|
|
18
|
-
compactExpressInstruments:
|
|
18
|
+
compactExpressInstruments: true,
|
|
19
19
|
googlePay: {
|
|
20
20
|
displayOptions: {
|
|
21
21
|
buttonColor: 'black',
|
|
@@ -1,20 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mainStyle } from '../../style';
|
|
2
2
|
import { addDOMElement } from '../../utils';
|
|
3
|
-
import { minifyCss } from '../../style/utils/minifyCss';
|
|
4
3
|
|
|
5
|
-
export default ({
|
|
4
|
+
export default async ({
|
|
6
5
|
options: {
|
|
7
6
|
theme = {},
|
|
8
7
|
css,
|
|
9
8
|
}
|
|
10
9
|
} = {}) => {
|
|
11
|
-
// Adds base
|
|
12
|
-
const
|
|
13
|
-
|
|
10
|
+
// Adds base stylesheet
|
|
11
|
+
const style = await mainStyle(theme || {});
|
|
14
12
|
addDOMElement({
|
|
15
13
|
element: 'style',
|
|
16
14
|
attributes: { type: 'text/css' },
|
|
17
|
-
content:
|
|
15
|
+
content: style,
|
|
18
16
|
target: 'head'
|
|
19
17
|
});
|
|
20
18
|
|
|
@@ -23,10 +21,10 @@ export default ({
|
|
|
23
21
|
addDOMElement({
|
|
24
22
|
element: 'style',
|
|
25
23
|
attributes: { type: 'text/css' },
|
|
26
|
-
content:
|
|
24
|
+
content: css,
|
|
27
25
|
target: 'head'
|
|
28
26
|
});
|
|
29
27
|
}
|
|
30
28
|
|
|
31
|
-
return
|
|
29
|
+
return style;
|
|
32
30
|
}
|
|
@@ -2,7 +2,6 @@ import { postPurchase, postPayment } from '../storefront/purchase';
|
|
|
2
2
|
import Events from '../events';
|
|
3
3
|
import { mountModal } from '../views/modal';
|
|
4
4
|
import { DataInstance } from './mount/fetch-data';
|
|
5
|
-
import { showError } from '../views/errors';
|
|
6
5
|
|
|
7
6
|
export async function makePayment({ state, payload }) {
|
|
8
7
|
const {
|
|
@@ -110,7 +109,11 @@ export async function purchase({ state, payload }) {
|
|
|
110
109
|
}
|
|
111
110
|
return fields;
|
|
112
111
|
} catch (error) {
|
|
113
|
-
|
|
112
|
+
// TODO: Display error to customer
|
|
113
|
+
console.error(error);
|
|
114
|
+
if(error.status === 422) {
|
|
115
|
+
error.details.forEach(e => console.error(e));
|
|
116
|
+
}
|
|
114
117
|
return error;
|
|
115
118
|
}
|
|
116
119
|
}
|
package/src/functions/setup.js
CHANGED
|
@@ -2,8 +2,7 @@ import { setupPaymentInstrument } from '../storefront/payment-instruments';
|
|
|
2
2
|
import Events from '../events';
|
|
3
3
|
import { mountModal } from '../views/modal';
|
|
4
4
|
import { DataInstance } from './mount/fetch-data';
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
|
|
7
6
|
export async function setup({ state, payload }) {
|
|
8
7
|
try {
|
|
9
8
|
const {
|
|
@@ -57,7 +56,11 @@ export async function setup({ state, payload }) {
|
|
|
57
56
|
|
|
58
57
|
return {instrument, transaction};
|
|
59
58
|
} catch (error) {
|
|
60
|
-
|
|
59
|
+
// TODO: Display error to customer
|
|
60
|
+
console.error(error);
|
|
61
|
+
if(error.status === 422) {
|
|
62
|
+
error.details.forEach(e => console.error(e));
|
|
63
|
+
}
|
|
61
64
|
return error;
|
|
62
65
|
}
|
|
63
66
|
}
|
package/src/functions/show.js
CHANGED
|
@@ -16,14 +16,14 @@ import { mountResult } from '../views/result';
|
|
|
16
16
|
export async function show({ componentName, payload, state }) {
|
|
17
17
|
switch (componentName) {
|
|
18
18
|
case 'result':
|
|
19
|
-
state.iframeComponents
|
|
19
|
+
state.iframeComponents = state.iframeComponents.filter((iframe) => {
|
|
20
20
|
iframe.destroy();
|
|
21
21
|
return false;
|
|
22
22
|
});
|
|
23
23
|
mountResult({payload, state});
|
|
24
24
|
break;
|
|
25
25
|
case 'confirmation':
|
|
26
|
-
state.iframeComponents
|
|
26
|
+
state.iframeComponents = state.iframeComponents.filter((iframe) => {
|
|
27
27
|
iframe.destroy();
|
|
28
28
|
return false;
|
|
29
29
|
});
|
|
@@ -12,7 +12,7 @@ describe('RebillyInstruments show', () => {
|
|
|
12
12
|
.mockReturnValue(Promise.resolve());
|
|
13
13
|
|
|
14
14
|
const instance = new RebillyInstrumentsInstance();
|
|
15
|
-
instance.state.iframeComponents.
|
|
15
|
+
instance.state.iframeComponents.push(iframeMock);
|
|
16
16
|
|
|
17
17
|
const payload = {
|
|
18
18
|
test: 'value'
|
|
@@ -22,7 +22,7 @@ describe('RebillyInstruments show', () => {
|
|
|
22
22
|
|
|
23
23
|
expect(mountResult).toBeCalledTimes(1);
|
|
24
24
|
expect(mountResult).toBeCalledWith({payload, state: instance.state});
|
|
25
|
-
expect(instance.state.iframeComponents
|
|
25
|
+
expect(instance.state.iframeComponents).toEqual([]);
|
|
26
26
|
});
|
|
27
27
|
|
|
28
28
|
it('should show confirmation component', async () => {
|
|
@@ -31,7 +31,7 @@ describe('RebillyInstruments show', () => {
|
|
|
31
31
|
.mockReturnValue(Promise.resolve());
|
|
32
32
|
|
|
33
33
|
const instance = new RebillyInstrumentsInstance();
|
|
34
|
-
instance.state.iframeComponents.
|
|
34
|
+
instance.state.iframeComponents.push(iframeMock);
|
|
35
35
|
|
|
36
36
|
const payload = {
|
|
37
37
|
test: 'value'
|
|
@@ -41,7 +41,7 @@ describe('RebillyInstruments show', () => {
|
|
|
41
41
|
|
|
42
42
|
expect(mountConfirmation).toBeCalledTimes(1);
|
|
43
43
|
expect(mountConfirmation).toBeCalledWith({payload, state: instance.state});
|
|
44
|
-
expect(instance.state.iframeComponents
|
|
44
|
+
expect(instance.state.iframeComponents).toEqual([]);
|
|
45
45
|
});
|
|
46
46
|
|
|
47
47
|
it('should fail for non supported component', async () => {
|
|
@@ -31,7 +31,7 @@ describe('RebillyInstruments Update', () => {
|
|
|
31
31
|
call
|
|
32
32
|
}
|
|
33
33
|
};
|
|
34
|
-
rebillyInstruments.state.iframeComponents
|
|
34
|
+
rebillyInstruments.state.iframeComponents = [fakeIFrameComponent];
|
|
35
35
|
|
|
36
36
|
await rebillyInstruments.update({ locale: 'ja' });
|
|
37
37
|
|
|
@@ -58,7 +58,7 @@ describe('RebillyInstruments Update', () => {
|
|
|
58
58
|
call
|
|
59
59
|
}
|
|
60
60
|
};
|
|
61
|
-
rebillyInstruments.state.iframeComponents
|
|
61
|
+
rebillyInstruments.state.iframeComponents = [fakeIFrameComponent];
|
|
62
62
|
|
|
63
63
|
await rebillyInstruments.update({
|
|
64
64
|
countryCode: 'ES'
|
|
@@ -83,8 +83,7 @@ describe('RebillyInstruments Update', () => {
|
|
|
83
83
|
call
|
|
84
84
|
}
|
|
85
85
|
};
|
|
86
|
-
|
|
87
|
-
rebillyInstruments.state.iframeComponents.form = [fakeIFrameComponent];
|
|
86
|
+
rebillyInstruments.iframeComponents = [fakeIFrameComponent];
|
|
88
87
|
|
|
89
88
|
await rebillyInstruments.update({
|
|
90
89
|
items: [
|
package/src/instance.js
CHANGED
|
@@ -18,10 +18,7 @@ export class InstrumentsState {
|
|
|
18
18
|
this.summary = null;
|
|
19
19
|
this.loader = new Loader();
|
|
20
20
|
this.translate = new Translate();
|
|
21
|
-
this.iframeComponents =
|
|
22
|
-
summary: [],
|
|
23
|
-
form: [],
|
|
24
|
-
};
|
|
21
|
+
this.iframeComponents = [];
|
|
25
22
|
this.hasMounted = false;
|
|
26
23
|
}
|
|
27
24
|
}
|
package/src/loader/index.js
CHANGED
|
@@ -1,86 +1,54 @@
|
|
|
1
1
|
import isDOMElement from '../utils/is-dom-element';
|
|
2
2
|
|
|
3
|
-
export const
|
|
4
|
-
<div class="rebilly-instruments-
|
|
5
|
-
<div
|
|
6
|
-
<
|
|
3
|
+
export const loaderHTML = `
|
|
4
|
+
<div class="rebilly-instruments-loader is-active">
|
|
5
|
+
<div class="rebilly-instruments-loader-spinner"></div>
|
|
6
|
+
<span class="rebilly-instuments-loader-message"></span>
|
|
7
7
|
</div>
|
|
8
|
-
`;
|
|
9
|
-
|
|
10
|
-
export const methodsLoaderHTML = `
|
|
11
|
-
<div class="rebilly-instruments-methods-loader">
|
|
12
|
-
<div class="rebilly-instruments-loader-form-el is-el-loading"></div>
|
|
13
|
-
<div class="rebilly-instruments-divider">
|
|
14
|
-
<span class="rebilly-instruments-divider-label"><span class="is-el-loading">Divi</span></span>
|
|
15
|
-
</div>
|
|
16
|
-
<div class="rebilly-instruments-loader-display-flex rebilly-instruments-loader-justify-end">
|
|
17
|
-
<div class="rebilly-instruments-methods-loader-card-icon is-el-loading"></div>
|
|
18
|
-
<div class="rebilly-instruments-methods-loader-card-icon is-el-loading"></div>
|
|
19
|
-
</div>
|
|
20
|
-
<div class="rebilly-instruments-loader-form-el is-el-loading"></div>
|
|
21
|
-
<div class="rebilly-instruments-methods-loader-form-fields">
|
|
22
|
-
<div class="rebilly-instruments-loader-form-label"><small class="is-el-loading">Card holder name</small></div>
|
|
23
|
-
<div class="rebilly-instruments-loader-form-el is-el-loading"></div>
|
|
24
|
-
</div>
|
|
25
|
-
<div class="rebilly-instruments-loader-form-el is-button">Continue</div>
|
|
26
|
-
</div>
|
|
27
|
-
`;
|
|
28
|
-
|
|
29
|
-
const loaderContainer = (padding = '0px') => `
|
|
30
|
-
<div class="rebilly-instruments-loader is-active" style="padding: ${padding}"></div>
|
|
31
8
|
`
|
|
32
9
|
|
|
33
|
-
export const basicLoaderHTML = `
|
|
34
|
-
<div class="rebilly-instruments-loader-spinner"></div>
|
|
35
|
-
`;
|
|
36
|
-
|
|
37
10
|
export class Loader {
|
|
38
11
|
constructor() {
|
|
39
12
|
this.summary = [];
|
|
40
13
|
this.form = [];
|
|
41
14
|
this.modal = [];
|
|
42
15
|
this.DOM = {
|
|
43
|
-
|
|
44
|
-
summaryLoaderHTML,
|
|
45
|
-
methodsLoaderHTML,
|
|
46
|
-
basicLoaderHTML
|
|
16
|
+
loading: loaderHTML
|
|
47
17
|
};
|
|
48
18
|
}
|
|
49
19
|
|
|
50
20
|
addDOMElement({ section = 'form', el = null } = {}) {
|
|
51
21
|
if (isDOMElement(el)) {
|
|
52
22
|
el.style.position = 'relative';
|
|
23
|
+
|
|
53
24
|
this.DOM[section] = el;
|
|
54
25
|
}
|
|
55
26
|
}
|
|
56
27
|
|
|
57
|
-
startLoading({section = 'form', id = ''} = {}) {
|
|
28
|
+
startLoading({state, section = 'form', id = '', message = null } = {}) {
|
|
29
|
+
const minHeight = '200px';
|
|
58
30
|
this[section].push(id);
|
|
59
31
|
|
|
60
|
-
const rootEl = document.querySelector(':root');
|
|
61
|
-
const contentPadding = 2;
|
|
62
|
-
let minHeight = '240px';
|
|
63
|
-
|
|
64
32
|
if (this.DOM?.[section]) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if (!loaderEl) {
|
|
68
|
-
this.DOM[section].innerHTML = loaderContainer(`${parseFloat(padding) + contentPadding}px`);
|
|
69
|
-
loaderEl = this.DOM[section].querySelector('.rebilly-instruments-loader');
|
|
70
|
-
if (section === 'form') {
|
|
71
|
-
loaderEl.insertAdjacentHTML('afterbegin', this.DOM.methodsLoaderHTML);
|
|
72
|
-
minHeight = getComputedStyle(rootEl).getPropertyValue('--rebilly-methodLoaderMinHeight');
|
|
73
|
-
} else if (section === 'summary') {
|
|
74
|
-
loaderEl.insertAdjacentHTML('afterbegin', this.DOM.summaryLoaderHTML);
|
|
75
|
-
minHeight = getComputedStyle(rootEl).getPropertyValue('--rebilly-summaryLoaderMinHeight');
|
|
76
|
-
}
|
|
33
|
+
if (!this.DOM[section].querySelector('.rebilly-instruments-loader')) {
|
|
34
|
+
this.DOM[section].innerHTML = this.DOM.loading;
|
|
77
35
|
} else {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
36
|
+
this.DOM[section]
|
|
37
|
+
.querySelector('.rebilly-instruments-loader')
|
|
38
|
+
.classList.add('is-active');
|
|
39
|
+
}
|
|
40
|
+
this.DOM[section].style.minHeight = minHeight;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (message) {
|
|
44
|
+
const loaderMessage = this.DOM[section].querySelector('.rebilly-instuments-loader-message');
|
|
45
|
+
if (loaderMessage) {
|
|
46
|
+
loaderMessage.innerHTML = message;
|
|
47
|
+
loaderMessage.style.marginTop = '10px';
|
|
48
|
+
loaderMessage.setAttribute('data-message-id', id);
|
|
49
|
+
loaderMessage.setAttribute('data-rebilly-i18n', message);
|
|
50
|
+
state.i18n({state});
|
|
82
51
|
}
|
|
83
|
-
this.DOM[section].style.minHeight = `calc(${minHeight} + ${paddingTop} + ${paddingBottom} + ${contentPadding * 2}px)`;
|
|
84
52
|
}
|
|
85
53
|
}
|
|
86
54
|
|
|
@@ -100,6 +68,14 @@ export class Loader {
|
|
|
100
68
|
.classList.remove('is-active');
|
|
101
69
|
this.DOM[section].style.minHeight = '';
|
|
102
70
|
}
|
|
71
|
+
|
|
72
|
+
const loaderMessage = this.DOM[section].querySelector(`.rebilly-instuments-loader-message[data-message-id="${id}"]`);
|
|
73
|
+
if (loaderMessage) {
|
|
74
|
+
loaderMessage.innerHTML = null;
|
|
75
|
+
loaderMessage.style.marginTop = '0px';
|
|
76
|
+
loaderMessage.removeAttribute('data-message-id');
|
|
77
|
+
loaderMessage.removeAttribute('data-rebilly-i18n');
|
|
78
|
+
}
|
|
103
79
|
}
|
|
104
80
|
|
|
105
81
|
clearAll() {
|