@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.
- package/.toolkitstate/ci.json +3 -3
- package/.toolkitstate/install.json +1 -1
- package/components/__snapshots__/payment-term.spec.js.snap +1 -1031
- package/components/delivery-option.stories.js +2 -2
- package/components/payment-term.jsx +249 -208
- package/components/payment-term.spec.js +675 -317
- package/components/payment-term.stories.js +135 -24
- package/dist/payment-term.jsx +198 -145
- package/helpers/duration-helpers.js +90 -0
- package/helpers/duration-helpers.spec.js +142 -0
- package/helpers/index.js +3 -0
- package/helpers/index.spec.js +8 -0
- package/package.json +2 -2
- package/styles/payment-term.scss +5 -5
- package/styles/payment-type.scss +0 -4
|
@@ -7,7 +7,7 @@ export default {
|
|
|
7
7
|
component: PaymentTerm,
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
-
export const
|
|
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
|
-
|
|
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
|
-
|
|
79
|
+
symbol: '$',
|
|
80
|
+
subscriptionAutoRenewTerm: true,
|
|
33
81
|
},
|
|
34
82
|
{
|
|
35
|
-
name: '
|
|
83
|
+
name: '13 monthly',
|
|
36
84
|
isTrial: false,
|
|
37
85
|
discount: '',
|
|
38
86
|
selected: false,
|
|
39
|
-
price: '
|
|
40
|
-
trialPrice: '
|
|
87
|
+
price: '£155.00',
|
|
88
|
+
trialPrice: '£0.00',
|
|
41
89
|
trialDuration: '',
|
|
42
|
-
monthlyPrice:
|
|
43
|
-
amount: '
|
|
90
|
+
monthlyPrice: null,
|
|
91
|
+
amount: '155.00',
|
|
44
92
|
trialAmount: null,
|
|
45
|
-
value: '
|
|
46
|
-
|
|
93
|
+
value: 'P13M',
|
|
94
|
+
symbol: '£',
|
|
95
|
+
subscriptionAutoRenewTerm: true,
|
|
47
96
|
},
|
|
97
|
+
// Annual whose value is P1Y
|
|
48
98
|
{
|
|
49
|
-
name: '
|
|
99
|
+
name: 'annual',
|
|
50
100
|
isTrial: false,
|
|
51
101
|
discount: '',
|
|
52
|
-
selected:
|
|
53
|
-
price: '$
|
|
102
|
+
selected: true,
|
|
103
|
+
price: '$385.00',
|
|
54
104
|
trialPrice: '$0.00',
|
|
55
105
|
trialDuration: '',
|
|
56
|
-
monthlyPrice: '
|
|
57
|
-
amount: '
|
|
106
|
+
monthlyPrice: '$32.09',
|
|
107
|
+
amount: '385.00',
|
|
58
108
|
trialAmount: null,
|
|
59
|
-
value: '
|
|
60
|
-
|
|
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:
|
|
67
|
-
price: '
|
|
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: '
|
|
71
|
-
amount: '
|
|
137
|
+
monthlyPrice: '0',
|
|
138
|
+
amount: '229.00',
|
|
72
139
|
trialAmount: null,
|
|
73
|
-
value: '
|
|
74
|
-
|
|
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
|
-
|
|
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
|
|
package/dist/payment-term.jsx
CHANGED
|
@@ -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
|
-
*
|
|
40
|
-
* @param {
|
|
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
|
|
46
|
-
|
|
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
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* @
|
|
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
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
}
|
|
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
|
-
|
|
223
|
-
|
|
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
|
|
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,
|