feat: update project to typescript #9
This commit is contained in:
parent
a603f31c1a
commit
8c5e4a08bf
5
src/global.d.ts
vendored
Normal file
5
src/global.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
/// <reference types="ksv741-react-scripts/global" />
|
||||||
|
|
||||||
|
declare module '*.css' {
|
||||||
|
export default Record<string, string>;
|
||||||
|
}
|
||||||
@ -13,6 +13,7 @@ const CalendarPage = () => (
|
|||||||
locale="en"
|
locale="en"
|
||||||
maxDate={new Date(2027, 2, 15)}
|
maxDate={new Date(2027, 2, 15)}
|
||||||
minDate={new Date(1996, 9, 15)}
|
minDate={new Date(1996, 9, 15)}
|
||||||
|
value={new Date(2023, 9, 15)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -13,6 +13,9 @@ export const MONTHS = {
|
|||||||
DECEMBER: 11,
|
DECEMBER: 11,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type MonthsKeys = keyof typeof MONTHS;
|
||||||
|
export type MonthsValues = typeof MONTHS[MonthsKeys];
|
||||||
|
|
||||||
export const DAYS_IN_WEEK = 7;
|
export const DAYS_IN_WEEK = 7;
|
||||||
|
|
||||||
export const WEEK_DAYS = {
|
export const WEEK_DAYS = {
|
||||||
@ -24,3 +27,6 @@ export const WEEK_DAYS = {
|
|||||||
FRIDAY: 5,
|
FRIDAY: 5,
|
||||||
SATURDAY: 6,
|
SATURDAY: 6,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type WeekDaysKeys = keyof typeof WEEK_DAYS;
|
||||||
|
export type WeekDaysValues = typeof WEEK_DAYS[WeekDaysKeys];
|
||||||
@ -1,2 +1,8 @@
|
|||||||
export { DAYS_IN_WEEK, MONTHS, WEEK_DAYS } from './date';
|
export { DAYS_IN_WEEK, MONTHS, WEEK_DAYS } from './date';
|
||||||
export { MONTHS_LABEL, WEEK_DAYS_LABEL } from './locale';
|
export { MONTHS_LABEL, WEEK_DAYS_LABEL } from './locale';
|
||||||
|
export type {
|
||||||
|
MonthsKeys,
|
||||||
|
MonthsValues,
|
||||||
|
WeekDaysKeys,
|
||||||
|
WeekDaysValues,
|
||||||
|
} from './date';
|
||||||
@ -1,6 +1,12 @@
|
|||||||
import { MONTHS, WEEK_DAYS } from './date';
|
import { MONTHS, WEEK_DAYS } from 'shared/constants/date';
|
||||||
|
import type { MonthsValues, WeekDaysValues } from 'shared/constants/date';
|
||||||
|
|
||||||
export const MONTHS_LABEL = {
|
type Locale<T = string> = {
|
||||||
|
ru: T;
|
||||||
|
en: T;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const MONTHS_LABEL: Record<MonthsValues, Locale> = {
|
||||||
[MONTHS.JANUARY]: {
|
[MONTHS.JANUARY]: {
|
||||||
ru: 'Январь',
|
ru: 'Январь',
|
||||||
en: 'January',
|
en: 'January',
|
||||||
@ -51,7 +57,14 @@ export const MONTHS_LABEL = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const WEEK_DAYS_LABEL = {
|
type WeekDaysLabel = {
|
||||||
|
full: string;
|
||||||
|
short: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type WeekDaysLabelLocale = Locale<WeekDaysLabel>;
|
||||||
|
|
||||||
|
export const WEEK_DAYS_LABEL: Record<WeekDaysValues, WeekDaysLabelLocale> = {
|
||||||
[WEEK_DAYS.SUNDAY]: {
|
[WEEK_DAYS.SUNDAY]: {
|
||||||
ru: {
|
ru: {
|
||||||
full: 'Воскресенье',
|
full: 'Воскресенье',
|
||||||
@ -2,13 +2,19 @@ import { fireEvent, render, screen } from '@testing-library/react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { useContext, useMemo, useState } from 'react';
|
import React, { useContext, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { withProvider } from 'shared/hoc/withProvider/index';
|
import withProvider from './withProvider.ui';
|
||||||
|
|
||||||
|
import type { PropsWithChildren } from 'react';
|
||||||
|
|
||||||
describe('Test withProvider', () => {
|
describe('Test withProvider', () => {
|
||||||
const renderCounter = () => {
|
const renderCounter = () => {
|
||||||
const TestContext = React.createContext({});
|
type TestContextValue = {
|
||||||
|
testState: number;
|
||||||
|
setTestState: React.Dispatch<React.SetStateAction<number>>;
|
||||||
|
};
|
||||||
|
const TestContext = React.createContext<TestContextValue>({} as TestContextValue);
|
||||||
|
|
||||||
const TestProvider = (props) => {
|
const TestProvider = (props: PropsWithChildren) => {
|
||||||
const { children } = props;
|
const { children } = props;
|
||||||
|
|
||||||
const [testState, setTestState] = useState(100);
|
const [testState, setTestState] = useState(100);
|
||||||
@ -74,7 +80,7 @@ describe('Test withProvider', () => {
|
|||||||
renderCounter();
|
renderCounter();
|
||||||
|
|
||||||
const counterElem = screen.getByTestId('counter');
|
const counterElem = screen.getByTestId('counter');
|
||||||
expect(counterElem).toHaveTextContent(100);
|
expect(counterElem).toHaveTextContent('100');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('change state - increment', () => {
|
test('change state - increment', () => {
|
||||||
@ -84,7 +90,7 @@ describe('Test withProvider', () => {
|
|||||||
fireEvent.click(plusBtn);
|
fireEvent.click(plusBtn);
|
||||||
|
|
||||||
const counterElem = screen.getByTestId('counter');
|
const counterElem = screen.getByTestId('counter');
|
||||||
expect(counterElem).toHaveTextContent(101);
|
expect(counterElem).toHaveTextContent('101');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('change state - decrement', () => {
|
test('change state - decrement', () => {
|
||||||
@ -94,6 +100,6 @@ describe('Test withProvider', () => {
|
|||||||
fireEvent.click(minusBtn);
|
fireEvent.click(minusBtn);
|
||||||
|
|
||||||
const counterElem = screen.getByTestId('counter');
|
const counterElem = screen.getByTestId('counter');
|
||||||
expect(counterElem).toHaveTextContent(99);
|
expect(counterElem).toHaveTextContent('99');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -1,9 +0,0 @@
|
|||||||
// todo fix eslint
|
|
||||||
// eslint-disable-next-line react/function-component-definition
|
|
||||||
const withProvider = (Provider) => (Component) => (...params) => (
|
|
||||||
<Provider>
|
|
||||||
<Component {...params} />
|
|
||||||
</Provider>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default withProvider;
|
|
||||||
13
src/shared/hoc/withProvider/ui/withProvider.ui.tsx
Normal file
13
src/shared/hoc/withProvider/ui/withProvider.ui.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// todo fix eslint
|
||||||
|
|
||||||
|
import type { FC, PropsWithChildren } from 'react';
|
||||||
|
|
||||||
|
// eslint-disable-next-line react/function-component-definition
|
||||||
|
const withProvider = <T,>(Provider: FC<PropsWithChildren>) => (Component: FC<T>) => (...params: T[]) => (
|
||||||
|
<Provider>
|
||||||
|
{/* @ts-ignore */}
|
||||||
|
<Component {...params} />
|
||||||
|
</Provider>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default withProvider;
|
||||||
@ -1,11 +1,11 @@
|
|||||||
export const firstDayOfMonthDate = (date) => {
|
export const firstDayOfMonthDate = (date: Date) => {
|
||||||
const monthIndex = date.getMonth();
|
const monthIndex = date.getMonth();
|
||||||
const year = date.getFullYear();
|
const year = date.getFullYear();
|
||||||
|
|
||||||
return new Date(year, monthIndex, 1);
|
return new Date(year, monthIndex, 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const lastDayOfMonthDate = (date) => {
|
export const lastDayOfMonthDate = (date: Date) => {
|
||||||
const monthIndex = date.getMonth();
|
const monthIndex = date.getMonth();
|
||||||
const year = date.getFullYear();
|
const year = date.getFullYear();
|
||||||
|
|
||||||
46
src/widgets/CalendarWidget/ui/CalendarWidget.spec.tsx
Normal file
46
src/widgets/CalendarWidget/ui/CalendarWidget.spec.tsx
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
|
||||||
|
import CalendarWidget from './CalendarWidget.ui';
|
||||||
|
|
||||||
|
import type { CalendarWidgetProps } from './CalendarWidget.ui';
|
||||||
|
|
||||||
|
describe('Test CalendarWidget', () => {
|
||||||
|
const setup = (props?: CalendarWidgetProps) => {
|
||||||
|
render(<CalendarWidget {...props} />);
|
||||||
|
};
|
||||||
|
|
||||||
|
test('Basic render', () => {
|
||||||
|
setup();
|
||||||
|
|
||||||
|
const calendarWidgetElem = screen.getByTestId('calendar-widget');
|
||||||
|
expect(calendarWidgetElem).toBeInTheDocument();
|
||||||
|
expect(calendarWidgetElem).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Render components', () => {
|
||||||
|
setup();
|
||||||
|
|
||||||
|
const calendarWidgetElem = screen.getByTestId('calendar-widget');
|
||||||
|
const headerRowElem = screen.getByTestId('header-row');
|
||||||
|
const dayOfWeekRowElem = screen.getByTestId('day-of-week-row');
|
||||||
|
const dateWrapperElem = screen.getByTestId('date-wrapper');
|
||||||
|
|
||||||
|
expect(calendarWidgetElem).toContainElement(headerRowElem);
|
||||||
|
expect(calendarWidgetElem).toContainElement(dayOfWeekRowElem);
|
||||||
|
expect(calendarWidgetElem).toContainElement(dateWrapperElem);
|
||||||
|
});
|
||||||
|
|
||||||
|
// todo
|
||||||
|
test('Render with value', () => {
|
||||||
|
setup({ value: new Date(2023, 1, 15) });
|
||||||
|
|
||||||
|
const calendarWidgetElem = screen.getByTestId('calendar-widget');
|
||||||
|
const headerRowElem = screen.getByTestId('header-row');
|
||||||
|
const dayOfWeekRowElem = screen.getByTestId('day-of-week-row');
|
||||||
|
const dateWrapperElem = screen.getByTestId('date-wrapper');
|
||||||
|
|
||||||
|
expect(calendarWidgetElem).toContainElement(headerRowElem);
|
||||||
|
expect(calendarWidgetElem).toContainElement(dayOfWeekRowElem);
|
||||||
|
expect(calendarWidgetElem).toContainElement(dateWrapperElem);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -1,14 +1,20 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
import classes from './CalendarWidget.module.css';
|
import classes from './CalendarWidget.module.css';
|
||||||
import { CalendarWidgetProvider } from './CalendarWidgetContext';
|
import { CalendarWidgetProvider } from './CalendarWidgetContext';
|
||||||
import { DateWrapper } from './components/DateWrapper';
|
import { DateWrapper } from './components/DateWrapper';
|
||||||
import { DayOfWeekRow } from './components/DayOfWeekRow';
|
import { DayOfWeekRow } from './components/DayOfWeekRow';
|
||||||
import { HeaderRow } from './components/HeaderRow';
|
import { HeaderRow } from './components/HeaderRow';
|
||||||
|
|
||||||
const CalendarWidget = (props) => (
|
import type { FC } from 'react';
|
||||||
|
|
||||||
|
export type CalendarWidgetProps = {
|
||||||
|
maxDate?: Date;
|
||||||
|
minDate?: Date;
|
||||||
|
value?: Date;
|
||||||
|
locale?: 'en' | 'ru';
|
||||||
|
};
|
||||||
|
const CalendarWidget: FC<CalendarWidgetProps> = (props) => (
|
||||||
<CalendarWidgetProvider {...props}>
|
<CalendarWidgetProvider {...props}>
|
||||||
<div className={classes.wrapper}>
|
<div className={classes.wrapper} data-testid="calendar-widget">
|
||||||
<HeaderRow />
|
<HeaderRow />
|
||||||
|
|
||||||
<DayOfWeekRow />
|
<DayOfWeekRow />
|
||||||
@ -18,10 +24,4 @@ const CalendarWidget = (props) => (
|
|||||||
</CalendarWidgetProvider>
|
</CalendarWidgetProvider>
|
||||||
);
|
);
|
||||||
|
|
||||||
CalendarWidget.propTypes = {
|
|
||||||
maxDate: PropTypes.instanceOf(Date),
|
|
||||||
minDate: PropTypes.instanceOf(Date),
|
|
||||||
value: PropTypes.instanceOf(Date),
|
|
||||||
};
|
|
||||||
|
|
||||||
export default CalendarWidget;
|
export default CalendarWidget;
|
||||||
@ -1,41 +0,0 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
import { createContext, useMemo, useState } from 'react';
|
|
||||||
|
|
||||||
export const CalendarWidgetContext = createContext({});
|
|
||||||
|
|
||||||
export const CalendarWidgetProvider = (props) => {
|
|
||||||
const {
|
|
||||||
children,
|
|
||||||
maxDate = new Date(2030, 0, 1),
|
|
||||||
minDate = new Date(1990, 0, 1),
|
|
||||||
locale = 'ru',
|
|
||||||
...restProps
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
const [targetDate, setTargetDate] = useState(new Date());
|
|
||||||
|
|
||||||
const contextValue = useMemo(() => ({
|
|
||||||
targetYear: targetDate.getFullYear(),
|
|
||||||
targetMonthIndex: targetDate.getMonth(),
|
|
||||||
targetDate,
|
|
||||||
setTargetDate,
|
|
||||||
minDate,
|
|
||||||
maxDate,
|
|
||||||
locale,
|
|
||||||
...restProps,
|
|
||||||
}), [maxDate, minDate, targetDate, locale, restProps]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<CalendarWidgetContext.Provider value={contextValue}>
|
|
||||||
{children}
|
|
||||||
</CalendarWidgetContext.Provider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
CalendarWidgetProvider.propTypes = {
|
|
||||||
children: PropTypes.node.isRequired,
|
|
||||||
|
|
||||||
maxDate: PropTypes.instanceOf(Date),
|
|
||||||
minDate: PropTypes.instanceOf(Date),
|
|
||||||
locale: PropTypes.oneOf(['ru', 'en']),
|
|
||||||
};
|
|
||||||
54
src/widgets/CalendarWidget/ui/CalendarWidgetContext.tsx
Normal file
54
src/widgets/CalendarWidget/ui/CalendarWidgetContext.tsx
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React, { createContext, useMemo, useState } from 'react';
|
||||||
|
|
||||||
|
import type { CalendarWidgetProps } from './CalendarWidget.ui';
|
||||||
|
import type { FC, PropsWithChildren } from 'react';
|
||||||
|
|
||||||
|
type CalendarWidgetContextValue = Required<CalendarWidgetProps> & {
|
||||||
|
targetYear: number;
|
||||||
|
targetMonthIndex: number;
|
||||||
|
targetDate: Date;
|
||||||
|
setTargetDate: React.Dispatch<React.SetStateAction<Date>>;
|
||||||
|
};
|
||||||
|
export const CalendarWidgetContext = createContext({} as CalendarWidgetContextValue);
|
||||||
|
|
||||||
|
export type CalendarWidgetProviderProps = PropsWithChildren<CalendarWidgetProps>;
|
||||||
|
|
||||||
|
export const CalendarWidgetProvider: FC<CalendarWidgetProviderProps> = (props) => {
|
||||||
|
const {
|
||||||
|
children,
|
||||||
|
maxDate = new Date(2030, 0, 1),
|
||||||
|
minDate = new Date(1990, 0, 1),
|
||||||
|
locale = 'ru',
|
||||||
|
value = new Date(),
|
||||||
|
...restProps
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const [targetDate, setTargetDate] = useState(value);
|
||||||
|
|
||||||
|
const contextValue = useMemo<CalendarWidgetContextValue>(() => ({
|
||||||
|
targetYear: targetDate.getFullYear(),
|
||||||
|
targetMonthIndex: targetDate.getMonth(),
|
||||||
|
targetDate,
|
||||||
|
setTargetDate,
|
||||||
|
minDate,
|
||||||
|
maxDate,
|
||||||
|
locale,
|
||||||
|
value,
|
||||||
|
...restProps,
|
||||||
|
}), [maxDate, minDate, targetDate, locale, restProps, value]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CalendarWidgetContext.Provider value={contextValue}>
|
||||||
|
{children}
|
||||||
|
</CalendarWidgetContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
CalendarWidgetProvider.propTypes = {
|
||||||
|
children: PropTypes.node.isRequired,
|
||||||
|
|
||||||
|
maxDate: PropTypes.instanceOf(Date),
|
||||||
|
minDate: PropTypes.instanceOf(Date),
|
||||||
|
locale: PropTypes.oneOf(['ru', 'en']),
|
||||||
|
};
|
||||||
@ -3,7 +3,7 @@ import { render, screen } from '@testing-library/react';
|
|||||||
import DateCell from './DateCell.ui';
|
import DateCell from './DateCell.ui';
|
||||||
|
|
||||||
describe('Base Render', () => {
|
describe('Base Render', () => {
|
||||||
const setup = (date) => {
|
const setup = (date: Date) => {
|
||||||
render(<DateCell date={date} />);
|
render(<DateCell date={date} />);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -16,13 +16,25 @@
|
|||||||
border-right: 1px solid black;
|
border-right: 1px solid black;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.today {
|
.today {
|
||||||
color: red;
|
color: red;
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.outMothRange {
|
.outMothRange {
|
||||||
color: darkgrey;
|
color: darkgrey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.valueDate {
|
||||||
|
color: gold;
|
||||||
|
background: red;
|
||||||
|
border-radius: 50%;
|
||||||
|
padding: 5px;
|
||||||
|
height: 1.2em;
|
||||||
|
width: 1.2em;
|
||||||
|
display: inline-flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,44 +1,49 @@
|
|||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
|
|
||||||
import { CalendarWidgetContext } from '../../../CalendarWidgetContext';
|
import { CalendarWidgetContext } from '../../../CalendarWidgetContext';
|
||||||
|
|
||||||
import classes from './DateCell.style.module.css';
|
import classes from './DateCell.style.module.css';
|
||||||
|
|
||||||
const DateCell = (props) => {
|
import type { FC } from 'react';
|
||||||
|
|
||||||
|
type DateCellProps = {
|
||||||
|
date: Date;
|
||||||
|
};
|
||||||
|
const DateCell: FC<DateCellProps> = (props) => {
|
||||||
const {
|
const {
|
||||||
date,
|
date,
|
||||||
} = props;
|
} = props;
|
||||||
const format = 'en-En';
|
const format = 'en-En';
|
||||||
|
|
||||||
const { targetMonthIndex } = useContext(CalendarWidgetContext);
|
const { targetMonthIndex, value } = useContext(CalendarWidgetContext);
|
||||||
|
|
||||||
const todayDate = new Date();
|
const todayDate = new Date();
|
||||||
const dataDate = new Intl.DateTimeFormat(format).format(date);
|
const dataDate = new Intl.DateTimeFormat(format).format(date);
|
||||||
const dataToday = new Intl.DateTimeFormat(format).format(todayDate);
|
const dataToday = new Intl.DateTimeFormat(format).format(todayDate);
|
||||||
|
const dataValue = new Intl.DateTimeFormat(format).format(value);
|
||||||
const isOutMonthRange = date.getMonth() !== targetMonthIndex;
|
const isOutMonthRange = date.getMonth() !== targetMonthIndex;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={dataDate}
|
key={dataDate}
|
||||||
className={classnames(
|
className={classes.dateCell}
|
||||||
{
|
|
||||||
[classes.dateCell]: true,
|
|
||||||
[classes.today]: dataDate === dataToday,
|
|
||||||
[classes.outMothRange]: isOutMonthRange,
|
|
||||||
},
|
|
||||||
)}
|
|
||||||
data-date={dataDate}
|
data-date={dataDate}
|
||||||
data-testid="date-cell"
|
data-testid="date-cell"
|
||||||
>
|
>
|
||||||
{date.getDate()}
|
<span
|
||||||
|
className={classnames(
|
||||||
|
{
|
||||||
|
[classes.today as string]: dataDate === dataToday,
|
||||||
|
[classes.outMothRange as string]: isOutMonthRange,
|
||||||
|
[classes.valueDate as string]: dataDate === dataValue,
|
||||||
|
},
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{date.getDate()}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
DateCell.propTypes = {
|
|
||||||
date: PropTypes.instanceOf(Date).isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default DateCell;
|
export default DateCell;
|
||||||
@ -2,8 +2,10 @@ import { render, screen } from '@testing-library/react';
|
|||||||
|
|
||||||
import DateRow from './DateRow.ui';
|
import DateRow from './DateRow.ui';
|
||||||
|
|
||||||
|
import type { DateRowType } from './DateRow.ui';
|
||||||
|
|
||||||
describe('Test Date Row', () => {
|
describe('Test Date Row', () => {
|
||||||
const setup = (cells) => {
|
const setup = (cells: DateRowType['cells']) => {
|
||||||
render(<DateRow cells={cells} />);
|
render(<DateRow cells={cells} />);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -53,13 +55,13 @@ describe('Test Date Row', () => {
|
|||||||
setupWeek();
|
setupWeek();
|
||||||
|
|
||||||
const dateCellElems = screen.getAllByTestId('date-cell');
|
const dateCellElems = screen.getAllByTestId('date-cell');
|
||||||
expect(dateCellElems[0]).toHaveTextContent(15);
|
expect(dateCellElems[0]).toHaveTextContent('15');
|
||||||
expect(dateCellElems[1]).toHaveTextContent(16);
|
expect(dateCellElems[1]).toHaveTextContent('16');
|
||||||
expect(dateCellElems[2]).toHaveTextContent(17);
|
expect(dateCellElems[2]).toHaveTextContent('17');
|
||||||
expect(dateCellElems[3]).toHaveTextContent(18);
|
expect(dateCellElems[3]).toHaveTextContent('18');
|
||||||
expect(dateCellElems[4]).toHaveTextContent(19);
|
expect(dateCellElems[4]).toHaveTextContent('19');
|
||||||
expect(dateCellElems[5]).toHaveTextContent(20);
|
expect(dateCellElems[5]).toHaveTextContent('20');
|
||||||
expect(dateCellElems[6]).toHaveTextContent(21);
|
expect(dateCellElems[6]).toHaveTextContent('21');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -1,10 +1,13 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
import { DateCell } from '../../DateCell';
|
import { DateCell } from '../../DateCell';
|
||||||
|
|
||||||
import classes from './DateRow.style.module.css';
|
import classes from './DateRow.style.module.css';
|
||||||
|
|
||||||
const DateRow = (props) => {
|
import type { FC } from 'react';
|
||||||
|
|
||||||
|
export type DateRowType = {
|
||||||
|
cells: Date[];
|
||||||
|
};
|
||||||
|
const DateRow: FC<DateRowType> = (props) => {
|
||||||
const {
|
const {
|
||||||
cells,
|
cells,
|
||||||
} = props;
|
} = props;
|
||||||
@ -28,8 +31,4 @@ const DateRow = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
DateRow.propTypes = {
|
|
||||||
cells: PropTypes.arrayOf(PropTypes.instanceOf(Date)),
|
|
||||||
};
|
|
||||||
|
|
||||||
export default DateRow;
|
export default DateRow;
|
||||||
@ -7,14 +7,17 @@ import { CalendarWidgetProvider } from '../../../CalendarWidgetContext';
|
|||||||
|
|
||||||
import DayOfWeekCell from './DayOfWeekCell.ui';
|
import DayOfWeekCell from './DayOfWeekCell.ui';
|
||||||
|
|
||||||
|
import type { DayOfWeekCellProps } from './DayOfWeekCell.ui';
|
||||||
|
import type { CalendarWidgetProviderProps } from '../../../CalendarWidgetContext';
|
||||||
|
|
||||||
describe('Test DayOfWeekCell', () => {
|
describe('Test DayOfWeekCell', () => {
|
||||||
const setup = (day, locale) => {
|
const setup = (day: DayOfWeekCellProps['day'], locale: CalendarWidgetProviderProps['locale']) => {
|
||||||
const DayOfWeekCellComponent = () => (
|
const DayOfWeekCellComponent = () => (
|
||||||
<DayOfWeekCell day={day} />
|
<DayOfWeekCell day={day} />
|
||||||
);
|
);
|
||||||
|
|
||||||
const Provider = (props) => (
|
const Provider = (props: CalendarWidgetProviderProps) => (
|
||||||
<CalendarWidgetProvider {...props} locale={locale} />
|
<CalendarWidgetProvider {...props} locale={locale ?? 'ru'} />
|
||||||
);
|
);
|
||||||
|
|
||||||
const DayOfWeekCellWithProvider = withProvider(Provider)(DayOfWeekCellComponent);
|
const DayOfWeekCellWithProvider = withProvider(Provider)(DayOfWeekCellComponent);
|
||||||
@ -1,16 +1,21 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
|
|
||||||
import { WEEK_DAYS_LABEL, WEEK_DAYS } from 'shared/constants';
|
import type { WeekDaysValues } from 'shared/constants';
|
||||||
|
import { WEEK_DAYS_LABEL } from 'shared/constants';
|
||||||
|
|
||||||
import { CalendarWidgetContext } from '../../../CalendarWidgetContext';
|
import { CalendarWidgetContext } from '../../../CalendarWidgetContext';
|
||||||
|
|
||||||
import classes from './DayOfWeekCell.style.module.css';
|
import classes from './DayOfWeekCell.style.module.css';
|
||||||
|
|
||||||
const DayOfWeekCell = (props) => {
|
import type { FC } from 'react';
|
||||||
|
|
||||||
|
export type DayOfWeekCellProps = {
|
||||||
|
day: WeekDaysValues;
|
||||||
|
};
|
||||||
|
const DayOfWeekCell: FC<DayOfWeekCellProps> = (props) => {
|
||||||
const { day } = props;
|
const { day } = props;
|
||||||
const { locale } = useContext(CalendarWidgetContext);
|
const { locale } = useContext(CalendarWidgetContext);
|
||||||
const content = WEEK_DAYS_LABEL[day][locale]?.short;
|
const content = WEEK_DAYS_LABEL[day]?.[locale].short;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className={classes.content} data-testid="day-of-week-cell">
|
<span className={classes.content} data-testid="day-of-week-cell">
|
||||||
@ -20,8 +25,4 @@ const DayOfWeekCell = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
DayOfWeekCell.propTypes = {
|
|
||||||
day: PropTypes.oneOf(Object.values(WEEK_DAYS)).isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default DayOfWeekCell;
|
export default DayOfWeekCell;
|
||||||
@ -15,11 +15,15 @@ describe('Test MonthSelect', () => {
|
|||||||
user = userEvent.setup();
|
user = userEvent.setup();
|
||||||
});
|
});
|
||||||
|
|
||||||
const setup = (props) => {
|
const setup = (props, providerProps) => {
|
||||||
const MonthSelectComponent = () => (
|
const MonthSelectComponent = () => (
|
||||||
<MonthSelect {...props} />
|
<MonthSelect {...props} />
|
||||||
);
|
);
|
||||||
const MonthSelectWithProvider = withProvider(CalendarWidgetProvider)(MonthSelectComponent);
|
|
||||||
|
const Provider = (params) => (
|
||||||
|
<CalendarWidgetProvider {...params} {...providerProps} />
|
||||||
|
);
|
||||||
|
const MonthSelectWithProvider = withProvider(Provider)(MonthSelectComponent);
|
||||||
|
|
||||||
render(<MonthSelectWithProvider />);
|
render(<MonthSelectWithProvider />);
|
||||||
};
|
};
|
||||||
@ -40,13 +44,13 @@ describe('Test MonthSelect', () => {
|
|||||||
test('onChange handler', async () => {
|
test('onChange handler', async () => {
|
||||||
const onChange = jest.fn();
|
const onChange = jest.fn();
|
||||||
|
|
||||||
setup({ onChange });
|
setup({ onChange }, { value: new Date(2020, 9, 15) });
|
||||||
|
|
||||||
const monthSelectElem = screen.getByTestId('month-select');
|
const monthSelectElem = screen.getByTestId('month-select');
|
||||||
await user.selectOptions(monthSelectElem, String(MONTHS.JULY));
|
await user.selectOptions(monthSelectElem, String(MONTHS.JULY));
|
||||||
|
|
||||||
expect(onChange).toHaveBeenCalled();
|
expect(onChange).toHaveBeenCalled();
|
||||||
const newDate = new Date(2024, 6);
|
const newDate = new Date(2020, 6);
|
||||||
expect(onChange).toHaveBeenCalledWith(newDate);
|
expect(onChange).toHaveBeenCalledWith(newDate);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -7,18 +7,25 @@ import { CalendarWidgetProvider } from '../../../CalendarWidgetContext';
|
|||||||
|
|
||||||
import NextMonthButton from './NextMonthButton.ui';
|
import NextMonthButton from './NextMonthButton.ui';
|
||||||
|
|
||||||
|
import type { NextMonthButtonProps } from './NextMonthButton.ui';
|
||||||
|
import type { CalendarWidgetProviderProps } from '../../../CalendarWidgetContext';
|
||||||
|
import type { UserEvent } from '@testing-library/user-event';
|
||||||
|
|
||||||
describe('Test NextMonthButton', () => {
|
describe('Test NextMonthButton', () => {
|
||||||
let user;
|
let user: UserEvent;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
user = userEvent.setup();
|
user = userEvent.setup();
|
||||||
});
|
});
|
||||||
|
|
||||||
const setup = (props) => {
|
const setup = (props?: NextMonthButtonProps, providerProps?: CalendarWidgetProviderProps) => {
|
||||||
const NextMonthButtonComponent = () => (
|
const NextMonthButtonComponent = () => (
|
||||||
<NextMonthButton {...props} />
|
<NextMonthButton {...props} />
|
||||||
);
|
);
|
||||||
const NextMonthButtonWithProvider = withProvider(CalendarWidgetProvider)(NextMonthButtonComponent);
|
const Provider = (params: CalendarWidgetProviderProps) => (
|
||||||
|
<CalendarWidgetProvider {...providerProps} {...params} />
|
||||||
|
);
|
||||||
|
const NextMonthButtonWithProvider = withProvider(Provider)(NextMonthButtonComponent);
|
||||||
|
|
||||||
render(<NextMonthButtonWithProvider />);
|
render(<NextMonthButtonWithProvider />);
|
||||||
};
|
};
|
||||||
@ -33,11 +40,12 @@ describe('Test NextMonthButton', () => {
|
|||||||
|
|
||||||
test('onClick handler', async () => {
|
test('onClick handler', async () => {
|
||||||
const onClick = jest.fn();
|
const onClick = jest.fn();
|
||||||
setup({ onClick });
|
setup({ onClick }, { value: new Date(2020, 9, 15) });
|
||||||
|
|
||||||
const nextMontButtonElem = screen.getByTestId('next-month-button');
|
const nextMontButtonElem = screen.getByTestId('next-month-button');
|
||||||
await user.click(nextMontButtonElem);
|
await user.click(nextMontButtonElem);
|
||||||
|
|
||||||
expect(onClick).toHaveBeenCalled();
|
expect(onClick).toHaveBeenCalled();
|
||||||
|
expect(onClick).toHaveBeenCalledWith(new Date(2020, 10, 1));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -1,9 +1,15 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
|
|
||||||
import { CalendarWidgetContext } from '../../../CalendarWidgetContext';
|
import { CalendarWidgetContext } from '../../../CalendarWidgetContext';
|
||||||
|
|
||||||
const NextMonthButton = (props) => {
|
import type { ReactNode, FC } from 'react';
|
||||||
|
|
||||||
|
export type NextMonthButtonProps = {
|
||||||
|
children?: ReactNode;
|
||||||
|
onClick?: (newDate: Date) => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
};
|
||||||
|
const NextMonthButton: FC<NextMonthButtonProps> = (props) => {
|
||||||
const {
|
const {
|
||||||
children = 'next',
|
children = 'next',
|
||||||
disabled,
|
disabled,
|
||||||
@ -27,7 +33,7 @@ const NextMonthButton = (props) => {
|
|||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
data-testid="next-month-button"
|
data-testid="next-month-button"
|
||||||
disabled={disabled || maxDate < nextDate}
|
disabled={disabled ?? maxDate < nextDate}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onClickHandler}
|
onClick={onClickHandler}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
@ -37,10 +43,4 @@ const NextMonthButton = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
NextMonthButton.propTypes = {
|
|
||||||
children: PropTypes.node,
|
|
||||||
onClick: PropTypes.func,
|
|
||||||
disabled: PropTypes.bool,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default NextMonthButton;
|
export default NextMonthButton;
|
||||||
@ -3,22 +3,28 @@ import { userEvent } from '@testing-library/user-event';
|
|||||||
|
|
||||||
import { withProvider } from 'shared/hoc/withProvider';
|
import { withProvider } from 'shared/hoc/withProvider';
|
||||||
|
|
||||||
import { CalendarWidgetProvider } from '../../../CalendarWidgetContext';
|
import { CalendarWidgetProvider, type CalendarWidgetProviderProps } from '../../../CalendarWidgetContext';
|
||||||
|
|
||||||
import PrevMonthButton from './PrevMonthButton.ui';
|
import PrevMonthButton from './PrevMonthButton.ui';
|
||||||
|
|
||||||
|
import type { PrevMonthButtonProps } from './PrevMonthButton.ui';
|
||||||
|
import type { UserEvent } from '@testing-library/user-event';
|
||||||
|
|
||||||
describe('Test NextMonthButton', () => {
|
describe('Test NextMonthButton', () => {
|
||||||
let user;
|
let user: UserEvent;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
user = userEvent.setup();
|
user = userEvent.setup();
|
||||||
});
|
});
|
||||||
|
|
||||||
const setup = (props) => {
|
const setup = (props?: PrevMonthButtonProps, providerProps?: CalendarWidgetProviderProps) => {
|
||||||
const PrevMonthButtonComponent = () => (
|
const PrevMonthButtonComponent = () => (
|
||||||
<PrevMonthButton {...props} />
|
<PrevMonthButton {...props} />
|
||||||
);
|
);
|
||||||
const PrevMonthButtonWithProvider = withProvider(CalendarWidgetProvider)(PrevMonthButtonComponent);
|
const Provider = (params: CalendarWidgetProviderProps) => (
|
||||||
|
<CalendarWidgetProvider {...providerProps} {...params} />
|
||||||
|
);
|
||||||
|
const PrevMonthButtonWithProvider = withProvider(Provider)(PrevMonthButtonComponent);
|
||||||
|
|
||||||
render(<PrevMonthButtonWithProvider />);
|
render(<PrevMonthButtonWithProvider />);
|
||||||
};
|
};
|
||||||
@ -33,11 +39,12 @@ describe('Test NextMonthButton', () => {
|
|||||||
|
|
||||||
test('onClick handler', async () => {
|
test('onClick handler', async () => {
|
||||||
const onClick = jest.fn();
|
const onClick = jest.fn();
|
||||||
setup({ onClick });
|
setup({ onClick }, { value: new Date(2020, 9, 15) });
|
||||||
|
|
||||||
const prevMontButtonElem = screen.getByTestId('prev-month-button');
|
const prevMontButtonElem = screen.getByTestId('prev-month-button');
|
||||||
await user.click(prevMontButtonElem);
|
await user.click(prevMontButtonElem);
|
||||||
|
|
||||||
expect(onClick).toHaveBeenCalled();
|
expect(onClick).toHaveBeenCalled();
|
||||||
|
expect(onClick).toHaveBeenCalledWith(new Date(2020, 9, 0));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -1,9 +1,15 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
|
|
||||||
import { CalendarWidgetContext } from '../../../CalendarWidgetContext';
|
import { CalendarWidgetContext } from '../../../CalendarWidgetContext';
|
||||||
|
|
||||||
const PrevMonthButton = (props) => {
|
import type { FC, ReactNode } from 'react';
|
||||||
|
|
||||||
|
export type PrevMonthButtonProps = {
|
||||||
|
children?: ReactNode;
|
||||||
|
onClick?: (newDate: Date) => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
};
|
||||||
|
const PrevMonthButton: FC<PrevMonthButtonProps> = (props) => {
|
||||||
const {
|
const {
|
||||||
children = 'prev',
|
children = 'prev',
|
||||||
onClick,
|
onClick,
|
||||||
@ -27,7 +33,7 @@ const PrevMonthButton = (props) => {
|
|||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
data-testid="prev-month-button"
|
data-testid="prev-month-button"
|
||||||
disabled={disabled || prevDate < minDate}
|
disabled={disabled ?? prevDate < minDate}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onClickHandler}
|
onClick={onClickHandler}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
@ -37,10 +43,4 @@ const PrevMonthButton = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
PrevMonthButton.propTypes = {
|
|
||||||
children: PropTypes.node,
|
|
||||||
onClick: PropTypes.func,
|
|
||||||
disabled: PropTypes.bool,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default PrevMonthButton;
|
export default PrevMonthButton;
|
||||||
@ -7,14 +7,17 @@ import { CalendarWidgetProvider } from '../../../CalendarWidgetContext';
|
|||||||
|
|
||||||
import TodayButton from './TodayButton.ui';
|
import TodayButton from './TodayButton.ui';
|
||||||
|
|
||||||
|
import type { TodayButtonProps } from './TodayButton.ui';
|
||||||
|
import type { UserEvent } from '@testing-library/user-event';
|
||||||
|
|
||||||
describe('Test NextMonthButton', () => {
|
describe('Test NextMonthButton', () => {
|
||||||
let user;
|
let user: UserEvent;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
user = userEvent.setup();
|
user = userEvent.setup();
|
||||||
});
|
});
|
||||||
|
|
||||||
const setup = (props) => {
|
const setup = (props?: TodayButtonProps) => {
|
||||||
const TodayButtonComponent = () => (
|
const TodayButtonComponent = () => (
|
||||||
<TodayButton {...props} />
|
<TodayButton {...props} />
|
||||||
);
|
);
|
||||||
@ -40,7 +43,8 @@ describe('Test NextMonthButton', () => {
|
|||||||
|
|
||||||
expect(onClick).toHaveBeenCalled();
|
expect(onClick).toHaveBeenCalled();
|
||||||
|
|
||||||
const onClickArgument = onClick.mock.calls[0][0];
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||||
|
const onClickArgument = onClick.mock.calls[0][0] as number;
|
||||||
const calledDate = new Date(onClickArgument);
|
const calledDate = new Date(onClickArgument);
|
||||||
const calledYear = calledDate.getFullYear();
|
const calledYear = calledDate.getFullYear();
|
||||||
const calledMonthIndex = calledDate.getMonth();
|
const calledMonthIndex = calledDate.getMonth();
|
||||||
@ -1,9 +1,14 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
|
|
||||||
import { CalendarWidgetContext } from '../../../CalendarWidgetContext';
|
import { CalendarWidgetContext } from '../../../CalendarWidgetContext';
|
||||||
|
|
||||||
const TodayButton = (props) => {
|
import type { FC, ReactNode } from 'react';
|
||||||
|
|
||||||
|
export type TodayButtonProps = {
|
||||||
|
children?: ReactNode;
|
||||||
|
onClick?: (newDate: Date) => void;
|
||||||
|
};
|
||||||
|
const TodayButton: FC<TodayButtonProps> = (props) => {
|
||||||
const {
|
const {
|
||||||
children = 'today',
|
children = 'today',
|
||||||
onClick,
|
onClick,
|
||||||
@ -30,9 +35,4 @@ const TodayButton = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
TodayButton.propTypes = {
|
|
||||||
children: PropTypes.node,
|
|
||||||
onClick: PropTypes.func,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default TodayButton;
|
export default TodayButton;
|
||||||
@ -7,14 +7,17 @@ import { CalendarWidgetProvider } from '../../../CalendarWidgetContext';
|
|||||||
|
|
||||||
import YearSelect from './YearSelect.ui';
|
import YearSelect from './YearSelect.ui';
|
||||||
|
|
||||||
|
import type { YearSelectProps } from './YearSelect.ui';
|
||||||
|
import type { UserEvent } from '@testing-library/user-event';
|
||||||
|
|
||||||
describe('Test YearSelect', () => {
|
describe('Test YearSelect', () => {
|
||||||
let user;
|
let user: UserEvent;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
user = userEvent.setup();
|
user = userEvent.setup();
|
||||||
});
|
});
|
||||||
|
|
||||||
const setup = (props) => {
|
const setup = (props?: YearSelectProps) => {
|
||||||
const YearSelectComponent = () => (
|
const YearSelectComponent = () => (
|
||||||
<YearSelect {...props} />
|
<YearSelect {...props} />
|
||||||
);
|
);
|
||||||
@ -1,20 +1,25 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
|
|
||||||
import { CalendarWidgetContext } from '../../../CalendarWidgetContext';
|
import { CalendarWidgetContext } from '../../../CalendarWidgetContext';
|
||||||
|
|
||||||
const YearSelect = (props) => {
|
import type { FC, ChangeEventHandler } from 'react';
|
||||||
|
|
||||||
|
export type YearSelectProps = {
|
||||||
|
onChange?: (newDate: Date) => void;
|
||||||
|
};
|
||||||
|
const YearSelect: FC<YearSelectProps> = (props) => {
|
||||||
const {
|
const {
|
||||||
onChange,
|
onChange,
|
||||||
...restProps
|
...restProps
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
// todo eslint fix
|
// todo eslint fix
|
||||||
const {
|
const {
|
||||||
targetYear, targetMonthIndex, setTargetDate, minDate, maxDate,
|
targetYear, targetMonthIndex, setTargetDate, minDate, maxDate,
|
||||||
} = useContext(CalendarWidgetContext);
|
} = useContext(CalendarWidgetContext);
|
||||||
|
|
||||||
const onChangeHandler = (event) => {
|
const onChangeHandler: ChangeEventHandler<HTMLSelectElement> = (event) => {
|
||||||
let newDate = new Date(event.target.value, targetMonthIndex);
|
let newDate = new Date(Number(event.target.value), targetMonthIndex);
|
||||||
|
|
||||||
if (newDate < minDate) {
|
if (newDate < minDate) {
|
||||||
newDate = minDate;
|
newDate = minDate;
|
||||||
@ -54,8 +59,6 @@ const YearSelect = (props) => {
|
|||||||
return (
|
return (
|
||||||
<select
|
<select
|
||||||
data-testid="year-select"
|
data-testid="year-select"
|
||||||
id=""
|
|
||||||
name="year"
|
|
||||||
value={targetYear}
|
value={targetYear}
|
||||||
onChange={onChangeHandler}
|
onChange={onChangeHandler}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
@ -65,8 +68,4 @@ const YearSelect = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
YearSelect.propTypes = {
|
|
||||||
onChange: PropTypes.func,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default YearSelect;
|
export default YearSelect;
|
||||||
Loading…
x
Reference in New Issue
Block a user