@financial-times/n-conversion-forms 46.0.1 → 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.
@@ -7,7 +7,7 @@ export default {
7
7
  component: PaymentTerm,
8
8
  };
9
9
 
10
- export const Basic = (args) => (
10
+ export const AutoRenewingTermType = (args) => (
11
11
  <div className="ncf">
12
12
  <Fieldset>
13
13
  <PaymentTerm {...args} />
@@ -15,8 +15,55 @@ export const Basic = (args) => (
15
15
  </div>
16
16
  );
17
17
 
18
- Basic.args = {
18
+ AutoRenewingTermType.args = {
19
19
  options: [
20
+ {
21
+ name: '3 yearly',
22
+ isTrial: false,
23
+ discount: '',
24
+ selected: false,
25
+ price: '$909.00',
26
+ trialPrice: '$0.00',
27
+ trialDuration: '',
28
+ monthlyPrice: '0',
29
+ amount: '909.00',
30
+ trialAmount: null,
31
+ value: 'P3Y',
32
+ symbol: '$',
33
+ subscriptionAutoRenewTerm: true,
34
+ },
35
+ {
36
+ name: '26 monthly',
37
+ isTrial: false,
38
+ discount: '',
39
+ selected: false,
40
+ price: '£335.00',
41
+ trialPrice: '£0.00',
42
+ trialDuration: '',
43
+ monthlyPrice: null,
44
+ amount: '335.00',
45
+ trialAmount: null,
46
+ value: 'P26M',
47
+ symbol: '£',
48
+ subscriptionAutoRenewTerm: true,
49
+ },
50
+ // 2 yearly (non-trial)
51
+ {
52
+ name: '2 yearly',
53
+ isTrial: false,
54
+ discount: '',
55
+ selected: false,
56
+ price: '£310.00',
57
+ trialPrice: '£0.00',
58
+ trialDuration: '',
59
+ monthlyPrice: null,
60
+ amount: '310.00',
61
+ trialAmount: null,
62
+ value: 'P2Y',
63
+ symbol: '£',
64
+ subscriptionAutoRenewTerm: true,
65
+ },
66
+ // 2 yearly (trial)
20
67
  {
21
68
  name: '2 yearly',
22
69
  isTrial: true,
@@ -29,49 +76,70 @@ Basic.args = {
29
76
  amount: '645.00',
30
77
  trialAmount: 100,
31
78
  value: 'P2Y',
32
- currency: 'USD',
79
+ symbol: '$',
80
+ subscriptionAutoRenewTerm: true,
33
81
  },
34
82
  {
35
- name: '3 yearly',
83
+ name: '13 monthly',
36
84
  isTrial: false,
37
85
  discount: '',
38
86
  selected: false,
39
- price: '$909.00',
40
- trialPrice: '$0.00',
87
+ price: '£155.00',
88
+ trialPrice: '£0.00',
41
89
  trialDuration: '',
42
- monthlyPrice: '0',
43
- amount: '909.00',
90
+ monthlyPrice: null,
91
+ amount: '155.00',
44
92
  trialAmount: null,
45
- value: 'P3Y',
46
- currency: 'USD',
93
+ value: 'P13M',
94
+ symbol: '£',
95
+ subscriptionAutoRenewTerm: true,
47
96
  },
97
+ // Annual whose value is P1Y
48
98
  {
49
- name: '6 monthly',
99
+ name: 'annual',
50
100
  isTrial: false,
51
101
  discount: '',
52
- selected: false,
53
- price: '$229.00',
102
+ selected: true,
103
+ price: '$385.00',
54
104
  trialPrice: '$0.00',
55
105
  trialDuration: '',
56
- monthlyPrice: '0',
57
- amount: '229.00',
106
+ monthlyPrice: '$32.09',
107
+ amount: '385.00',
58
108
  trialAmount: null,
59
- value: 'P6M',
60
- currency: 'USD',
109
+ value: 'P1Y',
110
+ symbol: '$',
111
+ subscriptionAutoRenewTerm: true,
61
112
  },
113
+ // Annual whose value is P52W
62
114
  {
63
115
  name: 'annual',
64
116
  isTrial: false,
65
117
  discount: '',
66
- selected: true,
67
- price: '$385.00',
118
+ selected: false,
119
+ price: '£140.00',
120
+ trialPrice: '£0.00',
121
+ trialDuration: '',
122
+ monthlyPrice: null,
123
+ amount: '140.00',
124
+ trialAmount: null,
125
+ value: 'P52W',
126
+ symbol: '£',
127
+ subscriptionAutoRenewTerm: true,
128
+ },
129
+ {
130
+ name: '6 monthly',
131
+ isTrial: false,
132
+ discount: '',
133
+ selected: false,
134
+ price: '$229.00',
68
135
  trialPrice: '$0.00',
69
136
  trialDuration: '',
70
- monthlyPrice: '$32.09',
71
- amount: '385.00',
137
+ monthlyPrice: '0',
138
+ amount: '229.00',
72
139
  trialAmount: null,
73
- value: 'P1Y',
74
- currency: 'USD',
140
+ value: 'P6M',
141
+ symbol: '$',
142
+ subscriptionAutoRenewTerm: true,
75
143
  },
76
144
  {
77
145
  name: 'quarterly',
@@ -85,9 +153,27 @@ Basic.args = {
85
153
  amount: '95.00',
86
154
  trialAmount: null,
87
155
  value: 'P3M',
88
- currency: 'USD',
156
+ symbol: '$',
157
+ subscriptionAutoRenewTerm: true,
158
+ },
159
+ {
160
+ name: 'monthly',
161
+ isTrial: false,
162
+ discount: '',
163
+ selected: false,
164
+ price: '£42.00',
165
+ trialPrice: '£0.00',
166
+ trialDuration: '',
167
+ monthlyPrice: null,
168
+ amount: '42.00',
169
+ trialAmount: null,
170
+ value: 'P1M',
171
+ symbol: '£',
172
+ subscriptionAutoRenewTerm: true,
89
173
  },
90
174
  ],
175
+ isAutoRenewingSubscriptionTermType: true,
176
+ isNonRenewingSubscriptionTermType: false,
91
177
  };
92
178
 
93
179
  export const NonRenewingTermType = (args) => (
@@ -99,13 +185,38 @@ export const NonRenewingTermType = (args) => (
99
185
  );
100
186
  NonRenewingTermType.args = {
101
187
  options: [
188
+ {
189
+ name: 'quarterly',
190
+ isTrial: false,
191
+ discount: '',
192
+ selected: true,
193
+ price: '£15.00',
194
+ trialPrice: '£0.00',
195
+ trialDuration: '',
196
+ monthlyPrice: null,
197
+ amount: '15.00',
198
+ trialAmount: null,
199
+ value: 'P13W',
200
+ symbol: '£',
201
+ subscriptionAutoRenewTerm: false,
202
+ },
102
203
  {
103
204
  name: '8 weeks',
205
+ isTrial: false,
206
+ discount: '',
207
+ selected: false,
104
208
  price: '£19.00',
209
+ trialPrice: '£0.00',
210
+ trialDuration: '',
211
+ monthlyPrice: null,
105
212
  amount: '19.00',
213
+ trialAmount: null,
106
214
  value: 'P8W',
215
+ symbol: '£',
216
+ subscriptionAutoRenewTerm: false,
107
217
  },
108
218
  ],
219
+ isAutoRenewingSubscriptionTermType: false,
109
220
  isNonRenewingSubscriptionTermType: true,
110
221
  };
111
222
 
@@ -10,6 +10,7 @@ var _react = _interopRequireDefault(require("react"));
10
10
  var _propTypes = _interopRequireDefault(require("prop-types"));
11
11
  var _classnames = _interopRequireDefault(require("classnames"));
12
12
  var _nPricing = require("@financial-times/n-pricing");
13
+ var _helpers = require("../helpers");
13
14
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
14
15
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2["default"])(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
15
16
  function PaymentTerm(_ref) {
@@ -36,138 +37,41 @@ function PaymentTerm(_ref) {
36
37
  _ref$isNonRenewingSub = _ref.isNonRenewingSubscriptionTermType,
37
38
  isNonRenewingSubscriptionTermType = _ref$isNonRenewingSub === void 0 ? false : _ref$isNonRenewingSub;
38
39
  /**
39
- * Compute monthly price for given term name
40
- * @param {number} amount price in number format
41
- * @param {string} currency country id of the currency
42
- * @param {string} period (expressed in IS0 8601 duration format): e.g. PxY (yearly) or PxM (montly) where x is the amount of years/months
40
+ * Capitalises a string.
41
+ * @param {string} Input string to be capitalised
43
42
  * @returns {string}
44
43
  */
45
- var getMonthlyPriceFromPeriod = function getMonthlyPriceFromPeriod(amount, currency, period) {
46
- var periodObj = new _nPricing.Period(period);
47
- var monthlyPrice = periodObj.calculatePrice('P1M', amount);
48
- return new _nPricing.Monthly({
49
- value: monthlyPrice,
50
- currency: currency
51
- }).getAmount('monthly');
44
+ var capitalise = function capitalise(string) {
45
+ return Boolean(string) ? string[0].toUpperCase() + string.slice(1) : string;
52
46
  };
53
47
 
54
48
  /**
55
- * returns period converted to time if found
56
- * otherwise returns empty string to avoid show information not mapped
57
- * @param {string} period (expressed in IS0 8601 duration format): PxY (yearly), PxM (montly), PxW (weekly), of PxD (daily), where x is the amount of years/months/weeks/days
58
- * @returns {string}
49
+ * Creates the JSX for a single payment-term option, including the input,
50
+ * title, discount messaging, and descriptive pricing copy.
51
+ *
52
+ * @param {Object} option - Payment term configuration
53
+ * @param {string} option.value - ISO 8601 duration of the subscription term of the offer
54
+ * @param {string} option.name - term name, e.g. "monthly", "annual", "2 yearly
55
+ * @param {string} option.price - Formatted display price
56
+ * @param {string|number} [option.amount] - Price expressed in numerical terms
57
+ * @param {string} [option.symbol] - Currency symbol, e.g. £
58
+ * @param {string} [option.monthlyPrice] - Precomputed monthly equivalent price (can be with or without currency symbol)
59
+ * @param {boolean} [option.discount] - Whether the option should display discount messaging
60
+ * @param {boolean} [option.bestOffer] - Whether the option should show "Best offer" instead of standard discount copy
61
+ * @param {boolean} [option.selected] - Whether the option is selected by default
62
+ * @param {boolean} [option.isTrial] - Whether the option is a trial offer
63
+ * @param {boolean} [option.subscriptionAutoRenewTerm] - Whether the option is for an auto-renewing subscription
64
+ * @param {number} [option.trialAmount] - Amount used for trial pricing
65
+ * @param {string} [option.trialDuration] - Human-readable trial duration copy
66
+ * @param {string} [option.trialPrice] - Formatted trial price
67
+ * @param {string} [option.displayName] - Override label for the term title
68
+ * @param {string} [option.title] - Fallback title for legacy or non-period terms
69
+ * @param {string} [option.subTitle] - Optional subtitle shown alongside the term title
70
+ * @param {string} [option.chargeOnText] - Optional charge timing copy for non-period offers
71
+ * @param {boolean} [option.b2cPartnership] - Whether the option is part of a B2C partnership offer
72
+ * @param {string} [option.b2cDiscountCopy] - Partnership-specific discount copy
73
+ * @returns {React.ReactElement} A rendered payment term option
59
74
  */
60
- var getTimeFromPeriod = function getTimeFromPeriod(period) {
61
- var periodUnitCodeToWordMap = {
62
- Y: 'years',
63
- M: 'months',
64
- W: 'weeks',
65
- D: 'days'
66
- };
67
- var periodUnitCode = period.substring(period.length - 1);
68
- var freq = periodUnitCodeToWordMap[periodUnitCode] || '';
69
- var amount = period.substring(1, period.length - 1);
70
- return period ? "".concat(amount, " ").concat(freq) : '';
71
- };
72
- var isValidPeriod = function isValidPeriod(period) {
73
- try {
74
- // Period should throw an error if it is not properly provided
75
- // in order to validate it, we just send in case type is string
76
- new _nPricing.Period(typeof period === 'string' ? period : '');
77
- return true;
78
- } catch (e) {
79
- return false;
80
- }
81
- };
82
- var nameMap = {
83
- annual: {
84
- title: 'Annual',
85
- price: function price(_price) {
86
- return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, "Single", ' ', /*#__PURE__*/_react["default"].createElement("span", {
87
- className: "ncf__payment-term__price ncf__strong"
88
- }, _price), ' ', "payment");
89
- },
90
- trialPrice: function trialPrice(price) {
91
- return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, "Unless you cancel during your trial you will be billed", ' ', /*#__PURE__*/_react["default"].createElement("span", {
92
- className: "ncf__payment-term__price"
93
- }, price), " per year after the trial period.");
94
- },
95
- monthlyPrice: function monthlyPrice(price) {
96
- return price && /*#__PURE__*/_react["default"].createElement("span", {
97
- className: "ncf__payment-term__equivalent-price"
98
- }, "That\u2019s equivalent to", ' ', /*#__PURE__*/_react["default"].createElement("span", {
99
- className: "ncf__payment-term__monthly-price"
100
- }, price), ' ', "per month");
101
- },
102
- renewsText: function renewsText() {
103
- return /*#__PURE__*/_react["default"].createElement("p", {
104
- className: "ncf__payment-term__renews-text"
105
- }, "Renews annually unless cancelled");
106
- }
107
- },
108
- quarterly: {
109
- title: 'Quarterly',
110
- price: function price(_price2) {
111
- return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, /*#__PURE__*/_react["default"].createElement("span", {
112
- className: "ncf__payment-term__price"
113
- }, _price2), " per quarter");
114
- },
115
- trialPrice: function trialPrice(price) {
116
- return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, "Unless you cancel during your trial you will be billed", ' ', /*#__PURE__*/_react["default"].createElement("span", {
117
- className: "ncf__payment-term__price"
118
- }, price), " per quarter after the trial period.");
119
- },
120
- monthlyPrice: function monthlyPrice() {},
121
- renewsText: function renewsText() {
122
- return /*#__PURE__*/_react["default"].createElement("p", {
123
- className: "ncf__payment-term__renews-text"
124
- }, "Renews quarterly unless cancelled");
125
- }
126
- },
127
- monthly: {
128
- title: 'Monthly',
129
- price: function price(_price3) {
130
- return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, /*#__PURE__*/_react["default"].createElement("span", {
131
- className: "ncf__payment-term__price"
132
- }, _price3), " per month");
133
- },
134
- trialPrice: function trialPrice(price) {
135
- return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, "Unless you cancel during your trial you will be billed", ' ', /*#__PURE__*/_react["default"].createElement("span", {
136
- className: "ncf__payment-term__price"
137
- }, price), " per month after the trial period.");
138
- },
139
- monthlyPrice: function monthlyPrice() {},
140
- renewsText: function renewsText() {
141
- return /*#__PURE__*/_react["default"].createElement("p", {
142
- className: "ncf__payment-term__renews-text"
143
- }, 'Renews monthly unless cancelled');
144
- }
145
- },
146
- custom: {
147
- price: function price(_price4) {
148
- return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, "Single", ' ', /*#__PURE__*/_react["default"].createElement("span", {
149
- className: "ncf__payment-term__price ncf__strong"
150
- }, _price4), ' ', "payment");
151
- },
152
- trialPrice: function trialPrice(_trialPrice, trialPeriod) {
153
- return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, "Unless you cancel during your trial you will be billed", ' ', /*#__PURE__*/_react["default"].createElement("span", {
154
- className: "ncf__payment-term__price"
155
- }, _trialPrice), " per", ' ', trialPeriod, "after the trial period.");
156
- },
157
- monthlyPrice: function monthlyPrice(_monthlyPrice) {
158
- return Boolean(_monthlyPrice) && /*#__PURE__*/_react["default"].createElement("span", {
159
- className: "ncf__payment-term__equivalent-price"
160
- }, "That\u2019s equivalent to", ' ', /*#__PURE__*/_react["default"].createElement("span", {
161
- className: "ncf__payment-term__monthly-price"
162
- }, _monthlyPrice), ' ', "per month");
163
- },
164
- renewsText: function renewsText(renewalPeriod) {
165
- return Boolean(renewalPeriod) && /*#__PURE__*/_react["default"].createElement("p", {
166
- className: "ncf__payment-term__renews-text"
167
- }, "Renews every ", renewalPeriod, " unless cancelled");
168
- }
169
- }
170
- };
171
75
  var createPaymentTerm = function createPaymentTerm(option) {
172
76
  var className = (0, _classnames["default"])(['ncf__payment-term__item', 'o-forms-input--radio-round', {
173
77
  'ncf__payment-term__item--discount': option.discount
@@ -182,50 +86,197 @@ function PaymentTerm(_ref) {
182
86
  }, option.selected && {
183
87
  defaultChecked: true
184
88
  });
89
+
90
+ /**
91
+ * Determines whether input is a valid ISO 8601 duration value that can be decoded by the Period class.
92
+ * @returns {boolean}
93
+ */
94
+ var isValidPeriod = function isValidPeriod() {
95
+ try {
96
+ // Period should throw an error if it is not properly provided
97
+ // in order to validate it, we just send in case type is string
98
+ new _nPricing.Period(typeof option.value === 'string' ? option.value : '');
99
+ return true;
100
+ } catch (error) {
101
+ return false;
102
+ }
103
+ };
104
+
105
+ /**
106
+ * Compute monthly price for given term name, if the term if 90 days or longer.
107
+ * @returns {string | undefined}
108
+ */
109
+ var getCalculatedMonthlyPriceIfEligible = function getCalculatedMonthlyPriceIfEligible() {
110
+ var _priceObject$getMonth;
111
+ var priceObject = new _nPricing.Price({
112
+ value: option.amount,
113
+ symbol: option.symbol
114
+ }, {
115
+ period: option.value
116
+ });
117
+ return (_priceObject$getMonth = priceObject.getMonthlyEquivalentIf90DaysOrLonger()) === null || _priceObject$getMonth === void 0 ? void 0 : _priceObject$getMonth.amount.value;
118
+ };
119
+
120
+ /**
121
+ * Returns elements that include the text describing the price of the offer option.
122
+ * @returns {React.ReactElement}
123
+ */
124
+ var getPriceText = function getPriceText() {
125
+ var isExpressedAsSinglePayment = !option.subscriptionAutoRenewTerm ||
126
+ // With an auto-renewing annual term there is a high chance
127
+ // it will not be the same price in the second year,
128
+ // so we do not want to imply that the price will remain consistent.
129
+ // For shorter auto-renewing terms there is higher confidence that the price
130
+ // will remain consistent across subsequent terms.
131
+ option.subscriptionAutoRenewTerm && (0, _helpers.is52WeeksOrLonger)(option.value);
132
+ var isExpressedAsRecurringPayment = !isExpressedAsSinglePayment;
133
+ if (isExpressedAsSinglePayment) {
134
+ return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, "Single", ' ', /*#__PURE__*/_react["default"].createElement("span", {
135
+ className: "ncf__payment-term__price"
136
+ }, option.price), ' ', "payment");
137
+ }
138
+ if (isExpressedAsRecurringPayment) {
139
+ return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, /*#__PURE__*/_react["default"].createElement("span", {
140
+ className: "ncf__payment-term__price"
141
+ }, option.price), " per", ' ', (0, _helpers.getDurationFromISO8601Value)({
142
+ iso8601Value: option.value
143
+ }));
144
+ }
145
+ };
146
+
147
+ /**
148
+ * Returns elements that include the text describing the price increase following the trial period.
149
+ * @returns {React.ReactElement}
150
+ */
151
+ var getTrialPriceExplanatoryText = function getTrialPriceExplanatoryText() {
152
+ return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, "Unless you cancel during your trial you will be billed", ' ', /*#__PURE__*/_react["default"].createElement("span", {
153
+ className: "ncf__payment-term__price"
154
+ }, option.price), " per", ' ', (0, _helpers.getDurationFromISO8601Value)({
155
+ iso8601Value: option.value
156
+ }), ' ', "after the trial period.");
157
+ };
158
+
159
+ /**
160
+ * Returns elements that include the text describing how regularly an auto-renewing subscription will renew.
161
+ * @returns {React.ReactElement}
162
+ */
163
+ var getRenewalPeriodText = function getRenewalPeriodText() {
164
+ return /*#__PURE__*/_react["default"].createElement("p", {
165
+ className: "ncf__payment-term__renews-text"
166
+ }, "Renews every", ' ', (0, _helpers.getDurationFromISO8601Value)({
167
+ iso8601Value: option.value
168
+ }), " unless cancelled");
169
+ };
170
+
171
+ /**
172
+ * Returns elements that include the text describing the monthly equivalent of the subscription.
173
+ * Returns null if the term is shorter than 90 days
174
+ * @returns {string | null}
175
+ */
176
+ var getEquivalentMonthlyPrice = function getEquivalentMonthlyPrice() {
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) {
183
+ return isNaN(option.monthlyPrice) ? option.monthlyPrice : "".concat(option.symbol).concat(option.monthlyPrice);
184
+ }
185
+ return calculatedMonthlyPrice;
186
+ };
187
+
188
+ /**
189
+ * Returns elements that include the text describing the monthly equivalent of the subscription, if available.
190
+ * @returns {React.ReactElement | null}
191
+ */
192
+ var getEquivalentMonthlyPriceText = function getEquivalentMonthlyPriceText() {
193
+ var equivalentMonthlyPrice = getEquivalentMonthlyPrice();
194
+ if (!equivalentMonthlyPrice) {
195
+ return null;
196
+ }
197
+ return /*#__PURE__*/_react["default"].createElement("span", {
198
+ className: "ncf__payment-term__equivalent-price"
199
+ }, "That\u2019s equivalent to", ' ', /*#__PURE__*/_react["default"].createElement("span", {
200
+ className: "ncf__payment-term__monthly-price"
201
+ }, equivalentMonthlyPrice), ' ', "per month");
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
+ */
185
210
  var createDiscount = function createDiscount() {
186
211
  return option.discount && /*#__PURE__*/_react["default"].createElement("span", {
187
212
  className: "ncf__payment-term__discount"
188
213
  }, option.bestOffer ? 'Best offer' : "Save ".concat(option.discount, " off RRP"));
189
214
  };
215
+
216
+ /**
217
+ * Creates B2C partnership discount copy for eligible annual offers.
218
+ *
219
+ * @returns {React.ReactElement} The B2C discount element, or false when the option is not eligible
220
+ */
190
221
  var createB2cDiscountCopy = function createB2cDiscountCopy() {
191
222
  return option.name === 'annual' && option.b2cPartnership && option.b2cDiscountCopy && /*#__PURE__*/_react["default"].createElement("span", {
192
223
  className: "ncf__payment-term__discount"
193
224
  }, option.b2cDiscountCopy);
194
225
  };
226
+
227
+ /**
228
+ * Creates the description shown beneath the term title.
229
+ * This may include trial copy, price-per-period copy, equivalent monthly price,
230
+ * renewal messaging, or fallback non-period pricing text.
231
+ *
232
+ * @returns {React.ReactElement} The description block for the payment term
233
+ */
195
234
  var createDescription = function createDescription() {
196
- return option.isTrial ? /*#__PURE__*/_react["default"].createElement("div", {
197
- className: "ncf__payment-term__description"
198
- }, option.trialDuration || '4 weeks', " for", ' ', /*#__PURE__*/_react["default"].createElement("span", {
199
- className: "ncf__payment-term__trial-price"
200
- }, option.trialPrice), /*#__PURE__*/_react["default"].createElement("br", null), nameMap[option.name] && nameMap[option.name].trialPrice(option.price)) : /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, nameMap[option.name] ? /*#__PURE__*/_react["default"].createElement("div", {
201
- className: "ncf__payment-term__description"
202
- }, nameMap[option.name].price(option.price), nameMap[option.name].monthlyPrice(option.monthlyPrice), isAutoRenewingSubscriptionTermType && nameMap[option.name].renewsText()) :
203
- // this should cover the cases different than annual, quarterly and monthly
204
- // for those containing period on option.value, render custom template, for the rest keep legacy render
205
- isValidPeriod(option.value) ? /*#__PURE__*/_react["default"].createElement("div", {
206
- className: "ncf__payment-term__description"
207
- }, nameMap['custom'].price(option.price), nameMap['custom'].monthlyPrice(option.monthlyPrice && option.monthlyPrice !== '0' ? Number(option.monthlyPrice) : getMonthlyPriceFromPeriod(option.amount, option.currency, option.value)), isAutoRenewingSubscriptionTermType && nameMap['custom'].renewsText(getTimeFromPeriod(option.value))) : /*#__PURE__*/_react["default"].createElement("div", null, /*#__PURE__*/_react["default"].createElement("span", {
235
+ if (option.isTrial) {
236
+ return /*#__PURE__*/_react["default"].createElement("div", {
237
+ className: "ncf__payment-term__description"
238
+ }, option.trialDuration || '4 weeks', " for", ' ', /*#__PURE__*/_react["default"].createElement("span", {
239
+ className: "ncf__payment-term__trial-price"
240
+ }, option.trialPrice), /*#__PURE__*/_react["default"].createElement("br", null), getTrialPriceExplanatoryText());
241
+ }
242
+ if (isValidPeriod(option.value)) {
243
+ return /*#__PURE__*/_react["default"].createElement("div", {
244
+ className: "ncf__payment-term__description"
245
+ }, getPriceText(), getEquivalentMonthlyPriceText(), option.subscriptionAutoRenewTerm && getRenewalPeriodText());
246
+ }
247
+ return /*#__PURE__*/_react["default"].createElement("div", null, /*#__PURE__*/_react["default"].createElement("span", {
208
248
  className: largePrice ? 'ncf__payment-term__large-price' : ''
209
249
  }, option.price), option.chargeOnText && /*#__PURE__*/_react["default"].createElement("p", {
210
250
  className: "ncf__payment-term__charge-on-text"
211
- }, option.chargeOnText)));
251
+ }, option.chargeOnText));
212
252
  };
253
+
254
+ /**
255
+ * Builds the display name shown as the payment term title.
256
+ * May prepend trial copy, use the capitalised term name for auto-renewing terms,
257
+ * derive a human-readable period for valid non-renewing terms, or fall back to
258
+ * a legacy title when no valid period is available.
259
+ *
260
+ * @returns {string} The formatted display name for the payment term
261
+ */
213
262
  var getTermDisplayName = function getTermDisplayName() {
214
263
  var showTrialCopyInTitle = option.isTrial && !isPrintOrBundle && !isDigitalEdition;
215
- var title = option.name && nameMap[option.name] ? nameMap[option.name].title : '';
216
264
  var termDisplayName = '';
217
265
  if (showTrialCopyInTitle) {
218
266
  var termName = option.displayName ? option.displayName : 'Premium Digital';
219
267
  termDisplayName = "Trial: ".concat(termName, " - ");
220
268
  }
221
269
  var getTermPeriod = function getTermPeriod() {
222
- // annual, quarterly and monthly
223
- if (nameMap[option.name]) {
224
- return title;
270
+ if (option.subscriptionAutoRenewTerm && option.name) {
271
+ return capitalise(option.name);
225
272
  }
273
+
226
274
  // custom offer with period provided
227
- if (isValidPeriod(option.value)) {
228
- return getTimeFromPeriod(option.value);
275
+ if (!option.subscriptionAutoRenewTerm && isValidPeriod(option.value)) {
276
+ return (0, _helpers.getDurationFromISO8601Value)({
277
+ iso8601Value: option.value,
278
+ excludeAmountWhenSingular: false
279
+ });
229
280
  }
230
281
  // custom legacy cases, where period is not provided
231
282
  return option.title;
@@ -284,12 +335,14 @@ PaymentTerm.propTypes = {
284
335
  isB2cPartnership: _propTypes["default"].bool,
285
336
  discount: _propTypes["default"].string,
286
337
  isTrial: _propTypes["default"].bool,
338
+ subscriptionAutoRenewTerm: _propTypes["default"].bool,
287
339
  name: _propTypes["default"].string.isRequired,
288
340
  price: _propTypes["default"].string.isRequired,
289
341
  selected: _propTypes["default"].bool,
290
342
  trialDuration: _propTypes["default"].string,
291
343
  trialPrice: _propTypes["default"].string,
292
344
  amount: _propTypes["default"].string,
345
+ symbol: _propTypes["default"].string,
293
346
  trialAmount: _propTypes["default"].number,
294
347
  value: _propTypes["default"].string.isRequired,
295
348
  monthlyPrice: _propTypes["default"].string,