feat: add DatePicker
This commit is contained in:
parent
c950bc6757
commit
422bef601f
@ -2,4 +2,5 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
gap: 50px
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { CalendarWidget } from 'widgets/CalendarWidget';
|
import { CalendarWidget } from 'widgets/CalendarWidget';
|
||||||
|
import { DatePicker } from 'widgets/DatePicker';
|
||||||
|
|
||||||
import classes from './CalendarPage.module.css';
|
import classes from './CalendarPage.module.css';
|
||||||
|
|
||||||
@ -10,6 +11,12 @@ const CalendarPage = () => (
|
|||||||
|
|
||||||
<div className={classes.calendarWrapper}>
|
<div className={classes.calendarWrapper}>
|
||||||
<CalendarWidget />
|
<CalendarWidget />
|
||||||
|
|
||||||
|
<DatePicker
|
||||||
|
firstDate={new Date(2024, 9, 15)}
|
||||||
|
lastDate={new Date(2024, 9, 18)}
|
||||||
|
value={new Date(2024, 9, 15)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
1
src/widgets/DatePicker/index.ts
Normal file
1
src/widgets/DatePicker/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default as DatePicker } from './ui/DatePicker.ui';
|
||||||
360
src/widgets/DatePicker/ui/DatePicker.spec.tsx
Normal file
360
src/widgets/DatePicker/ui/DatePicker.spec.tsx
Normal file
@ -0,0 +1,360 @@
|
|||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
|
||||||
|
import { getDateCellByDataDate, pickCellByDataDate } from 'shared/utils/spec-helpers/date';
|
||||||
|
|
||||||
|
import DatePicker from './DatePicker.ui';
|
||||||
|
|
||||||
|
import type { DatePickerProps } from './DatePicker.ui';
|
||||||
|
|
||||||
|
describe('Test DatePicker', () => {
|
||||||
|
const setup = (props?: DatePickerProps) => render(
|
||||||
|
<DatePicker {...props} />,
|
||||||
|
);
|
||||||
|
|
||||||
|
test('Basic render DatePicker', () => {
|
||||||
|
setup();
|
||||||
|
|
||||||
|
const datePickerElem = screen.queryByTestId('calendar-widget');
|
||||||
|
expect(datePickerElem).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Test base props', () => {
|
||||||
|
test('Default picked first date', () => {
|
||||||
|
setup({
|
||||||
|
firstDate: new Date(2024, 9, 11),
|
||||||
|
value: new Date(2024, 9, 15),
|
||||||
|
});
|
||||||
|
|
||||||
|
const firstPickedCellElem = screen.queryByTestId('first-selected-cell');
|
||||||
|
expect(firstPickedCellElem).toBeVisible();
|
||||||
|
expect(firstPickedCellElem).toHaveAttribute('data-date', '10/11/2024');
|
||||||
|
|
||||||
|
const lastPickedCellElem = screen.queryByTestId('last-selected-cell');
|
||||||
|
expect(lastPickedCellElem).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Default picked last date', () => {
|
||||||
|
setup({
|
||||||
|
lastDate: new Date(2024, 9, 18),
|
||||||
|
value: new Date(2024, 9, 15),
|
||||||
|
});
|
||||||
|
|
||||||
|
const lastPickedCellElem = screen.queryByTestId('last-selected-cell');
|
||||||
|
expect(lastPickedCellElem).toBeVisible();
|
||||||
|
expect(lastPickedCellElem).toHaveAttribute('data-date', '10/18/2024');
|
||||||
|
|
||||||
|
const firstPickedCellElem = screen.queryByTestId('first-selected-cell');
|
||||||
|
expect(firstPickedCellElem).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('onSelect handler', () => {
|
||||||
|
test('No default picked', () => {
|
||||||
|
const onSelect = jest.fn();
|
||||||
|
|
||||||
|
const { container } = setup({
|
||||||
|
onSelect,
|
||||||
|
value: new Date(2024, 9, 15),
|
||||||
|
});
|
||||||
|
|
||||||
|
pickCellByDataDate(container, '10/18/2024');
|
||||||
|
|
||||||
|
expect(onSelect).toHaveBeenCalled();
|
||||||
|
expect(onSelect).toHaveBeenCalledWith({
|
||||||
|
dataDate: '10/18/2024',
|
||||||
|
date: new Date('10/18/2024'),
|
||||||
|
type: 'firstDate',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Picked first date', () => {
|
||||||
|
const onSelect = jest.fn();
|
||||||
|
|
||||||
|
const { container } = setup({
|
||||||
|
onSelect,
|
||||||
|
value: new Date(2024, 9, 15),
|
||||||
|
firstDate: new Date(2024, 9, 15),
|
||||||
|
});
|
||||||
|
|
||||||
|
pickCellByDataDate(container, '10/18/2024');
|
||||||
|
|
||||||
|
expect(onSelect).toHaveBeenCalled();
|
||||||
|
expect(onSelect).toHaveBeenCalledWith({
|
||||||
|
dataDate: '10/18/2024',
|
||||||
|
date: new Date('10/18/2024'),
|
||||||
|
type: 'lastDate',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Picked last date', () => {
|
||||||
|
const onSelect = jest.fn();
|
||||||
|
|
||||||
|
const { container } = setup({
|
||||||
|
onSelect,
|
||||||
|
value: new Date(2024, 9, 15),
|
||||||
|
lastDate: new Date(2024, 9, 15),
|
||||||
|
});
|
||||||
|
|
||||||
|
pickCellByDataDate(container, '10/11/2024');
|
||||||
|
|
||||||
|
expect(onSelect).toHaveBeenCalled();
|
||||||
|
expect(onSelect).toHaveBeenCalledWith({
|
||||||
|
dataDate: '10/11/2024',
|
||||||
|
date: new Date('10/11/2024'),
|
||||||
|
type: 'firstDate',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('onUnselect handler', () => {
|
||||||
|
test('Unpick first date', () => {
|
||||||
|
const onUnselect = jest.fn();
|
||||||
|
|
||||||
|
const { container } = setup({
|
||||||
|
onUnselect,
|
||||||
|
value: new Date(2024, 9, 15),
|
||||||
|
firstDate: new Date(2024, 9, 15),
|
||||||
|
lastDate: new Date(2024, 9, 18),
|
||||||
|
});
|
||||||
|
|
||||||
|
pickCellByDataDate(container, '10/15/2024');
|
||||||
|
|
||||||
|
expect(onUnselect).toHaveBeenCalled();
|
||||||
|
expect(onUnselect).toHaveBeenCalledWith({
|
||||||
|
dataDate: '10/15/2024',
|
||||||
|
date: new Date('10/15/2024'),
|
||||||
|
type: 'firstDate',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Unpick last date', () => {
|
||||||
|
const onUnselect = jest.fn();
|
||||||
|
|
||||||
|
const { container } = setup({
|
||||||
|
onUnselect,
|
||||||
|
value: new Date(2024, 9, 15),
|
||||||
|
firstDate: new Date(2024, 9, 15),
|
||||||
|
lastDate: new Date(2024, 9, 18),
|
||||||
|
});
|
||||||
|
|
||||||
|
pickCellByDataDate(container, '10/18/2024');
|
||||||
|
|
||||||
|
expect(onUnselect).toHaveBeenCalled();
|
||||||
|
expect(onUnselect).toHaveBeenCalledWith({
|
||||||
|
dataDate: '10/18/2024',
|
||||||
|
date: new Date('10/18/2024'),
|
||||||
|
type: 'lastDate',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Test pick date', () => {
|
||||||
|
test('No picked date, select first', () => {
|
||||||
|
const { container } = setup({
|
||||||
|
value: new Date(2024, 9, 15),
|
||||||
|
});
|
||||||
|
|
||||||
|
const cellElem = getDateCellByDataDate(container, '10/11/2024');
|
||||||
|
pickCellByDataDate(container, '10/11/2024');
|
||||||
|
|
||||||
|
const firstSelectedCellElem = screen.queryByTestId('first-selected-cell');
|
||||||
|
expect(firstSelectedCellElem).toBe(cellElem);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Picked first date, pick before first date', () => {
|
||||||
|
const { container } = setup({
|
||||||
|
value: new Date(2024, 9, 15),
|
||||||
|
firstDate: new Date(2024, 9, 15),
|
||||||
|
});
|
||||||
|
|
||||||
|
pickCellByDataDate(container, '10/11/2024');
|
||||||
|
|
||||||
|
const firstPickedCellElem = screen.queryByTestId('first-selected-cell');
|
||||||
|
expect(firstPickedCellElem).toHaveAttribute('data-date', '10/11/2024');
|
||||||
|
|
||||||
|
const lastPickedCellElem = screen.queryByTestId('last-selected-cell');
|
||||||
|
expect(lastPickedCellElem).toHaveAttribute('data-date', '10/15/2024');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Picked first date, pick after first date', () => {
|
||||||
|
const { container } = setup({
|
||||||
|
value: new Date(2024, 9, 15),
|
||||||
|
firstDate: new Date(2024, 9, 15),
|
||||||
|
});
|
||||||
|
|
||||||
|
pickCellByDataDate(container, '10/18/2024');
|
||||||
|
|
||||||
|
const firstPickedCellElem = screen.queryByTestId('first-selected-cell');
|
||||||
|
expect(firstPickedCellElem).toHaveAttribute('data-date', '10/15/2024');
|
||||||
|
|
||||||
|
const lastPickedCellElem = screen.queryByTestId('last-selected-cell');
|
||||||
|
expect(lastPickedCellElem).toHaveAttribute('data-date', '10/18/2024');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Picked first date, pick this date', () => {
|
||||||
|
const { container } = setup({
|
||||||
|
value: new Date(2024, 9, 15),
|
||||||
|
firstDate: new Date(2024, 9, 15),
|
||||||
|
});
|
||||||
|
|
||||||
|
pickCellByDataDate(container, '10/15/2024');
|
||||||
|
|
||||||
|
const firstPickedCellElem = screen.queryByTestId('first-selected-cell');
|
||||||
|
expect(firstPickedCellElem).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Picked last date, pick before last date', () => {
|
||||||
|
const { container } = setup({
|
||||||
|
value: new Date(2024, 9, 15),
|
||||||
|
lastDate: new Date(2024, 9, 15),
|
||||||
|
});
|
||||||
|
|
||||||
|
pickCellByDataDate(container, '10/11/2024');
|
||||||
|
|
||||||
|
const firstPickedCellElem = screen.queryByTestId('first-selected-cell');
|
||||||
|
expect(firstPickedCellElem).toHaveAttribute('data-date', '10/11/2024');
|
||||||
|
|
||||||
|
const lastPickedCellElem = screen.queryByTestId('last-selected-cell');
|
||||||
|
expect(lastPickedCellElem).toHaveAttribute('data-date', '10/15/2024');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Picked last date, pick after last date', () => {
|
||||||
|
const { container } = setup({
|
||||||
|
value: new Date(2024, 9, 15),
|
||||||
|
lastDate: new Date(2024, 9, 15),
|
||||||
|
});
|
||||||
|
|
||||||
|
pickCellByDataDate(container, '10/18/2024');
|
||||||
|
|
||||||
|
const firstPickedCellElem = screen.queryByTestId('first-selected-cell');
|
||||||
|
expect(firstPickedCellElem).toHaveAttribute('data-date', '10/15/2024');
|
||||||
|
|
||||||
|
const lastPickedCellElem = screen.queryByTestId('last-selected-cell');
|
||||||
|
expect(lastPickedCellElem).toHaveAttribute('data-date', '10/18/2024');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Picked last date, pick this date', () => {
|
||||||
|
const { container } = setup({
|
||||||
|
value: new Date(2024, 9, 15),
|
||||||
|
lastDate: new Date(2024, 9, 15),
|
||||||
|
});
|
||||||
|
|
||||||
|
pickCellByDataDate(container, '10/15/2024');
|
||||||
|
|
||||||
|
const lastPickedCellElem = screen.queryByTestId('last-selected-cell');
|
||||||
|
expect(lastPickedCellElem).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Picked first & last date, pick date before first', () => {
|
||||||
|
const { container } = setup({
|
||||||
|
value: new Date(2024, 9, 15),
|
||||||
|
firstDate: new Date(2024, 9, 15),
|
||||||
|
lastDate: new Date(2024, 9, 18),
|
||||||
|
});
|
||||||
|
|
||||||
|
pickCellByDataDate(container, '10/11/2024');
|
||||||
|
|
||||||
|
const firstPickedCellElem = screen.queryByTestId('first-selected-cell');
|
||||||
|
expect(firstPickedCellElem).toHaveAttribute('data-date', '10/11/2024');
|
||||||
|
|
||||||
|
const lastPickedCellElem = screen.queryByTestId('last-selected-cell');
|
||||||
|
expect(lastPickedCellElem).toHaveAttribute('data-date', '10/18/2024');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Picked first & last date, pick date after last', () => {
|
||||||
|
const { container } = setup({
|
||||||
|
value: new Date(2024, 9, 15),
|
||||||
|
firstDate: new Date(2024, 9, 15),
|
||||||
|
lastDate: new Date(2024, 9, 18),
|
||||||
|
});
|
||||||
|
|
||||||
|
pickCellByDataDate(container, '10/21/2024');
|
||||||
|
|
||||||
|
const firstPickedCellElem = screen.queryByTestId('first-selected-cell');
|
||||||
|
expect(firstPickedCellElem).toHaveAttribute('data-date', '10/15/2024');
|
||||||
|
|
||||||
|
const lastPickedCellElem = screen.queryByTestId('last-selected-cell');
|
||||||
|
expect(lastPickedCellElem).toHaveAttribute('data-date', '10/21/2024');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Picked first & last date, pick fist date', () => {
|
||||||
|
const { container } = setup({
|
||||||
|
value: new Date(2024, 9, 15),
|
||||||
|
firstDate: new Date(2024, 9, 15),
|
||||||
|
lastDate: new Date(2024, 9, 18),
|
||||||
|
});
|
||||||
|
|
||||||
|
pickCellByDataDate(container, '10/15/2024');
|
||||||
|
|
||||||
|
const firstPickedCellElem = screen.queryByTestId('first-selected-cell');
|
||||||
|
expect(firstPickedCellElem).not.toBeInTheDocument();
|
||||||
|
|
||||||
|
const lastPickedCellElem = screen.queryByTestId('last-selected-cell');
|
||||||
|
expect(lastPickedCellElem).toHaveAttribute('data-date', '10/18/2024');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Picked first & last date, pick last date', () => {
|
||||||
|
const { container } = setup({
|
||||||
|
value: new Date(2024, 9, 15),
|
||||||
|
firstDate: new Date(2024, 9, 15),
|
||||||
|
lastDate: new Date(2024, 9, 18),
|
||||||
|
});
|
||||||
|
|
||||||
|
pickCellByDataDate(container, '10/18/2024');
|
||||||
|
|
||||||
|
const firstPickedCellElem = screen.queryByTestId('first-selected-cell');
|
||||||
|
expect(firstPickedCellElem).toHaveAttribute('data-date', '10/15/2024');
|
||||||
|
|
||||||
|
const lastPickedCellElem = screen.queryByTestId('last-selected-cell');
|
||||||
|
expect(lastPickedCellElem).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Picked first & last date, pick the date closer to first date', () => {
|
||||||
|
const { container } = setup({
|
||||||
|
value: new Date(2024, 9, 15),
|
||||||
|
firstDate: new Date(2024, 9, 15),
|
||||||
|
lastDate: new Date(2024, 9, 18),
|
||||||
|
});
|
||||||
|
|
||||||
|
pickCellByDataDate(container, '10/16/2024');
|
||||||
|
|
||||||
|
const firstPickedCellElem = screen.queryByTestId('first-selected-cell');
|
||||||
|
expect(firstPickedCellElem).toHaveAttribute('data-date', '10/16/2024');
|
||||||
|
|
||||||
|
const lastPickedCellElem = screen.queryByTestId('last-selected-cell');
|
||||||
|
expect(lastPickedCellElem).toHaveAttribute('data-date', '10/18/2024');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Picked first & last date, pick the date closer to last date', () => {
|
||||||
|
const { container } = setup({
|
||||||
|
value: new Date(2024, 9, 15),
|
||||||
|
firstDate: new Date(2024, 9, 15),
|
||||||
|
lastDate: new Date(2024, 9, 18),
|
||||||
|
});
|
||||||
|
|
||||||
|
pickCellByDataDate(container, '10/17/2024');
|
||||||
|
|
||||||
|
const firstPickedCellElem = screen.queryByTestId('first-selected-cell');
|
||||||
|
expect(firstPickedCellElem).toHaveAttribute('data-date', '10/15/2024');
|
||||||
|
|
||||||
|
const lastPickedCellElem = screen.queryByTestId('last-selected-cell');
|
||||||
|
expect(lastPickedCellElem).toHaveAttribute('data-date', '10/17/2024');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Picked first & last date, pick the equidistant date', () => {
|
||||||
|
const { container } = setup({
|
||||||
|
value: new Date(2024, 9, 15),
|
||||||
|
firstDate: new Date(2024, 9, 15),
|
||||||
|
lastDate: new Date(2024, 9, 19),
|
||||||
|
});
|
||||||
|
|
||||||
|
pickCellByDataDate(container, '10/17/2024');
|
||||||
|
|
||||||
|
const firstPickedCellElem = screen.queryByTestId('first-selected-cell');
|
||||||
|
expect(firstPickedCellElem).toHaveAttribute('data-date', '10/17/2024');
|
||||||
|
|
||||||
|
const lastPickedCellElem = screen.queryByTestId('last-selected-cell');
|
||||||
|
expect(lastPickedCellElem).toHaveAttribute('data-date', '10/19/2024');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
16
src/widgets/DatePicker/ui/DatePicker.style.module.css
Normal file
16
src/widgets/DatePicker/ui/DatePicker.style.module.css
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
.firstDate {
|
||||||
|
background-color: blue;
|
||||||
|
color: white;
|
||||||
|
border-top-left-radius: 10px
|
||||||
|
}
|
||||||
|
|
||||||
|
.inSelection {
|
||||||
|
background: gold;
|
||||||
|
color: darkgrey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lastDate {
|
||||||
|
background-color: blue;
|
||||||
|
color: white;
|
||||||
|
border-bottom-right-radius: 10px
|
||||||
|
}
|
||||||
262
src/widgets/DatePicker/ui/DatePicker.ui.tsx
Normal file
262
src/widgets/DatePicker/ui/DatePicker.ui.tsx
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
import classnames from 'classnames';
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
import type { DataDateString } from 'shared/types/date';
|
||||||
|
import { daysCountBetween, getDataDateString } from 'shared/utils/date';
|
||||||
|
import { exhaustiveCheck } from 'shared/utils/type';
|
||||||
|
|
||||||
|
import { CalendarWidget } from '../../CalendarWidget';
|
||||||
|
|
||||||
|
import classes from './DatePicker.style.module.css';
|
||||||
|
|
||||||
|
import type { CalendarWidgetProps } from '../../CalendarWidget';
|
||||||
|
import type { FC } from 'react';
|
||||||
|
|
||||||
|
export type DatePickerProps = CalendarWidgetProps & {
|
||||||
|
firstDate?: Date;
|
||||||
|
lastDate?: Date;
|
||||||
|
onSelect?: (params: { dataDate: DataDateString; date: Date; type: 'firstDate' | 'lastDate' }) => void;
|
||||||
|
onUnselect?: (params: { dataDate: DataDateString; date: Date; type: 'firstDate' | 'lastDate' }) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const DatePicker: FC<DatePickerProps> = (props) => {
|
||||||
|
const {
|
||||||
|
firstDate,
|
||||||
|
lastDate,
|
||||||
|
onSelect,
|
||||||
|
onUnselect,
|
||||||
|
...restWidgetProps
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const [firstSelectedDate, setFirstSelectedDate] = useState<DataDateString | null>(
|
||||||
|
firstDate
|
||||||
|
? getDataDateString(firstDate)
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
const [lastSelectedDate, setLastSelectedDate] = useState<DataDateString | null>(
|
||||||
|
lastDate
|
||||||
|
? getDataDateString(lastDate)
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
const isSelectedFirstDate = firstSelectedDate !== null;
|
||||||
|
const isSelectedLastDate = lastSelectedDate !== null;
|
||||||
|
const isSelectedBothDate = isSelectedFirstDate && isSelectedLastDate;
|
||||||
|
|
||||||
|
const isCellInSelection = (dataDate: DataDateString) => {
|
||||||
|
if (!isSelectedFirstDate || !isSelectedLastDate) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dateTime = new Date(dataDate).getTime();
|
||||||
|
const firstDateTime = new Date(firstSelectedDate).getTime();
|
||||||
|
const lastDateTime = new Date(lastSelectedDate).getTime();
|
||||||
|
|
||||||
|
return dateTime >= firstDateTime && dateTime <= lastDateTime;
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleCellDate = (params: { dataDate: DataDateString | null; type: 'firstDate' | 'lastDate' }) => {
|
||||||
|
const { dataDate, type } = params;
|
||||||
|
|
||||||
|
if (dataDate === null) {
|
||||||
|
let typedDataDate: DataDateString;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 'firstDate':
|
||||||
|
if (!isSelectedFirstDate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
typedDataDate = firstSelectedDate;
|
||||||
|
setFirstSelectedDate(null);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'lastDate':
|
||||||
|
if (!isSelectedLastDate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
typedDataDate = lastSelectedDate;
|
||||||
|
setLastSelectedDate(null);
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
exhaustiveCheck(type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnselect?.({
|
||||||
|
type,
|
||||||
|
// @ts-ignore
|
||||||
|
dataDate: typedDataDate,
|
||||||
|
// @ts-ignore
|
||||||
|
date: new Date(typedDataDate),
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 'firstDate':
|
||||||
|
setFirstSelectedDate(dataDate);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'lastDate':
|
||||||
|
setLastSelectedDate(dataDate);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
exhaustiveCheck(type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
onSelect?.({
|
||||||
|
type,
|
||||||
|
dataDate,
|
||||||
|
date: new Date(dataDate),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleCellSelection = (dataDate: DataDateString) => {
|
||||||
|
if (!isSelectedFirstDate && !isSelectedLastDate) {
|
||||||
|
toggleCellDate({ dataDate, type: 'firstDate' });
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSelectedFirstDate && !isSelectedLastDate) {
|
||||||
|
if (dataDate < firstSelectedDate) {
|
||||||
|
toggleCellDate({ dataDate: firstSelectedDate, type: 'lastDate' });
|
||||||
|
toggleCellDate({ dataDate, type: 'firstDate' });
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataDate > firstSelectedDate) {
|
||||||
|
toggleCellDate({ dataDate, type: 'lastDate' });
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleCellDate({ dataDate: null, type: 'firstDate' });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isSelectedFirstDate && isSelectedLastDate) {
|
||||||
|
if (dataDate < lastSelectedDate) {
|
||||||
|
toggleCellDate({ dataDate, type: 'firstDate' });
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataDate > lastSelectedDate) {
|
||||||
|
toggleCellDate({ dataDate: lastSelectedDate, type: 'firstDate' });
|
||||||
|
toggleCellDate({ dataDate, type: 'lastDate' });
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleCellDate({ dataDate: null, type: 'lastDate' });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSelectedBothDate) {
|
||||||
|
if (dataDate < firstSelectedDate) {
|
||||||
|
toggleCellDate({ dataDate, type: 'firstDate' });
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataDate > lastSelectedDate) {
|
||||||
|
toggleCellDate({ dataDate, type: 'lastDate' });
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataDate === firstSelectedDate) {
|
||||||
|
toggleCellDate({ dataDate: null, type: 'firstDate' });
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataDate === lastSelectedDate) {
|
||||||
|
toggleCellDate({ dataDate: null, type: 'lastDate' });
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const daysToFirstDate = daysCountBetween(new Date(firstSelectedDate), new Date(dataDate));
|
||||||
|
const daysToLastDate = daysCountBetween(new Date(lastSelectedDate), new Date(dataDate));
|
||||||
|
|
||||||
|
if (daysToFirstDate < daysToLastDate) {
|
||||||
|
toggleCellDate({ dataDate, type: 'firstDate' });
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (daysToFirstDate > daysToLastDate) {
|
||||||
|
toggleCellDate({ dataDate, type: 'lastDate' });
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleCellDate({ dataDate, type: 'firstDate' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const isFirstDate = (dataDate: DataDateString) => dataDate === firstSelectedDate;
|
||||||
|
|
||||||
|
const isLastDate = (dataDate: DataDateString) => dataDate === lastSelectedDate;
|
||||||
|
|
||||||
|
const getDataTestId = (dataDate: DataDateString) => {
|
||||||
|
if (isFirstDate(dataDate)) {
|
||||||
|
return {
|
||||||
|
'data-testid': 'first-selected-cell',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLastDate(dataDate)) {
|
||||||
|
return {
|
||||||
|
'data-testid': 'last-selected-cell',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isCellInSelection(dataDate)) {
|
||||||
|
return {
|
||||||
|
'data-testid': 'cell-in-range',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
setLastSelectedDate(null);
|
||||||
|
setFirstSelectedDate(null);
|
||||||
|
}}
|
||||||
|
onKeyPress={() => {}}
|
||||||
|
>
|
||||||
|
reset
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<CalendarWidget
|
||||||
|
DateCellProps={({ dataDate }) => ({
|
||||||
|
onClick: () => {
|
||||||
|
toggleCellSelection(dataDate);
|
||||||
|
},
|
||||||
|
className: classnames({
|
||||||
|
[classes.firstDate as string]: isFirstDate(dataDate),
|
||||||
|
[classes.inSelection as string]: isCellInSelection(dataDate)
|
||||||
|
&& !isFirstDate(dataDate)
|
||||||
|
&& !isLastDate(dataDate),
|
||||||
|
[classes.lastDate as string]: isLastDate(dataDate),
|
||||||
|
}),
|
||||||
|
...getDataTestId(dataDate),
|
||||||
|
})}
|
||||||
|
{...restWidgetProps}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DatePicker;
|
||||||
Loading…
x
Reference in New Issue
Block a user