@rebilly/instruments 2.1.0-beta.0 → 3.1.0-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.
Files changed (87) hide show
  1. package/dist/functions/mount/fetch-data.js +70 -56
  2. package/dist/functions/mount/fetch-data.spec.js +58 -34
  3. package/dist/functions/mount/index.js +6 -0
  4. package/dist/functions/mount/mount.spec.js +2 -4
  5. package/dist/functions/mount/setup-framepay-theme.js +95 -0
  6. package/dist/functions/mount/setup-options.js +3 -0
  7. package/dist/i18n/en.json +1 -1
  8. package/dist/i18n/index.js +1 -1
  9. package/dist/style/base/__snapshots__/theme.spec.js.snap +220 -45
  10. package/dist/style/base/default-theme.js +804 -0
  11. package/dist/style/base/index.js +48 -16
  12. package/dist/style/base/theme.js +16 -49
  13. package/dist/style/base/theme.spec.js +4 -15
  14. package/dist/style/components/address.js +3 -3
  15. package/dist/style/components/button.js +48 -22
  16. package/dist/style/components/divider.js +9 -9
  17. package/dist/style/components/forms/checkbox.js +12 -9
  18. package/dist/style/components/forms/field.js +18 -6
  19. package/dist/style/components/forms/form.js +2 -2
  20. package/dist/style/components/forms/input.js +54 -13
  21. package/dist/style/components/forms/label.js +39 -18
  22. package/dist/style/components/forms/select.js +54 -22
  23. package/dist/style/components/forms/validation.js +53 -6
  24. package/dist/style/components/icons.js +4 -4
  25. package/dist/style/components/loader.js +5 -3
  26. package/dist/style/components/methods.js +18 -15
  27. package/dist/style/components/overlay.js +5 -5
  28. package/dist/style/helpers/index.js +46 -46
  29. package/dist/style/index.js +3 -1
  30. package/dist/style/payment-instruments/payment-card.js +4 -4
  31. package/dist/style/utils/border.js +47 -0
  32. package/dist/style/utils/color-values.js +39 -3
  33. package/dist/style/utils/remove-empty-null.js +20 -0
  34. package/dist/style/vendor/framepay.js +11 -8
  35. package/dist/style/vendor/postmate.js +2 -2
  36. package/dist/style/views/confirmation.js +13 -13
  37. package/dist/style/views/method-selector.js +2 -2
  38. package/dist/style/views/modal.js +6 -6
  39. package/dist/style/views/result.js +4 -4
  40. package/dist/style/views/summary.js +23 -23
  41. package/dist/views/__snapshots__/summary.spec.js.snap +4 -40
  42. package/dist/views/common/iframe/modal-iframe.js +6 -1
  43. package/dist/views/summary.js +17 -11
  44. package/package.json +3 -1
  45. package/src/functions/mount/fetch-data.js +60 -46
  46. package/src/functions/mount/fetch-data.spec.js +67 -33
  47. package/src/functions/mount/index.js +2 -0
  48. package/src/functions/mount/mount.spec.js +3 -5
  49. package/src/functions/mount/setup-framepay-theme.js +82 -0
  50. package/src/functions/mount/setup-options.js +3 -0
  51. package/src/i18n/en.json +1 -1
  52. package/src/i18n/index.js +1 -1
  53. package/src/style/base/__snapshots__/theme.spec.js.snap +220 -45
  54. package/src/style/base/default-theme.js +777 -0
  55. package/src/style/base/index.js +48 -16
  56. package/src/style/base/theme.js +17 -47
  57. package/src/style/base/theme.spec.js +4 -16
  58. package/src/style/components/address.js +3 -3
  59. package/src/style/components/button.js +48 -24
  60. package/src/style/components/divider.js +9 -9
  61. package/src/style/components/forms/checkbox.js +11 -11
  62. package/src/style/components/forms/field.js +18 -6
  63. package/src/style/components/forms/form.js +2 -2
  64. package/src/style/components/forms/input.js +54 -13
  65. package/src/style/components/forms/label.js +39 -18
  66. package/src/style/components/forms/select.js +54 -22
  67. package/src/style/components/forms/validation.js +53 -6
  68. package/src/style/components/icons.js +4 -4
  69. package/src/style/components/loader.js +4 -5
  70. package/src/style/components/methods.js +18 -15
  71. package/src/style/components/overlay.js +5 -5
  72. package/src/style/helpers/index.js +46 -46
  73. package/src/style/index.js +2 -1
  74. package/src/style/payment-instruments/payment-card.js +4 -4
  75. package/src/style/utils/border.js +34 -0
  76. package/src/style/utils/color-values.js +27 -1
  77. package/src/style/utils/remove-empty-null.js +10 -0
  78. package/src/style/vendor/framepay.js +11 -8
  79. package/src/style/vendor/postmate.js +2 -2
  80. package/src/style/views/confirmation.js +13 -13
  81. package/src/style/views/method-selector.js +2 -2
  82. package/src/style/views/modal.js +6 -6
  83. package/src/style/views/result.js +4 -4
  84. package/src/style/views/summary.js +23 -23
  85. package/src/views/__snapshots__/summary.spec.js.snap +4 -40
  86. package/src/views/common/iframe/modal-iframe.js +7 -1
  87. package/src/views/summary.js +17 -11
@@ -3,8 +3,8 @@ import { fetchPlans } from '../../storefront/plans';
3
3
  import { fetchProducts } from '../../storefront/products';
4
4
  import { fetchReadyToPay } from '../../storefront/ready-to-pay';
5
5
  import { fetchSummary } from '../../storefront/summary';
6
- import { fetchInvoice } from '../../storefront/invoices';
7
- import { fetchTransaction } from '../../storefront/transactions';
6
+ import { fetchInvoice as FetchInvoice } from '../../storefront/invoices';
7
+ import { fetchTransaction as FetchTransaction } from '../../storefront/transactions';
8
8
 
9
9
  export class DataInstance {
10
10
  constructor({
@@ -81,58 +81,72 @@ export class DataInstance {
81
81
 
82
82
  return lineItems;
83
83
  }
84
+
85
+ get isShippingRequired() {
86
+ return this.products.some(product => product.requiresShipping);
87
+ }
84
88
  }
85
89
 
86
90
  export async function fetchData({
87
91
  state = null,
88
92
  riskMetadata = null,
89
- summaryPayload = null
93
+ summaryPayload = null,
94
+
95
+ // Dependancy injectable functions
96
+ fetchInvoice = FetchInvoice,
97
+ fetchTransaction = FetchTransaction
90
98
  }) {
91
- let transaction = null;
92
- if (state.options?.transactionId) {
93
- transaction = await fetchTransaction({data: {
94
- id: state.options.transactionId
95
- }, state});
96
- state.data.transaction = transaction;
97
- }
99
+ try {
100
+ let transaction = null;
101
+ if (state.options?.transactionId) {
102
+ transaction = await fetchTransaction({data: {
103
+ id: state.options.transactionId
104
+ }, state});
105
+ state.data.transaction = transaction;
106
+ }
98
107
 
99
- let invoice = null;
100
- if (state.options?.invoiceId || state.data?.transaction?.hasInvoice) {
101
- invoice = await fetchInvoice({data: {
102
- id: state.options.invoiceId
103
- }, state});
104
- state.data.invoice = invoice;
105
- }
108
+ let invoice = null;
109
+ if (state.options?.invoiceId || state.data?.transaction?.hasInvoice) {
110
+ invoice = await fetchInvoice({data: {
111
+ id: state.options?.invoiceId || state.data?.transaction?.invoiceId
112
+ }, state});
113
+ state.data.invoice = invoice;
114
+ }
115
+
116
+ if (!riskMetadata) {
117
+ const { riskMetadata: data } = await collectData();
118
+ riskMetadata = data;
119
+ }
106
120
 
107
- if (!riskMetadata) {
108
- const { riskMetadata: data } = await collectData();
109
- riskMetadata = data;
121
+ state.data = new DataInstance({
122
+ state,
123
+ invoice,
124
+ transaction,
125
+ riskMetadata
126
+ });
127
+
128
+ const [readyToPay, previewPurchase] = await Promise.all([
129
+ state.data?.readyToPay || fetchReadyToPay({ riskMetadata, state }),
130
+ state.options.items ? fetchSummary({ data: summaryPayload, state }) : null
131
+ ]);
132
+
133
+ const plans = await fetchPlans({ state });
134
+ state.data.plans = plans;
135
+ const products = await fetchProducts({ state });
136
+
137
+ return new DataInstance({
138
+ state,
139
+ readyToPay,
140
+ previewPurchase,
141
+ plans,
142
+ products,
143
+ invoice,
144
+ transaction,
145
+ riskMetadata
146
+ });
147
+ } catch(error) {
148
+ // console.log(error);
110
149
  }
111
150
 
112
- state.data = new DataInstance({
113
- state,
114
- invoice,
115
- transaction,
116
- riskMetadata
117
- });
118
-
119
- const [readyToPay, previewPurchase] = await Promise.all([
120
- state.data?.readyToPay || fetchReadyToPay({ riskMetadata, state }),
121
- state.options.items ? fetchSummary({ data: summaryPayload, state }) : null
122
- ]);
123
-
124
- const plans = await fetchPlans({ state });
125
- state.data.plans = plans;
126
- const products = await fetchProducts({ state });
127
-
128
- return new DataInstance({
129
- state,
130
- readyToPay,
131
- previewPurchase,
132
- plans,
133
- products,
134
- invoice,
135
- transaction,
136
- riskMetadata
137
- });
151
+ return new DataInstance({});
138
152
  }
@@ -1,46 +1,80 @@
1
1
  import { fetchData, DataInstance } from './fetch-data';
2
-
3
- describe.skip('Fetch Summary Data function helper', () => {
4
- class TestInstance {
5
- constructor() {
6
- this.storefront = jest.fn();
7
- this.options = jest.fn();
8
-
9
- this._fetchSummary = jest.fn(() => {
10
- return new Promise((resolve) => resolve({}));
11
- });
12
-
13
- this._fetchProducts = jest.fn();
2
+ import TransactionModel from '../../storefront/models/transaction-model';
3
+
4
+ describe('fetchData function', () => {
5
+ it('Should use correct invoice id for invoiceId', async () => {
6
+ const mockFetchInvoice = jest.fn();
7
+ const invoiceId = 'test-invoice-id';
8
+ const invoiceState = {
9
+ options: {
10
+ invoiceId
11
+ }
14
12
  }
15
- }
16
-
17
- it('should fetch all the data', async () => {
18
- const instance = new TestInstance();
19
- await fetchData({ riskMetadata: {}, state: instance });
20
- expect(fetchReadyToPay).toBeCalledTimes(1);
21
- expect(instance._fetchSummary).toBeCalledTimes(1);
22
- expect(instance._fetchPlans).toBeCalledTimes(1);
23
- expect(instance._fetchProducts).toBeCalledTimes(1);
13
+
14
+ fetchData({
15
+ state: invoiceState,
16
+ fetchInvoice: mockFetchInvoice
17
+ });
18
+
19
+ expect(mockFetchInvoice).toBeCalledTimes(1);
20
+ expect(mockFetchInvoice).toBeCalledWith(
21
+ expect.objectContaining({
22
+ data:{
23
+ id: invoiceId
24
+ }
25
+ })
26
+ );
24
27
  });
25
28
 
26
- it('should pass riskMetadata to ready to pay', async () => {
27
- const testRiskMetadata = {};
28
- const instance = new TestInstance();
29
+ it('Should use correct invoice id for transaction with invoiceIds', async () => {
30
+ const mockFetchInvoice = jest.fn();
31
+ const invoiceId = 'test-invoice-id';
32
+ const invoiceState = {
33
+ options: {},
34
+ data: {
35
+ transaction: new TransactionModel({
36
+ invoiceIds: [invoiceId]
37
+ }),
38
+ }
39
+ }
29
40
 
30
- await fetchData({ riskMetadata: testRiskMetadata, state: instance });
41
+ fetchData({
42
+ state: invoiceState,
43
+ fetchInvoice: mockFetchInvoice
44
+ });
45
+
46
+ expect(mockFetchInvoice).toBeCalledTimes(1);
47
+ expect(mockFetchInvoice).toBeCalledWith(
48
+ expect.objectContaining({
49
+ data:{
50
+ id: invoiceId
51
+ }
52
+ })
53
+ );
54
+ });
31
55
 
32
- expect(instance._fetchReadyToPay).toBeCalledWith(testRiskMetadata);
56
+ it('Should not fetch invoice for transaction with no invoice Ids', async () => {
57
+ const mockFetchInvoice = jest.fn();
58
+ const invoiceState = {
59
+ options: {},
60
+ data: {
61
+ transaction: new TransactionModel({
62
+ invoiceIds: []
63
+ }),
64
+ }
65
+ }
33
66
 
34
- expect(async () => {
35
- await fetchData({ state: instance });
36
- }).rejects.toEqual(
37
- new Error('riskMetadata is required for FetchSummaryData')
38
- );
67
+ fetchData({
68
+ state: invoiceState,
69
+ fetchInvoice: mockFetchInvoice
70
+ });
71
+
72
+ expect(mockFetchInvoice).toBeCalledTimes(0);
73
+
39
74
  });
40
75
  });
41
76
 
42
77
  describe('DataInstance', () => {
43
-
44
78
  it ('Should correctly determine amountAndCurrency', () => {
45
79
  const expectedAmountAndCurrency = {
46
80
  amount: 10,
@@ -199,6 +233,6 @@ describe('DataInstance', () => {
199
233
  }
200
234
  });
201
235
  expect(fetchedData.summaryLineItems).toEqual(expectedSummaryLineItems);
202
- })
236
+ });
203
237
  });
204
238
 
@@ -10,6 +10,7 @@ import setupOptions from './setup-options';
10
10
  import setupFramepay from './setup-framepay';
11
11
  import setupStyles from './setup-styles';
12
12
  import setupI18n from './setup-i18n';
13
+ import setupFramepayTheme from './setup-framepay-theme';
13
14
 
14
15
  /**
15
16
  * @typedef {object} Item
@@ -95,6 +96,7 @@ export async function mount({
95
96
  state.options = setupOptions({ options });
96
97
  state.mainStyle = await setupStyles({ options });
97
98
  state.data = await fetchData({ state });
99
+ state.options.themeFramepay = await setupFramepayTheme({ state, options });
98
100
  const i18n = setupI18n({ state });
99
101
  setupFramepay({ state });
100
102
 
@@ -23,9 +23,7 @@ describe('RebillyInstruments instance', () => {
23
23
  }
24
24
  ],
25
25
  theme: {
26
- color: {
27
- background: '#000'
28
- }
26
+ colorBackground: '#000'
29
27
  },
30
28
  css: `
31
29
  .rebilly-instruments-summary-line-item-synopsis-title {
@@ -47,8 +45,8 @@ describe('RebillyInstruments instance', () => {
47
45
  const SUMMARY_CONTAINER = summarySelector.querySelector(
48
46
  '.rebilly-instruments-content'
49
47
  );
50
- expect(getComputedStyle(SUMMARY_CONTAINER).background).toEqual(
51
- 'rgb(0, 0, 0)'
48
+ expect(getComputedStyle(SUMMARY_CONTAINER).getPropertyValue('--rebilly-colorBackground')).toEqual(
49
+ '#000'
52
50
  );
53
51
 
54
52
  // CSS config property overrides initial styles
@@ -0,0 +1,82 @@
1
+ import css from 'css';
2
+ import postcss from 'postcss';
3
+ import postcssCustomProperties from 'postcss-custom-properties';
4
+ import camelCase from 'lodash.camelcase';
5
+
6
+ const resolveCssVars = async (rawCss) => postcss([
7
+ postcssCustomProperties({ preserve: false })
8
+ ])
9
+ .process(rawCss, { from: undefined })
10
+ .then(output => output.css);
11
+
12
+ const getStyleProps = (ast, selector) => {
13
+ const { rules } = ast.stylesheet;
14
+ const output = {
15
+ color: null,
16
+ fontFamily: null,
17
+ fontSize: null,
18
+ lineHeight: null,
19
+ fontWeight: null,
20
+ background: null
21
+ }
22
+
23
+ for(let i = 0; i < rules.length; i += 1) {
24
+ const rule = rules[i];
25
+
26
+ if(rule.type === 'rule' && rule.selectors.includes(selector)) {
27
+ rule.declarations.forEach(decl => {
28
+ const propName = camelCase(decl.property);
29
+ if(typeof output[propName] !== 'undefined') {
30
+ output[propName] = decl.value;
31
+ }
32
+ })
33
+ }
34
+ }
35
+ return output;
36
+ }
37
+
38
+ export default async ({
39
+ state,
40
+ options = {}
41
+ }) => {
42
+ const fullCss = `
43
+ ${state.mainStyle}
44
+ ${options.css || ''}
45
+ `;
46
+
47
+ const resolvedCss = await resolveCssVars(fullCss);
48
+ const cssAst = css.parse(resolvedCss);
49
+
50
+ const cssSelectors = {
51
+ base: '.rebilly-instruments-form-field-input',
52
+ baseHover: '.rebilly-instruments-form-field-input:hover',
53
+ baseFocus: '.rebilly-instruments-form-field-input:focus',
54
+ basePlaceholder: '.rebilly-instruments-form-field-input::placeholder',
55
+ baseSelection: '.rebilly-instruments-form-field-input::selection',
56
+
57
+ invalid: '.rebilly-instruments-form-field.is-error .rebilly-instruments-form-field-input',
58
+ invalidHover: '.rebilly-instruments-form-field.is-error .rebilly-instruments-form-field-input:hover',
59
+ invalidFocus: '.rebilly-instruments-form-field.is-error .rebilly-instruments-form-field-input:focus',
60
+ invalidPlaceholder: '.rebilly-instruments-form-field.is-error .rebilly-instruments-form-field-input::placeholder',
61
+ invalidSelection: '.rebilly-instruments-form-field.is-error .rebilly-instruments-form-field-input::selection'
62
+ }
63
+
64
+ const framepayStyle = {
65
+ base: {
66
+ ...getStyleProps(cssAst, cssSelectors.base),
67
+ ':hover': getStyleProps(cssAst, cssSelectors.baseHover),
68
+ ':focus': getStyleProps(cssAst, cssSelectors.baseFocus),
69
+ '::placeholder': getStyleProps(cssAst, cssSelectors.basePlaceholder),
70
+ '::selection': getStyleProps(cssAst, cssSelectors.baseSelection),
71
+ },
72
+ invalid: {
73
+ ...getStyleProps(cssAst, cssSelectors.invalid),
74
+ ':hover': getStyleProps(cssAst, cssSelectors.invalidHover),
75
+ ':focus': getStyleProps(cssAst, cssSelectors.invalidFocus),
76
+ '::placeholder': getStyleProps(cssAst, cssSelectors.invalidPlaceholder),
77
+ '::selection': getStyleProps(cssAst, cssSelectors.invalidSelection),
78
+ }
79
+ }
80
+
81
+ return framepayStyle;
82
+ }
@@ -3,6 +3,9 @@ import merge from 'lodash.merge';
3
3
  export const defaults = {
4
4
  countryCode: 'US',
5
5
  locale: 'auto',
6
+ theme: {
7
+ labels: 'floating'
8
+ },
6
9
  paymentInstruments: {
7
10
  address: {
8
11
  name: 'default',
package/src/i18n/en.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "en": {
3
3
  "summary": {
4
4
  "subTotal": "Sub Total",
5
- "discounts": "Discouts",
5
+ "discounts": "Discounts",
6
6
  "taxes": "Taxes",
7
7
  "shipping": "Shipping",
8
8
  "total": "Total"
package/src/i18n/index.js CHANGED
@@ -12,7 +12,7 @@ export class Translate {
12
12
  init(locale, messages) {
13
13
  this.items = document.querySelectorAll('[data-rebilly-i18n]');
14
14
  this.locale = this.getLocale(locale);
15
- this.languages = merge({ ...en, ...es }, messages);
15
+ this.languages = merge({}, { ...en, ...es }, messages);
16
16
  }
17
17
 
18
18
  translateItems() {