@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.
@@ -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
  };
@@ -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": "46.0.0",
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": {
@@ -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
+ }
@@ -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
+ }