@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
|
@@ -3,6 +3,12 @@ import PropTypes from 'prop-types';
|
|
|
3
3
|
import classNames from 'classnames';
|
|
4
4
|
import { Period, Monthly } from '@financial-times/n-pricing';
|
|
5
5
|
|
|
6
|
+
import {
|
|
7
|
+
getDurationFromISO8601Value,
|
|
8
|
+
is52WeeksOrLonger,
|
|
9
|
+
is90DaysOrLonger,
|
|
10
|
+
} from '../helpers';
|
|
11
|
+
|
|
6
12
|
export function PaymentTerm({
|
|
7
13
|
fieldId = 'paymentTermField',
|
|
8
14
|
inputName = 'paymentTerm',
|
|
@@ -17,159 +23,40 @@ export function PaymentTerm({
|
|
|
17
23
|
isNonRenewingSubscriptionTermType = false,
|
|
18
24
|
}) {
|
|
19
25
|
/**
|
|
20
|
-
*
|
|
21
|
-
* @param {
|
|
22
|
-
* @param {string} currency country id of the currency
|
|
23
|
-
* @param {string} period (expressed in IS0 8601 duration format): e.g. PxY (yearly) or PxM (montly) where x is the amount of years/months
|
|
26
|
+
* Capitalises a string.
|
|
27
|
+
* @param {string} Input string to be capitalised
|
|
24
28
|
* @returns {string}
|
|
25
29
|
*/
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
const monthlyPrice = periodObj.calculatePrice('P1M', amount);
|
|
29
|
-
return new Monthly({ value: monthlyPrice, currency }).getAmount('monthly');
|
|
30
|
-
};
|
|
30
|
+
const capitalise = (string) =>
|
|
31
|
+
Boolean(string) ? string[0].toUpperCase() + string.slice(1) : string;
|
|
31
32
|
|
|
32
33
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* @
|
|
34
|
+
* Creates the JSX for a single payment-term option, including the input,
|
|
35
|
+
* title, discount messaging, and descriptive pricing copy.
|
|
36
|
+
*
|
|
37
|
+
* @param {Object} option - Payment term configuration
|
|
38
|
+
* @param {string} option.value - ISO 8601 duration of the subscription term of the offer
|
|
39
|
+
* @param {string} option.name - term name, e.g. "monthly", "annual", "2 yearly
|
|
40
|
+
* @param {string} option.price - Formatted display price
|
|
41
|
+
* @param {string|number} [option.amount] - Price expressed in numerical terms
|
|
42
|
+
* @param {string} [option.symbol] - Currency symbol, e.g. £
|
|
43
|
+
* @param {string} [option.monthlyPrice] - Precomputed monthly equivalent price (can be with or without currency symbol)
|
|
44
|
+
* @param {boolean} [option.discount] - Whether the option should display discount messaging
|
|
45
|
+
* @param {boolean} [option.bestOffer] - Whether the option should show "Best offer" instead of standard discount copy
|
|
46
|
+
* @param {boolean} [option.selected] - Whether the option is selected by default
|
|
47
|
+
* @param {boolean} [option.isTrial] - Whether the option is a trial offer
|
|
48
|
+
* @param {boolean} [option.subscriptionAutoRenewTerm] - Whether the option is for an auto-renewing subscription
|
|
49
|
+
* @param {number} [option.trialAmount] - Amount used for trial pricing
|
|
50
|
+
* @param {string} [option.trialDuration] - Human-readable trial duration copy
|
|
51
|
+
* @param {string} [option.trialPrice] - Formatted trial price
|
|
52
|
+
* @param {string} [option.displayName] - Override label for the term title
|
|
53
|
+
* @param {string} [option.title] - Fallback title for legacy or non-period terms
|
|
54
|
+
* @param {string} [option.subTitle] - Optional subtitle shown alongside the term title
|
|
55
|
+
* @param {string} [option.chargeOnText] - Optional charge timing copy for non-period offers
|
|
56
|
+
* @param {boolean} [option.b2cPartnership] - Whether the option is part of a B2C partnership offer
|
|
57
|
+
* @param {string} [option.b2cDiscountCopy] - Partnership-specific discount copy
|
|
58
|
+
* @returns {React.ReactElement} A rendered payment term option
|
|
37
59
|
*/
|
|
38
|
-
const getTimeFromPeriod = (period) => {
|
|
39
|
-
const periodUnitCodeToWordMap = {
|
|
40
|
-
Y: 'years',
|
|
41
|
-
M: 'months',
|
|
42
|
-
W: 'weeks',
|
|
43
|
-
D: 'days',
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
const periodUnitCode = period.substring(period.length - 1);
|
|
47
|
-
|
|
48
|
-
const freq = periodUnitCodeToWordMap[periodUnitCode] || '';
|
|
49
|
-
|
|
50
|
-
const amount = period.substring(1, period.length - 1);
|
|
51
|
-
|
|
52
|
-
return period ? `${amount} ${freq}` : '';
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const isValidPeriod = (period) => {
|
|
56
|
-
try {
|
|
57
|
-
// Period should throw an error if it is not properly provided
|
|
58
|
-
// in order to validate it, we just send in case type is string
|
|
59
|
-
new Period(typeof period === 'string' ? period : '');
|
|
60
|
-
return true;
|
|
61
|
-
} catch (e) {
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
const nameMap = {
|
|
67
|
-
annual: {
|
|
68
|
-
title: 'Annual',
|
|
69
|
-
price: (price) => (
|
|
70
|
-
<React.Fragment>
|
|
71
|
-
Single{' '}
|
|
72
|
-
<span className="ncf__payment-term__price ncf__strong">{price}</span>{' '}
|
|
73
|
-
payment
|
|
74
|
-
</React.Fragment>
|
|
75
|
-
),
|
|
76
|
-
trialPrice: (price) => (
|
|
77
|
-
<React.Fragment>
|
|
78
|
-
Unless you cancel during your trial you will be billed{' '}
|
|
79
|
-
<span className="ncf__payment-term__price">{price}</span> per year
|
|
80
|
-
after the trial period.
|
|
81
|
-
</React.Fragment>
|
|
82
|
-
),
|
|
83
|
-
monthlyPrice: (price) =>
|
|
84
|
-
price && (
|
|
85
|
-
<span className="ncf__payment-term__equivalent-price">
|
|
86
|
-
That’s equivalent to{' '}
|
|
87
|
-
<span className="ncf__payment-term__monthly-price">{price}</span>{' '}
|
|
88
|
-
per month
|
|
89
|
-
</span>
|
|
90
|
-
),
|
|
91
|
-
renewsText: () => (
|
|
92
|
-
<p className="ncf__payment-term__renews-text">
|
|
93
|
-
Renews annually unless cancelled
|
|
94
|
-
</p>
|
|
95
|
-
),
|
|
96
|
-
},
|
|
97
|
-
quarterly: {
|
|
98
|
-
title: 'Quarterly',
|
|
99
|
-
price: (price) => (
|
|
100
|
-
<React.Fragment>
|
|
101
|
-
<span className="ncf__payment-term__price">{price}</span> per quarter
|
|
102
|
-
</React.Fragment>
|
|
103
|
-
),
|
|
104
|
-
trialPrice: (price) => (
|
|
105
|
-
<React.Fragment>
|
|
106
|
-
Unless you cancel during your trial you will be billed{' '}
|
|
107
|
-
<span className="ncf__payment-term__price">{price}</span> per quarter
|
|
108
|
-
after the trial period.
|
|
109
|
-
</React.Fragment>
|
|
110
|
-
),
|
|
111
|
-
monthlyPrice: () => {},
|
|
112
|
-
renewsText: () => (
|
|
113
|
-
<p className="ncf__payment-term__renews-text">
|
|
114
|
-
Renews quarterly unless cancelled
|
|
115
|
-
</p>
|
|
116
|
-
),
|
|
117
|
-
},
|
|
118
|
-
monthly: {
|
|
119
|
-
title: 'Monthly',
|
|
120
|
-
price: (price) => (
|
|
121
|
-
<React.Fragment>
|
|
122
|
-
<span className="ncf__payment-term__price">{price}</span> per month
|
|
123
|
-
</React.Fragment>
|
|
124
|
-
),
|
|
125
|
-
trialPrice: (price) => (
|
|
126
|
-
<React.Fragment>
|
|
127
|
-
Unless you cancel during your trial you will be billed{' '}
|
|
128
|
-
<span className="ncf__payment-term__price">{price}</span> per month
|
|
129
|
-
after the trial period.
|
|
130
|
-
</React.Fragment>
|
|
131
|
-
),
|
|
132
|
-
monthlyPrice: () => {},
|
|
133
|
-
renewsText: () => (
|
|
134
|
-
<p className="ncf__payment-term__renews-text">
|
|
135
|
-
{'Renews monthly unless cancelled'}
|
|
136
|
-
</p>
|
|
137
|
-
),
|
|
138
|
-
},
|
|
139
|
-
custom: {
|
|
140
|
-
price: (price) => (
|
|
141
|
-
<React.Fragment>
|
|
142
|
-
Single{' '}
|
|
143
|
-
<span className="ncf__payment-term__price ncf__strong">{price}</span>{' '}
|
|
144
|
-
payment
|
|
145
|
-
</React.Fragment>
|
|
146
|
-
),
|
|
147
|
-
trialPrice: (trialPrice, trialPeriod) => (
|
|
148
|
-
<React.Fragment>
|
|
149
|
-
Unless you cancel during your trial you will be billed{' '}
|
|
150
|
-
<span className="ncf__payment-term__price">{trialPrice}</span> per{' '}
|
|
151
|
-
{trialPeriod}
|
|
152
|
-
after the trial period.
|
|
153
|
-
</React.Fragment>
|
|
154
|
-
),
|
|
155
|
-
monthlyPrice: (monthlyPrice) =>
|
|
156
|
-
Boolean(monthlyPrice) && (
|
|
157
|
-
<span className="ncf__payment-term__equivalent-price">
|
|
158
|
-
That’s equivalent to{' '}
|
|
159
|
-
<span className="ncf__payment-term__monthly-price">
|
|
160
|
-
{monthlyPrice}
|
|
161
|
-
</span>{' '}
|
|
162
|
-
per month
|
|
163
|
-
</span>
|
|
164
|
-
),
|
|
165
|
-
renewsText: (renewalPeriod) =>
|
|
166
|
-
Boolean(renewalPeriod) && (
|
|
167
|
-
<p className="ncf__payment-term__renews-text">
|
|
168
|
-
Renews every {renewalPeriod} unless cancelled
|
|
169
|
-
</p>
|
|
170
|
-
),
|
|
171
|
-
},
|
|
172
|
-
};
|
|
173
60
|
const createPaymentTerm = (option) => {
|
|
174
61
|
const className = classNames([
|
|
175
62
|
'ncf__payment-term__item',
|
|
@@ -187,6 +74,139 @@ export function PaymentTerm({
|
|
|
187
74
|
...(option.selected && { defaultChecked: true }),
|
|
188
75
|
};
|
|
189
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Determines whether input is a valid ISO 8601 duration value that can be decoded by the Period class.
|
|
79
|
+
* @returns {boolean}
|
|
80
|
+
*/
|
|
81
|
+
const isValidPeriod = () => {
|
|
82
|
+
try {
|
|
83
|
+
// Period should throw an error if it is not properly provided
|
|
84
|
+
// in order to validate it, we just send in case type is string
|
|
85
|
+
new Period(typeof option.value === 'string' ? option.value : '');
|
|
86
|
+
return true;
|
|
87
|
+
} catch (error) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Compute monthly price for given term name.
|
|
94
|
+
* @returns {string}
|
|
95
|
+
*/
|
|
96
|
+
const getMonthlyPriceFromPeriod = () => {
|
|
97
|
+
const periodObj = new Period(option.value);
|
|
98
|
+
const monthlyPrice = periodObj.calculatePrice('P1M', option.amount);
|
|
99
|
+
return new Monthly({
|
|
100
|
+
value: monthlyPrice,
|
|
101
|
+
symbol: option.symbol,
|
|
102
|
+
}).getAmount('monthly');
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Returns elements that include the text describing the price of the offer option.
|
|
107
|
+
* @returns {React.ReactElement}
|
|
108
|
+
*/
|
|
109
|
+
const getPriceText = () => {
|
|
110
|
+
const isExpressedAsSinglePayment =
|
|
111
|
+
!option.subscriptionAutoRenewTerm ||
|
|
112
|
+
// With an auto-renewing annual term there is a high chance
|
|
113
|
+
// it will not be the same price in the second year,
|
|
114
|
+
// so we do not want to imply that the price will remain consistent.
|
|
115
|
+
// For shorter auto-renewing terms there is higher confidence that the price
|
|
116
|
+
// will remain consistent across subsequent terms.
|
|
117
|
+
(option.subscriptionAutoRenewTerm && is52WeeksOrLonger(option.value));
|
|
118
|
+
|
|
119
|
+
const isExpressedAsRecurringPayment = !isExpressedAsSinglePayment;
|
|
120
|
+
|
|
121
|
+
if (isExpressedAsSinglePayment) {
|
|
122
|
+
return (
|
|
123
|
+
<React.Fragment>
|
|
124
|
+
Single{' '}
|
|
125
|
+
<span className="ncf__payment-term__price">{option.price}</span>{' '}
|
|
126
|
+
payment
|
|
127
|
+
</React.Fragment>
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (isExpressedAsRecurringPayment) {
|
|
132
|
+
return (
|
|
133
|
+
<React.Fragment>
|
|
134
|
+
<span className="ncf__payment-term__price">{option.price}</span> per{' '}
|
|
135
|
+
{getDurationFromISO8601Value({
|
|
136
|
+
iso8601Value: option.value,
|
|
137
|
+
})}
|
|
138
|
+
</React.Fragment>
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Returns elements that include the text describing the price increase following the trial period.
|
|
145
|
+
* @returns {React.ReactElement}
|
|
146
|
+
*/
|
|
147
|
+
const getTrialPriceExplanatoryText = () => {
|
|
148
|
+
return (
|
|
149
|
+
<React.Fragment>
|
|
150
|
+
Unless you cancel during your trial you will be billed{' '}
|
|
151
|
+
<span className="ncf__payment-term__price">{option.price}</span> per{' '}
|
|
152
|
+
{getDurationFromISO8601Value({
|
|
153
|
+
iso8601Value: option.value,
|
|
154
|
+
})}{' '}
|
|
155
|
+
after the trial period.
|
|
156
|
+
</React.Fragment>
|
|
157
|
+
);
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Returns elements that include the text describing how regularly an auto-reniewing subscription will renew.
|
|
162
|
+
* @returns {React.ReactElement}
|
|
163
|
+
*/
|
|
164
|
+
const getRenewalPeriodText = () => {
|
|
165
|
+
return (
|
|
166
|
+
<p className="ncf__payment-term__renews-text">
|
|
167
|
+
Renews every{' '}
|
|
168
|
+
{getDurationFromISO8601Value({ iso8601Value: option.value })} unless
|
|
169
|
+
cancelled
|
|
170
|
+
</p>
|
|
171
|
+
);
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Returns elements that include the text describing the monthly equivalent of the subscription.
|
|
176
|
+
* @returns {string}
|
|
177
|
+
*/
|
|
178
|
+
const getEquivalentMonthlyPrice = () => {
|
|
179
|
+
if (Boolean(option.monthlyPrice) && option.monthlyPrice !== '0') {
|
|
180
|
+
return isNaN(option.monthlyPrice)
|
|
181
|
+
? option.monthlyPrice
|
|
182
|
+
: `${option.symbol}${option.monthlyPrice}`;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return getMonthlyPriceFromPeriod();
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Returns elements that include the text describing the monthly equivalent of the subscription.
|
|
190
|
+
* @returns {React.ReactElement}
|
|
191
|
+
*/
|
|
192
|
+
const getEquivalentMonthlyPriceText = () => {
|
|
193
|
+
return (
|
|
194
|
+
<span className="ncf__payment-term__equivalent-price">
|
|
195
|
+
That’s equivalent to{' '}
|
|
196
|
+
<span className="ncf__payment-term__monthly-price">
|
|
197
|
+
{getEquivalentMonthlyPrice()}
|
|
198
|
+
</span>{' '}
|
|
199
|
+
per month
|
|
200
|
+
</span>
|
|
201
|
+
);
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Creates the standard discount badge for an option.
|
|
206
|
+
* Displays either "Best offer" or "Save X off RRP" when a discount exists.
|
|
207
|
+
*
|
|
208
|
+
* @returns {React.ReactElement} The discount element, or false when no discount should be shown
|
|
209
|
+
*/
|
|
190
210
|
const createDiscount = () => {
|
|
191
211
|
return (
|
|
192
212
|
option.discount && (
|
|
@@ -199,6 +219,11 @@ export function PaymentTerm({
|
|
|
199
219
|
);
|
|
200
220
|
};
|
|
201
221
|
|
|
222
|
+
/**
|
|
223
|
+
* Creates B2C partnership discount copy for eligible annual offers.
|
|
224
|
+
*
|
|
225
|
+
* @returns {React.ReactElement} The B2C discount element, or false when the option is not eligible
|
|
226
|
+
*/
|
|
202
227
|
const createB2cDiscountCopy = () => {
|
|
203
228
|
return (
|
|
204
229
|
option.name === 'annual' &&
|
|
@@ -211,70 +236,65 @@ export function PaymentTerm({
|
|
|
211
236
|
);
|
|
212
237
|
};
|
|
213
238
|
|
|
239
|
+
/**
|
|
240
|
+
* Creates the description shown beneath the term title.
|
|
241
|
+
* This may include trial copy, price-per-period copy, equivalent monthly price,
|
|
242
|
+
* renewal messaging, or fallback non-period pricing text.
|
|
243
|
+
*
|
|
244
|
+
* @returns {React.ReactElement} The description block for the payment term
|
|
245
|
+
*/
|
|
214
246
|
const createDescription = () => {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
247
|
+
if (option.isTrial) {
|
|
248
|
+
return (
|
|
249
|
+
<div className="ncf__payment-term__description">
|
|
250
|
+
{option.trialDuration || '4 weeks'} for{' '}
|
|
251
|
+
<span className="ncf__payment-term__trial-price">
|
|
252
|
+
{option.trialPrice}
|
|
253
|
+
</span>
|
|
254
|
+
<br />
|
|
255
|
+
{getTrialPriceExplanatoryText()}
|
|
256
|
+
</div>
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (isValidPeriod(option.value)) {
|
|
261
|
+
return (
|
|
262
|
+
<div className="ncf__payment-term__description">
|
|
263
|
+
{getPriceText()}
|
|
264
|
+
|
|
265
|
+
{is90DaysOrLonger(option.value) && getEquivalentMonthlyPriceText()}
|
|
266
|
+
|
|
267
|
+
{option.subscriptionAutoRenewTerm && getRenewalPeriodText()}
|
|
268
|
+
</div>
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return (
|
|
273
|
+
<div>
|
|
274
|
+
<span className={largePrice ? 'ncf__payment-term__large-price' : ''}>
|
|
275
|
+
{option.price}
|
|
220
276
|
</span>
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
) : (
|
|
226
|
-
<React.Fragment>
|
|
227
|
-
{nameMap[option.name] ? (
|
|
228
|
-
<div className="ncf__payment-term__description">
|
|
229
|
-
{nameMap[option.name].price(option.price)}
|
|
230
|
-
{nameMap[option.name].monthlyPrice(option.monthlyPrice)}
|
|
231
|
-
{isAutoRenewingSubscriptionTermType &&
|
|
232
|
-
nameMap[option.name].renewsText()}
|
|
233
|
-
{/* Remove this discount text temporarily in favour of monthly price */}
|
|
234
|
-
{/* <br />Save up to 25% when you pay annually */}
|
|
235
|
-
</div>
|
|
236
|
-
) : // this should cover the cases different than annual, quarterly and monthly
|
|
237
|
-
// for those containing period on option.value, render custom template, for the rest keep legacy render
|
|
238
|
-
isValidPeriod(option.value) ? (
|
|
239
|
-
<div className="ncf__payment-term__description">
|
|
240
|
-
{nameMap['custom'].price(option.price)}
|
|
241
|
-
{nameMap['custom'].monthlyPrice(
|
|
242
|
-
option.monthlyPrice && option.monthlyPrice !== '0'
|
|
243
|
-
? Number(option.monthlyPrice)
|
|
244
|
-
: getMonthlyPriceFromPeriod(
|
|
245
|
-
option.amount,
|
|
246
|
-
option.currency,
|
|
247
|
-
option.value
|
|
248
|
-
)
|
|
249
|
-
)}
|
|
250
|
-
{isAutoRenewingSubscriptionTermType &&
|
|
251
|
-
nameMap['custom'].renewsText(getTimeFromPeriod(option.value))}
|
|
252
|
-
</div>
|
|
253
|
-
) : (
|
|
254
|
-
<div>
|
|
255
|
-
<span
|
|
256
|
-
className={largePrice ? 'ncf__payment-term__large-price' : ''}
|
|
257
|
-
>
|
|
258
|
-
{option.price}
|
|
259
|
-
</span>
|
|
260
|
-
{option.chargeOnText && (
|
|
261
|
-
<p className="ncf__payment-term__charge-on-text">
|
|
262
|
-
{option.chargeOnText}
|
|
263
|
-
</p>
|
|
264
|
-
)}
|
|
265
|
-
</div>
|
|
277
|
+
{option.chargeOnText && (
|
|
278
|
+
<p className="ncf__payment-term__charge-on-text">
|
|
279
|
+
{option.chargeOnText}
|
|
280
|
+
</p>
|
|
266
281
|
)}
|
|
267
|
-
</
|
|
282
|
+
</div>
|
|
268
283
|
);
|
|
269
284
|
};
|
|
270
285
|
|
|
286
|
+
/**
|
|
287
|
+
* Builds the display name shown as the payment term title.
|
|
288
|
+
* May prepend trial copy, use the capitalised term name for auto-renewing terms,
|
|
289
|
+
* derive a human-readable period for valid non-renewing terms, or fall back to
|
|
290
|
+
* a legacy title when no valid period is available.
|
|
291
|
+
*
|
|
292
|
+
* @returns {string} The formatted display name for the payment term
|
|
293
|
+
*/
|
|
271
294
|
const getTermDisplayName = () => {
|
|
272
295
|
const showTrialCopyInTitle =
|
|
273
296
|
option.isTrial && !isPrintOrBundle && !isDigitalEdition;
|
|
274
297
|
|
|
275
|
-
const title =
|
|
276
|
-
option.name && nameMap[option.name] ? nameMap[option.name].title : '';
|
|
277
|
-
|
|
278
298
|
let termDisplayName = '';
|
|
279
299
|
if (showTrialCopyInTitle) {
|
|
280
300
|
const termName = option.displayName
|
|
@@ -284,13 +304,16 @@ export function PaymentTerm({
|
|
|
284
304
|
}
|
|
285
305
|
|
|
286
306
|
const getTermPeriod = () => {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
return title;
|
|
307
|
+
if (option.subscriptionAutoRenewTerm && option.name) {
|
|
308
|
+
return capitalise(option.name);
|
|
290
309
|
}
|
|
310
|
+
|
|
291
311
|
// custom offer with period provided
|
|
292
|
-
if (isValidPeriod(option.value)) {
|
|
293
|
-
return
|
|
312
|
+
if (!option.subscriptionAutoRenewTerm && isValidPeriod(option.value)) {
|
|
313
|
+
return getDurationFromISO8601Value({
|
|
314
|
+
iso8601Value: option.value,
|
|
315
|
+
excludeAmountWhenSingular: false,
|
|
316
|
+
});
|
|
294
317
|
}
|
|
295
318
|
// custom legacy cases, where period is not provided
|
|
296
319
|
return option.title;
|
|
@@ -399,12 +422,14 @@ PaymentTerm.propTypes = {
|
|
|
399
422
|
isB2cPartnership: PropTypes.bool,
|
|
400
423
|
discount: PropTypes.string,
|
|
401
424
|
isTrial: PropTypes.bool,
|
|
425
|
+
subscriptionAutoRenewTerm: PropTypes.bool,
|
|
402
426
|
name: PropTypes.string.isRequired,
|
|
403
427
|
price: PropTypes.string.isRequired,
|
|
404
428
|
selected: PropTypes.bool,
|
|
405
429
|
trialDuration: PropTypes.string,
|
|
406
430
|
trialPrice: PropTypes.string,
|
|
407
431
|
amount: PropTypes.string,
|
|
432
|
+
symbol: PropTypes.string,
|
|
408
433
|
trialAmount: PropTypes.number,
|
|
409
434
|
value: PropTypes.string.isRequired,
|
|
410
435
|
monthlyPrice: PropTypes.string,
|