@financial-times/n-conversion-forms 20.1.1 → 20.3.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.
@@ -1266,6 +1266,66 @@ exports[`AcceptTerms renders appropriately if is transition with transition type
1266
1266
  </div>
1267
1267
  `;
1268
1268
 
1269
+ exports[`AcceptTerms renders appropriately if is transition with transition type other than immediate and is single term 1`] = `
1270
+ <div id="acceptTermsField"
1271
+ class="o-forms-field o-layout-typography ncf__validation-error"
1272
+ data-validate="required,checked"
1273
+ >
1274
+ <ul class="o-typography-list ncf__accept-terms-list">
1275
+ <li>
1276
+ <span class="terms-default">
1277
+ I confirm I am 16 years or older and have read and agree to the
1278
+ <a class="ncf__link--external"
1279
+ href="http://help.ft.com/help/legal-privacy/terms-conditions/"
1280
+ target="_blank"
1281
+ rel="noopener noreferrer"
1282
+ data-trackable="terms-and-conditions"
1283
+ >
1284
+ Terms &amp; Conditions
1285
+ </a>
1286
+ .
1287
+ </span>
1288
+ </li>
1289
+ <li>
1290
+ <span class="terms-transition terms-transition--other">
1291
+ By placing my order, I acknowledge that my subscription will start and the chosen payment method will be charged on the date given above. Any cancellation notice received after that date will take effect at the end of my subscription term and previously paid amounts are non-refundable.
1292
+ </span>
1293
+ </li>
1294
+ <li>
1295
+ <span class="terms-transition">
1296
+ Find out more about our cancellation policy in our
1297
+ <a class="ncf__link--external"
1298
+ href="http://help.ft.com/help/legal-privacy/terms-conditions/"
1299
+ target="_blank"
1300
+ rel="noopener noreferrer"
1301
+ >
1302
+ Terms &amp; Conditions
1303
+ </a>
1304
+ .
1305
+ </span>
1306
+ </li>
1307
+ </ul>
1308
+ <label class="o-forms-input o-forms-input--checkbox"
1309
+ for="termsAcceptance"
1310
+ >
1311
+ <input type="checkbox"
1312
+ id="termsAcceptance"
1313
+ name="termsAcceptance"
1314
+ value="true"
1315
+ data-trackable="field-terms"
1316
+ aria-required="true"
1317
+ required
1318
+ >
1319
+ <span class="o-forms-input__label">
1320
+ I agree to the above terms &amp; conditions.
1321
+ </span>
1322
+ <p class="o-forms-input__error">
1323
+ Please accept our terms &amp; conditions
1324
+ </p>
1325
+ </label>
1326
+ </div>
1327
+ `;
1328
+
1269
1329
  exports[`AcceptTerms renders with an error 1`] = `
1270
1330
  <div id="acceptTermsField"
1271
1331
  class="o-forms-field o-layout-typography ncf__validation-error"
@@ -18,9 +18,9 @@ exports[`PaymentTerm When using custom options renders when not using an option
18
18
  <span class="ncf__payment-term__discount">
19
19
  Best offer - 33% off RRP
20
20
  </span>
21
- <span class="ncf__payment-term__title">
21
+ <span class="ncf__payment-term__title ncf__payment-term__title--large-price">
22
22
  Annual
23
- <span class="ncf__regular">
23
+ <span class="ncf__regular ncf__payment-term__sub-title">
24
24
  (Renews annually unless cancelled)
25
25
  </span>
26
26
  </span>
@@ -48,7 +48,7 @@ exports[`PaymentTerm When using custom options renders when not using an option
48
48
  <span class="ncf__payment-term__discount">
49
49
  Save 10% off RRP
50
50
  </span>
51
- <span class="ncf__payment-term__title">
51
+ <span class="ncf__payment-term__title ncf__payment-term__title--large-price">
52
52
  12 Month Subscription
53
53
  </span>
54
54
  <div>
@@ -523,6 +523,179 @@ exports[`PaymentType render with enablePaypal 1`] = `
523
523
  </div>
524
524
  `;
525
525
 
526
+ exports[`PaymentType render with isSingleTerm 1`] = `
527
+ <div class="ncf__security-seal">
528
+ </div>
529
+ <div id="paymentTypeField"
530
+ class="o-forms-field"
531
+ >
532
+ <div class="o-forms-input o-forms-input--radio-box ncf__payment-type-selector">
533
+ <div class="o-forms-input--radio-box__container ncf__payment-type ncf__payment-type--creditcard ncf__hidden">
534
+ <label for="creditcard">
535
+ <input type="radio"
536
+ name="paymentType"
537
+ value="creditcard"
538
+ id="creditcard"
539
+ aria-label="Credit / Debit Card"
540
+ >
541
+ <span class="o-forms-input__label"
542
+ aria-hidden="true"
543
+ >
544
+ Credit / Debit Card
545
+ </span>
546
+ </label>
547
+ </div>
548
+ <div class="o-forms-input--radio-box__container ncf__payment-type ncf__payment-type--paypal ncf__hidden">
549
+ <label for="paypal">
550
+ <input type="radio"
551
+ name="paymentType"
552
+ value="paypal"
553
+ id="paypal"
554
+ aria-label="PayPal"
555
+ >
556
+ <span class="o-forms-input__label"
557
+ aria-hidden="true"
558
+ >
559
+ PayPal
560
+ </span>
561
+ </label>
562
+ </div>
563
+ <div class="o-forms-input--radio-box__container ncf__payment-type ncf__payment-type--directdebit ncf__hidden">
564
+ <label for="directdebit">
565
+ <input type="radio"
566
+ name="paymentType"
567
+ value="directdebit"
568
+ id="directdebit"
569
+ aria-label="Direct Debit"
570
+ >
571
+ <span class="o-forms-input__label"
572
+ aria-hidden="true"
573
+ >
574
+ Direct Debit
575
+ </span>
576
+ </label>
577
+ </div>
578
+ <div class="o-forms-input--radio-box__container ncf__payment-type ncf__payment-type--applepay ncf__hidden">
579
+ <label for="applepay">
580
+ <input type="radio"
581
+ name="paymentType"
582
+ value="applepay"
583
+ id="applepay"
584
+ aria-label="Apple Pay"
585
+ >
586
+ <span class="o-forms-input__label"
587
+ aria-hidden="true"
588
+ >
589
+ Apple Pay
590
+ </span>
591
+ </label>
592
+ </div>
593
+ </div>
594
+ <div class="o-forms-input__error">
595
+ Please enter a valid payment type
596
+ </div>
597
+ <label class="o-forms-input o-forms-input--checkbox o-forms-input--suffix ncf__payment-type-pay-faster-next-time-checkbox"
598
+ for="payFasterNextTime"
599
+ >
600
+ <input type="checkbox"
601
+ id="payFasterNextTime"
602
+ name="payFasterNextTime"
603
+ value="true"
604
+ >
605
+ <span class="o-forms-input__label">
606
+ Use these details to pay faster next time
607
+ </span>
608
+ </label>
609
+ </div>
610
+ `;
611
+
612
+ exports[`PaymentType render with isSingleTermChecked 1`] = `
613
+ <div class="ncf__security-seal">
614
+ </div>
615
+ <div id="paymentTypeField"
616
+ class="o-forms-field"
617
+ >
618
+ <div class="o-forms-input o-forms-input--radio-box ncf__payment-type-selector">
619
+ <div class="o-forms-input--radio-box__container ncf__payment-type ncf__payment-type--creditcard ncf__hidden">
620
+ <label for="creditcard">
621
+ <input type="radio"
622
+ name="paymentType"
623
+ value="creditcard"
624
+ id="creditcard"
625
+ aria-label="Credit / Debit Card"
626
+ >
627
+ <span class="o-forms-input__label"
628
+ aria-hidden="true"
629
+ >
630
+ Credit / Debit Card
631
+ </span>
632
+ </label>
633
+ </div>
634
+ <div class="o-forms-input--radio-box__container ncf__payment-type ncf__payment-type--paypal ncf__hidden">
635
+ <label for="paypal">
636
+ <input type="radio"
637
+ name="paymentType"
638
+ value="paypal"
639
+ id="paypal"
640
+ aria-label="PayPal"
641
+ >
642
+ <span class="o-forms-input__label"
643
+ aria-hidden="true"
644
+ >
645
+ PayPal
646
+ </span>
647
+ </label>
648
+ </div>
649
+ <div class="o-forms-input--radio-box__container ncf__payment-type ncf__payment-type--directdebit ncf__hidden">
650
+ <label for="directdebit">
651
+ <input type="radio"
652
+ name="paymentType"
653
+ value="directdebit"
654
+ id="directdebit"
655
+ aria-label="Direct Debit"
656
+ >
657
+ <span class="o-forms-input__label"
658
+ aria-hidden="true"
659
+ >
660
+ Direct Debit
661
+ </span>
662
+ </label>
663
+ </div>
664
+ <div class="o-forms-input--radio-box__container ncf__payment-type ncf__payment-type--applepay ncf__hidden">
665
+ <label for="applepay">
666
+ <input type="radio"
667
+ name="paymentType"
668
+ value="applepay"
669
+ id="applepay"
670
+ aria-label="Apple Pay"
671
+ >
672
+ <span class="o-forms-input__label"
673
+ aria-hidden="true"
674
+ >
675
+ Apple Pay
676
+ </span>
677
+ </label>
678
+ </div>
679
+ </div>
680
+ <div class="o-forms-input__error">
681
+ Please enter a valid payment type
682
+ </div>
683
+ <label class="o-forms-input o-forms-input--checkbox o-forms-input--suffix ncf__payment-type-pay-faster-next-time-checkbox"
684
+ for="payFasterNextTime"
685
+ >
686
+ <input type="checkbox"
687
+ id="payFasterNextTime"
688
+ name="payFasterNextTime"
689
+ value="true"
690
+ checked
691
+ >
692
+ <span class="o-forms-input__label">
693
+ Use these details to pay faster next time
694
+ </span>
695
+ </label>
696
+ </div>
697
+ `;
698
+
526
699
  exports[`PaymentType render with value 1`] = `
527
700
  <div class="ncf__security-seal">
528
701
  </div>
@@ -0,0 +1,162 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`PersonalTitle can render a disable select 1`] = `
4
+ <label id="titleField"
5
+ class="o-forms-field ncf__validation-error"
6
+ for="title"
7
+ >
8
+ <span class="o-forms-title">
9
+ <span class="o-forms-title__main">
10
+ Title
11
+ </span>
12
+ </span>
13
+ <span class="o-forms-input o-forms-input--select">
14
+ <select id="title"
15
+ name="title"
16
+ data-trackable="title"
17
+ aria-required="true"
18
+ required
19
+ disabled
20
+ >
21
+ <option value>
22
+ Please select a title
23
+ </option>
24
+ <option value="Mr">
25
+ Mr
26
+ </option>
27
+ <option value="Mrs">
28
+ Mrs
29
+ </option>
30
+ <option value="Miss">
31
+ Miss
32
+ </option>
33
+ <option value="Ms">
34
+ Ms
35
+ </option>
36
+ </select>
37
+ <span class="o-forms-input__error">
38
+ Please select your personal title
39
+ </span>
40
+ </span>
41
+ </label>
42
+ `;
43
+
44
+ exports[`PersonalTitle can render an error message 1`] = `
45
+ <label id="titleField"
46
+ class="o-forms-field ncf__validation-error"
47
+ for="title"
48
+ >
49
+ <span class="o-forms-title">
50
+ <span class="o-forms-title__main">
51
+ Title
52
+ </span>
53
+ </span>
54
+ <span class="o-forms-input o-forms-input--select o-forms-input--invalid">
55
+ <select id="title"
56
+ name="title"
57
+ data-trackable="title"
58
+ aria-required="true"
59
+ required
60
+ >
61
+ <option value>
62
+ Please select a title
63
+ </option>
64
+ <option value="Mr">
65
+ Mr
66
+ </option>
67
+ <option value="Mrs">
68
+ Mrs
69
+ </option>
70
+ <option value="Miss">
71
+ Miss
72
+ </option>
73
+ <option value="Ms">
74
+ Ms
75
+ </option>
76
+ </select>
77
+ <span class="o-forms-input__error">
78
+ Please select your personal title
79
+ </span>
80
+ </span>
81
+ </label>
82
+ `;
83
+
84
+ exports[`PersonalTitle can render an initial selected value 1`] = `
85
+ <label id="titleField"
86
+ class="o-forms-field ncf__validation-error"
87
+ for="title"
88
+ >
89
+ <span class="o-forms-title">
90
+ <span class="o-forms-title__main">
91
+ Title
92
+ </span>
93
+ </span>
94
+ <span class="o-forms-input o-forms-input--select">
95
+ <select id="title"
96
+ name="title"
97
+ data-trackable="title"
98
+ aria-required="true"
99
+ required
100
+ >
101
+ <option value>
102
+ Please select a title
103
+ </option>
104
+ <option value="Mr">
105
+ Mr
106
+ </option>
107
+ <option value="Mrs">
108
+ Mrs
109
+ </option>
110
+ <option value="Miss">
111
+ Miss
112
+ </option>
113
+ <option value="Ms">
114
+ Ms
115
+ </option>
116
+ </select>
117
+ <span class="o-forms-input__error">
118
+ Please select your personal title
119
+ </span>
120
+ </span>
121
+ </label>
122
+ `;
123
+
124
+ exports[`PersonalTitle render a select with a label 1`] = `
125
+ <label id="titleField"
126
+ class="o-forms-field ncf__validation-error"
127
+ for="title"
128
+ >
129
+ <span class="o-forms-title">
130
+ <span class="o-forms-title__main">
131
+ Title
132
+ </span>
133
+ </span>
134
+ <span class="o-forms-input o-forms-input--select">
135
+ <select id="title"
136
+ name="title"
137
+ data-trackable="title"
138
+ aria-required="true"
139
+ required
140
+ >
141
+ <option value>
142
+ Please select a title
143
+ </option>
144
+ <option value="Mr">
145
+ Mr
146
+ </option>
147
+ <option value="Mrs">
148
+ Mrs
149
+ </option>
150
+ <option value="Miss">
151
+ Miss
152
+ </option>
153
+ <option value="Ms">
154
+ Ms
155
+ </option>
156
+ </select>
157
+ <span class="o-forms-input__error">
158
+ Please select your personal title
159
+ </span>
160
+ </span>
161
+ </label>
162
+ `;
@@ -1,5 +1,24 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
+ exports[`ProgressIndicator renders completed items with disabled links 1`] = `
4
+ <div class="ncf__stepped-progress o-stepped-progress"
5
+ data-o-component="o-stepped-progress"
6
+ >
7
+ <ol class="o-stepped-progress__steps">
8
+ <li>
9
+ <span class="o-stepped-progress__step o-stepped-progress__step--complete">
10
+ <span class="o-stepped-progress__label">
11
+ Item name
12
+ <span class="o-stepped-progress__status">
13
+ (completed)
14
+ </span>
15
+ </span>
16
+ </span>
17
+ </li>
18
+ </ol>
19
+ </div>
20
+ `;
21
+
3
22
  exports[`ProgressIndicator renders items that are complete 1`] = `
4
23
  <div class="ncf__stepped-progress o-stepped-progress"
5
24
  data-o-component="o-stepped-progress"
@@ -19,6 +19,7 @@ export function AcceptTerms({
19
19
  transitionType = null,
20
20
  isPrintProduct = false,
21
21
  specialTerms = null,
22
+ isSingleTerm = false,
22
23
  }) {
23
24
  const divProps = {
24
25
  id: 'acceptTermsField',
@@ -132,22 +133,24 @@ export function AcceptTerms({
132
133
 
133
134
  const transitionTerms = isTransition && (
134
135
  <>
135
- <li>
136
- <span className="terms-transition">
137
- I give consent for my chosen payment method to be charged
138
- automatically at the end of each subscription term until I cancel it
139
- by contacting{' '}
140
- <a
141
- className="ncf__link--external"
142
- href="https://help.ft.com/help/contact-us/"
143
- target="_blank"
144
- rel="noopener noreferrer"
145
- >
146
- customer care through chat, phone or email
147
- </a>
148
- .
149
- </span>
150
- </li>
136
+ {!isSingleTerm && (
137
+ <li>
138
+ <span className="terms-transition">
139
+ I give consent for my chosen payment method to be charged
140
+ automatically at the end of each subscription term until I cancel it
141
+ by contacting{' '}
142
+ <a
143
+ className="ncf__link--external"
144
+ href="https://help.ft.com/help/contact-us/"
145
+ target="_blank"
146
+ rel="noopener noreferrer"
147
+ >
148
+ customer care through chat, phone or email
149
+ </a>
150
+ .
151
+ </span>
152
+ </li>
153
+ )}
151
154
  {transitionType === 'immediate' ? (
152
155
  <li>
153
156
  <span className="terms-transition terms-transition--immediate">
@@ -160,6 +163,9 @@ export function AcceptTerms({
160
163
  <li>
161
164
  <span className="terms-transition terms-transition--other">
162
165
  By placing my order, I acknowledge that my subscription will start
166
+ {isSingleTerm
167
+ ? ' and the chosen payment method will be charged '
168
+ : ' '}
163
169
  on the date given above. Any cancellation notice received after that
164
170
  date will take effect at the end of my subscription term and
165
171
  previously paid amounts are non-refundable.
@@ -326,4 +332,5 @@ AcceptTerms.propTypes = {
326
332
  transitionType: PropTypes.string,
327
333
  isPrintProduct: PropTypes.bool,
328
334
  specialTerms: PropTypes.string,
335
+ isSingleTerm: PropTypes.bool,
329
336
  };
@@ -145,6 +145,16 @@ describe('AcceptTerms', () => {
145
145
  expect(AcceptTerms).toRenderCorrectly(props);
146
146
  });
147
147
 
148
+ it('renders appropriately if is transition with transition type other than immediate and is single term', () => {
149
+ const props = {
150
+ isTransition: true,
151
+ transitionType: 'foobar',
152
+ isSingleTerm: true,
153
+ };
154
+
155
+ expect(AcceptTerms).toRenderCorrectly(props);
156
+ });
157
+
148
158
  it('renders appropriately if is B2C Partnership', () => {
149
159
  const props = { isB2cPartnership: true };
150
160
 
@@ -29,6 +29,7 @@ export { FirstName } from './first-name';
29
29
  export { Form } from './form';
30
30
  export { Industry } from './industry';
31
31
  export { JobTitle } from './job-title';
32
+ export { PersonalTitle } from './personal-title';
32
33
  export { LastName } from './last-name';
33
34
  export { LicenceConfirmation } from './licence-confirmation';
34
35
  export { LicenceHeader } from './licence-header';
@@ -170,11 +170,18 @@ export function PaymentTerm({
170
170
  >
171
171
  {createDiscount()}
172
172
 
173
- <span className="ncf__payment-term__title">
173
+ <span
174
+ className={classNames([
175
+ 'ncf__payment-term__title',
176
+ { 'ncf__payment-term__title--large-price': largePrice },
177
+ ])}
178
+ >
174
179
  {showTrialCopyInTitle ? 'Trial: Premium Digital - ' : ''}
175
180
  {nameMap[option.name] ? title : option.title}{' '}
176
181
  {option.subTitle && (
177
- <span className="ncf__regular">{option.subTitle}</span>
182
+ <span className="ncf__regular ncf__payment-term__sub-title">
183
+ {option.subTitle}
184
+ </span>
178
185
  )}
179
186
  </span>
180
187
 
@@ -39,6 +39,8 @@ export function PaymentType({
39
39
  fieldId = 'paymentTypeField',
40
40
  inputId = 'paymentType',
41
41
  value,
42
+ isSingleTerm = false,
43
+ isSingleTermChecked = false,
42
44
  }) {
43
45
  const createSecuritySeal = () => {
44
46
  return (
@@ -220,6 +222,15 @@ export function PaymentType({
220
222
  );
221
223
  };
222
224
 
225
+ const inputCheckProps = {
226
+ id: 'payFasterNextTime',
227
+ type: 'checkbox',
228
+ name: 'payFasterNextTime',
229
+ value: 'true',
230
+ required: false,
231
+ ...(isSingleTermChecked && { defaultChecked: true }),
232
+ };
233
+
223
234
  return (
224
235
  <React.Fragment>
225
236
  {createSecuritySeal()}
@@ -236,6 +247,17 @@ export function PaymentType({
236
247
  {createDirectDebitPanel()}
237
248
 
238
249
  {createZuoraPanel()}
250
+
251
+ {isSingleTerm && (
252
+ <>
253
+ <label className='o-forms-input o-forms-input--checkbox o-forms-input--suffix ncf__payment-type-pay-faster-next-time-checkbox' htmlFor="payFasterNextTime">
254
+ <input {...inputCheckProps}/>
255
+ <span className="o-forms-input__label">
256
+ Use these details to pay faster next time
257
+ </span>
258
+ </label>
259
+ </>
260
+ )}
239
261
  </div>
240
262
  </React.Fragment>
241
263
  );
@@ -251,4 +273,6 @@ PaymentType.propTypes = {
251
273
  fieldId: PropTypes.string,
252
274
  inputId: PropTypes.string,
253
275
  value: PropTypes.string,
276
+ isSingleTerm: PropTypes.bool,
277
+ isSingleTermChecked: PropTypes.bool,
254
278
  };
@@ -57,4 +57,21 @@ describe('PaymentType', () => {
57
57
 
58
58
  expect(PaymentType).toRenderCorrectly({}, props);
59
59
  });
60
+
61
+ it('render with isSingleTerm', () => {
62
+ const props = {
63
+ isSingleTerm: true,
64
+ };
65
+
66
+ expect(PaymentType).toRenderCorrectly(props);
67
+ });
68
+
69
+ it('render with isSingleTermChecked', () => {
70
+ const props = {
71
+ isSingleTerm: true,
72
+ isSingleTermChecked: true,
73
+ };
74
+
75
+ expect(PaymentType).toRenderCorrectly(props);
76
+ });
60
77
  });
@@ -0,0 +1,86 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import classNames from 'classnames';
4
+
5
+ export const defaultPersonalTitles = [
6
+ { code: 'Mr', description: 'Mr' },
7
+ { code: 'Mrs', description: 'Mrs' },
8
+ { code: 'Miss', description: 'Miss' },
9
+ { code: 'Ms', description: 'Ms' },
10
+ ];
11
+
12
+ export function PersonalTitle ({
13
+ value,
14
+ isDisabled = false,
15
+ hasError = false,
16
+ fieldId = 'titleField',
17
+ selectId = 'title',
18
+ selectName = 'title',
19
+ options = defaultPersonalTitles,
20
+ fieldLabel = 'Title',
21
+ isRequired = true,
22
+ }) {
23
+ const inputWrapperClassName = classNames([
24
+ 'o-forms-input',
25
+ 'o-forms-input--select',
26
+ { 'o-forms-input--invalid': hasError },
27
+ ]);
28
+
29
+ const fieldTitleClassName = classNames([
30
+ 'o-forms-title',
31
+ { 'o-forms-field--optional': !isRequired },
32
+ ]);
33
+
34
+ return (
35
+ <label
36
+ id={fieldId}
37
+ className="o-forms-field ncf__validation-error"
38
+ htmlFor={selectId}
39
+ >
40
+ <span className={fieldTitleClassName}>
41
+ <span className="o-forms-title__main">{fieldLabel}</span>
42
+ </span>
43
+ <span className={inputWrapperClassName}>
44
+ <select
45
+ id={selectId}
46
+ name={selectName}
47
+ data-trackable="title"
48
+ aria-required={isRequired}
49
+ required={isRequired}
50
+ disabled={isDisabled}
51
+ defaultValue={value}
52
+ >
53
+ <option value="">Please select a title</option>
54
+ {options.map(({ code, description }) => {
55
+ return (
56
+ <option key={code} value={code}>
57
+ {description}
58
+ </option>
59
+ );
60
+ })}
61
+ </select>
62
+ <span className="o-forms-input__error">
63
+ Please select your personal title
64
+ </span>
65
+ </span>
66
+ </label>
67
+ );
68
+ }
69
+
70
+ PersonalTitle.propTypes = {
71
+ value: PropTypes.string,
72
+ isDisabled: PropTypes.bool,
73
+ hasError: PropTypes.bool,
74
+ fieldId: PropTypes.string,
75
+ selectId: PropTypes.string,
76
+ selectName: PropTypes.string,
77
+ options: PropTypes.arrayOf(
78
+ PropTypes.shape({
79
+ code: PropTypes.string,
80
+ description: PropTypes.string,
81
+ })
82
+ ),
83
+ fieldLabel: PropTypes.string,
84
+ isRequired: PropTypes.bool,
85
+ };
86
+
@@ -0,0 +1,93 @@
1
+ import { PersonalTitle } from './index';
2
+ import { expectToRenderCorrectly } from '../test-jest/helpers/expect-to-render-correctly';
3
+ import { defaultPersonalTitles } from './personal-title';
4
+
5
+ import Enzyme, { mount } from 'enzyme';
6
+ import Adapter from 'enzyme-adapter-react-16';
7
+
8
+ Enzyme.configure({ adapter: new Adapter() });
9
+
10
+ expect.extend(expectToRenderCorrectly);
11
+
12
+ describe('PersonalTitle', () => {
13
+ it('render a select with a label', () => {
14
+ const props = {
15
+ options: defaultPersonalTitles
16
+ };
17
+
18
+ expect(PersonalTitle).toRenderCorrectly(props);
19
+ });
20
+
21
+ it('can render an initial selected value', () => {
22
+ const props = {
23
+ options: defaultPersonalTitles,
24
+ value: 'mr',
25
+ };
26
+
27
+ expect(PersonalTitle).toRenderCorrectly(props);
28
+ });
29
+
30
+ it('can render a disable select', () => {
31
+ const props = {
32
+ options: defaultPersonalTitles,
33
+ isDisabled: true,
34
+ };
35
+
36
+ expect(PersonalTitle).toRenderCorrectly(props);
37
+ });
38
+
39
+ it('can render an error message', () => {
40
+ const props = {
41
+ options: defaultPersonalTitles,
42
+ hasError: true,
43
+ };
44
+
45
+ expect(PersonalTitle).toRenderCorrectly(props);
46
+ });
47
+
48
+ it('can override id and name for select', () => {
49
+ const props = {
50
+ selectId: 'selectId',
51
+ selectName: 'selectName',
52
+ };
53
+ const component = mount(PersonalTitle(props));
54
+ const select = component.find('select#selectId');
55
+
56
+ expect(select.exists()).toBe(true);
57
+ });
58
+
59
+ it('can override id for field', () => {
60
+ const props = {
61
+ fieldId: 'fieldID',
62
+ };
63
+ const component = mount(PersonalTitle(props));
64
+ const field = component.find('#fieldID');
65
+
66
+ expect(field.exists()).toBe(true);
67
+ });
68
+
69
+ it('renders with default label wording', () => {
70
+ const props = {};
71
+
72
+ const component = mount(PersonalTitle(props));
73
+
74
+ expect(component.find('.o-forms-title__main').text()).toEqual(
75
+ 'Title'
76
+ );
77
+ });
78
+
79
+ it('renders with custom label wording', () => {
80
+ const props = { fieldLabel: 'PersonalTitle' };
81
+
82
+ const component = mount(PersonalTitle(props));
83
+
84
+ expect(component.find('.o-forms-title__main').text()).toEqual('PersonalTitle');
85
+ });
86
+
87
+ it('renders with optional title class, when not required', () => {
88
+ const props = { isRequired: false };
89
+ const component = mount(PersonalTitle(props));
90
+
91
+ expect(component.find('.o-forms-title.o-forms-field--optional').length).toEqual(1);
92
+ });
93
+ });
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import { PersonalTitle } from './personal-title';
3
+
4
+ export default {
5
+ title: 'PersonalTitle',
6
+ component: PersonalTitle,
7
+ };
8
+
9
+ export const Basic = (args) => <PersonalTitle {...args} />;
10
+
11
+ export const CustomPersonalTitle = (args) => <PersonalTitle {...args} />;
12
+ CustomPersonalTitle.args = {
13
+ options: [
14
+ { code: 'Mr', description: 'Mr' },
15
+ { code: 'Mrs', description: 'Mrs' },
16
+ ],
17
+ };
@@ -2,9 +2,16 @@ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import classNames from 'classnames';
4
4
 
5
- export function ProgressIndicator({ items = [] }) {
5
+ export function ProgressIndicator({ items = [], disableLinks = false }) {
6
6
  function getElementsForComplete(item) {
7
- return (
7
+ return disableLinks? (
8
+ <span className="o-stepped-progress__step o-stepped-progress__step--complete">
9
+ <span className="o-stepped-progress__label">
10
+ {item.name}
11
+ <span className="o-stepped-progress__status">(completed)</span>
12
+ </span>
13
+ </span>
14
+ ) : (
8
15
  <a
9
16
  href={item.url}
10
17
  className="o-stepped-progress__step o-stepped-progress__step--complete"
@@ -66,4 +73,5 @@ ProgressIndicator.propTypes = {
66
73
  url: PropTypes.string,
67
74
  })
68
75
  ),
76
+ disableLinks: PropTypes.bool,
69
77
  };
@@ -61,4 +61,20 @@ describe('ProgressIndicator', () => {
61
61
 
62
62
  expect(ProgressIndicator).toRenderCorrectly(props);
63
63
  });
64
+
65
+ it('renders completed items with disabled links', () => {
66
+ const props = {
67
+ items: [
68
+ {
69
+ url: 'https://foo.com',
70
+ name: 'Item name',
71
+ isComplete: true,
72
+ isCurrent: false,
73
+ },
74
+ ],
75
+ disableLinks: true,
76
+ };
77
+
78
+ expect(ProgressIndicator).toRenderCorrectly(props);
79
+ });
64
80
  });
@@ -29,3 +29,28 @@ Basic.args = {
29
29
  },
30
30
  ],
31
31
  };
32
+
33
+ export const WithLinksDisabled = (args) => <ProgressIndicator {...args} />;
34
+ WithLinksDisabled.args = {
35
+ items: [
36
+ {
37
+ isComplete: true,
38
+ isCurrent: false,
39
+ name: 'Get Business',
40
+ url: 'https://ft.com',
41
+ },
42
+ {
43
+ isComplete: true,
44
+ isCurrent: true,
45
+ name: '????',
46
+ url: 'https://google.com',
47
+ },
48
+ {
49
+ isComplete: false,
50
+ isCurrent: false,
51
+ name: 'Profit',
52
+ url: 'https://ft.com',
53
+ },
54
+ ],
55
+ disableLinks: true,
56
+ };
@@ -49,7 +49,9 @@ function AcceptTerms(_ref) {
49
49
  _ref$isPrintProduct = _ref.isPrintProduct,
50
50
  isPrintProduct = _ref$isPrintProduct === void 0 ? false : _ref$isPrintProduct,
51
51
  _ref$specialTerms = _ref.specialTerms,
52
- specialTerms = _ref$specialTerms === void 0 ? null : _ref$specialTerms;
52
+ specialTerms = _ref$specialTerms === void 0 ? null : _ref$specialTerms,
53
+ _ref$isSingleTerm = _ref.isSingleTerm,
54
+ isSingleTerm = _ref$isSingleTerm === void 0 ? false : _ref$isSingleTerm;
53
55
 
54
56
  var divProps = _objectSpread(_objectSpread({
55
57
  id: 'acceptTermsField',
@@ -114,7 +116,7 @@ function AcceptTerms(_ref) {
114
116
  className: "terms-corp-signup"
115
117
  }, "This trial is to demonstrate the value of a group subscription and we\u2019ll contact you during your trial.")));
116
118
 
117
- var transitionTerms = isTransition && /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, /*#__PURE__*/_react["default"].createElement("li", null, /*#__PURE__*/_react["default"].createElement("span", {
119
+ var transitionTerms = isTransition && /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, !isSingleTerm && /*#__PURE__*/_react["default"].createElement("li", null, /*#__PURE__*/_react["default"].createElement("span", {
118
120
  className: "terms-transition"
119
121
  }, "I give consent for my chosen payment method to be charged automatically at the end of each subscription term until I cancel it by contacting", ' ', /*#__PURE__*/_react["default"].createElement("a", {
120
122
  className: "ncf__link--external",
@@ -125,7 +127,7 @@ function AcceptTerms(_ref) {
125
127
  className: "terms-transition terms-transition--immediate"
126
128
  }, "By placing my order, my subscription will start immediately. Cancellation notice would take effect at the end of the subscription period and previously paid amounts are non-refundable.")) : /*#__PURE__*/_react["default"].createElement("li", null, /*#__PURE__*/_react["default"].createElement("span", {
127
129
  className: "terms-transition terms-transition--other"
128
- }, "By placing my order, I acknowledge that my subscription will start on the date given above. Any cancellation notice received after that date will take effect at the end of my subscription term and previously paid amounts are non-refundable.")), /*#__PURE__*/_react["default"].createElement("li", null, /*#__PURE__*/_react["default"].createElement("span", {
130
+ }, "By placing my order, I acknowledge that my subscription will start", isSingleTerm ? ' and the chosen payment method will be charged ' : ' ', "on the date given above. Any cancellation notice received after that date will take effect at the end of my subscription term and previously paid amounts are non-refundable.")), /*#__PURE__*/_react["default"].createElement("li", null, /*#__PURE__*/_react["default"].createElement("span", {
129
131
  className: "terms-transition"
130
132
  }, "Find out more about our cancellation policy in our", ' ', /*#__PURE__*/_react["default"].createElement("a", {
131
133
  className: "ncf__link--external",
@@ -205,5 +207,6 @@ AcceptTerms.propTypes = {
205
207
  isTransition: _propTypes["default"].bool,
206
208
  transitionType: _propTypes["default"].string,
207
209
  isPrintProduct: _propTypes["default"].bool,
208
- specialTerms: _propTypes["default"].string
210
+ specialTerms: _propTypes["default"].string,
211
+ isSingleTerm: _propTypes["default"].bool
209
212
  };
package/dist/index.js CHANGED
@@ -189,6 +189,12 @@ Object.defineProperty(exports, "JobTitle", {
189
189
  return _jobTitle.JobTitle;
190
190
  }
191
191
  });
192
+ Object.defineProperty(exports, "PersonalTitle", {
193
+ enumerable: true,
194
+ get: function get() {
195
+ return _personalTitle.PersonalTitle;
196
+ }
197
+ });
192
198
  Object.defineProperty(exports, "LastName", {
193
199
  enumerable: true,
194
200
  get: function get() {
@@ -396,6 +402,8 @@ var _industry = require("./industry");
396
402
 
397
403
  var _jobTitle = require("./job-title");
398
404
 
405
+ var _personalTitle = require("./personal-title");
406
+
399
407
  var _lastName = require("./last-name");
400
408
 
401
409
  var _licenceConfirmation = require("./licence-confirmation");
@@ -153,9 +153,11 @@ function PaymentTerm(_ref) {
153
153
  htmlFor: option.value,
154
154
  className: "o-forms-input__label ncf__payment-term__label"
155
155
  }, createDiscount(), /*#__PURE__*/_react["default"].createElement("span", {
156
- className: "ncf__payment-term__title"
156
+ className: (0, _classnames["default"])(['ncf__payment-term__title', {
157
+ 'ncf__payment-term__title--large-price': largePrice
158
+ }])
157
159
  }, showTrialCopyInTitle ? 'Trial: Premium Digital - ' : '', nameMap[option.name] ? title : option.title, ' ', option.subTitle && /*#__PURE__*/_react["default"].createElement("span", {
158
- className: "ncf__regular"
160
+ className: "ncf__regular ncf__payment-term__sub-title"
159
161
  }, option.subTitle)), createDescription()));
160
162
  };
161
163
 
@@ -56,7 +56,11 @@ function PaymentType(_ref) {
56
56
  fieldId = _ref$fieldId === void 0 ? 'paymentTypeField' : _ref$fieldId,
57
57
  _ref$inputId = _ref.inputId,
58
58
  inputId = _ref$inputId === void 0 ? 'paymentType' : _ref$inputId,
59
- value = _ref.value;
59
+ value = _ref.value,
60
+ _ref$isSingleTerm = _ref.isSingleTerm,
61
+ isSingleTerm = _ref$isSingleTerm === void 0 ? false : _ref$isSingleTerm,
62
+ _ref$isSingleTermChec = _ref.isSingleTermChecked,
63
+ isSingleTermChecked = _ref$isSingleTermChec === void 0 ? false : _ref$isSingleTermChec;
60
64
 
61
65
  var createSecuritySeal = function createSecuritySeal() {
62
66
  return /*#__PURE__*/_react["default"].createElement("div", {
@@ -180,6 +184,16 @@ function PaymentType(_ref) {
180
184
  });
181
185
  };
182
186
 
187
+ var inputCheckProps = _objectSpread({
188
+ id: 'payFasterNextTime',
189
+ type: 'checkbox',
190
+ name: 'payFasterNextTime',
191
+ value: 'true',
192
+ required: false
193
+ }, isSingleTermChecked && {
194
+ defaultChecked: true
195
+ });
196
+
183
197
  return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, createSecuritySeal(), /*#__PURE__*/_react["default"].createElement("div", {
184
198
  id: fieldId,
185
199
  className: "o-forms-field"
@@ -187,7 +201,12 @@ function PaymentType(_ref) {
187
201
  className: "o-forms-input o-forms-input--radio-box ncf__payment-type-selector"
188
202
  }, createPaymentTypes()), /*#__PURE__*/_react["default"].createElement("div", {
189
203
  className: "o-forms-input__error"
190
- }, "Please enter a valid payment type"), createDirectDebitPanel(), createZuoraPanel()));
204
+ }, "Please enter a valid payment type"), createDirectDebitPanel(), createZuoraPanel(), isSingleTerm && /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, /*#__PURE__*/_react["default"].createElement("label", {
205
+ className: "o-forms-input o-forms-input--checkbox o-forms-input--suffix ncf__payment-type-pay-faster-next-time-checkbox",
206
+ htmlFor: "payFasterNextTime"
207
+ }, /*#__PURE__*/_react["default"].createElement("input", inputCheckProps), /*#__PURE__*/_react["default"].createElement("span", {
208
+ className: "o-forms-input__label"
209
+ }, "Use these details to pay faster next time")))));
191
210
  }
192
211
 
193
212
  PaymentType.propTypes = {
@@ -199,5 +218,7 @@ PaymentType.propTypes = {
199
218
  showPaypalCustomerCareMessage: _propTypes["default"].bool,
200
219
  fieldId: _propTypes["default"].string,
201
220
  inputId: _propTypes["default"].string,
202
- value: _propTypes["default"].string
221
+ value: _propTypes["default"].string,
222
+ isSingleTerm: _propTypes["default"].bool,
223
+ isSingleTermChecked: _propTypes["default"].bool
203
224
  };
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.PersonalTitle = PersonalTitle;
9
+ exports.defaultPersonalTitles = void 0;
10
+
11
+ var _react = _interopRequireDefault(require("react"));
12
+
13
+ var _propTypes = _interopRequireDefault(require("prop-types"));
14
+
15
+ var _classnames = _interopRequireDefault(require("classnames"));
16
+
17
+ var defaultPersonalTitles = [{
18
+ code: 'Mr',
19
+ description: 'Mr'
20
+ }, {
21
+ code: 'Mrs',
22
+ description: 'Mrs'
23
+ }, {
24
+ code: 'Miss',
25
+ description: 'Miss'
26
+ }, {
27
+ code: 'Ms',
28
+ description: 'Ms'
29
+ }];
30
+ exports.defaultPersonalTitles = defaultPersonalTitles;
31
+
32
+ function PersonalTitle(_ref) {
33
+ var value = _ref.value,
34
+ _ref$isDisabled = _ref.isDisabled,
35
+ isDisabled = _ref$isDisabled === void 0 ? false : _ref$isDisabled,
36
+ _ref$hasError = _ref.hasError,
37
+ hasError = _ref$hasError === void 0 ? false : _ref$hasError,
38
+ _ref$fieldId = _ref.fieldId,
39
+ fieldId = _ref$fieldId === void 0 ? 'titleField' : _ref$fieldId,
40
+ _ref$selectId = _ref.selectId,
41
+ selectId = _ref$selectId === void 0 ? 'title' : _ref$selectId,
42
+ _ref$selectName = _ref.selectName,
43
+ selectName = _ref$selectName === void 0 ? 'title' : _ref$selectName,
44
+ _ref$options = _ref.options,
45
+ options = _ref$options === void 0 ? defaultPersonalTitles : _ref$options,
46
+ _ref$fieldLabel = _ref.fieldLabel,
47
+ fieldLabel = _ref$fieldLabel === void 0 ? 'Title' : _ref$fieldLabel,
48
+ _ref$isRequired = _ref.isRequired,
49
+ isRequired = _ref$isRequired === void 0 ? true : _ref$isRequired;
50
+ var inputWrapperClassName = (0, _classnames["default"])(['o-forms-input', 'o-forms-input--select', {
51
+ 'o-forms-input--invalid': hasError
52
+ }]);
53
+ var fieldTitleClassName = (0, _classnames["default"])(['o-forms-title', {
54
+ 'o-forms-field--optional': !isRequired
55
+ }]);
56
+ return /*#__PURE__*/_react["default"].createElement("label", {
57
+ id: fieldId,
58
+ className: "o-forms-field ncf__validation-error",
59
+ htmlFor: selectId
60
+ }, /*#__PURE__*/_react["default"].createElement("span", {
61
+ className: fieldTitleClassName
62
+ }, /*#__PURE__*/_react["default"].createElement("span", {
63
+ className: "o-forms-title__main"
64
+ }, fieldLabel)), /*#__PURE__*/_react["default"].createElement("span", {
65
+ className: inputWrapperClassName
66
+ }, /*#__PURE__*/_react["default"].createElement("select", {
67
+ id: selectId,
68
+ name: selectName,
69
+ "data-trackable": "title",
70
+ "aria-required": isRequired,
71
+ required: isRequired,
72
+ disabled: isDisabled,
73
+ defaultValue: value
74
+ }, /*#__PURE__*/_react["default"].createElement("option", {
75
+ value: ""
76
+ }, "Please select a title"), options.map(function (_ref2) {
77
+ var code = _ref2.code,
78
+ description = _ref2.description;
79
+ return /*#__PURE__*/_react["default"].createElement("option", {
80
+ key: code,
81
+ value: code
82
+ }, description);
83
+ })), /*#__PURE__*/_react["default"].createElement("span", {
84
+ className: "o-forms-input__error"
85
+ }, "Please select your personal title")));
86
+ }
87
+
88
+ PersonalTitle.propTypes = {
89
+ value: _propTypes["default"].string,
90
+ isDisabled: _propTypes["default"].bool,
91
+ hasError: _propTypes["default"].bool,
92
+ fieldId: _propTypes["default"].string,
93
+ selectId: _propTypes["default"].string,
94
+ selectName: _propTypes["default"].string,
95
+ options: _propTypes["default"].arrayOf(_propTypes["default"].shape({
96
+ code: _propTypes["default"].string,
97
+ description: _propTypes["default"].string
98
+ })),
99
+ fieldLabel: _propTypes["default"].string,
100
+ isRequired: _propTypes["default"].bool
101
+ };
@@ -15,10 +15,18 @@ var _classnames = _interopRequireDefault(require("classnames"));
15
15
 
16
16
  function ProgressIndicator(_ref) {
17
17
  var _ref$items = _ref.items,
18
- items = _ref$items === void 0 ? [] : _ref$items;
18
+ items = _ref$items === void 0 ? [] : _ref$items,
19
+ _ref$disableLinks = _ref.disableLinks,
20
+ disableLinks = _ref$disableLinks === void 0 ? false : _ref$disableLinks;
19
21
 
20
22
  function getElementsForComplete(item) {
21
- return /*#__PURE__*/_react["default"].createElement("a", {
23
+ return disableLinks ? /*#__PURE__*/_react["default"].createElement("span", {
24
+ className: "o-stepped-progress__step o-stepped-progress__step--complete"
25
+ }, /*#__PURE__*/_react["default"].createElement("span", {
26
+ className: "o-stepped-progress__label"
27
+ }, item.name, /*#__PURE__*/_react["default"].createElement("span", {
28
+ className: "o-stepped-progress__status"
29
+ }, "(completed)"))) : /*#__PURE__*/_react["default"].createElement("a", {
22
30
  href: item.url,
23
31
  className: "o-stepped-progress__step o-stepped-progress__step--complete",
24
32
  "data-trackable": "change-progress"
@@ -62,5 +70,6 @@ ProgressIndicator.propTypes = {
62
70
  isCurrent: _propTypes["default"].bool,
63
71
  name: _propTypes["default"].string,
64
72
  url: _propTypes["default"].string
65
- }))
73
+ })),
74
+ disableLinks: _propTypes["default"].bool
66
75
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@financial-times/n-conversion-forms",
3
- "version": "20.1.1",
3
+ "version": "20.3.0",
4
4
  "description": "Containing jsx components and styles for forms included on Accounts and Acqusition apps (next-signup, next-profile, next-retention, etc).",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -7,7 +7,7 @@
7
7
  @include oGridRespondTo(L) {
8
8
  &__options-grid {
9
9
  display: flex;
10
- align-items: baseline;
10
+ align-items: flex-end;
11
11
 
12
12
  > * {
13
13
  flex: 1;
@@ -77,5 +77,13 @@
77
77
  margin-bottom: 0;
78
78
  margin-top: oSpacingByName('s1');
79
79
  }
80
+
81
+ &__title--large-price {
82
+ @include oTypographySans($scale: 0, $include-font-family: false);
83
+ }
84
+
85
+ &__sub-title {
86
+ @include oTypographySans($scale: -1, $include-font-family: false);
87
+ }
80
88
  }
81
89
  }
@@ -110,3 +110,7 @@
110
110
  .ncf__payment-type-paypal-message {
111
111
  margin-bottom: oSpacingByName('s3');
112
112
  }
113
+
114
+ .o-forms-input.o-forms-input--checkbox.o-forms-input--suffix.ncf__payment-type-pay-faster-next-time-checkbox {
115
+ margin-top: oSpacingByName('s3');
116
+ }