bright-components 10.0.0 → 10.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -26,6 +26,8 @@ import breakpoints from 'constants/breakpoints';
26
26
 
27
27
  import CalendarIcon from 'components/Icons/Calendar/';
28
28
 
29
+ import NewDayPicker from './NewDayPicker';
30
+
29
31
  const friendlyShort = 'EEE dd MMM';
30
32
  const friendlyShortWithYear = 'EEE dd MMM yyyy';
31
33
 
@@ -232,11 +234,12 @@ class DayPicker extends React.Component {
232
234
  panelAbsoluteOnDesktop,
233
235
  onSelectedDate,
234
236
  isDateSelect,
237
+ typeable,
235
238
  ...rest
236
239
  } = this.props;
237
240
 
238
241
  const { dayPickerOpen } = this.state;
239
- const { range } = this.props;
242
+ const { range, locale } = this.props;
240
243
 
241
244
  const fromDate = range.from
242
245
  ? format(range.from, this.getDisplayFormat())
@@ -250,20 +253,39 @@ class DayPicker extends React.Component {
250
253
 
251
254
  return (
252
255
  <DayPickerInputContainer {...rest}>
253
- <InputBox
254
- onClick={this.toggleDayPicker}
255
- error={error}
256
- disabled={disabled}
257
- legacyInputStyle={legacyInputStyle}
258
- data-testid="input-selector"
259
- >
260
- {datesToDisplay ? (
261
- <span>{datesToDisplay}</span>
262
- ) : (
263
- <Placeholder>{placeholder}</Placeholder>
264
- )}
265
- <OpenCalendarIcon size={22} disabled={disabled} />
266
- </InputBox>
256
+ {!typeable || dateRange ? (
257
+ <InputBox
258
+ onClick={this.toggleDayPicker}
259
+ error={error}
260
+ disabled={disabled}
261
+ legacyInputStyle={legacyInputStyle}
262
+ data-testid="input-selector"
263
+ >
264
+ {datesToDisplay ? (
265
+ <span>{datesToDisplay}</span>
266
+ ) : (
267
+ <Placeholder>{placeholder}</Placeholder>
268
+ )}
269
+ <OpenCalendarIcon size={22} disabled={disabled} />
270
+ </InputBox>
271
+ ) : (
272
+ <NewDayPicker
273
+ placeholder={placeholder}
274
+ datesToDisplay={datesToDisplay}
275
+ range={range}
276
+ allowClear={allowClear}
277
+ yearRange={yearRange}
278
+ onSelectedDate={onSelectedDate}
279
+ locale={locale}
280
+ clearValue={this.clearValue}
281
+ disabled={disabled}
282
+ error={error}
283
+ toggleDayPicker={this.toggleDayPicker}
284
+ GA={GA}
285
+ recordValue={recordValue}
286
+ dayPickerOpen={dayPickerOpen}
287
+ />
288
+ )}
267
289
 
268
290
  {dayPickerOpen && (
269
291
  <DayRangeContainer
@@ -330,7 +352,9 @@ DayPicker.propTypes = {
330
352
  legacyInputStyle: bool,
331
353
  closeButton: bool,
332
354
  panelAbsoluteOnDesktop: bool,
333
- isDateSelect: bool
355
+ isDateSelect: bool,
356
+ typeable: bool,
357
+ locale: string
334
358
  };
335
359
 
336
360
  DayPicker.defaultProps = {
@@ -356,7 +380,9 @@ DayPicker.defaultProps = {
356
380
  legacyInputStyle: false,
357
381
  closeButton: false,
358
382
  panelAbsoluteOnDesktop: true,
359
- isDateSelect: false
383
+ isDateSelect: false,
384
+ typeable: false,
385
+ locale: 'GB'
360
386
  };
361
387
 
362
388
  export { DayPicker as Unwrapped };
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
- import { render, fireEvent } from '@testing-library/react';
2
+ import { render, fireEvent, wait } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
3
4
  import ReactGA from 'react-ga';
4
5
  import DayPicker from '.';
5
6
 
@@ -406,4 +407,299 @@ describe('<DayPicker />', () => {
406
407
  expect(ReactGA.event).toHaveBeenCalledTimes(1);
407
408
  });
408
409
  });
410
+
411
+ describe('Typing date', () => {
412
+ it('should set the correct date when typed in', async () => {
413
+ wrapper.rerender(
414
+ <DayPicker
415
+ {...props}
416
+ typeable
417
+ dateRange={false}
418
+ yearRange={{ min: 2000, max: 2100 }}
419
+ GA={{
420
+ category: undefined,
421
+ actionId: undefined
422
+ }}
423
+ />
424
+ );
425
+ const inputSelect = wrapper.getByTestId('new input');
426
+
427
+ fireEvent.focus(inputSelect);
428
+ userEvent.type(inputSelect, `010203`);
429
+ await wait(() => expect(inputSelect.value).toEqual('01/02/03'));
430
+ fireEvent.blur(inputSelect);
431
+
432
+ expect(onMockSelectedDate).toHaveBeenLastCalledWith({
433
+ from: new Date('2003-02-01T00:00:00.000Z'),
434
+ to: new Date('2003-02-01T00:00:00.000Z')
435
+ });
436
+ });
437
+
438
+ it('should set the correct date when typed in - CA', () => {
439
+ wrapper.rerender(
440
+ <DayPicker
441
+ {...props}
442
+ typeable
443
+ dateRange={false}
444
+ yearRange={{ min: 2000, max: 2100 }}
445
+ locale="CA"
446
+ />
447
+ );
448
+ const inputSelect = wrapper.getByTestId('new input');
449
+
450
+ fireEvent.focus(inputSelect);
451
+ userEvent.type(inputSelect, '010203');
452
+ fireEvent.blur(inputSelect);
453
+
454
+ expect(onMockSelectedDate).toHaveBeenLastCalledWith({
455
+ from: new Date('2001-02-03T00:00:00.000Z'),
456
+ to: new Date('2001-02-03T00:00:00.000Z')
457
+ });
458
+ });
459
+
460
+ it('should show the correct date when date pre set', () => {
461
+ wrapper.rerender(
462
+ <DayPicker
463
+ {...props}
464
+ typeable
465
+ dateRange={false}
466
+ yearRange={{ min: 2000, max: 2100 }}
467
+ range={{
468
+ from: new Date('2019-08-01'),
469
+ to: undefined
470
+ }}
471
+ />
472
+ );
473
+ const inputSelect = wrapper.getByTestId('new input');
474
+
475
+ fireEvent.focus(inputSelect);
476
+
477
+ expect(inputSelect.value).toEqual('01/08/19');
478
+ });
479
+
480
+ it('should show the correct date when date pre set - CA', () => {
481
+ wrapper.rerender(
482
+ <DayPicker
483
+ {...props}
484
+ typeable
485
+ dateRange={false}
486
+ yearRange={{ min: 2000, max: 2100 }}
487
+ range={{
488
+ from: new Date('2019-08-01'),
489
+ to: undefined
490
+ }}
491
+ locale="CA"
492
+ />
493
+ );
494
+ const inputSelect = wrapper.getByTestId('new input');
495
+
496
+ fireEvent.focus(inputSelect);
497
+
498
+ expect(inputSelect.value).toEqual('19/08/01');
499
+ });
500
+
501
+ it('should allow clearing date', () => {
502
+ wrapper.rerender(
503
+ <DayPicker
504
+ {...props}
505
+ typeable
506
+ dateRange={false}
507
+ yearRange={{ min: 2000, max: 2100 }}
508
+ range={{
509
+ from: new Date('2019-08-01'),
510
+ to: undefined
511
+ }}
512
+ />
513
+ );
514
+ const inputSelect = wrapper.getByTestId('new input');
515
+
516
+ fireEvent.focus(inputSelect);
517
+ userEvent.type(inputSelect, '{selectall}{backspace}');
518
+ fireEvent.blur(inputSelect);
519
+
520
+ expect(onMockSelectedDate).toHaveBeenLastCalledWith({
521
+ from: undefined,
522
+ to: undefined
523
+ });
524
+ });
525
+
526
+ it('shouldnt save invalid dates', () => {
527
+ wrapper.rerender(
528
+ <DayPicker
529
+ {...props}
530
+ typeable
531
+ dateRange={false}
532
+ yearRange={{ min: 2000, max: 2100 }}
533
+ range={{
534
+ from: new Date('2019-08-01'),
535
+ to: undefined
536
+ }}
537
+ />
538
+ );
539
+ const inputSelect = wrapper.getByTestId('new input');
540
+
541
+ fireEvent.focus(inputSelect);
542
+ fireEvent.blur(inputSelect);
543
+ fireEvent.focus(inputSelect);
544
+ userEvent.type(inputSelect, '{selectall}{backspace}0101');
545
+ fireEvent.blur(inputSelect);
546
+
547
+ expect(onMockSelectedDate).toHaveBeenLastCalledWith('');
548
+ expect(wrapper.getByText('Date is invalid')).toBeInTheDocument();
549
+ });
550
+
551
+ it('shouldnt save dates outside the range', () => {
552
+ wrapper.rerender(
553
+ <DayPicker
554
+ {...props}
555
+ typeable
556
+ dateRange={false}
557
+ yearRange={{ min: 2018, max: 2030 }}
558
+ range={{
559
+ from: new Date('2019-08-01'),
560
+ to: undefined
561
+ }}
562
+ allowClear={false}
563
+ />
564
+ );
565
+ const inputSelect = wrapper.getByTestId('new input');
566
+
567
+ fireEvent.focus(inputSelect);
568
+ userEvent.type(inputSelect, '{selectall}{backspace}010131');
569
+ fireEvent.blur(inputSelect);
570
+
571
+ expect(onMockSelectedDate).toHaveBeenLastCalledWith({
572
+ from: new Date('2019-08-01T00:00:00.000Z'),
573
+ to: undefined
574
+ });
575
+ expect(
576
+ wrapper.getByText(
577
+ 'Year is outside of range. Must be between 2018 - 2030'
578
+ )
579
+ ).toBeInTheDocument();
580
+ });
581
+
582
+ it('should revert invalid date to empty if no initial date', () => {
583
+ onMockSelectedDate.mockClear();
584
+ wrapper.rerender(
585
+ <DayPicker
586
+ {...props}
587
+ typeable
588
+ dateRange={false}
589
+ yearRange={{ min: 2000, max: 2100 }}
590
+ range={{
591
+ from: undefined,
592
+ to: undefined
593
+ }}
594
+ allowClear={false}
595
+ />
596
+ );
597
+ const inputSelect = wrapper.getByTestId('new input');
598
+
599
+ fireEvent.focus(inputSelect);
600
+ fireEvent.blur(inputSelect);
601
+ fireEvent.focus(inputSelect);
602
+ userEvent.type(inputSelect, '{selectall}{backspace}0101');
603
+ fireEvent.blur(inputSelect);
604
+
605
+ expect(onMockSelectedDate).not.toHaveBeenCalled();
606
+ });
607
+
608
+ it('backspace / automatically', () => {
609
+ wrapper.rerender(
610
+ <DayPicker
611
+ {...props}
612
+ typeable
613
+ dateRange={false}
614
+ yearRange={{ min: 2000, max: 2100 }}
615
+ range={{
616
+ from: new Date('2019-08-01'),
617
+ to: undefined
618
+ }}
619
+ />
620
+ );
621
+ const inputSelect = wrapper.getByTestId('new input');
622
+
623
+ fireEvent.focus(inputSelect);
624
+ userEvent.type(inputSelect, `{backspace}{backspace}/`);
625
+ expect(inputSelect.value).toEqual('01/08/');
626
+ });
627
+
628
+ it('should open calendar view with the icon', () => {
629
+ wrapper.rerender(
630
+ <DayPicker
631
+ {...props}
632
+ typeable
633
+ dateRange={false}
634
+ yearRange={{ min: 2000, max: 2100 }}
635
+ range={{
636
+ from: new Date('2019-08-01'),
637
+ to: undefined
638
+ }}
639
+ />
640
+ );
641
+
642
+ fireEvent.click(wrapper.getByTestId('calendarIcon'));
643
+ expect(wrapper.getByTestId('daypicker-panel')).toBeInTheDocument();
644
+
645
+ const inputSelect = wrapper.getByTestId('new input');
646
+ fireEvent.focus(inputSelect);
647
+ fireEvent.blur(inputSelect);
648
+
649
+ expect(
650
+ wrapper.queryByTestId('daypicker-panel')
651
+ ).not.toBeInTheDocument();
652
+ });
653
+
654
+ it('should apply the error styling if error', () => {
655
+ wrapper.rerender(
656
+ <DayPicker {...props} dateRange={false} typeable error />
657
+ );
658
+
659
+ const inputSelect = wrapper.getByTestId('input-selector');
660
+ expect(inputSelect).toHaveStyleRule(
661
+ 'border-color',
662
+ '#FF5000 !important'
663
+ );
664
+ });
665
+
666
+ it('should apply the error styling if disabled', () => {
667
+ wrapper.rerender(
668
+ <DayPicker {...props} typeable dateRange={false} disabled />
669
+ );
670
+
671
+ const inputSelect = wrapper.getByTestId('new input');
672
+ expect(inputSelect).toBeDisabled();
673
+ });
674
+
675
+ it('should call the correct GA tags when the date is typed', async () => {
676
+ wrapper.rerender(
677
+ <DayPicker
678
+ {...props}
679
+ typeable
680
+ dateRange={false}
681
+ range={{
682
+ from: undefined,
683
+ to: undefined
684
+ }}
685
+ recordValue
686
+ />
687
+ );
688
+ expect(ReactGA.event).toHaveBeenCalledTimes(0);
689
+
690
+ const inputSelect = wrapper.getByTestId('new input');
691
+ fireEvent.focus(inputSelect);
692
+ userEvent.type(inputSelect, `201222`);
693
+ await wait(() => expect(inputSelect.value).toEqual('20/12/22'));
694
+ fireEvent.blur(inputSelect);
695
+
696
+ await wait(() =>
697
+ expect(ReactGA.event).toHaveBeenCalledWith({
698
+ action: 'ActionID - Set via Typing',
699
+ category: 'Test',
700
+ label: 'Tue 20 Dec 2022'
701
+ })
702
+ );
703
+ });
704
+ });
409
705
  });
@@ -178,7 +178,7 @@ class DayPickerPanel extends React.Component {
178
178
  range: { from, to }
179
179
  } = this.state;
180
180
 
181
- const actionEvent = selectedDay ? 'Set' : 'Apply';
181
+ const actionEvent = selectedDay ? 'Set via Date Picker' : 'Apply';
182
182
 
183
183
  if (category) {
184
184
  const label = dateRange
@@ -73,7 +73,7 @@ describe('Month Year and Calendar view', () => {
73
73
 
74
74
  expect(event).toHaveBeenCalledWith({
75
75
  category: 'Cat',
76
- action: 'Action ID - Set',
76
+ action: 'Action ID - Set via Date Picker',
77
77
  label: 'Tue 03 Apr 2018'
78
78
  });
79
79
  });
@@ -20,7 +20,7 @@ describe('<DurationInput />', () => {
20
20
  });
21
21
 
22
22
  it('should select a new days value when the days input is changed', () => {
23
- const daysInput = wrapper.getByRole('textbox');
23
+ const daysInput = wrapper.getByRole('spinbutton');
24
24
 
25
25
  expect(onChange).not.toHaveBeenCalled();
26
26
 
@@ -36,7 +36,7 @@ describe('<DurationInput />', () => {
36
36
  const blurProps = { ...props, onBlur: jest.fn() };
37
37
  wrapper.rerender(<DurationInput {...blurProps} />);
38
38
 
39
- const daysInput = wrapper.getByRole('textbox');
39
+ const daysInput = wrapper.getByRole('spinbutton');
40
40
  fireEvent.blur(daysInput);
41
41
 
42
42
  expect(blurProps.onBlur).toHaveBeenCalled();
@@ -54,7 +54,9 @@ describe('<DurationInput />', () => {
54
54
  });
55
55
 
56
56
  it('should select a new hours value and a new minutes value when the inputs are changed', () => {
57
- const [hoursInput, minutesInput] = wrapper.getAllByRole('textbox');
57
+ const [hoursInput, minutesInput] = wrapper.getAllByRole(
58
+ 'spinbutton'
59
+ );
58
60
 
59
61
  expect(onChange).not.toHaveBeenCalled();
60
62
 
@@ -33,7 +33,7 @@ describe('EmployeePickerFilterBar', () => {
33
33
  });
34
34
 
35
35
  const getInput = () => element.getByPlaceholderText('Enter name');
36
- const getSelect = () => element.getByRole('listbox');
36
+ const getSelect = () => element.getByRole('combobox');
37
37
 
38
38
  it('should call updateType when the user selects a filter type', () => {
39
39
  const input = getInput();
@@ -15,7 +15,7 @@ describe('<ResponsiveTabs />', () => {
15
15
  </ResponsiveTabs>
16
16
  );
17
17
 
18
- expect(getByRole('listbox')).toBeInTheDocument();
18
+ expect(getByRole('combobox')).toBeInTheDocument();
19
19
  expect(getAllByRole('option')).toHaveLength(2);
20
20
  });
21
21
 
@@ -38,7 +38,7 @@ describe('<ResponsiveTabs />', () => {
38
38
  expect(getByTestId('tab1')).toBeVisible();
39
39
  expect(getByTestId('tab2')).not.toBeVisible();
40
40
 
41
- const dropdown = getByRole('listbox');
41
+ const dropdown = getByRole('combobox');
42
42
  fireEvent.change(dropdown, { target: { value: 'Two' } });
43
43
 
44
44
  expect(getByTestId('tab1')).not.toBeVisible();
@@ -90,7 +90,7 @@ describe('<ResponsiveTabs />', () => {
90
90
  </ResponsiveTabs>
91
91
  );
92
92
 
93
- fireEvent.change(getByRole('listbox'), { target: { value: 'One' } });
93
+ fireEvent.change(getByRole('combobox'), { target: { value: 'One' } });
94
94
  expect(event).not.toHaveBeenCalled();
95
95
 
96
96
  fireEvent.click(getByRole('tab'));
@@ -118,6 +118,7 @@ const TimePicker = ({
118
118
  <>
119
119
  <MobileTimePicker
120
120
  type="time"
121
+ data-testid="mobileTimePicker"
121
122
  onChange={e => {
122
123
  const timeString = e.target.value;
123
124
  if (timeString.length === 5) {