@financial-times/n-conversion-forms 46.0.0 → 47.0.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/.toolkitstate/ci.json +3 -3
- package/components/__snapshots__/payment-term.spec.js.snap +1 -1031
- package/components/payment-term.jsx +232 -207
- package/components/payment-term.spec.js +646 -319
- package/components/payment-term.stories.js +135 -24
- package/dist/payment-term.jsx +186 -145
- package/helpers/duration-helpers.js +104 -0
- package/helpers/duration-helpers.spec.js +175 -0
- package/helpers/index.js +4 -0
- package/helpers/index.spec.js +12 -0
- package/package.json +1 -1
- package/styles/payment-term.scss +5 -5
- package/styles/payment-type.scss +11 -2
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns period converted to time if found
|
|
3
|
+
* otherwise returns empty string to avoid show information not mapped.
|
|
4
|
+
* @param {string} iso8601Value: PxY (yearly), PxM (montly), PxW (weekly), of PxD (daily), where x is the amount of years/months/weeks/days
|
|
5
|
+
* @param {boolean} excludeAmountWhenSingular: Omits the amount from the returned string when the discerned amount is singular.
|
|
6
|
+
* @returns {string}
|
|
7
|
+
*/
|
|
8
|
+
const getDurationFromISO8601Value = ({
|
|
9
|
+
iso8601Value,
|
|
10
|
+
excludeAmountWhenSingular = true,
|
|
11
|
+
}) => {
|
|
12
|
+
const amount = iso8601Value.substring(1, iso8601Value.length - 1);
|
|
13
|
+
|
|
14
|
+
const PERIOD_UNIT_CODE_TO_PLURAL_TERM_MAP = {
|
|
15
|
+
Y: 'years',
|
|
16
|
+
M: 'months',
|
|
17
|
+
W: 'weeks',
|
|
18
|
+
D: 'days',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const PERIOD_UNIT_CODE_TO_SINGULAR_TERM_MAP = {
|
|
22
|
+
Y: 'year',
|
|
23
|
+
M: 'month',
|
|
24
|
+
W: 'week',
|
|
25
|
+
D: 'day',
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const periodUnitCode = iso8601Value.substring(iso8601Value.length - 1);
|
|
29
|
+
|
|
30
|
+
if (iso8601Value) {
|
|
31
|
+
const unit =
|
|
32
|
+
amount === '1'
|
|
33
|
+
? PERIOD_UNIT_CODE_TO_SINGULAR_TERM_MAP[periodUnitCode] || ''
|
|
34
|
+
: PERIOD_UNIT_CODE_TO_PLURAL_TERM_MAP[periodUnitCode] || '';
|
|
35
|
+
|
|
36
|
+
return amount === '1' && excludeAmountWhenSingular
|
|
37
|
+
? unit
|
|
38
|
+
: `${amount} ${unit}`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return '';
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const DAYS_IN_A_YEAR = 365; // Disregarding leap years
|
|
45
|
+
const DAYS_IN_A_MONTH = 30; // Approximate
|
|
46
|
+
const DAYS_IN_A_WEEK = 7;
|
|
47
|
+
|
|
48
|
+
const DAYS_IN_90_DAYS = 90;
|
|
49
|
+
const DAYS_IN_52_WEEKS = 52 * DAYS_IN_A_WEEK;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Parses an ISO 8601 duration string and converts it into an approximate total number of days.
|
|
53
|
+
* @param {string} iso8601Duration: PxY (yearly), PxM (monthly), PxW (weekly), or PxD (daily), where x is the amount.
|
|
54
|
+
* @returns {number|null} Total number of days represented by the duration or null if the input is not a valid ISO 8601 duration.
|
|
55
|
+
*/
|
|
56
|
+
const parseISODurationToDays = (iso8601Duration) => {
|
|
57
|
+
const match = iso8601Duration.match(
|
|
58
|
+
/^P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)W)?(?:(\d+)D)?$/
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
if (!match) return null;
|
|
62
|
+
|
|
63
|
+
const years = Number(match[1] ?? 0);
|
|
64
|
+
const months = Number(match[2] ?? 0);
|
|
65
|
+
const weeks = Number(match[3] ?? 0);
|
|
66
|
+
const days = Number(match[4] ?? 0);
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
years * DAYS_IN_A_YEAR +
|
|
70
|
+
months * DAYS_IN_A_MONTH +
|
|
71
|
+
weeks * DAYS_IN_A_WEEK +
|
|
72
|
+
days
|
|
73
|
+
);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Approximate check of whether an ISO 8601 duration is 52 weeks or shorter.
|
|
78
|
+
* @param {string} iso8601Duration
|
|
79
|
+
* @returns {boolean}
|
|
80
|
+
*/
|
|
81
|
+
const is52WeeksOrLonger = (iso8601Duration) => {
|
|
82
|
+
const totalDays = parseISODurationToDays(iso8601Duration);
|
|
83
|
+
if (totalDays === null) return false;
|
|
84
|
+
|
|
85
|
+
return totalDays >= DAYS_IN_52_WEEKS;
|
|
86
|
+
};
|
|
87
|
+
|
|
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
|
+
module.exports = {
|
|
101
|
+
getDurationFromISO8601Value,
|
|
102
|
+
is52WeeksOrLonger,
|
|
103
|
+
is90DaysOrLonger,
|
|
104
|
+
};
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
const {
|
|
2
|
+
getDurationFromISO8601Value,
|
|
3
|
+
is52WeeksOrLonger,
|
|
4
|
+
is90DaysOrLonger,
|
|
5
|
+
} = require('./duration-helpers');
|
|
6
|
+
|
|
7
|
+
describe('Duration Utils', () => {
|
|
8
|
+
describe('getDurationFromISO8601Value', () => {
|
|
9
|
+
describe('plural units', () => {
|
|
10
|
+
const PLURAL_UNITS = [
|
|
11
|
+
{
|
|
12
|
+
input: 'P3Y',
|
|
13
|
+
expectation: '3 years',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
input: 'P26M',
|
|
17
|
+
expectation: '26 months',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
input: 'P2Y',
|
|
21
|
+
expectation: '2 years',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
input: 'P13M',
|
|
25
|
+
expectation: '13 months',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
input: 'P52W',
|
|
29
|
+
expectation: '52 weeks',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
input: 'P6M',
|
|
33
|
+
expectation: '6 months',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
input: 'P13W',
|
|
37
|
+
expectation: '13 weeks',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
input: 'P3M',
|
|
41
|
+
expectation: '3 months',
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
input: 'P8W',
|
|
45
|
+
expectation: '8 weeks',
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
PLURAL_UNITS.forEach(({ input, expectation }) => {
|
|
50
|
+
it(`returns "${expectation}" for ${input}`, () => {
|
|
51
|
+
expect(getDurationFromISO8601Value({ iso8601Value: input })).toBe(
|
|
52
|
+
expectation
|
|
53
|
+
);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe('singular units', () => {
|
|
59
|
+
describe('excludeAmountWhenSingular is true', () => {
|
|
60
|
+
const SINGULAR_UNITS = [
|
|
61
|
+
{
|
|
62
|
+
input: 'P1Y',
|
|
63
|
+
expectation: 'year',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
input: 'P1M',
|
|
67
|
+
expectation: 'month',
|
|
68
|
+
},
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
SINGULAR_UNITS.forEach(({ input, expectation }) => {
|
|
72
|
+
it(`returns "${expectation}" for ${input}`, () => {
|
|
73
|
+
expect(
|
|
74
|
+
getDurationFromISO8601Value({
|
|
75
|
+
iso8601Value: input,
|
|
76
|
+
excludeAmountWhenSingular: true,
|
|
77
|
+
})
|
|
78
|
+
).toBe(expectation);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe('excludeAmountWhenSingular is false', () => {
|
|
84
|
+
const SINGULAR_UNITS = [
|
|
85
|
+
{
|
|
86
|
+
input: 'P1Y',
|
|
87
|
+
expectation: '1 year',
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
input: 'P1M',
|
|
91
|
+
expectation: '1 month',
|
|
92
|
+
},
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
SINGULAR_UNITS.forEach(({ input, expectation }) => {
|
|
96
|
+
it(`returns "${expectation}" for ${input}`, () => {
|
|
97
|
+
expect(
|
|
98
|
+
getDurationFromISO8601Value({
|
|
99
|
+
iso8601Value: input,
|
|
100
|
+
excludeAmountWhenSingular: false,
|
|
101
|
+
})
|
|
102
|
+
).toBe(expectation);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
describe('is52WeeksOrLonger', () => {
|
|
110
|
+
describe('returns true for durations >= 52 weeks', () => {
|
|
111
|
+
const DURATIONS_OF_52_WEEKS_OR_MORE = [
|
|
112
|
+
'P3Y',
|
|
113
|
+
'P26M',
|
|
114
|
+
'P2Y',
|
|
115
|
+
'P13M',
|
|
116
|
+
'P1Y',
|
|
117
|
+
'P52W',
|
|
118
|
+
];
|
|
119
|
+
|
|
120
|
+
DURATIONS_OF_52_WEEKS_OR_MORE.forEach((duration) => {
|
|
121
|
+
it(`returns true for ${duration}`, () => {
|
|
122
|
+
expect(is52WeeksOrLonger(duration)).toBe(true);
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
describe('returns false for durations < 52 weeks', () => {
|
|
128
|
+
const DURATIONS_OF_LESS_THAN_52_WEEKS = [
|
|
129
|
+
'P8W',
|
|
130
|
+
'P1M',
|
|
131
|
+
'P3M',
|
|
132
|
+
'P13W',
|
|
133
|
+
'P6M',
|
|
134
|
+
];
|
|
135
|
+
|
|
136
|
+
DURATIONS_OF_LESS_THAN_52_WEEKS.forEach((duration) => {
|
|
137
|
+
it(`returns false for ${duration}`, () => {
|
|
138
|
+
expect(is52WeeksOrLonger(duration)).toBe(false);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
});
|
|
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
|
+
});
|
package/helpers/index.js
CHANGED
|
@@ -14,4 +14,8 @@ module.exports = {
|
|
|
14
14
|
allSupportedPostcodeExamples: require('./supportedPostcodeExamples')
|
|
15
15
|
.allSupportedPostcodeExamples,
|
|
16
16
|
billingCountries: require('./billing-countries').billingCountries,
|
|
17
|
+
getDurationFromISO8601Value:
|
|
18
|
+
require('./duration-helpers').getDurationFromISO8601Value,
|
|
19
|
+
is52WeeksOrLonger: require('./duration-helpers').is52WeeksOrLonger,
|
|
20
|
+
is90DaysOrLonger: require('./duration-helpers').is90DaysOrLonger,
|
|
17
21
|
};
|
package/helpers/index.spec.js
CHANGED
|
@@ -45,4 +45,16 @@ describe('helpers', () => {
|
|
|
45
45
|
it('export allSupportedPostcodeExamples', () => {
|
|
46
46
|
expect(helpers).toHaveProperty('allSupportedPostcodeExamples');
|
|
47
47
|
});
|
|
48
|
+
|
|
49
|
+
it('export getDurationFromISO8601Value', () => {
|
|
50
|
+
expect(helpers).toHaveProperty('getDurationFromISO8601Value');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('export is52WeeksOrLonger', () => {
|
|
54
|
+
expect(helpers).toHaveProperty('is52WeeksOrLonger');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('export is90DaysOrLonger', () => {
|
|
58
|
+
expect(helpers).toHaveProperty('is90DaysOrLonger');
|
|
59
|
+
});
|
|
48
60
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@financial-times/n-conversion-forms",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "47.0.0",
|
|
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": {
|
package/styles/payment-term.scss
CHANGED
|
@@ -58,6 +58,10 @@
|
|
|
58
58
|
margin: 20px 0;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
&__price, &__monthly-price, &__trial-price {
|
|
62
|
+
font-weight: var(--o3-font-weight-semibold);
|
|
63
|
+
}
|
|
64
|
+
|
|
61
65
|
&__equivalent-price {
|
|
62
66
|
font-family: var(--o3-type-detail-font-family);
|
|
63
67
|
font-size: var(--o3-type-detail-font-size);
|
|
@@ -66,10 +70,6 @@
|
|
|
66
70
|
display: block;
|
|
67
71
|
}
|
|
68
72
|
|
|
69
|
-
&__monthly-price {
|
|
70
|
-
font-weight: var(--o3-font-weight-semibold);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
73
|
&__large-price {
|
|
74
74
|
font-size: var(--o3-font-size-metric2-5);
|
|
75
75
|
line-height: var(--o3-font-lineheight-metric2-5);
|
|
@@ -108,4 +108,4 @@
|
|
|
108
108
|
margin-bottom: 2px;
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
|
-
}
|
|
111
|
+
}
|
package/styles/payment-type.scss
CHANGED
|
@@ -37,6 +37,15 @@
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
.o-forms-input--radio-box .o-forms-input--radio-box__container.ncf__payment-type--applepay {
|
|
41
|
+
|
|
42
|
+
// when the radio button is not checked
|
|
43
|
+
[type='radio']+.o-forms-input__label {
|
|
44
|
+
color: var(--o3-color-palette-black);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
}
|
|
48
|
+
|
|
40
49
|
@mixin ncfPaymentType() {
|
|
41
50
|
|
|
42
51
|
// #1 - Need to be this specific to override specific o-forms styles.
|
|
@@ -64,7 +73,7 @@
|
|
|
64
73
|
|
|
65
74
|
span {
|
|
66
75
|
max-height: none;
|
|
67
|
-
|
|
76
|
+
|
|
68
77
|
@include oGridRespondTo($from: L) {
|
|
69
78
|
line-height: var(--o3-spacing-2xs);
|
|
70
79
|
}
|
|
@@ -138,4 +147,4 @@
|
|
|
138
147
|
|
|
139
148
|
.o-forms-input.o-forms-input--checkbox.o-forms-input--suffix.ncf__payment-type-pay-faster-next-time-checkbox {
|
|
140
149
|
margin-top: var(--o3-spacing-3xs);
|
|
141
|
-
}
|
|
150
|
+
}
|