@rebilly/instruments 1.0.2-beta.8 → 2.1.1-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/.babelrc +13 -4
- package/.eslintrc.js +3 -0
- package/.prettierrc.js +11 -0
- package/README.md +15 -314
- package/dist/events/base-event.js +6 -9
- package/dist/events/events.spec.js +4 -4
- package/dist/events/index.js +2 -1
- package/dist/functions/destroy.js +12 -14
- package/dist/functions/destroy.spec.js +3 -3
- package/dist/functions/mount/fetch-data.js +183 -0
- package/dist/functions/mount/fetch-data.spec.js +189 -0
- package/dist/functions/mount/index.js +158 -251
- package/dist/functions/mount/mount.spec.js +24 -121
- package/dist/functions/mount/setup-element.js +40 -0
- package/dist/functions/mount/setup-framepay.js +46 -0
- package/dist/functions/mount/setup-i18n.js +33 -0
- package/dist/functions/mount/setup-options.js +96 -0
- package/dist/functions/mount/setup-options.spec.js +66 -0
- package/dist/functions/mount/setup-storefront.js +34 -0
- package/dist/functions/mount/setup-styles.js +43 -0
- package/dist/functions/on.js +13 -4
- package/dist/functions/on.spec.js +19 -5
- package/dist/functions/purchase.js +139 -22
- package/dist/functions/purchase.spec.js +23 -19
- package/dist/functions/setup.js +85 -0
- package/dist/functions/setup.spec.js +87 -0
- package/dist/functions/show.js +31 -14
- package/dist/functions/show.spec.js +47 -18
- package/dist/functions/update.js +53 -27
- package/dist/functions/update.spec.js +40 -21
- package/dist/i18n/en.json +4 -1
- package/dist/i18n/es.json +4 -1
- package/dist/index.js +67 -56
- package/dist/index.spec.js +7 -27
- package/dist/loader/index.js +4 -3
- package/dist/storefront/index.js +33 -0
- package/dist/storefront/invoices.js +27 -0
- package/dist/storefront/models/base-model.js +18 -0
- package/dist/storefront/models/invoice-model.js +14 -0
- package/dist/storefront/models/plan-model.js +4 -35
- package/dist/storefront/models/product-model.js +4 -23
- package/dist/storefront/models/summary-model.js +12 -25
- package/dist/storefront/models/transaction-model.js +31 -0
- package/dist/storefront/payment-instruments.js +47 -0
- package/dist/storefront/payment-instruments.spec.js +55 -0
- package/dist/storefront/plans.js +15 -24
- package/dist/storefront/plans.spec.js +17 -44
- package/dist/storefront/products.js +16 -20
- package/dist/storefront/products.spec.js +25 -49
- package/dist/storefront/purchase.js +28 -16
- package/dist/storefront/purchase.spec.js +4 -22
- package/dist/storefront/ready-to-pay.js +26 -22
- package/dist/storefront/ready-to-pay.spec.js +25 -54
- package/dist/storefront/storefront.spec.js +1 -1
- package/dist/storefront/summary.js +27 -24
- package/dist/storefront/summary.spec.js +44 -86
- package/dist/storefront/transactions.js +27 -0
- package/dist/style/base/theme.js +3 -3
- package/dist/style/components/methods.js +43 -42
- package/dist/style/utils/color-values.js +1 -3
- package/dist/style/views/confirmation.js +0 -4
- package/dist/style/views/method-selector.js +1 -1
- package/dist/style/views/modal.js +3 -1
- package/dist/style/views/summary.js +5 -1
- package/dist/utils/format-currency.js +4 -2
- package/dist/utils/has-valid-css-selector.js +1 -1
- package/dist/utils/process-property-as-dom-element.js +0 -2
- package/dist/views/__snapshots__/summary.spec.js.snap +103 -113
- package/dist/views/common/iframe/base-iframe.js +10 -2
- package/dist/views/common/iframe/modal-iframe.js +44 -3
- package/dist/views/confirmation.js +44 -20
- package/dist/views/method-selector/express-methods/apple-pay.js +92 -0
- package/dist/views/method-selector/express-methods/google-pay.js +31 -0
- package/dist/views/method-selector/express-methods/paypal.js +19 -0
- package/dist/views/method-selector/generate-digital-wallet.js +68 -0
- package/dist/views/method-selector/generate-digital-wallet.spec.js +135 -0
- package/dist/views/method-selector/get-payment-methods.js +28 -8
- package/dist/views/method-selector/get-payment-methods.spec.js +25 -26
- package/dist/views/method-selector/index.js +55 -86
- package/dist/views/method-selector/method-selector.spec.js +80 -69
- package/dist/views/method-selector/mount-express-methods.js +38 -62
- package/dist/views/method-selector/mount-methods.js +18 -18
- package/dist/views/modal.js +21 -15
- package/dist/views/result.js +13 -16
- package/dist/views/summary.js +170 -114
- package/dist/views/summary.spec.js +72 -76
- package/package.json +5 -4
- package/src/events/base-event.js +15 -17
- package/src/events/events.spec.js +6 -4
- package/src/events/index.js +6 -3
- package/src/functions/destroy.js +12 -13
- package/src/functions/destroy.spec.js +30 -31
- package/src/functions/mount/fetch-data.js +148 -0
- package/src/functions/mount/fetch-data.spec.js +238 -0
- package/src/functions/mount/index.js +129 -244
- package/src/functions/mount/mount.spec.js +35 -139
- package/src/functions/mount/setup-element.js +26 -0
- package/src/functions/mount/setup-framepay.js +41 -0
- package/src/functions/mount/setup-i18n.js +19 -0
- package/src/functions/mount/setup-options.js +100 -0
- package/src/functions/mount/setup-options.spec.js +60 -0
- package/src/functions/mount/setup-storefront.js +24 -0
- package/src/functions/mount/setup-styles.js +30 -0
- package/src/functions/on.js +13 -8
- package/src/functions/on.spec.js +30 -17
- package/src/functions/purchase.js +101 -19
- package/src/functions/purchase.spec.js +18 -18
- package/src/functions/setup.js +48 -0
- package/src/functions/setup.spec.js +98 -0
- package/src/functions/show.js +20 -10
- package/src/functions/show.spec.js +43 -22
- package/src/functions/update.js +50 -27
- package/src/functions/update.spec.js +57 -22
- package/src/i18n/en.json +4 -1
- package/src/i18n/es.json +4 -1
- package/src/i18n/i18n.spec.js +6 -4
- package/src/i18n/index.js +14 -11
- package/src/index.js +41 -52
- package/src/index.spec.js +8 -37
- package/src/loader/index.js +51 -47
- package/src/loader/loader.spec.js +26 -19
- package/src/storefront/index.js +37 -7
- package/src/storefront/invoices.js +11 -0
- package/src/storefront/models/base-model.js +10 -0
- package/src/storefront/models/invoice-model.js +3 -0
- package/src/storefront/models/plan-model.js +3 -35
- package/src/storefront/models/product-model.js +3 -23
- package/src/storefront/models/ready-to-pay-model.js +3 -3
- package/src/storefront/models/summary-model.js +15 -29
- package/src/storefront/models/transaction-model.js +19 -0
- package/src/storefront/payment-instruments.js +30 -0
- package/src/storefront/payment-instruments.spec.js +69 -0
- package/src/storefront/plans.js +16 -23
- package/src/storefront/plans.spec.js +25 -54
- package/src/storefront/products.js +18 -22
- package/src/storefront/products.spec.js +23 -54
- package/src/storefront/purchase.js +14 -14
- package/src/storefront/purchase.spec.js +17 -29
- package/src/storefront/ready-to-pay.js +26 -23
- package/src/storefront/ready-to-pay.spec.js +41 -71
- package/src/storefront/storefront.spec.js +1 -1
- package/src/storefront/summary.js +26 -22
- package/src/storefront/summary.spec.js +60 -109
- package/src/storefront/transactions.js +11 -0
- package/src/style/base/theme.js +10 -8
- package/src/style/base/theme.spec.js +4 -2
- package/src/style/browserslist.js +1 -3
- package/src/style/components/button.js +3 -1
- package/src/style/components/forms/checkbox.js +3 -1
- package/src/style/components/index.js +1 -1
- package/src/style/components/loader.js +3 -1
- package/src/style/components/methods.js +43 -42
- package/src/style/helpers/index.js +1 -1
- package/src/style/index.js +2 -1
- package/src/style/utils/color-values.js +4 -4
- package/src/style/vendor/framepay.js +1 -1
- package/src/style/vendor/postmate.js +1 -1
- package/src/style/views/confirmation.js +0 -4
- package/src/style/views/index.js +1 -1
- package/src/style/views/method-selector.js +1 -1
- package/src/style/views/modal.js +4 -2
- package/src/style/views/summary.js +5 -1
- package/src/utils/add-dom-element.js +12 -13
- package/src/utils/format-currency.js +6 -2
- package/src/utils/has-valid-css-selector.js +2 -2
- package/src/utils/is-dom-element.js +1 -1
- package/src/utils/process-property-as-dom-element.js +27 -24
- package/src/utils/sleep.js +1 -1
- package/src/views/__snapshots__/summary.spec.js.snap +103 -113
- package/src/views/common/iframe/base-iframe.js +12 -4
- package/src/views/common/iframe/event-listeners.js +6 -6
- package/src/views/common/iframe/index.js +1 -1
- package/src/views/common/iframe/method-iframe.js +3 -6
- package/src/views/common/iframe/modal-iframe.js +42 -6
- package/src/views/common/iframe/view-iframe.js +3 -5
- package/src/views/common/render-utilities.js +3 -3
- package/src/views/confirmation.js +34 -25
- package/src/views/method-selector/express-methods/apple-pay.js +78 -0
- package/src/views/method-selector/express-methods/google-pay.js +24 -0
- package/src/views/method-selector/express-methods/paypal.js +7 -0
- package/src/views/method-selector/generate-digital-wallet.js +51 -0
- package/src/views/method-selector/generate-digital-wallet.spec.js +135 -0
- package/src/views/method-selector/get-method-data.js +7 -4
- package/src/views/method-selector/get-payment-methods.js +38 -29
- package/src/views/method-selector/get-payment-methods.spec.js +26 -33
- package/src/views/method-selector/index.js +70 -99
- package/src/views/method-selector/method-selector.spec.js +88 -78
- package/src/views/method-selector/mount-express-methods.js +36 -60
- package/src/views/method-selector/mount-methods.js +32 -21
- package/src/views/modal.js +37 -23
- package/src/views/result.js +12 -15
- package/src/views/summary.js +169 -101
- package/src/views/summary.spec.js +99 -74
- package/tests/async-utilities.js +22 -0
- package/tests/mocks/rebilly-instruments-mock.js +89 -77
- package/tests/mocks/storefront-api-mock.js +8 -0
- package/tests/mocks/storefront-mock.js +17 -0
- package/dist/events/purchase-completed.js +0 -24
- package/dist/functions/initialize.js +0 -82
- package/dist/functions/initialize.spec.js +0 -34
- package/dist/functions/mount/fetch-summary-data.js +0 -31
- package/dist/functions/mount/fetch-summary-data.spec.js +0 -45
- package/dist/views/method-selector/process-digital-wallet-options.js +0 -35
- package/dist/views/method-selector/process-digital-wallet-options.spec.js +0 -80
- package/src/events/purchase-completed.js +0 -11
- package/src/functions/initialize.js +0 -74
- package/src/functions/initialize.spec.js +0 -38
- package/src/functions/mount/fetch-summary-data.js +0 -26
- package/src/functions/mount/fetch-summary-data.spec.js +0 -46
- package/src/views/method-selector/process-digital-wallet-options.js +0 -16
- package/src/views/method-selector/process-digital-wallet-options.spec.js +0 -94
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { addDOMElement } from '../../utils';
|
|
2
|
+
|
|
3
|
+
export default ({
|
|
4
|
+
state: {
|
|
5
|
+
options: {
|
|
6
|
+
_dev
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
} = {}) => {
|
|
10
|
+
const framePayUrls = {
|
|
11
|
+
script: _dev
|
|
12
|
+
? _dev.framePayScriptLink || 'https://framepay.rebilly.com/rebilly.js'
|
|
13
|
+
: 'https://framepay.rebilly.com/rebilly.js',
|
|
14
|
+
style: _dev
|
|
15
|
+
? _dev.framePayStyleLink || 'https://framepay.rebilly.com/rebilly.css'
|
|
16
|
+
: 'https://framepay.rebilly.com/rebilly.css'
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
if (!document.querySelectorAll('[framepay*="script"]').length) {
|
|
20
|
+
addDOMElement({
|
|
21
|
+
element: 'script',
|
|
22
|
+
attributes: {
|
|
23
|
+
framepay: 'script',
|
|
24
|
+
src: framePayUrls.script
|
|
25
|
+
},
|
|
26
|
+
target: 'head'
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!document.querySelectorAll('[framepay*="stylesheet"]').length) {
|
|
31
|
+
addDOMElement({
|
|
32
|
+
element: 'link',
|
|
33
|
+
attributes: {
|
|
34
|
+
framepay: 'stylesheet',
|
|
35
|
+
href: framePayUrls.style,
|
|
36
|
+
rel: 'stylesheet'
|
|
37
|
+
},
|
|
38
|
+
target: 'head'
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const triggerTranslations = ({state}) => {
|
|
2
|
+
state.translate.init(state.options.locale, state.options.i18n);
|
|
3
|
+
state.translate.translateItems();
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export default ({state = {}}) => {
|
|
7
|
+
if (
|
|
8
|
+
state.options.locale === 'auto' &&
|
|
9
|
+
state.data.riskMetadata?.browserData?.language
|
|
10
|
+
) {
|
|
11
|
+
const {
|
|
12
|
+
browserData: { language }
|
|
13
|
+
} = state.data.riskMetadata;
|
|
14
|
+
state.options.locale = language;
|
|
15
|
+
}
|
|
16
|
+
state.translate.init(state.options.locale, state.options.i18n);
|
|
17
|
+
|
|
18
|
+
return triggerTranslations;
|
|
19
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import merge from 'lodash.merge';
|
|
2
|
+
|
|
3
|
+
export const defaults = {
|
|
4
|
+
countryCode: 'US',
|
|
5
|
+
locale: 'auto',
|
|
6
|
+
paymentInstruments: {
|
|
7
|
+
address: {
|
|
8
|
+
name: 'default',
|
|
9
|
+
region: 'default',
|
|
10
|
+
hide: [],
|
|
11
|
+
show: [],
|
|
12
|
+
require: []
|
|
13
|
+
},
|
|
14
|
+
compactExpressInstruments: true,
|
|
15
|
+
googlePay: {
|
|
16
|
+
displayOptions: {
|
|
17
|
+
buttonColor: 'black',
|
|
18
|
+
buttonType: 'short',
|
|
19
|
+
buttonHeight: '44px'
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
applePay: {
|
|
23
|
+
displayOptions: {
|
|
24
|
+
buttonColor: 'black',
|
|
25
|
+
buttonType: 'plain',
|
|
26
|
+
buttonHeight: '44px'
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
paymentCard: {
|
|
30
|
+
popup: false
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
transactionType: 'purchase',
|
|
34
|
+
features: {
|
|
35
|
+
autoConfirmation: true,
|
|
36
|
+
autoResult: true
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export function validateOptions(options) {
|
|
41
|
+
// TODO: validate more options
|
|
42
|
+
const purchaseData = [
|
|
43
|
+
options.items,
|
|
44
|
+
options.invoiceId,
|
|
45
|
+
options.money,
|
|
46
|
+
options.transactionId,
|
|
47
|
+
].filter(v => v);
|
|
48
|
+
|
|
49
|
+
if (purchaseData.length === 0) {
|
|
50
|
+
throw new Error('Must provide purchase data');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (purchaseData.length > 1) {
|
|
54
|
+
throw new Error('Must provide only one purchase data type');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export default ({
|
|
59
|
+
options = {}
|
|
60
|
+
} = {}) => {
|
|
61
|
+
validateOptions(options);
|
|
62
|
+
|
|
63
|
+
const _computed = {
|
|
64
|
+
paymentMethodsUrl: options._dev
|
|
65
|
+
? options._dev.paymentMethodsUrl || 'https://forms.local.rebilly.dev:3000'
|
|
66
|
+
: 'https://forms.secure-payments.app'
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const combinedOptions = merge({...defaults}, {
|
|
70
|
+
organizationId: options.organizationId,
|
|
71
|
+
publishableKey: options.publishableKey,
|
|
72
|
+
websiteId: options.websiteId,
|
|
73
|
+
apiMode: options.apiMode,
|
|
74
|
+
i18n: options.i18n,
|
|
75
|
+
theme: options.theme,
|
|
76
|
+
css: options.css,
|
|
77
|
+
locale: options.locale,
|
|
78
|
+
countryCode: options.countryCode,
|
|
79
|
+
features: options.features,
|
|
80
|
+
paymentInstruments: options.paymentInstruments,
|
|
81
|
+
transactionType: options.transactionType,
|
|
82
|
+
_computed
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Add optional key's
|
|
86
|
+
[
|
|
87
|
+
'items',
|
|
88
|
+
'money',
|
|
89
|
+
'invoiceId',
|
|
90
|
+
'transactionId',
|
|
91
|
+
'customerJwt',
|
|
92
|
+
'_dev'
|
|
93
|
+
].forEach(key => {
|
|
94
|
+
if (options[key]) {
|
|
95
|
+
combinedOptions[key] = options[key];
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
return combinedOptions;
|
|
100
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { RenderMockRebillyInstruments } from 'tests/mocks/rebilly-instruments-mock';
|
|
2
|
+
import setupOptions, {validateOptions, defaults} from './setup-options';
|
|
3
|
+
|
|
4
|
+
describe('Setup mount options', () => {
|
|
5
|
+
it("should fill with default options", () => {
|
|
6
|
+
const options = setupOptions({
|
|
7
|
+
options: {
|
|
8
|
+
items: [
|
|
9
|
+
{
|
|
10
|
+
planId: "test-plan-id",
|
|
11
|
+
quantity: 1
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
expect(options).toMatchObject(defaults);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("should setup options from mount", async () => {
|
|
20
|
+
const options = {
|
|
21
|
+
publishableKey: 'test-publishable-key',
|
|
22
|
+
organizationId: 'test-organization-id',
|
|
23
|
+
websiteId: 'test-website-id',
|
|
24
|
+
invoiceId: 'test-invoice-id',
|
|
25
|
+
customerJwt: 'test-customer-jwt'
|
|
26
|
+
}
|
|
27
|
+
const rebillyInstruments = await RenderMockRebillyInstruments(options);
|
|
28
|
+
expect(rebillyInstruments.state.options).toMatchObject(options);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('Validate mount options', () => {
|
|
33
|
+
it("should throw an error with no purchase data", async () => {
|
|
34
|
+
let error = null;
|
|
35
|
+
try {
|
|
36
|
+
const options = {};
|
|
37
|
+
validateOptions(options);
|
|
38
|
+
} catch (e) {
|
|
39
|
+
error = e;
|
|
40
|
+
}
|
|
41
|
+
expect(error.message).toBe('Must provide purchase data');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("should throw error if there are more than one purchase property", () => {
|
|
45
|
+
let error = null;
|
|
46
|
+
try {
|
|
47
|
+
const options = {
|
|
48
|
+
invoiceId: "test-invoice-id",
|
|
49
|
+
items: [{
|
|
50
|
+
planId: "test-plan-id",
|
|
51
|
+
quantity: 1
|
|
52
|
+
}]
|
|
53
|
+
};
|
|
54
|
+
validateOptions(options);
|
|
55
|
+
} catch (e) {
|
|
56
|
+
error = e;
|
|
57
|
+
}
|
|
58
|
+
expect(error.message).toBe('Must provide only one purchase data type');
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import Storefront from '../../storefront';
|
|
2
|
+
|
|
3
|
+
export default ({
|
|
4
|
+
options:{
|
|
5
|
+
publishableKey,
|
|
6
|
+
orgnizationId,
|
|
7
|
+
apiMode,
|
|
8
|
+
_dev
|
|
9
|
+
}
|
|
10
|
+
}) => {
|
|
11
|
+
const storefront = {
|
|
12
|
+
publishableKey,
|
|
13
|
+
orgnizationId,
|
|
14
|
+
mode: apiMode || 'live'
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
if (_dev) {
|
|
18
|
+
storefront.liveUrl = _dev.liveUrl || 'https://api.rebilly.com';
|
|
19
|
+
storefront.sandboxUrl =
|
|
20
|
+
_dev.sandboxUrl || 'https://api-sandbox.rebilly.com';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return Storefront(storefront);
|
|
24
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { mainStyle } from '../../style';
|
|
2
|
+
import { addDOMElement } from '../../utils';
|
|
3
|
+
|
|
4
|
+
export default async ({
|
|
5
|
+
options: {
|
|
6
|
+
theme = {},
|
|
7
|
+
css,
|
|
8
|
+
}
|
|
9
|
+
} = {}) => {
|
|
10
|
+
// Adds base stylesheet
|
|
11
|
+
const style = await mainStyle(theme || {});
|
|
12
|
+
addDOMElement({
|
|
13
|
+
element: 'style',
|
|
14
|
+
attributes: { type: 'text/css' },
|
|
15
|
+
content: style,
|
|
16
|
+
target: 'head'
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// Adds options CSS to override any styles
|
|
20
|
+
if (css) {
|
|
21
|
+
addDOMElement({
|
|
22
|
+
element: 'style',
|
|
23
|
+
attributes: { type: 'text/css' },
|
|
24
|
+
content: css,
|
|
25
|
+
target: 'head'
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return style;
|
|
30
|
+
}
|
package/src/functions/on.js
CHANGED
|
@@ -1,17 +1,22 @@
|
|
|
1
|
-
import camelCase from 'lodash.camelcase'
|
|
1
|
+
import camelCase from 'lodash.camelcase';
|
|
2
2
|
import Events, { publicEventNames } from '../events';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
@typedef OnParams
|
|
6
|
+
@type {Object}
|
|
7
|
+
@property {string} eventName - The name of the event
|
|
8
|
+
@property {function} callback - The function that is triggered by the event.
|
|
8
9
|
*/
|
|
9
|
-
export function On (eventName, callback) {
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Register events that will be triggered
|
|
13
|
+
* @param {OnParams} params
|
|
14
|
+
*/
|
|
15
|
+
export function on({ eventName, callback }) {
|
|
11
16
|
if (!publicEventNames.includes(eventName)) {
|
|
12
17
|
throw new Error(`${eventName} is not a supported event`);
|
|
13
18
|
}
|
|
14
|
-
|
|
15
|
-
const internalEventName =
|
|
19
|
+
|
|
20
|
+
const internalEventName = camelCase(eventName);
|
|
16
21
|
Events[internalEventName].addEventListener(callback);
|
|
17
|
-
}
|
|
22
|
+
}
|
package/src/functions/on.spec.js
CHANGED
|
@@ -1,32 +1,45 @@
|
|
|
1
1
|
import camelCase from 'lodash.camelcase';
|
|
2
|
+
import { RenderMockRebillyInstruments } from 'tests/mocks/rebilly-instruments-mock';
|
|
2
3
|
import Events from '../events';
|
|
3
|
-
import { MockRebillyInstruments } from 'tests/mocks/rebilly-instruments-mock';
|
|
4
4
|
|
|
5
5
|
describe('RebillyInstruments on', () => {
|
|
6
6
|
it('should register event listeners', async () => {
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
const publicEventNames = ['instrument-ready', 'purchase-completed']
|
|
7
|
+
const rebillyInstruments = await RenderMockRebillyInstruments();
|
|
8
|
+
const publicEventNames = ['instrument-ready', 'purchase-completed'];
|
|
10
9
|
|
|
11
|
-
await Promise.all(
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
await Promise.all(
|
|
11
|
+
publicEventNames.map(async (eventName) => {
|
|
12
|
+
const callback = jest.fn();
|
|
13
|
+
rebillyInstruments.on(eventName, callback);
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
const details = {
|
|
16
|
+
test: 'data'
|
|
17
|
+
};
|
|
18
|
+
Events[camelCase(eventName)].dispatch(details);
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
expect(callback).toBeCalledTimes(1);
|
|
21
|
+
expect(callback).toBeCalledWith(details);
|
|
22
|
+
})
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should throw error for internal namespaced events', async () => {
|
|
27
|
+
const callback = jest.fn();
|
|
28
|
+
const rebillyInstruments = await RenderMockRebillyInstruments();
|
|
23
29
|
|
|
24
|
-
|
|
30
|
+
let error;
|
|
31
|
+
try {
|
|
32
|
+
// rebilly-instruments-purchase-completed will be used internally but not available externally
|
|
33
|
+
await rebillyInstruments.on('rebilly-instruments-purchase-completed', callback);
|
|
34
|
+
} catch (e) {
|
|
35
|
+
error = e;
|
|
36
|
+
}
|
|
37
|
+
expect(error).toEqual(new Error('rebilly-instruments-purchase-completed is not a supported event'));
|
|
25
38
|
});
|
|
26
39
|
|
|
27
40
|
it('should throw error for a non defined event', async () => {
|
|
28
41
|
const callback = jest.fn();
|
|
29
|
-
const rebillyInstruments =
|
|
42
|
+
const rebillyInstruments = await RenderMockRebillyInstruments();
|
|
30
43
|
|
|
31
44
|
let error;
|
|
32
45
|
try {
|
|
@@ -34,6 +47,6 @@ describe('RebillyInstruments on', () => {
|
|
|
34
47
|
} catch (e) {
|
|
35
48
|
error = e;
|
|
36
49
|
}
|
|
37
|
-
expect(error).toEqual(new Error(
|
|
50
|
+
expect(error).toEqual(new Error('not-an-event is not a supported event'));
|
|
38
51
|
});
|
|
39
52
|
});
|
|
@@ -1,28 +1,110 @@
|
|
|
1
|
+
import { postPurchase, postPayment } from '../storefront/purchase';
|
|
1
2
|
import Events from '../events';
|
|
3
|
+
import { mountModal } from '../views/modal';
|
|
4
|
+
import { DataInstance } from './mount/fetch-data';
|
|
2
5
|
|
|
3
|
-
export async function
|
|
6
|
+
export async function makePayment({ state, payload }) {
|
|
7
|
+
const {
|
|
8
|
+
_raw: {
|
|
9
|
+
id: token
|
|
10
|
+
}
|
|
11
|
+
} = payload;
|
|
12
|
+
|
|
13
|
+
const data = {
|
|
14
|
+
token,
|
|
15
|
+
...payload
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
if (state.options.invoiceId) {
|
|
19
|
+
data.invoiceId = state.options.invoiceId;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (state.options.transactionId) {
|
|
23
|
+
data.transactionId = state.options.transactionId;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (state.options.money) {
|
|
27
|
+
data.websiteId = state.options.websiteId;
|
|
28
|
+
data.amount = state.options.money.amount;
|
|
29
|
+
data.currency = state.options.money.currency;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let { fields } = await postPayment({
|
|
33
|
+
state,
|
|
34
|
+
data
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
fields = {
|
|
38
|
+
transaction: fields,
|
|
39
|
+
token: fields.token || state.options.customerJwt
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
if (state.data.invoice) {
|
|
43
|
+
fields.invoice = state.data.invoice;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return fields;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function makePurchase({ state, payload }) {
|
|
50
|
+
const { fields } = await postPurchase({
|
|
51
|
+
state,
|
|
52
|
+
data: {
|
|
53
|
+
websiteId: state.options.websiteId,
|
|
54
|
+
items: state.options.items,
|
|
55
|
+
paymentInstruction: {
|
|
56
|
+
token: payload._raw.id
|
|
57
|
+
},
|
|
58
|
+
...payload
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
return fields;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function handleApprovalUrl({state, fields}) {
|
|
65
|
+
const { paymentMethodsUrl } = state.options._computed;
|
|
66
|
+
|
|
67
|
+
const model = {};
|
|
68
|
+
if (state.data.isPayment) {
|
|
69
|
+
model.payment = fields;
|
|
70
|
+
} else {
|
|
71
|
+
model.purchase = fields;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
state.data = new DataInstance({state, ...fields});
|
|
75
|
+
|
|
76
|
+
mountModal({
|
|
77
|
+
state,
|
|
78
|
+
name: 'rebilly-instruments-approval-url',
|
|
79
|
+
url: `${paymentMethodsUrl}/approval-url`,
|
|
80
|
+
model,
|
|
81
|
+
close: (updatedPurchase) => {
|
|
82
|
+
Events.purchaseCompleted.dispatch(updatedPurchase);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export async function purchase({ state, payload }) {
|
|
4
88
|
try {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const { paymentMethodsUrl } = this.options._computed;
|
|
9
|
-
|
|
10
|
-
this._mountModal({
|
|
11
|
-
name: 'rebilly-instruments-approval-url',
|
|
12
|
-
url: `${paymentMethodsUrl}/approval-url`,
|
|
13
|
-
model: {
|
|
14
|
-
purchase
|
|
15
|
-
},
|
|
16
|
-
close: (updatedPurchase) => {
|
|
17
|
-
// TODO: Check if this is purchase...
|
|
18
|
-
Events.purchaseCompleted.dispatch(updatedPurchase);
|
|
19
|
-
}
|
|
20
|
-
});
|
|
89
|
+
let fields;
|
|
90
|
+
if (state.data.isPayment) {
|
|
91
|
+
fields = await makePayment({ state, payload });
|
|
21
92
|
} else {
|
|
22
|
-
|
|
93
|
+
fields = await makePurchase({ state, payload });
|
|
23
94
|
}
|
|
24
|
-
|
|
95
|
+
|
|
96
|
+
if (fields.transaction?.approvalUrl) {
|
|
97
|
+
handleApprovalUrl({state, fields});
|
|
98
|
+
} else {
|
|
99
|
+
Events.purchaseCompleted.dispatch(fields);
|
|
100
|
+
}
|
|
101
|
+
return fields;
|
|
102
|
+
} catch (error) {
|
|
25
103
|
// TODO: Display error to customer
|
|
104
|
+
console.error(error);
|
|
105
|
+
if(error.status === 422) {
|
|
106
|
+
error.details.forEach(e => console.error(e));
|
|
107
|
+
}
|
|
26
108
|
return error;
|
|
27
109
|
}
|
|
28
110
|
}
|
|
@@ -1,20 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RenderMockRebillyInstruments } from 'tests/mocks/rebilly-instruments-mock';
|
|
2
2
|
import { ok, post } from 'msw-when-then';
|
|
3
3
|
import { when } from 'tests/msw/server';
|
|
4
4
|
import { storefrontURL } from 'tests/mocks/storefront-api-mock';
|
|
5
5
|
import Events from '../events';
|
|
6
|
+
import { avoidUnhandledPromises } from 'tests/async-utilities';
|
|
6
7
|
|
|
7
8
|
describe('RebillyInstruments purchase', () => {
|
|
8
9
|
it('should be able to make a purchase', async () => {
|
|
9
|
-
const configs = {
|
|
10
|
-
websiteId: 'test-website-id'
|
|
11
|
-
};
|
|
12
10
|
const options = {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
{ planId: 'test-plan-id', quantity: 1 }
|
|
16
|
-
]
|
|
17
|
-
}
|
|
11
|
+
websiteId: 'test-website-id',
|
|
12
|
+
items: [{ planId: 'test-plan-id', quantity: 1 }]
|
|
18
13
|
};
|
|
19
14
|
|
|
20
15
|
const token = {
|
|
@@ -38,8 +33,8 @@ describe('RebillyInstruments purchase', () => {
|
|
|
38
33
|
};
|
|
39
34
|
|
|
40
35
|
when(post(`${storefrontURL}/purchase`)).thenReturn(ok(fields));
|
|
41
|
-
const rebillyInstruments =
|
|
42
|
-
jest.spyOn(rebillyInstruments.storefront.purchase, 'purchase');
|
|
36
|
+
const rebillyInstruments = await RenderMockRebillyInstruments(options);
|
|
37
|
+
const spyStorefrontPurchase = jest.spyOn(rebillyInstruments.state.storefront.purchase, 'purchase');
|
|
43
38
|
jest.spyOn(Events.purchaseCompleted, 'dispatch');
|
|
44
39
|
|
|
45
40
|
const purchaseCompletedListener = jest.fn();
|
|
@@ -47,8 +42,14 @@ describe('RebillyInstruments purchase', () => {
|
|
|
47
42
|
rebillyInstruments.on('purchase-completed', purchaseCompletedListener);
|
|
48
43
|
|
|
49
44
|
const purchasePayload = {
|
|
50
|
-
|
|
51
|
-
|
|
45
|
+
billingAddress,
|
|
46
|
+
deliveryAddress,
|
|
47
|
+
_raw: token
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const purchasePayloadParsed = {
|
|
51
|
+
websiteId: rebillyInstruments.state.options.websiteId,
|
|
52
|
+
items: rebillyInstruments.state.options.items,
|
|
52
53
|
billingAddress,
|
|
53
54
|
deliveryAddress,
|
|
54
55
|
paymentInstruction: {
|
|
@@ -58,10 +59,8 @@ describe('RebillyInstruments purchase', () => {
|
|
|
58
59
|
|
|
59
60
|
await rebillyInstruments.purchase(purchasePayload);
|
|
60
61
|
|
|
61
|
-
expect(
|
|
62
|
-
expect(
|
|
63
|
-
expect.objectContaining({data: purchasePayload})
|
|
64
|
-
);
|
|
62
|
+
expect(spyStorefrontPurchase).toBeCalledTimes(1);
|
|
63
|
+
expect(spyStorefrontPurchase).toBeCalledWith(expect.objectContaining({ data: purchasePayloadParsed }));
|
|
65
64
|
|
|
66
65
|
expect(Events.purchaseCompleted.dispatch).toBeCalledTimes(1);
|
|
67
66
|
|
|
@@ -69,5 +68,6 @@ describe('RebillyInstruments purchase', () => {
|
|
|
69
68
|
expect(purchaseCompletedListener).toBeCalledWith(
|
|
70
69
|
expect.objectContaining(fields)
|
|
71
70
|
);
|
|
71
|
+
await avoidUnhandledPromises();
|
|
72
72
|
});
|
|
73
|
-
});
|
|
73
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { setupPaymentInstrument } from '../storefront/payment-instruments';
|
|
2
|
+
import Events from '../events';
|
|
3
|
+
import { mountModal } from '../views/modal';
|
|
4
|
+
import { DataInstance } from './mount/fetch-data';
|
|
5
|
+
|
|
6
|
+
export async function setup({ state, payload }) {
|
|
7
|
+
try {
|
|
8
|
+
const {instrument, transaction} = await setupPaymentInstrument({
|
|
9
|
+
state,
|
|
10
|
+
data: {
|
|
11
|
+
token: payload._raw.id,
|
|
12
|
+
websiteId: state.options?.websiteId,
|
|
13
|
+
...payload
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
state.data = new DataInstance({state, instrument, transaction});
|
|
18
|
+
|
|
19
|
+
if (transaction.approvalUrl) {
|
|
20
|
+
const { paymentMethodsUrl } = state.options._computed;
|
|
21
|
+
mountModal({
|
|
22
|
+
state,
|
|
23
|
+
name: 'rebilly-instruments-approval-url',
|
|
24
|
+
url: `${paymentMethodsUrl}/approval-url`,
|
|
25
|
+
model: {
|
|
26
|
+
setup: {transaction}
|
|
27
|
+
},
|
|
28
|
+
close: ({transaction: updatedTransaction = transaction}) => {
|
|
29
|
+
Events.setupCompleted.dispatch({
|
|
30
|
+
instrument,
|
|
31
|
+
transaction: updatedTransaction
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
} else {
|
|
36
|
+
Events.setupCompleted.dispatch({instrument, transaction});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return {instrument, transaction};
|
|
40
|
+
} catch (error) {
|
|
41
|
+
// TODO: Display error to customer
|
|
42
|
+
console.error(error);
|
|
43
|
+
if(error.status === 422) {
|
|
44
|
+
error.details.forEach(e => console.error(e));
|
|
45
|
+
}
|
|
46
|
+
return error;
|
|
47
|
+
}
|
|
48
|
+
}
|