@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.
Files changed (111) hide show
  1. package/.circleci/config.yml +4 -4
  2. package/.eslintignore +1 -0
  3. package/.github/workflows/gh-pages-deploy.yml +1 -0
  4. package/.storybook/main.js +0 -1
  5. package/__mocks__/@financial-times/o-expander.js +9 -0
  6. package/__mocks__/@financial-times/o-forms-input.js +11 -0
  7. package/__mocks__/@financial-times/o-forms.js +40 -0
  8. package/build-state/npm-shrinkwrap.json +294 -6334
  9. package/components/__snapshots__/b2c-partnership-confirmation.spec.js.snap +1 -1
  10. package/components/__snapshots__/confirmation.spec.js.snap +0 -3
  11. package/components/__snapshots__/debug.spec.js.snap +25 -13
  12. package/components/__snapshots__/delivery-postcode.spec.js.snap +1 -1
  13. package/components/__snapshots__/payment-term.spec.js.snap +1 -1
  14. package/components/__snapshots__/payment-type.spec.js.snap +19 -0
  15. package/components/__snapshots__/registration-confirmation.spec.js.snap +230 -74
  16. package/components/accept-terms.jsx +57 -36
  17. package/components/accept-terms.stories.js +28 -1
  18. package/components/b2c-partnership-confirmation.jsx +1 -1
  19. package/components/confirmation.jsx +15 -8
  20. package/components/confirmation.spec.js +1 -1
  21. package/components/debug.jsx +19 -12
  22. package/components/debug.stories.js +13 -0
  23. package/components/delivery-address.jsx +21 -58
  24. package/components/delivery-address.stories.js +7 -0
  25. package/components/delivery-city.jsx +4 -2
  26. package/components/delivery-city.stories.js +9 -0
  27. package/components/delivery-option.jsx +5 -3
  28. package/components/delivery-option.stories.js +7 -1
  29. package/components/delivery-postcode.jsx +32 -13
  30. package/components/delivery-postcode.stories.js +2 -1
  31. package/components/delivery-security-instructions.spec.js +3 -3
  32. package/components/graduation-date.spec.js +8 -8
  33. package/components/index.jsx +1 -1
  34. package/components/message.jsx +1 -1
  35. package/components/payment-term.jsx +152 -25
  36. package/components/payment-term.spec.js +46 -4
  37. package/components/payment-term.stories.js +69 -14
  38. package/components/payment-type.jsx +3 -1
  39. package/components/position.jsx +6 -3
  40. package/components/position.spec.js +15 -5
  41. package/components/registration-confirmation.jsx +111 -32
  42. package/components/responsibility.jsx +6 -3
  43. package/components/responsibility.spec.js +15 -5
  44. package/components/text-input.jsx +73 -0
  45. package/components/text-input.spec.js +118 -0
  46. package/components/text-input.stories.js +31 -0
  47. package/dist/accept-terms.js +15 -7
  48. package/dist/b2c-partnership-confirmation.js +1 -1
  49. package/dist/confirmation.js +11 -2
  50. package/dist/debug.js +6 -6
  51. package/dist/delivery-address.js +19 -32
  52. package/dist/delivery-city.js +4 -2
  53. package/dist/delivery-option.js +5 -2
  54. package/dist/delivery-postcode.js +31 -12
  55. package/dist/index.js +9 -9
  56. package/dist/message.js +1 -1
  57. package/dist/payment-term.js +117 -11
  58. package/dist/payment-type.js +5 -2
  59. package/dist/position.js +6 -2
  60. package/dist/registration-confirmation.js +87 -29
  61. package/dist/responsibility.js +6 -2
  62. package/dist/text-input.js +84 -0
  63. package/helpers/constants.js +7 -0
  64. package/helpers/deliveryAddressMap.js +167 -0
  65. package/helpers/index.js +7 -0
  66. package/helpers/index.spec.js +11 -0
  67. package/helpers/ncf-common-data.spec.js +34 -0
  68. package/helpers/ncf-countries.spec.js +136 -0
  69. package/helpers/supportedCountries.js +76 -0
  70. package/helpers/supportedPostcodeExamples.js +57 -0
  71. package/helpers/supportedPostcodeValidators.js +53 -0
  72. package/helpers/utilities.js +14 -0
  73. package/jest.config.js +8 -1
  74. package/main.scss +461 -0
  75. package/package.json +6 -3
  76. package/styles/confirmation.scss +122 -0
  77. package/styles/payment-term.scss +3 -0
  78. package/utils/app-banner.spec.js +68 -0
  79. package/utils/apple-pay.spec.js +177 -0
  80. package/utils/billing-country.spec.js +87 -0
  81. package/utils/billing-postcode.spec.js +138 -0
  82. package/utils/company-name.spec.js +3 -7
  83. package/utils/country.spec.js +87 -0
  84. package/utils/delivery-address-type.spec.js +24 -11
  85. package/utils/delivery-option-messages.js +15 -0
  86. package/utils/delivery-option-messages.spec.js +3 -3
  87. package/utils/delivery-option.spec.js +100 -15
  88. package/utils/delivery-postcode.spec.js +138 -0
  89. package/utils/delivery-start-date.spec.js +177 -0
  90. package/utils/email.spec.js +210 -0
  91. package/utils/event-notifier.spec.js +116 -0
  92. package/utils/form-element.spec.js +71 -0
  93. package/utils/loader.spec.js +161 -0
  94. package/utils/password.spec.js +65 -0
  95. package/utils/payment-term.js +25 -1
  96. package/utils/payment-term.spec.js +198 -0
  97. package/utils/payment-type.js +1 -1
  98. package/utils/payment-type.spec.js +136 -0
  99. package/utils/postcode.spec.js +122 -0
  100. package/utils/salesforce.spec.js +30 -0
  101. package/utils/submit.spec.js +81 -0
  102. package/utils/tracking.spec.js +174 -0
  103. package/utils/validation.js +2 -2
  104. package/utils/validation.spec.js +234 -0
  105. package/utils/zuora.spec.js +249 -0
  106. package/components/__snapshots__/b2c-partnership-payment-term.spec.js.snap +0 -193
  107. package/components/b2c-partnership-payment-term.jsx +0 -126
  108. package/components/b2c-partnership-payment-term.spec.js +0 -52
  109. package/components/b2c-partnership-payment-term.stories.js +0 -44
  110. package/dist/b2c-partnership-payment-term.js +0 -91
  111. 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('set maxLength to 10', () => {
107
+ it('sets maxLength to 10', () => {
108
108
  expect(textAreaProps.maxLength).toBe(10);
109
109
  });
110
110
 
111
- it('set rows to 3', () => {
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('set value', () => {
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('should display graduationDateMonth options as English month names', () => {
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('should store graduationDateMonth values as two-digit numbers', () => {
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('should set the default month', () => {
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('should set the default year', () => {
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('should not set any default values', () => {
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('should disable both select fields', () => {
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('should make both fields required', () => {
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('should add an invalid modifier class', () => {
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
  );
@@ -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';
@@ -87,7 +87,7 @@ const actionType = PropTypes.shape({
87
87
  link: PropTypes.string.isRequired,
88
88
  isSecondary: PropTypes.bool,
89
89
  text: PropTypes.string,
90
- target: '_self',
90
+ target: PropTypes.oneOf(['_self']),
91
91
  });
92
92
 
93
93
  Message.propTypes = {
@@ -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
- displayName,
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
- const showTrialCopyInTitle =
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 -' : 'Save'} {option.discount} off
120
- RRP
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
- <div>
148
- <span
149
- className={largePrice ? 'ncf__payment-term__large-price' : ''}
150
- >
151
- {option.price}
152
- </span>
153
- {option.chargeOnText && (
154
- <p className="ncf__payment-term__charge-on-text">
155
- {option.chargeOnText}
156
- </p>
157
- )}
158
- </div>
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
- {showTrialCopyInTitle ? 'Trial: Premium Digital - ' : ''}
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.number,
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
- displayName: PropTypes.string,
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
- displayName="Mix & Match"
133
+ offerDisplayName="Mix & Match"
134
134
  />
135
135
  );
136
136
 
137
- it('should not include renewal text', () => {
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('should render fixed term renewal text in English', () => {
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('should render offer name on payment term title', () => {
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: 'monthly',
21
- price: '£49.99',
22
- value: 49.99,
23
- isTrial: false,
24
- discount: '33%',
25
- selected: false,
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: 'annual',
29
- price: '£299.99',
30
- value: 299.99,
31
- isTrial: false,
32
- discount: null,
33
- selected: true,
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
- displayName: 'Mix & Match',
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
@@ -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 defaultOptions = demographics.positions.positions;
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
- options = defaultOptions,
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 defaultOptions = demographics.positions.positions;
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: defaultOptions,
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: defaultOptions,
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: defaultOptions,
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: defaultOptions,
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
  });