@financial-times/n-conversion-forms 47.0.0 → 47.0.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.
- package/.toolkitstate/ci.json +3 -3
- package/.toolkitstate/install.json +1 -1
- package/components/delivery-option.stories.js +2 -2
- package/components/payment-term.jsx +41 -25
- package/components/payment-term.spec.js +32 -1
- package/dist/payment-term.jsx +28 -16
- package/helpers/duration-helpers.js +0 -14
- package/helpers/duration-helpers.spec.js +0 -33
- package/helpers/index.js +0 -1
- package/helpers/index.spec.js +0 -4
- package/package.json +2 -2
- package/styles/payment-type.scss +0 -4
package/.toolkitstate/ci.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
2
|
".toolkitrc.yml": "XiiIocllEaT8xqKRCTpTbJ+yUyduDo5aEHARUQ3vJFfSe187Ci13PEs3bWL272GFJyNz2QgRQhdov2/+LFRKuw==",
|
|
3
|
-
"package.json": "
|
|
3
|
+
"package.json": "QBfshsb3yvKX/+ogZ5/b81C1BfSdRcV5RZAv599ZTmGXV2w3Lt5k4FQOPWk//m1p3+B1FjXnfdsXISbJ42rlQA==",
|
|
4
4
|
".circleci/config.yml": "eph42EF3EsL7jvhiiC7D7vG3vGBAGBFVC+Ncmy4Dj4rUNzK8Rls0/cr+bEF/ttMN3J6iSL1xtCXKIJVrtZ4OSQ=="
|
|
5
5
|
}
|
|
@@ -34,12 +34,12 @@ Basic.args = {
|
|
|
34
34
|
],
|
|
35
35
|
};
|
|
36
36
|
|
|
37
|
-
export const
|
|
37
|
+
export const UKPaperVoucherAutoRenewingDeliveryOptions = (args) => (
|
|
38
38
|
<div className="ncf">
|
|
39
39
|
<DeliveryOption {...args} />
|
|
40
40
|
</div>
|
|
41
41
|
);
|
|
42
|
-
|
|
42
|
+
UKPaperVoucherAutoRenewingDeliveryOptions.args = {
|
|
43
43
|
country: 'GBR',
|
|
44
44
|
options: [
|
|
45
45
|
{
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import classNames from 'classnames';
|
|
4
|
-
import { Period,
|
|
4
|
+
import { Period, Price } from '@financial-times/n-pricing';
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
getDurationFromISO8601Value,
|
|
8
|
-
is52WeeksOrLonger,
|
|
9
|
-
is90DaysOrLonger,
|
|
10
|
-
} from '../helpers';
|
|
6
|
+
import { getDurationFromISO8601Value, is52WeeksOrLonger } from '../helpers';
|
|
11
7
|
|
|
12
8
|
export function PaymentTerm({
|
|
13
9
|
fieldId = 'paymentTermField',
|
|
@@ -90,16 +86,20 @@ export function PaymentTerm({
|
|
|
90
86
|
};
|
|
91
87
|
|
|
92
88
|
/**
|
|
93
|
-
* Compute monthly price for given term name.
|
|
94
|
-
* @returns {string}
|
|
89
|
+
* Compute monthly price for given term name, if the term if 90 days or longer.
|
|
90
|
+
* @returns {string | undefined}
|
|
95
91
|
*/
|
|
96
|
-
const
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
92
|
+
const getCalculatedMonthlyPriceIfEligible = () => {
|
|
93
|
+
const priceObject = new Price(
|
|
94
|
+
{
|
|
95
|
+
value: option.amount,
|
|
96
|
+
symbol: option.symbol,
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
period: option.value,
|
|
100
|
+
}
|
|
101
|
+
);
|
|
102
|
+
return priceObject.getMonthlyEquivalentIf90DaysOrLonger()?.amount.value;
|
|
103
103
|
};
|
|
104
104
|
|
|
105
105
|
/**
|
|
@@ -158,7 +158,7 @@ export function PaymentTerm({
|
|
|
158
158
|
};
|
|
159
159
|
|
|
160
160
|
/**
|
|
161
|
-
* Returns elements that include the text describing how regularly an auto-
|
|
161
|
+
* Returns elements that include the text describing how regularly an auto-renewing subscription will renew.
|
|
162
162
|
* @returns {React.ReactElement}
|
|
163
163
|
*/
|
|
164
164
|
const getRenewalPeriodText = () => {
|
|
@@ -173,28 +173,46 @@ export function PaymentTerm({
|
|
|
173
173
|
|
|
174
174
|
/**
|
|
175
175
|
* Returns elements that include the text describing the monthly equivalent of the subscription.
|
|
176
|
-
*
|
|
176
|
+
* Returns null if the term is shorter than 90 days
|
|
177
|
+
* @returns {string | null}
|
|
177
178
|
*/
|
|
178
179
|
const getEquivalentMonthlyPrice = () => {
|
|
179
|
-
|
|
180
|
+
const calculatedMonthlyPrice = getCalculatedMonthlyPriceIfEligible();
|
|
181
|
+
|
|
182
|
+
if (!calculatedMonthlyPrice) {
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const hasValidMonthlyPrice =
|
|
187
|
+
option.monthlyPrice !== null &&
|
|
188
|
+
option.monthlyPrice !== undefined &&
|
|
189
|
+
option.monthlyPrice !== '' &&
|
|
190
|
+
option.monthlyPrice !== '0';
|
|
191
|
+
|
|
192
|
+
if (hasValidMonthlyPrice) {
|
|
180
193
|
return isNaN(option.monthlyPrice)
|
|
181
194
|
? option.monthlyPrice
|
|
182
195
|
: `${option.symbol}${option.monthlyPrice}`;
|
|
183
196
|
}
|
|
184
197
|
|
|
185
|
-
return
|
|
198
|
+
return calculatedMonthlyPrice;
|
|
186
199
|
};
|
|
187
200
|
|
|
188
201
|
/**
|
|
189
|
-
* Returns elements that include the text describing the monthly equivalent of the subscription.
|
|
190
|
-
* @returns {React.ReactElement}
|
|
202
|
+
* Returns elements that include the text describing the monthly equivalent of the subscription, if available.
|
|
203
|
+
* @returns {React.ReactElement | null}
|
|
191
204
|
*/
|
|
192
205
|
const getEquivalentMonthlyPriceText = () => {
|
|
206
|
+
const equivalentMonthlyPrice = getEquivalentMonthlyPrice();
|
|
207
|
+
|
|
208
|
+
if (!equivalentMonthlyPrice) {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
193
211
|
return (
|
|
194
212
|
<span className="ncf__payment-term__equivalent-price">
|
|
195
213
|
That’s equivalent to{' '}
|
|
196
214
|
<span className="ncf__payment-term__monthly-price">
|
|
197
|
-
{
|
|
215
|
+
{equivalentMonthlyPrice}
|
|
198
216
|
</span>{' '}
|
|
199
217
|
per month
|
|
200
218
|
</span>
|
|
@@ -261,9 +279,7 @@ export function PaymentTerm({
|
|
|
261
279
|
return (
|
|
262
280
|
<div className="ncf__payment-term__description">
|
|
263
281
|
{getPriceText()}
|
|
264
|
-
|
|
265
|
-
{is90DaysOrLonger(option.value) && getEquivalentMonthlyPriceText()}
|
|
266
|
-
|
|
282
|
+
{getEquivalentMonthlyPriceText()}
|
|
267
283
|
{option.subscriptionAutoRenewTerm && getRenewalPeriodText()}
|
|
268
284
|
</div>
|
|
269
285
|
);
|
|
@@ -8,6 +8,20 @@ import { expectToRenderCorrectly } from '../test-jest/helpers/expect-to-render-c
|
|
|
8
8
|
expect.extend(expectToRenderCorrectly);
|
|
9
9
|
Enzyme.configure({ adapter: new Adapter() });
|
|
10
10
|
|
|
11
|
+
const mockGetMonthlyEquivalentIf90DaysOrLonger = jest.fn();
|
|
12
|
+
|
|
13
|
+
jest.mock('@financial-times/n-pricing', () => {
|
|
14
|
+
const actual = jest.requireActual('@financial-times/n-pricing');
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
...actual,
|
|
18
|
+
Price: jest.fn().mockImplementation(() => ({
|
|
19
|
+
getMonthlyEquivalentIf90DaysOrLonger:
|
|
20
|
+
mockGetMonthlyEquivalentIf90DaysOrLonger,
|
|
21
|
+
})),
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
|
|
11
25
|
const buildOption = (overrides = {}) => ({
|
|
12
26
|
name: 'monthly',
|
|
13
27
|
price: '£20.00',
|
|
@@ -21,6 +35,10 @@ const buildOption = (overrides = {}) => ({
|
|
|
21
35
|
});
|
|
22
36
|
|
|
23
37
|
describe('PaymentTerm', () => {
|
|
38
|
+
beforeEach(() => {
|
|
39
|
+
mockGetMonthlyEquivalentIf90DaysOrLonger.mockReset();
|
|
40
|
+
});
|
|
41
|
+
|
|
24
42
|
describe('default props are used', () => {
|
|
25
43
|
it('renders correctly', () => {
|
|
26
44
|
const props = {};
|
|
@@ -478,6 +496,9 @@ describe('PaymentTerm', () => {
|
|
|
478
496
|
describe('option.monthlyPrice is provided', () => {
|
|
479
497
|
describe('option.monthlyPrice value is "0"', () => {
|
|
480
498
|
it('displays the equivalent monthly price calculated from the option property values', () => {
|
|
499
|
+
mockGetMonthlyEquivalentIf90DaysOrLonger.mockReturnValue({
|
|
500
|
+
amount: { value: '£10.00' },
|
|
501
|
+
});
|
|
481
502
|
const option = buildOption({
|
|
482
503
|
name: 'annual',
|
|
483
504
|
value: 'P1Y',
|
|
@@ -503,6 +524,9 @@ describe('PaymentTerm', () => {
|
|
|
503
524
|
|
|
504
525
|
describe('option.monthlyPrice value can be parsed as a number, e.g. 54.17', () => {
|
|
505
526
|
it('displays the equivalent monthly price constructed from option.symbol and option.monthlyPrice values', () => {
|
|
527
|
+
mockGetMonthlyEquivalentIf90DaysOrLonger.mockReturnValue({
|
|
528
|
+
amount: { value: '£99.99' }, // This value should be ignored in favour of the option.monthlyPrice value
|
|
529
|
+
});
|
|
506
530
|
const option = buildOption({
|
|
507
531
|
name: 'annual',
|
|
508
532
|
value: 'P1Y',
|
|
@@ -526,8 +550,11 @@ describe('PaymentTerm', () => {
|
|
|
526
550
|
});
|
|
527
551
|
});
|
|
528
552
|
|
|
529
|
-
describe('option.monthlyPrice value cannot be
|
|
553
|
+
describe('option.monthlyPrice value cannot be parsed as a number, e.g. "£54.17"', () => {
|
|
530
554
|
it('displays the equivalent monthly price derived directly from the option.monthlyPrice value', () => {
|
|
555
|
+
mockGetMonthlyEquivalentIf90DaysOrLonger.mockReturnValue({
|
|
556
|
+
amount: { value: '£99.99' }, // This value should be ignored in favour of the option.monthlyPrice value
|
|
557
|
+
});
|
|
531
558
|
const option = buildOption({
|
|
532
559
|
name: 'annual',
|
|
533
560
|
value: 'P1Y',
|
|
@@ -554,6 +581,9 @@ describe('PaymentTerm', () => {
|
|
|
554
581
|
|
|
555
582
|
describe('option.monthlyPrice is not provided', () => {
|
|
556
583
|
it('displays the equivalent monthly price calculated from the option property values', () => {
|
|
584
|
+
mockGetMonthlyEquivalentIf90DaysOrLonger.mockReturnValue({
|
|
585
|
+
amount: { value: '£10.00' },
|
|
586
|
+
});
|
|
557
587
|
const option = buildOption({
|
|
558
588
|
name: 'annual',
|
|
559
589
|
value: 'P1Y',
|
|
@@ -580,6 +610,7 @@ describe('PaymentTerm', () => {
|
|
|
580
610
|
|
|
581
611
|
describe('offer term is shorter than 90 days', () => {
|
|
582
612
|
it('does not display the equivalent monthly price', () => {
|
|
613
|
+
mockGetMonthlyEquivalentIf90DaysOrLonger.mockReturnValue(undefined);
|
|
583
614
|
const options = [
|
|
584
615
|
buildOption({
|
|
585
616
|
value: 'P8W',
|
package/dist/payment-term.jsx
CHANGED
|
@@ -103,16 +103,18 @@ function PaymentTerm(_ref) {
|
|
|
103
103
|
};
|
|
104
104
|
|
|
105
105
|
/**
|
|
106
|
-
* Compute monthly price for given term name.
|
|
107
|
-
* @returns {string}
|
|
106
|
+
* Compute monthly price for given term name, if the term if 90 days or longer.
|
|
107
|
+
* @returns {string | undefined}
|
|
108
108
|
*/
|
|
109
|
-
var
|
|
110
|
-
var
|
|
111
|
-
var
|
|
112
|
-
|
|
113
|
-
value: monthlyPrice,
|
|
109
|
+
var getCalculatedMonthlyPriceIfEligible = function getCalculatedMonthlyPriceIfEligible() {
|
|
110
|
+
var _priceObject$getMonth;
|
|
111
|
+
var priceObject = new _nPricing.Price({
|
|
112
|
+
value: option.amount,
|
|
114
113
|
symbol: option.symbol
|
|
115
|
-
}
|
|
114
|
+
}, {
|
|
115
|
+
period: option.value
|
|
116
|
+
});
|
|
117
|
+
return (_priceObject$getMonth = priceObject.getMonthlyEquivalentIf90DaysOrLonger()) === null || _priceObject$getMonth === void 0 ? void 0 : _priceObject$getMonth.amount.value;
|
|
116
118
|
};
|
|
117
119
|
|
|
118
120
|
/**
|
|
@@ -155,7 +157,7 @@ function PaymentTerm(_ref) {
|
|
|
155
157
|
};
|
|
156
158
|
|
|
157
159
|
/**
|
|
158
|
-
* Returns elements that include the text describing how regularly an auto-
|
|
160
|
+
* Returns elements that include the text describing how regularly an auto-renewing subscription will renew.
|
|
159
161
|
* @returns {React.ReactElement}
|
|
160
162
|
*/
|
|
161
163
|
var getRenewalPeriodText = function getRenewalPeriodText() {
|
|
@@ -168,25 +170,35 @@ function PaymentTerm(_ref) {
|
|
|
168
170
|
|
|
169
171
|
/**
|
|
170
172
|
* Returns elements that include the text describing the monthly equivalent of the subscription.
|
|
171
|
-
*
|
|
173
|
+
* Returns null if the term is shorter than 90 days
|
|
174
|
+
* @returns {string | null}
|
|
172
175
|
*/
|
|
173
176
|
var getEquivalentMonthlyPrice = function getEquivalentMonthlyPrice() {
|
|
174
|
-
|
|
177
|
+
var calculatedMonthlyPrice = getCalculatedMonthlyPriceIfEligible();
|
|
178
|
+
if (!calculatedMonthlyPrice) {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
var hasValidMonthlyPrice = option.monthlyPrice !== null && option.monthlyPrice !== undefined && option.monthlyPrice !== '' && option.monthlyPrice !== '0';
|
|
182
|
+
if (hasValidMonthlyPrice) {
|
|
175
183
|
return isNaN(option.monthlyPrice) ? option.monthlyPrice : "".concat(option.symbol).concat(option.monthlyPrice);
|
|
176
184
|
}
|
|
177
|
-
return
|
|
185
|
+
return calculatedMonthlyPrice;
|
|
178
186
|
};
|
|
179
187
|
|
|
180
188
|
/**
|
|
181
|
-
* Returns elements that include the text describing the monthly equivalent of the subscription.
|
|
182
|
-
* @returns {React.ReactElement}
|
|
189
|
+
* Returns elements that include the text describing the monthly equivalent of the subscription, if available.
|
|
190
|
+
* @returns {React.ReactElement | null}
|
|
183
191
|
*/
|
|
184
192
|
var getEquivalentMonthlyPriceText = function getEquivalentMonthlyPriceText() {
|
|
193
|
+
var equivalentMonthlyPrice = getEquivalentMonthlyPrice();
|
|
194
|
+
if (!equivalentMonthlyPrice) {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
185
197
|
return /*#__PURE__*/_react["default"].createElement("span", {
|
|
186
198
|
className: "ncf__payment-term__equivalent-price"
|
|
187
199
|
}, "That\u2019s equivalent to", ' ', /*#__PURE__*/_react["default"].createElement("span", {
|
|
188
200
|
className: "ncf__payment-term__monthly-price"
|
|
189
|
-
},
|
|
201
|
+
}, equivalentMonthlyPrice), ' ', "per month");
|
|
190
202
|
};
|
|
191
203
|
|
|
192
204
|
/**
|
|
@@ -230,7 +242,7 @@ function PaymentTerm(_ref) {
|
|
|
230
242
|
if (isValidPeriod(option.value)) {
|
|
231
243
|
return /*#__PURE__*/_react["default"].createElement("div", {
|
|
232
244
|
className: "ncf__payment-term__description"
|
|
233
|
-
}, getPriceText(),
|
|
245
|
+
}, getPriceText(), getEquivalentMonthlyPriceText(), option.subscriptionAutoRenewTerm && getRenewalPeriodText());
|
|
234
246
|
}
|
|
235
247
|
return /*#__PURE__*/_react["default"].createElement("div", null, /*#__PURE__*/_react["default"].createElement("span", {
|
|
236
248
|
className: largePrice ? 'ncf__payment-term__large-price' : ''
|
|
@@ -45,7 +45,6 @@ const DAYS_IN_A_YEAR = 365; // Disregarding leap years
|
|
|
45
45
|
const DAYS_IN_A_MONTH = 30; // Approximate
|
|
46
46
|
const DAYS_IN_A_WEEK = 7;
|
|
47
47
|
|
|
48
|
-
const DAYS_IN_90_DAYS = 90;
|
|
49
48
|
const DAYS_IN_52_WEEKS = 52 * DAYS_IN_A_WEEK;
|
|
50
49
|
|
|
51
50
|
/**
|
|
@@ -85,20 +84,7 @@ const is52WeeksOrLonger = (iso8601Duration) => {
|
|
|
85
84
|
return totalDays >= DAYS_IN_52_WEEKS;
|
|
86
85
|
};
|
|
87
86
|
|
|
88
|
-
/**
|
|
89
|
-
* Approximate check of whether an ISO 8601 duration is 90 days or longer.
|
|
90
|
-
* @param {string} iso8601Duration
|
|
91
|
-
* @returns {boolean}
|
|
92
|
-
*/
|
|
93
|
-
const is90DaysOrLonger = (iso8601Duration) => {
|
|
94
|
-
const totalDays = parseISODurationToDays(iso8601Duration);
|
|
95
|
-
if (totalDays === null) return false;
|
|
96
|
-
|
|
97
|
-
return totalDays >= DAYS_IN_90_DAYS;
|
|
98
|
-
};
|
|
99
|
-
|
|
100
87
|
module.exports = {
|
|
101
88
|
getDurationFromISO8601Value,
|
|
102
89
|
is52WeeksOrLonger,
|
|
103
|
-
is90DaysOrLonger,
|
|
104
90
|
};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
const {
|
|
2
2
|
getDurationFromISO8601Value,
|
|
3
3
|
is52WeeksOrLonger,
|
|
4
|
-
is90DaysOrLonger,
|
|
5
4
|
} = require('./duration-helpers');
|
|
6
5
|
|
|
7
6
|
describe('Duration Utils', () => {
|
|
@@ -140,36 +139,4 @@ describe('Duration Utils', () => {
|
|
|
140
139
|
});
|
|
141
140
|
});
|
|
142
141
|
});
|
|
143
|
-
|
|
144
|
-
describe('is90DaysOrLonger', () => {
|
|
145
|
-
describe('returns true for durations >= 90 days', () => {
|
|
146
|
-
const DURATIONS_OF_90_DAYS_OR_MORE = [
|
|
147
|
-
'P3Y',
|
|
148
|
-
'P26M',
|
|
149
|
-
'P2Y',
|
|
150
|
-
'P13M',
|
|
151
|
-
'P1Y',
|
|
152
|
-
'P52W',
|
|
153
|
-
'P6M',
|
|
154
|
-
'P13W',
|
|
155
|
-
'P3M',
|
|
156
|
-
];
|
|
157
|
-
|
|
158
|
-
DURATIONS_OF_90_DAYS_OR_MORE.forEach((duration) => {
|
|
159
|
-
it(`returns true for ${duration}`, () => {
|
|
160
|
-
expect(is90DaysOrLonger(duration)).toBe(true);
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
describe('returns false for durations < 90 days', () => {
|
|
166
|
-
const DURATIONS_OF_LESS_THAN_90_DAYS = ['P8W', 'P1M'];
|
|
167
|
-
|
|
168
|
-
DURATIONS_OF_LESS_THAN_90_DAYS.forEach((duration) => {
|
|
169
|
-
it(`returns false for ${duration}`, () => {
|
|
170
|
-
expect(is90DaysOrLonger(duration)).toBe(false);
|
|
171
|
-
});
|
|
172
|
-
});
|
|
173
|
-
});
|
|
174
|
-
});
|
|
175
142
|
});
|
package/helpers/index.js
CHANGED
package/helpers/index.spec.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@financial-times/n-conversion-forms",
|
|
3
|
-
"version": "47.0.
|
|
3
|
+
"version": "47.0.1",
|
|
4
4
|
"description": "Containing jsx components and styles for forms included on Accounts and Acquisition apps (next-signup, next-profile, next-retention, etc).",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"homepage": "https://github.com/Financial-Times/n-conversion-forms#readme",
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@babel/runtime": "^7.23.9",
|
|
28
|
-
"@financial-times/n-pricing": "8.
|
|
28
|
+
"@financial-times/n-pricing": "8.1.1",
|
|
29
29
|
"classnames": "2.5.1",
|
|
30
30
|
"fetchres": "1.7.2",
|
|
31
31
|
"lodash.get": "4.4.2",
|