react-date-range.tsx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. import type {CalendarProps, DateRangeProps, Range, RangeKeyDict} from 'react-date-range';
  2. import format from 'date-fns/format';
  3. /**
  4. * Auto-mock of the react-date-range library for jest
  5. *
  6. * We mock out these components in tests because they are heavy (causes timeouts),
  7. * difficult to interact with, and we don't need to validate their behavior.
  8. *
  9. * If your test is dependent on this library's functionality, you may unmock with
  10. * jest.unmock('react-date-range')
  11. */
  12. type DatePickerInputProps = {
  13. 'data-test-id': string;
  14. date?: Date;
  15. onChange?: (date: Date) => void;
  16. };
  17. type DateRangeInputsProps = {
  18. onChange: (range: Range) => void;
  19. range: Range;
  20. };
  21. function DatePickerInput({date, onChange, ...props}: DatePickerInputProps) {
  22. return (
  23. <input
  24. type="date"
  25. value={date ? format(date, 'yyyy-MM-dd') : ''}
  26. onChange={e => {
  27. const newDate = new Date(e.target.value + 'T00:00:00');
  28. onChange?.(newDate);
  29. }}
  30. {...props}
  31. />
  32. );
  33. }
  34. /**
  35. * Replaces the react-date-range Calendar component with a date input
  36. *
  37. * Example usage:
  38. *
  39. * const datePicker = screen.getByTestId('date-picker')
  40. * fireEvent.change(datePicker, {target: {value: '2022-01-01'}})
  41. */
  42. export function Calendar({date, onChange}: CalendarProps) {
  43. return <DatePickerInput data-test-id="date-picker" date={date} onChange={onChange} />;
  44. }
  45. function DateRangeInputs({range, onChange}: DateRangeInputsProps) {
  46. return (
  47. <div data-test-id={`date-range-${range.key}`}>
  48. <DatePickerInput
  49. data-test-id={`date-range-${range.key}-from`}
  50. date={range.startDate}
  51. onChange={date => {
  52. onChange({startDate: date, endDate: range.endDate ?? date, key: range.key});
  53. }}
  54. />
  55. <DatePickerInput
  56. data-test-id={`date-range-${range.key}-to`}
  57. date={range.endDate}
  58. onChange={date => {
  59. onChange({endDate: date, startDate: range.startDate ?? date, key: range.key});
  60. }}
  61. />
  62. </div>
  63. );
  64. }
  65. /**
  66. * Replaces the react-date-range DateRange component with multiple date inputs
  67. * Will render a pair of date inputs for each range
  68. *
  69. * Example usage:
  70. *
  71. * const datePickerFrom = screen.getByTestId(date-range-primary-from')
  72. * const datePickerTo = screen.getByTestId('date-range-primary-to')
  73. * fireEvent.change(datePickerFrom, {target: {value: '2022-01-01'}})
  74. * fireEvent.change(datePickerTo, {target: {value: '2022-01-02'}})
  75. */
  76. export function DateRange({ranges, onChange}: DateRangeProps) {
  77. return (
  78. <div data-test-id="date-range-picker">
  79. {ranges?.map(range => (
  80. <DateRangeInputs
  81. range={range}
  82. onChange={({startDate, endDate, key}) => {
  83. const rangesByKey = ranges?.reduce<RangeKeyDict>(
  84. (acc, nextRange) => ({
  85. ...acc,
  86. [nextRange?.key ?? '']:
  87. nextRange.key === key ? {...nextRange, startDate, endDate} : nextRange,
  88. }),
  89. {}
  90. );
  91. onChange?.(rangesByKey);
  92. }}
  93. key={range.key}
  94. />
  95. )) ?? null}
  96. </div>
  97. );
  98. }