@financial-times/n-conversion-forms 26.0.0 → 27.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/.circleci/config.yml +4 -4
- package/.eslintignore +1 -0
- package/.github/workflows/gh-pages-deploy.yml +1 -0
- package/.storybook/main.js +0 -1
- package/__mocks__/@financial-times/o-expander.js +9 -0
- package/__mocks__/@financial-times/o-forms-input.js +11 -0
- package/__mocks__/@financial-times/o-forms.js +40 -0
- package/build-state/npm-shrinkwrap.json +294 -6334
- package/components/__snapshots__/b2c-partnership-confirmation.spec.js.snap +1 -1
- package/components/__snapshots__/confirmation.spec.js.snap +0 -3
- package/components/__snapshots__/debug.spec.js.snap +25 -13
- package/components/__snapshots__/delivery-postcode.spec.js.snap +1 -1
- package/components/__snapshots__/payment-term.spec.js.snap +1 -1
- package/components/__snapshots__/payment-type.spec.js.snap +19 -0
- package/components/__snapshots__/registration-confirmation.spec.js.snap +230 -74
- package/components/accept-terms.jsx +57 -36
- package/components/accept-terms.stories.js +28 -1
- package/components/b2c-partnership-confirmation.jsx +1 -1
- package/components/confirmation.jsx +15 -8
- package/components/confirmation.spec.js +1 -1
- package/components/debug.jsx +19 -12
- package/components/debug.stories.js +13 -0
- package/components/delivery-address.jsx +21 -58
- package/components/delivery-address.stories.js +7 -0
- package/components/delivery-city.jsx +4 -2
- package/components/delivery-city.stories.js +9 -0
- package/components/delivery-option.jsx +5 -3
- package/components/delivery-option.stories.js +7 -1
- package/components/delivery-postcode.jsx +32 -13
- package/components/delivery-postcode.stories.js +2 -1
- package/components/delivery-security-instructions.spec.js +3 -3
- package/components/graduation-date.spec.js +8 -8
- package/components/index.jsx +1 -1
- package/components/message.jsx +1 -1
- package/components/payment-term.jsx +152 -25
- package/components/payment-term.spec.js +46 -4
- package/components/payment-term.stories.js +69 -14
- package/components/payment-type.jsx +3 -1
- package/components/position.jsx +6 -3
- package/components/position.spec.js +15 -5
- package/components/registration-confirmation.jsx +111 -32
- package/components/responsibility.jsx +6 -3
- package/components/responsibility.spec.js +15 -5
- package/components/text-input.jsx +73 -0
- package/components/text-input.spec.js +118 -0
- package/components/text-input.stories.js +31 -0
- package/dist/accept-terms.js +15 -7
- package/dist/b2c-partnership-confirmation.js +1 -1
- package/dist/confirmation.js +11 -2
- package/dist/debug.js +6 -6
- package/dist/delivery-address.js +19 -32
- package/dist/delivery-city.js +4 -2
- package/dist/delivery-option.js +5 -2
- package/dist/delivery-postcode.js +31 -12
- package/dist/index.js +9 -9
- package/dist/message.js +1 -1
- package/dist/payment-term.js +117 -11
- package/dist/payment-type.js +5 -2
- package/dist/position.js +6 -2
- package/dist/registration-confirmation.js +87 -29
- package/dist/responsibility.js +6 -2
- package/dist/text-input.js +84 -0
- package/helpers/constants.js +7 -0
- package/helpers/deliveryAddressMap.js +167 -0
- package/helpers/index.js +7 -0
- package/helpers/index.spec.js +11 -0
- package/helpers/ncf-common-data.spec.js +34 -0
- package/helpers/ncf-countries.spec.js +136 -0
- package/helpers/supportedCountries.js +76 -0
- package/helpers/supportedPostcodeExamples.js +57 -0
- package/helpers/supportedPostcodeValidators.js +53 -0
- package/helpers/utilities.js +14 -0
- package/jest.config.js +8 -1
- package/main.scss +461 -0
- package/package.json +6 -3
- package/styles/confirmation.scss +122 -0
- package/styles/payment-term.scss +3 -0
- package/utils/app-banner.spec.js +68 -0
- package/utils/apple-pay.spec.js +177 -0
- package/utils/billing-country.spec.js +87 -0
- package/utils/billing-postcode.spec.js +138 -0
- package/utils/company-name.spec.js +3 -7
- package/utils/country.spec.js +87 -0
- package/utils/delivery-address-type.spec.js +24 -11
- package/utils/delivery-option-messages.js +15 -0
- package/utils/delivery-option-messages.spec.js +3 -3
- package/utils/delivery-option.spec.js +100 -15
- package/utils/delivery-postcode.spec.js +138 -0
- package/utils/delivery-start-date.spec.js +177 -0
- package/utils/email.spec.js +210 -0
- package/utils/event-notifier.spec.js +116 -0
- package/utils/form-element.spec.js +71 -0
- package/utils/loader.spec.js +161 -0
- package/utils/password.spec.js +65 -0
- package/utils/payment-term.js +25 -1
- package/utils/payment-term.spec.js +198 -0
- package/utils/payment-type.js +1 -1
- package/utils/payment-type.spec.js +136 -0
- package/utils/postcode.spec.js +122 -0
- package/utils/salesforce.spec.js +30 -0
- package/utils/submit.spec.js +81 -0
- package/utils/tracking.spec.js +174 -0
- package/utils/validation.js +2 -2
- package/utils/validation.spec.js +234 -0
- package/utils/zuora.spec.js +249 -0
- package/components/__snapshots__/b2c-partnership-payment-term.spec.js.snap +0 -193
- package/components/b2c-partnership-payment-term.jsx +0 -126
- package/components/b2c-partnership-payment-term.spec.js +0 -52
- package/components/b2c-partnership-payment-term.stories.js +0 -44
- package/dist/b2c-partnership-payment-term.js +0 -91
- package/styles/b2c-partnership-payment-term.scss +0 -20
|
@@ -104,11 +104,11 @@ describe('DeliverySecurityInstructions', () => {
|
|
|
104
104
|
expect(textAreaProps.name).toBe('inputId');
|
|
105
105
|
});
|
|
106
106
|
|
|
107
|
-
it('
|
|
107
|
+
it('sets maxLength to 10', () => {
|
|
108
108
|
expect(textAreaProps.maxLength).toBe(10);
|
|
109
109
|
});
|
|
110
110
|
|
|
111
|
-
it('
|
|
111
|
+
it('sets rows to 3', () => {
|
|
112
112
|
expect(textAreaProps.rows).toBe(3);
|
|
113
113
|
});
|
|
114
114
|
|
|
@@ -120,7 +120,7 @@ describe('DeliverySecurityInstructions', () => {
|
|
|
120
120
|
expect(textAreaProps.disabled).toBeTrue;
|
|
121
121
|
});
|
|
122
122
|
|
|
123
|
-
it('
|
|
123
|
+
it('sets value', () => {
|
|
124
124
|
expect(textAreaProps.defaultValue).toBe('value');
|
|
125
125
|
});
|
|
126
126
|
});
|
|
@@ -24,7 +24,7 @@ describe('GraduationDate', () => {
|
|
|
24
24
|
).toBe(true);
|
|
25
25
|
});
|
|
26
26
|
|
|
27
|
-
it('
|
|
27
|
+
it('displays graduationDateMonth options as English month names', () => {
|
|
28
28
|
const wrapper = shallow(<GraduationDate />);
|
|
29
29
|
const values = wrapper
|
|
30
30
|
.find('#graduationDateMonth option')
|
|
@@ -45,7 +45,7 @@ describe('GraduationDate', () => {
|
|
|
45
45
|
]);
|
|
46
46
|
});
|
|
47
47
|
|
|
48
|
-
it('
|
|
48
|
+
it('stores graduationDateMonth values as two-digit numbers', () => {
|
|
49
49
|
const wrapper = shallow(<GraduationDate />);
|
|
50
50
|
const values = wrapper
|
|
51
51
|
.find('#graduationDateMonth option')
|
|
@@ -85,13 +85,13 @@ describe('GraduationDate', () => {
|
|
|
85
85
|
describe('given a valid value prop is passed', () => {
|
|
86
86
|
const wrapper = shallow(<GraduationDate value="2020-08-28" />);
|
|
87
87
|
|
|
88
|
-
it('
|
|
88
|
+
it('sets the default month', () => {
|
|
89
89
|
expect(wrapper.find('#graduationDateMonth').prop('defaultValue')).toEqual(
|
|
90
90
|
'08'
|
|
91
91
|
);
|
|
92
92
|
});
|
|
93
93
|
|
|
94
|
-
it('
|
|
94
|
+
it('sets the default year', () => {
|
|
95
95
|
expect(wrapper.find('#graduationDateYear').prop('defaultValue')).toEqual(
|
|
96
96
|
'2020'
|
|
97
97
|
);
|
|
@@ -101,7 +101,7 @@ describe('GraduationDate', () => {
|
|
|
101
101
|
describe('given an invalid value prop is passed', () => {
|
|
102
102
|
const wrapper = shallow(<GraduationDate value="invalid" />);
|
|
103
103
|
|
|
104
|
-
it('
|
|
104
|
+
it('does not set any default values', () => {
|
|
105
105
|
expect(
|
|
106
106
|
wrapper.find('#graduationDateMonth').prop('defaultValue')
|
|
107
107
|
).toBeFalsy();
|
|
@@ -114,7 +114,7 @@ describe('GraduationDate', () => {
|
|
|
114
114
|
describe('given the isDisabled prop is set to true', () => {
|
|
115
115
|
const wrapper = shallow(<GraduationDate isDisabled={true} />);
|
|
116
116
|
|
|
117
|
-
it('
|
|
117
|
+
it('disables both select fields', () => {
|
|
118
118
|
expect(
|
|
119
119
|
wrapper.find('#graduationDateMonth').prop('disabled')
|
|
120
120
|
).toBeTruthy();
|
|
@@ -125,7 +125,7 @@ describe('GraduationDate', () => {
|
|
|
125
125
|
describe('given the isRequired prop is set to true', () => {
|
|
126
126
|
const wrapper = shallow(<GraduationDate isRequired={true} />);
|
|
127
127
|
|
|
128
|
-
it('
|
|
128
|
+
it('makes both fields required', () => {
|
|
129
129
|
expect(
|
|
130
130
|
wrapper.find('#graduationDateMonth').prop('required')
|
|
131
131
|
).toBeTruthy();
|
|
@@ -136,7 +136,7 @@ describe('GraduationDate', () => {
|
|
|
136
136
|
describe('given the hasError prop is set to true', () => {
|
|
137
137
|
const wrapper = shallow(<GraduationDate hasError={true} />);
|
|
138
138
|
|
|
139
|
-
it('
|
|
139
|
+
it('adds an invalid modifier class', () => {
|
|
140
140
|
expect(wrapper.find('div.o-forms-input').prop('className')).toMatch(
|
|
141
141
|
'o-forms-input--invalid'
|
|
142
142
|
);
|
package/components/index.jsx
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export { AcceptTerms } from './accept-terms';
|
|
2
2
|
export { AppBanner } from './app-banner';
|
|
3
|
-
export { B2cPartnershipPaymentTerm } from './b2c-partnership-payment-term';
|
|
4
3
|
export { BillingCity } from './billing-city';
|
|
5
4
|
export { BillingCountry } from './billing-country';
|
|
6
5
|
export { BillingPostcode } from './billing-postcode';
|
|
@@ -54,3 +53,4 @@ export { EducationJobTitle } from './education-job-title';
|
|
|
54
53
|
export { GraduationDate } from './graduation-date';
|
|
55
54
|
export { LiteSubConfirmation } from './lite-sub-confirmation';
|
|
56
55
|
export { GoogleSignIn } from './google-sign-in';
|
|
56
|
+
export { TextInput } from './text-input';
|
package/components/message.jsx
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import classNames from 'classnames';
|
|
4
|
+
import {
|
|
5
|
+
Period,
|
|
6
|
+
Monthly,
|
|
7
|
+
} from '@financial-times/n-pricing';
|
|
8
|
+
|
|
4
9
|
export function PaymentTerm ({
|
|
5
10
|
fieldId = 'paymentTermField',
|
|
6
11
|
inputName = 'paymentTerm',
|
|
@@ -8,11 +13,50 @@ export function PaymentTerm ({
|
|
|
8
13
|
isEpaper = false,
|
|
9
14
|
options = [],
|
|
10
15
|
isFixedTermOffer = false,
|
|
11
|
-
|
|
16
|
+
offerDisplayName,
|
|
12
17
|
showLegal = true,
|
|
13
18
|
largePrice = false,
|
|
14
19
|
optionsInARow = false,
|
|
15
20
|
}) {
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Compute monthly price for given term name
|
|
24
|
+
* @param {number} amount price in number format
|
|
25
|
+
* @param {string} currency country id of the currency
|
|
26
|
+
* @param {string} period PxY (yearly) or PxM (montly) where x is the amount of years/months
|
|
27
|
+
* @returns {string}
|
|
28
|
+
*/
|
|
29
|
+
const getMontlyPriceFromPeriod = (amount, currency, period) => {
|
|
30
|
+
const periodObj = new Period(period);
|
|
31
|
+
const monthlyPrice = periodObj.calculatePrice('P1M', amount);
|
|
32
|
+
return new Monthly({ value: monthlyPrice, currency }).getAmount('monthly');
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* returns period converted to time if found
|
|
37
|
+
* otherwise returns empty string to avoid show information not mapped
|
|
38
|
+
* @param {string} period PxY (yearly) or PxM (montly) where x is the amount of years/months
|
|
39
|
+
* @returns {string}
|
|
40
|
+
*/
|
|
41
|
+
const getTimeFromPeriod = (period) => {
|
|
42
|
+
const freq = period.substring(period.length - 1) === 'Y' ? 'years' : 'months';
|
|
43
|
+
const amount = period.substring(1, period.length - 1);
|
|
44
|
+
return (
|
|
45
|
+
period ? `${amount} ${freq}` : ''
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const isValidPeriod = (period) => {
|
|
50
|
+
try {
|
|
51
|
+
// Period should throw an error if it is not properly provided
|
|
52
|
+
// in order to validate it, we just send in case type is string
|
|
53
|
+
new Period(typeof period === 'string' ? period : '');
|
|
54
|
+
return true;
|
|
55
|
+
} catch (e) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
16
60
|
const nameMap = {
|
|
17
61
|
annual: {
|
|
18
62
|
title: 'Annual',
|
|
@@ -89,6 +133,37 @@ export function PaymentTerm ({
|
|
|
89
133
|
);
|
|
90
134
|
},
|
|
91
135
|
},
|
|
136
|
+
custom: {
|
|
137
|
+
price: (price) => (
|
|
138
|
+
<React.Fragment>
|
|
139
|
+
Single{' '}
|
|
140
|
+
<span className="ncf__payment-term__price ncf__strong">{price}</span>{' '}
|
|
141
|
+
payment
|
|
142
|
+
</React.Fragment>
|
|
143
|
+
),
|
|
144
|
+
trialPrice: (trialPrice, trialPeriod) => (
|
|
145
|
+
<React.Fragment>
|
|
146
|
+
Unless you cancel during your trial you will be billed{' '}
|
|
147
|
+
<span className="ncf__payment-term__price">{trialPrice}</span> per {trialPeriod}
|
|
148
|
+
after the trial period.
|
|
149
|
+
</React.Fragment>
|
|
150
|
+
),
|
|
151
|
+
monthlyPrice: (monthlyPrice) =>
|
|
152
|
+
Boolean(monthlyPrice) && (
|
|
153
|
+
<span className="ncf__payment-term__equivalent-price">
|
|
154
|
+
That’s equivalent to{' '}
|
|
155
|
+
<span className="ncf__payment-term__monthly-price">{monthlyPrice}</span>{' '}
|
|
156
|
+
per month
|
|
157
|
+
</span>
|
|
158
|
+
),
|
|
159
|
+
renewsText: (renewalPeriod) => (
|
|
160
|
+
Boolean(renewalPeriod) && (
|
|
161
|
+
<p className="ncf__payment-term__renews-text">
|
|
162
|
+
Renews every {renewalPeriod} unless cancelled
|
|
163
|
+
</p>
|
|
164
|
+
)
|
|
165
|
+
),
|
|
166
|
+
}
|
|
92
167
|
};
|
|
93
168
|
const createPaymentTerm = (option) => {
|
|
94
169
|
const className = classNames([
|
|
@@ -106,18 +181,22 @@ export function PaymentTerm ({
|
|
|
106
181
|
'o-forms-input__radio o-forms-input__radio--right ncf__payment-term__input',
|
|
107
182
|
...(option.selected && { defaultChecked: true }),
|
|
108
183
|
};
|
|
109
|
-
|
|
110
|
-
option.isTrial && !isPrintOrBundle && !isEpaper;
|
|
111
|
-
const defaultTitle = option.name ? nameMap[option.name].title : '';
|
|
112
|
-
const title = isFixedTermOffer
|
|
113
|
-
? `${displayName} - ${defaultTitle}`
|
|
114
|
-
: defaultTitle;
|
|
184
|
+
|
|
115
185
|
const createDiscount = () => {
|
|
116
186
|
return (
|
|
117
187
|
option.discount && (
|
|
118
188
|
<span className="ncf__payment-term__discount">
|
|
119
|
-
{option.bestOffer ? 'Best offer
|
|
120
|
-
|
|
189
|
+
{option.bestOffer ? 'Best offer' : `Save ${option.discount} off RRP`}
|
|
190
|
+
</span>
|
|
191
|
+
)
|
|
192
|
+
);
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const createB2cDiscountCopy = () => {
|
|
196
|
+
return (
|
|
197
|
+
option.name === 'annual' && option.b2cPartnership && option.b2cDiscountCopy && (
|
|
198
|
+
<span className="ncf__payment-term__discount">
|
|
199
|
+
{option.b2cDiscountCopy}
|
|
121
200
|
</span>
|
|
122
201
|
)
|
|
123
202
|
);
|
|
@@ -144,23 +223,69 @@ export function PaymentTerm ({
|
|
|
144
223
|
{/* <br />Save up to 25% when you pay annually */}
|
|
145
224
|
</div>
|
|
146
225
|
) : (
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
>
|
|
151
|
-
{option.price}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
226
|
+
// this should cover the cases different than annual, quarterly and monthly
|
|
227
|
+
// for those containing period on option.value, render custom template, for the rest keep legacy render
|
|
228
|
+
isValidPeriod(option.value) ?
|
|
229
|
+
<div className="ncf__payment-term__description">
|
|
230
|
+
{nameMap['custom'].price(option.price)}
|
|
231
|
+
{nameMap['custom'].monthlyPrice(
|
|
232
|
+
option.monthlyPrice && option.monthlyPrice !== '0' ? Number(option.monthlyPrice) : getMontlyPriceFromPeriod(option.amount, option.currency, option.value)
|
|
233
|
+
)}
|
|
234
|
+
{nameMap['custom'].renewsText(getTimeFromPeriod(option.value))}
|
|
235
|
+
</div>
|
|
236
|
+
: (
|
|
237
|
+
<div>
|
|
238
|
+
<span className={largePrice ? 'ncf__payment-term__large-price' : ''}>
|
|
239
|
+
{option.price}
|
|
240
|
+
</span>
|
|
241
|
+
{option.chargeOnText && (
|
|
242
|
+
<p className="ncf__payment-term__charge-on-text">
|
|
243
|
+
{option.chargeOnText}
|
|
244
|
+
</p>
|
|
245
|
+
)}
|
|
246
|
+
</div>
|
|
247
|
+
)
|
|
159
248
|
)}
|
|
160
249
|
</React.Fragment>
|
|
161
250
|
);
|
|
162
251
|
};
|
|
163
252
|
|
|
253
|
+
const getTermDisplayName = () => {
|
|
254
|
+
|
|
255
|
+
const showTrialCopyInTitle =
|
|
256
|
+
option.isTrial && !isPrintOrBundle && !isEpaper;
|
|
257
|
+
|
|
258
|
+
const defaultTitle = (option.name && nameMap[option.name]) ? nameMap[option.name].title : '';
|
|
259
|
+
|
|
260
|
+
const title = isFixedTermOffer
|
|
261
|
+
? `${offerDisplayName} - ${defaultTitle}`
|
|
262
|
+
: defaultTitle;
|
|
263
|
+
|
|
264
|
+
let termDisplayName = '';
|
|
265
|
+
if (showTrialCopyInTitle) {
|
|
266
|
+
const termName = option.displayName ? option.displayName : 'Premium Digital';
|
|
267
|
+
termDisplayName = `Trial: ${termName} - `;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const getTermPeriod = () => {
|
|
271
|
+
// annual, quarterly and monthly
|
|
272
|
+
if (nameMap[option.name]) {
|
|
273
|
+
return title;
|
|
274
|
+
}
|
|
275
|
+
// custom offer with period provided
|
|
276
|
+
if (isValidPeriod(option.value)) {
|
|
277
|
+
return getTimeFromPeriod(option.value);
|
|
278
|
+
}
|
|
279
|
+
// custom legacy cases, where period is not provided
|
|
280
|
+
return option.title;
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
const termPeriod = getTermPeriod();
|
|
284
|
+
termDisplayName = `${termDisplayName}${termPeriod} `;
|
|
285
|
+
|
|
286
|
+
return termDisplayName;
|
|
287
|
+
};
|
|
288
|
+
|
|
164
289
|
return (
|
|
165
290
|
<div key={option.value} className={className}>
|
|
166
291
|
<input {...props} />
|
|
@@ -169,6 +294,7 @@ export function PaymentTerm ({
|
|
|
169
294
|
className="o-forms-input__label ncf__payment-term__label"
|
|
170
295
|
>
|
|
171
296
|
{createDiscount()}
|
|
297
|
+
{createB2cDiscountCopy()}
|
|
172
298
|
|
|
173
299
|
<span
|
|
174
300
|
className={classNames([
|
|
@@ -176,8 +302,7 @@ export function PaymentTerm ({
|
|
|
176
302
|
{ 'ncf__payment-term__title--large-price': largePrice },
|
|
177
303
|
])}
|
|
178
304
|
>
|
|
179
|
-
{
|
|
180
|
-
{nameMap[option.name] ? title : option.title}{' '}
|
|
305
|
+
{getTermDisplayName()}
|
|
181
306
|
{option.subTitle && (
|
|
182
307
|
<span className="ncf__regular ncf__payment-term__sub-title">
|
|
183
308
|
{option.subTitle}
|
|
@@ -250,6 +375,8 @@ PaymentTerm.propTypes = {
|
|
|
250
375
|
isEpaper: PropTypes.bool,
|
|
251
376
|
options: PropTypes.arrayOf(
|
|
252
377
|
PropTypes.shape({
|
|
378
|
+
b2cDiscountCopy: PropTypes.string,
|
|
379
|
+
isB2cPartnership: PropTypes.bool,
|
|
253
380
|
discount: PropTypes.string,
|
|
254
381
|
isTrial: PropTypes.bool,
|
|
255
382
|
name: PropTypes.string.isRequired,
|
|
@@ -257,7 +384,7 @@ PaymentTerm.propTypes = {
|
|
|
257
384
|
selected: PropTypes.bool,
|
|
258
385
|
trialDuration: PropTypes.string,
|
|
259
386
|
trialPrice: PropTypes.string,
|
|
260
|
-
amount: PropTypes.
|
|
387
|
+
amount: PropTypes.string,
|
|
261
388
|
trialAmount: PropTypes.number,
|
|
262
389
|
value: PropTypes.string.isRequired,
|
|
263
390
|
monthlyPrice: PropTypes.string,
|
|
@@ -268,7 +395,7 @@ PaymentTerm.propTypes = {
|
|
|
268
395
|
})
|
|
269
396
|
),
|
|
270
397
|
isFixedTermOffer: PropTypes.bool,
|
|
271
|
-
|
|
398
|
+
offerDisplayName: PropTypes.string,
|
|
272
399
|
showLegal: PropTypes.bool,
|
|
273
400
|
largePrice: PropTypes.bool,
|
|
274
401
|
optionsInARow: PropTypes.bool,
|
|
@@ -130,29 +130,71 @@ describe('PaymentTerm', () => {
|
|
|
130
130
|
<PaymentTerm
|
|
131
131
|
isFixedTermOffer={true}
|
|
132
132
|
options={options}
|
|
133
|
-
|
|
133
|
+
offerDisplayName="Mix & Match"
|
|
134
134
|
/>
|
|
135
135
|
);
|
|
136
136
|
|
|
137
|
-
it('
|
|
137
|
+
it('does not include renewal text', () => {
|
|
138
138
|
expect(
|
|
139
139
|
wrapper.find('.ncf__payment-term__renews-text').text()
|
|
140
140
|
).not.toMatch(/Renews (annually|monthly|quarterly) unless cancelled/);
|
|
141
141
|
});
|
|
142
142
|
|
|
143
|
-
it('
|
|
143
|
+
it('renders fixed term renewal text in English', () => {
|
|
144
144
|
expect(wrapper.find('.ncf__payment-term__renews-text').text()).toMatch(
|
|
145
145
|
/This subscription is for 3 months, charged monthly. You can cancel at anytime/
|
|
146
146
|
);
|
|
147
147
|
});
|
|
148
148
|
|
|
149
|
-
it('
|
|
149
|
+
it('renders offer name on payment term title', () => {
|
|
150
150
|
expect(wrapper.find('.ncf__payment-term__title').text()).toMatch(
|
|
151
151
|
'Mix & Match - Monthly'
|
|
152
152
|
);
|
|
153
153
|
});
|
|
154
154
|
});
|
|
155
155
|
|
|
156
|
+
describe('getDisplayName', () => {
|
|
157
|
+
const baseOptions = {
|
|
158
|
+
name: 'monthly',
|
|
159
|
+
value: 'monthly',
|
|
160
|
+
price: '£20.00',
|
|
161
|
+
monthlyPrice: '£1.67',
|
|
162
|
+
};
|
|
163
|
+
describe('non-trial terms', () => {
|
|
164
|
+
const options = [{
|
|
165
|
+
...baseOptions,
|
|
166
|
+
isTrial: false,
|
|
167
|
+
}];
|
|
168
|
+
it('renders with time period only if trial.option == false', () => {
|
|
169
|
+
const wrapper = shallow(<PaymentTerm options={options} />);
|
|
170
|
+
expect(wrapper.find('.ncf__payment-term__label').text()).toMatch(/^Monthly .*$/);
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
describe('getDisplayName', () => {
|
|
174
|
+
const trialOptions = {
|
|
175
|
+
...baseOptions,
|
|
176
|
+
isTrial: true,
|
|
177
|
+
};
|
|
178
|
+
it('defaults to `Premium digital`', () => {
|
|
179
|
+
const options = [trialOptions];
|
|
180
|
+
const wrapper = shallow(<PaymentTerm options={options} />);
|
|
181
|
+
expect(wrapper.find('.ncf__payment-term__label').text()).toMatch(
|
|
182
|
+
/^Trial: Premium Digital - Monthly .*$/
|
|
183
|
+
);
|
|
184
|
+
});
|
|
185
|
+
it('renders using displayName if available', () => {
|
|
186
|
+
const options = [{
|
|
187
|
+
...trialOptions,
|
|
188
|
+
displayName: 'someDisplayName',
|
|
189
|
+
}];
|
|
190
|
+
const wrapper = shallow(<PaymentTerm options={options} />);
|
|
191
|
+
expect(wrapper.find('.ncf__payment-term__label').text()).toMatch(
|
|
192
|
+
/^Trial: someDisplayName - Monthly .*/
|
|
193
|
+
);
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
156
198
|
describe('[data-base-amount]', () => {
|
|
157
199
|
it('renders option.amount as data-base-amount if isTrial is false', () => {
|
|
158
200
|
const options = [
|
|
@@ -14,25 +14,80 @@ export const Basic = (args) => (
|
|
|
14
14
|
</Fieldset>
|
|
15
15
|
</div>
|
|
16
16
|
);
|
|
17
|
+
|
|
17
18
|
Basic.args = {
|
|
18
19
|
options: [
|
|
19
20
|
{
|
|
20
|
-
name: '
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
'name': '2 yearly',
|
|
22
|
+
'isTrial': true,
|
|
23
|
+
'discount': '',
|
|
24
|
+
'selected': false,
|
|
25
|
+
'price': '$645.00',
|
|
26
|
+
'trialPrice': '$100.00',
|
|
27
|
+
'trialDuration': 'Trial period',
|
|
28
|
+
'monthlyPrice': '0',
|
|
29
|
+
'amount': '645.00',
|
|
30
|
+
'trialAmount': 100,
|
|
31
|
+
'value': 'P2Y',
|
|
32
|
+
'currency': 'USD'
|
|
26
33
|
},
|
|
27
34
|
{
|
|
28
|
-
name: '
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
'name': '3 yearly',
|
|
36
|
+
'isTrial': false,
|
|
37
|
+
'discount': '',
|
|
38
|
+
'selected': false,
|
|
39
|
+
'price': '$909.00',
|
|
40
|
+
'trialPrice': '$0.00',
|
|
41
|
+
'trialDuration': '',
|
|
42
|
+
'monthlyPrice': '0',
|
|
43
|
+
'amount': '909.00',
|
|
44
|
+
'trialAmount': null,
|
|
45
|
+
'value': 'P3Y',
|
|
46
|
+
'currency': 'USD'
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
'name': '6 monthly',
|
|
50
|
+
'isTrial': false,
|
|
51
|
+
'discount': '',
|
|
52
|
+
'selected': false,
|
|
53
|
+
'price': '$229.00',
|
|
54
|
+
'trialPrice': '$0.00',
|
|
55
|
+
'trialDuration': '',
|
|
56
|
+
'monthlyPrice': '0',
|
|
57
|
+
'amount': '229.00',
|
|
58
|
+
'trialAmount': null,
|
|
59
|
+
'value': 'P6M',
|
|
60
|
+
'currency': 'USD'
|
|
34
61
|
},
|
|
35
|
-
|
|
62
|
+
{
|
|
63
|
+
'name': 'annual',
|
|
64
|
+
'isTrial': false,
|
|
65
|
+
'discount': '',
|
|
66
|
+
'selected': true,
|
|
67
|
+
'price': '$385.00',
|
|
68
|
+
'trialPrice': '$0.00',
|
|
69
|
+
'trialDuration': '',
|
|
70
|
+
'monthlyPrice': '$32.09',
|
|
71
|
+
'amount': '385.00',
|
|
72
|
+
'trialAmount': null,
|
|
73
|
+
'value': 'P1Y',
|
|
74
|
+
'currency': 'USD'
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
'name': 'quarterly',
|
|
78
|
+
'isTrial': false,
|
|
79
|
+
'discount': '',
|
|
80
|
+
'selected': false,
|
|
81
|
+
'price': '$95.00',
|
|
82
|
+
'trialPrice': '$0.00',
|
|
83
|
+
'trialDuration': '',
|
|
84
|
+
'monthlyPrice': '$31.67',
|
|
85
|
+
'amount': '95.00',
|
|
86
|
+
'trialAmount': null,
|
|
87
|
+
'value': 'P3M',
|
|
88
|
+
'currency': 'USD'
|
|
89
|
+
}
|
|
90
|
+
]
|
|
36
91
|
};
|
|
37
92
|
|
|
38
93
|
export const FixedTermOffer = (args) => (
|
|
@@ -51,7 +106,7 @@ FixedTermOffer.args = {
|
|
|
51
106
|
},
|
|
52
107
|
],
|
|
53
108
|
isFixedTermOffer: true,
|
|
54
|
-
|
|
109
|
+
offerDisplayName: 'Mix & Match',
|
|
55
110
|
};
|
|
56
111
|
|
|
57
112
|
export const RenewOffers = (args) => (
|
|
@@ -228,6 +228,7 @@ export function PaymentType ({
|
|
|
228
228
|
name: 'payFasterNextTime',
|
|
229
229
|
value: 'true',
|
|
230
230
|
required: false,
|
|
231
|
+
checked: true,
|
|
231
232
|
...(isSingleTermChecked && { defaultChecked: true }),
|
|
232
233
|
};
|
|
233
234
|
|
|
@@ -247,7 +248,8 @@ export function PaymentType ({
|
|
|
247
248
|
{createDirectDebitPanel()}
|
|
248
249
|
|
|
249
250
|
{createZuoraPanel()}
|
|
250
|
-
|
|
251
|
+
</div>
|
|
252
|
+
<div className="o-forms-field">
|
|
251
253
|
{isSingleTerm && (
|
|
252
254
|
<>
|
|
253
255
|
<label
|
package/components/position.jsx
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import classNames from 'classnames';
|
|
4
|
-
import { demographics } from 'n-common-static-data';
|
|
5
|
-
const
|
|
4
|
+
import { b2b, demographics } from 'n-common-static-data';
|
|
5
|
+
const B2CPositions = demographics.positions.positions;
|
|
6
|
+
const B2BPositions = b2b.demographics.positions.positions;
|
|
6
7
|
|
|
7
8
|
export function Position ({
|
|
8
9
|
value,
|
|
@@ -11,7 +12,8 @@ export function Position ({
|
|
|
11
12
|
fieldId = 'positionField',
|
|
12
13
|
selectId = 'position',
|
|
13
14
|
selectName = 'position',
|
|
14
|
-
|
|
15
|
+
isB2B = false,
|
|
16
|
+
options = isB2B ? B2BPositions : B2CPositions,
|
|
15
17
|
isRequired = true,
|
|
16
18
|
fieldLabel = 'What’s your job position?',
|
|
17
19
|
}) {
|
|
@@ -70,6 +72,7 @@ Position.propTypes = {
|
|
|
70
72
|
fieldId: PropTypes.string,
|
|
71
73
|
selectId: PropTypes.string,
|
|
72
74
|
selectName: PropTypes.string,
|
|
75
|
+
isB2B: PropTypes.bool,
|
|
73
76
|
options: PropTypes.arrayOf(
|
|
74
77
|
PropTypes.shape({
|
|
75
78
|
code: PropTypes.string,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Position } from './index';
|
|
2
2
|
import { expectToRenderCorrectly } from '../test-jest/helpers/expect-to-render-correctly';
|
|
3
3
|
import { demographics } from 'n-common-static-data';
|
|
4
|
-
const
|
|
4
|
+
const B2CPositions = demographics.positions.positions;
|
|
5
5
|
|
|
6
6
|
import Enzyme, { mount } from 'enzyme';
|
|
7
7
|
import Adapter from 'enzyme-adapter-react-16';
|
|
@@ -12,7 +12,7 @@ expect.extend(expectToRenderCorrectly);
|
|
|
12
12
|
describe('Position', () => {
|
|
13
13
|
it('render a select with a label', () => {
|
|
14
14
|
const props = {
|
|
15
|
-
options:
|
|
15
|
+
options: B2CPositions,
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
expect(Position).toRenderCorrectly(props);
|
|
@@ -20,7 +20,7 @@ describe('Position', () => {
|
|
|
20
20
|
|
|
21
21
|
it('can render an initial selected value', () => {
|
|
22
22
|
const props = {
|
|
23
|
-
options:
|
|
23
|
+
options: B2CPositions,
|
|
24
24
|
value: 'CP',
|
|
25
25
|
};
|
|
26
26
|
|
|
@@ -29,7 +29,7 @@ describe('Position', () => {
|
|
|
29
29
|
|
|
30
30
|
it('can render a disable select', () => {
|
|
31
31
|
const props = {
|
|
32
|
-
options:
|
|
32
|
+
options: B2CPositions,
|
|
33
33
|
isDisabled: true,
|
|
34
34
|
};
|
|
35
35
|
|
|
@@ -38,7 +38,7 @@ describe('Position', () => {
|
|
|
38
38
|
|
|
39
39
|
it('can render an error message', () => {
|
|
40
40
|
const props = {
|
|
41
|
-
options:
|
|
41
|
+
options: B2CPositions,
|
|
42
42
|
hasError: true,
|
|
43
43
|
};
|
|
44
44
|
|
|
@@ -68,4 +68,14 @@ describe('Position', () => {
|
|
|
68
68
|
component.find('.o-forms-title.o-forms-field--optional').length
|
|
69
69
|
).toEqual(1);
|
|
70
70
|
});
|
|
71
|
+
|
|
72
|
+
it('defaults to B2B options if isB2B is true', () => {
|
|
73
|
+
const props = { isB2B: true };
|
|
74
|
+
const component = mount(Position(props));
|
|
75
|
+
|
|
76
|
+
// Look for an option which is only present in the default B2B data set and not in the B2C one.
|
|
77
|
+
const optionValue = component.find('option').at(1).instance().value;
|
|
78
|
+
|
|
79
|
+
expect(optionValue).toBe('OW');
|
|
80
|
+
});
|
|
71
81
|
});
|