Release 0.0.2 #17
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"
|
||||
maxDate={new Date(2027, 2, 15)}
|
||||
minDate={new Date(1996, 9, 15)}
|
||||
value={new Date(2023, 9, 15)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -13,6 +13,9 @@ export const MONTHS = {
|
||||
DECEMBER: 11,
|
||||
};
|
||||
|
||||
export type MonthsKeys = keyof typeof MONTHS;
|
||||
export type MonthsValues = typeof MONTHS[MonthsKeys];
|
||||
|
||||
export const DAYS_IN_WEEK = 7;
|
||||
|
||||
export const WEEK_DAYS = {
|
||||
@ -24,3 +27,6 @@ export const WEEK_DAYS = {
|
||||
FRIDAY: 5,
|
||||
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 { 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]: {
|
||||
ru: 'Январь',
|
||||
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]: {
|
||||
ru: {
|
||||
full: 'Воскресенье',
|
||||
@ -2,13 +2,19 @@ import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import PropTypes from 'prop-types';
|
||||
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', () => {
|
||||
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 [testState, setTestState] = useState(100);
|
||||
@ -74,7 +80,7 @@ describe('Test withProvider', () => {
|
||||
renderCounter();
|
||||
|
||||
const counterElem = screen.getByTestId('counter');
|
||||
expect(counterElem).toHaveTextContent(100);
|
||||
expect(counterElem).toHaveTextContent('100');
|
||||
});
|
||||
|
||||
test('change state - increment', () => {
|
||||
@ -84,7 +90,7 @@ describe('Test withProvider', () => {
|
||||
fireEvent.click(plusBtn);
|
||||
|
||||
const counterElem = screen.getByTestId('counter');
|
||||
expect(counterElem).toHaveTextContent(101);
|
||||
expect(counterElem).toHaveTextContent('101');
|
||||
});
|
||||
|
||||
test('change state - decrement', () => {
|
||||
@ -94,6 +100,6 @@ describe('Test withProvider', () => {
|
||||
fireEvent.click(minusBtn);
|
||||
|
||||
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 year = date.getFullYear();
|
||||
|
||||
return new Date(year, monthIndex, 1);
|
||||
};
|
||||
|
||||
export const lastDayOfMonthDate = (date) => {
|
||||
export const lastDayOfMonthDate = (date: Date) => {
|
||||
const monthIndex = date.getMonth();
|
||||
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 { CalendarWidgetProvider } from './CalendarWidgetContext';
|
||||
import { DateWrapper } from './components/DateWrapper';
|
||||
import { DayOfWeekRow } from './components/DayOfWeekRow';
|
||||
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}>
|
||||
<div className={classes.wrapper}>
|
||||
<div className={classes.wrapper} data-testid="calendar-widget">
|
||||
<HeaderRow />
|
||||
|
||||
<DayOfWeekRow />
|
||||
@ -18,10 +24,4 @@ const CalendarWidget = (props) => (
|
||||
</CalendarWidgetProvider>
|
||||
);
|
||||
|
||||
CalendarWidget.propTypes = {
|
||||
maxDate: PropTypes.instanceOf(Date),
|
||||
minDate: PropTypes.instanceOf(Date),
|
||||
value: PropTypes.instanceOf(Date),
|
||||
};
|
||||
|
||||
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';
|
||||
|
||||
describe('Base Render', () => {
|
||||
const setup = (date) => {
|
||||
const setup = (date: Date) => {
|
||||
render(<DateCell date={date} />);
|
||||
};
|
||||
|
||||
@ -16,13 +16,25 @@
|
||||
border-right: 1px solid black;
|
||||
}
|
||||
|
||||
&.today {
|
||||
.today {
|
||||
color: red;
|
||||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&.outMothRange {
|
||||
.outMothRange {
|
||||
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 PropTypes from 'prop-types';
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { CalendarWidgetContext } from '../../../CalendarWidgetContext';
|
||||
|
||||
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 {
|
||||
date,
|
||||
} = props;
|
||||
const format = 'en-En';
|
||||
|
||||
const { targetMonthIndex } = useContext(CalendarWidgetContext);
|
||||
const { targetMonthIndex, value } = useContext(CalendarWidgetContext);
|
||||
|
||||
const todayDate = new Date();
|
||||
const dataDate = new Intl.DateTimeFormat(format).format(date);
|
||||
const dataToday = new Intl.DateTimeFormat(format).format(todayDate);
|
||||
const dataValue = new Intl.DateTimeFormat(format).format(value);
|
||||
const isOutMonthRange = date.getMonth() !== targetMonthIndex;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={dataDate}
|
||||
className={classnames(
|
||||
{
|
||||
[classes.dateCell]: true,
|
||||
[classes.today]: dataDate === dataToday,
|
||||
[classes.outMothRange]: isOutMonthRange,
|
||||
},
|
||||
)}
|
||||
className={classes.dateCell}
|
||||
data-date={dataDate}
|
||||
data-testid="date-cell"
|
||||
>
|
||||
<span
|
||||
className={classnames(
|
||||
{
|
||||
[classes.today as string]: dataDate === dataToday,
|
||||
[classes.outMothRange as string]: isOutMonthRange,
|
||||
[classes.valueDate as string]: dataDate === dataValue,
|
||||
},
|
||||
)}
|
||||
>
|
||||
{date.getDate()}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
DateCell.propTypes = {
|
||||
date: PropTypes.instanceOf(Date).isRequired,
|
||||
};
|
||||
|
||||
export default DateCell;
|
||||
@ -2,8 +2,10 @@ import { render, screen } from '@testing-library/react';
|
||||
|
||||
import DateRow from './DateRow.ui';
|
||||
|
||||
import type { DateRowType } from './DateRow.ui';
|
||||
|
||||
describe('Test Date Row', () => {
|
||||
const setup = (cells) => {
|
||||
const setup = (cells: DateRowType['cells']) => {
|
||||
render(<DateRow cells={cells} />);
|
||||
};
|
||||
|
||||
@ -53,13 +55,13 @@ describe('Test Date Row', () => {
|
||||
setupWeek();
|
||||
|
||||
const dateCellElems = screen.getAllByTestId('date-cell');
|
||||
expect(dateCellElems[0]).toHaveTextContent(15);
|
||||
expect(dateCellElems[1]).toHaveTextContent(16);
|
||||
expect(dateCellElems[2]).toHaveTextContent(17);
|
||||
expect(dateCellElems[3]).toHaveTextContent(18);
|
||||
expect(dateCellElems[4]).toHaveTextContent(19);
|
||||
expect(dateCellElems[5]).toHaveTextContent(20);
|
||||
expect(dateCellElems[6]).toHaveTextContent(21);
|
||||
expect(dateCellElems[0]).toHaveTextContent('15');
|
||||
expect(dateCellElems[1]).toHaveTextContent('16');
|
||||
expect(dateCellElems[2]).toHaveTextContent('17');
|
||||
expect(dateCellElems[3]).toHaveTextContent('18');
|
||||
expect(dateCellElems[4]).toHaveTextContent('19');
|
||||
expect(dateCellElems[5]).toHaveTextContent('20');
|
||||
expect(dateCellElems[6]).toHaveTextContent('21');
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,10 +1,13 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { DateCell } from '../../DateCell';
|
||||
|
||||
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 {
|
||||
cells,
|
||||
} = props;
|
||||
@ -28,8 +31,4 @@ const DateRow = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
DateRow.propTypes = {
|
||||
cells: PropTypes.arrayOf(PropTypes.instanceOf(Date)),
|
||||
};
|
||||
|
||||
export default DateRow;
|
||||
@ -7,14 +7,17 @@ import { CalendarWidgetProvider } from '../../../CalendarWidgetContext';
|
||||
|
||||
import DayOfWeekCell from './DayOfWeekCell.ui';
|
||||
|
||||
import type { DayOfWeekCellProps } from './DayOfWeekCell.ui';
|
||||
import type { CalendarWidgetProviderProps } from '../../../CalendarWidgetContext';
|
||||
|
||||
describe('Test DayOfWeekCell', () => {
|
||||
const setup = (day, locale) => {
|
||||
const setup = (day: DayOfWeekCellProps['day'], locale: CalendarWidgetProviderProps['locale']) => {
|
||||
const DayOfWeekCellComponent = () => (
|
||||
<DayOfWeekCell day={day} />
|
||||
);
|
||||
|
||||
const Provider = (props) => (
|
||||
<CalendarWidgetProvider {...props} locale={locale} />
|
||||
const Provider = (props: CalendarWidgetProviderProps) => (
|
||||
<CalendarWidgetProvider {...props} locale={locale ?? 'ru'} />
|
||||
);
|
||||
|
||||
const DayOfWeekCellWithProvider = withProvider(Provider)(DayOfWeekCellComponent);
|
||||
@ -1,16 +1,21 @@
|
||||
import PropTypes from 'prop-types';
|
||||
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 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 { locale } = useContext(CalendarWidgetContext);
|
||||
const content = WEEK_DAYS_LABEL[day][locale]?.short;
|
||||
const content = WEEK_DAYS_LABEL[day]?.[locale].short;
|
||||
|
||||
return (
|
||||
<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;
|
||||
@ -15,11 +15,15 @@ describe('Test MonthSelect', () => {
|
||||
user = userEvent.setup();
|
||||
});
|
||||
|
||||
const setup = (props) => {
|
||||
const setup = (props, providerProps) => {
|
||||
const MonthSelectComponent = () => (
|
||||
<MonthSelect {...props} />
|
||||
);
|
||||
const MonthSelectWithProvider = withProvider(CalendarWidgetProvider)(MonthSelectComponent);
|
||||
|
||||
const Provider = (params) => (
|
||||
<CalendarWidgetProvider {...params} {...providerProps} />
|
||||
);
|
||||
const MonthSelectWithProvider = withProvider(Provider)(MonthSelectComponent);
|
||||
|
||||
render(<MonthSelectWithProvider />);
|
||||
};
|
||||
@ -40,13 +44,13 @@ describe('Test MonthSelect', () => {
|
||||
test('onChange handler', async () => {
|
||||
const onChange = jest.fn();
|
||||
|
||||
setup({ onChange });
|
||||
setup({ onChange }, { value: new Date(2020, 9, 15) });
|
||||
|
||||
const monthSelectElem = screen.getByTestId('month-select');
|
||||
await user.selectOptions(monthSelectElem, String(MONTHS.JULY));
|
||||
|
||||
expect(onChange).toHaveBeenCalled();
|
||||
const newDate = new Date(2024, 6);
|
||||
const newDate = new Date(2020, 6);
|
||||
expect(onChange).toHaveBeenCalledWith(newDate);
|
||||
});
|
||||
});
|
||||
|
||||
@ -7,18 +7,25 @@ import { CalendarWidgetProvider } from '../../../CalendarWidgetContext';
|
||||
|
||||
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', () => {
|
||||
let user;
|
||||
let user: UserEvent;
|
||||
|
||||
beforeEach(() => {
|
||||
user = userEvent.setup();
|
||||
});
|
||||
|
||||
const setup = (props) => {
|
||||
const setup = (props?: NextMonthButtonProps, providerProps?: CalendarWidgetProviderProps) => {
|
||||
const NextMonthButtonComponent = () => (
|
||||
<NextMonthButton {...props} />
|
||||
);
|
||||
const NextMonthButtonWithProvider = withProvider(CalendarWidgetProvider)(NextMonthButtonComponent);
|
||||
const Provider = (params: CalendarWidgetProviderProps) => (
|
||||
<CalendarWidgetProvider {...providerProps} {...params} />
|
||||
);
|
||||
const NextMonthButtonWithProvider = withProvider(Provider)(NextMonthButtonComponent);
|
||||
|
||||
render(<NextMonthButtonWithProvider />);
|
||||
};
|
||||
@ -33,11 +40,12 @@ describe('Test NextMonthButton', () => {
|
||||
|
||||
test('onClick handler', async () => {
|
||||
const onClick = jest.fn();
|
||||
setup({ onClick });
|
||||
setup({ onClick }, { value: new Date(2020, 9, 15) });
|
||||
|
||||
const nextMontButtonElem = screen.getByTestId('next-month-button');
|
||||
await user.click(nextMontButtonElem);
|
||||
|
||||
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 { 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 {
|
||||
children = 'next',
|
||||
disabled,
|
||||
@ -27,7 +33,7 @@ const NextMonthButton = (props) => {
|
||||
return (
|
||||
<button
|
||||
data-testid="next-month-button"
|
||||
disabled={disabled || maxDate < nextDate}
|
||||
disabled={disabled ?? maxDate < nextDate}
|
||||
type="button"
|
||||
onClick={onClickHandler}
|
||||
{...restProps}
|
||||
@ -37,10 +43,4 @@ const NextMonthButton = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
NextMonthButton.propTypes = {
|
||||
children: PropTypes.node,
|
||||
onClick: PropTypes.func,
|
||||
disabled: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default NextMonthButton;
|
||||
@ -3,22 +3,28 @@ import { userEvent } from '@testing-library/user-event';
|
||||
|
||||
import { withProvider } from 'shared/hoc/withProvider';
|
||||
|
||||
import { CalendarWidgetProvider } from '../../../CalendarWidgetContext';
|
||||
import { CalendarWidgetProvider, type CalendarWidgetProviderProps } from '../../../CalendarWidgetContext';
|
||||
|
||||
import PrevMonthButton from './PrevMonthButton.ui';
|
||||
|
||||
import type { PrevMonthButtonProps } from './PrevMonthButton.ui';
|
||||
import type { UserEvent } from '@testing-library/user-event';
|
||||
|
||||
describe('Test NextMonthButton', () => {
|
||||
let user;
|
||||
let user: UserEvent;
|
||||
|
||||
beforeEach(() => {
|
||||
user = userEvent.setup();
|
||||
});
|
||||
|
||||
const setup = (props) => {
|
||||
const setup = (props?: PrevMonthButtonProps, providerProps?: CalendarWidgetProviderProps) => {
|
||||
const PrevMonthButtonComponent = () => (
|
||||
<PrevMonthButton {...props} />
|
||||
);
|
||||
const PrevMonthButtonWithProvider = withProvider(CalendarWidgetProvider)(PrevMonthButtonComponent);
|
||||
const Provider = (params: CalendarWidgetProviderProps) => (
|
||||
<CalendarWidgetProvider {...providerProps} {...params} />
|
||||
);
|
||||
const PrevMonthButtonWithProvider = withProvider(Provider)(PrevMonthButtonComponent);
|
||||
|
||||
render(<PrevMonthButtonWithProvider />);
|
||||
};
|
||||
@ -33,11 +39,12 @@ describe('Test NextMonthButton', () => {
|
||||
|
||||
test('onClick handler', async () => {
|
||||
const onClick = jest.fn();
|
||||
setup({ onClick });
|
||||
setup({ onClick }, { value: new Date(2020, 9, 15) });
|
||||
|
||||
const prevMontButtonElem = screen.getByTestId('prev-month-button');
|
||||
await user.click(prevMontButtonElem);
|
||||
|
||||
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 { 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 {
|
||||
children = 'prev',
|
||||
onClick,
|
||||
@ -27,7 +33,7 @@ const PrevMonthButton = (props) => {
|
||||
return (
|
||||
<button
|
||||
data-testid="prev-month-button"
|
||||
disabled={disabled || prevDate < minDate}
|
||||
disabled={disabled ?? prevDate < minDate}
|
||||
type="button"
|
||||
onClick={onClickHandler}
|
||||
{...restProps}
|
||||
@ -37,10 +43,4 @@ const PrevMonthButton = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
PrevMonthButton.propTypes = {
|
||||
children: PropTypes.node,
|
||||
onClick: PropTypes.func,
|
||||
disabled: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default PrevMonthButton;
|
||||
@ -7,14 +7,17 @@ import { CalendarWidgetProvider } from '../../../CalendarWidgetContext';
|
||||
|
||||
import TodayButton from './TodayButton.ui';
|
||||
|
||||
import type { TodayButtonProps } from './TodayButton.ui';
|
||||
import type { UserEvent } from '@testing-library/user-event';
|
||||
|
||||
describe('Test NextMonthButton', () => {
|
||||
let user;
|
||||
let user: UserEvent;
|
||||
|
||||
beforeEach(() => {
|
||||
user = userEvent.setup();
|
||||
});
|
||||
|
||||
const setup = (props) => {
|
||||
const setup = (props?: TodayButtonProps) => {
|
||||
const TodayButtonComponent = () => (
|
||||
<TodayButton {...props} />
|
||||
);
|
||||
@ -40,7 +43,8 @@ describe('Test NextMonthButton', () => {
|
||||
|
||||
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 calledYear = calledDate.getFullYear();
|
||||
const calledMonthIndex = calledDate.getMonth();
|
||||
@ -1,9 +1,14 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useContext } from 'react';
|
||||
|
||||
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 {
|
||||
children = 'today',
|
||||
onClick,
|
||||
@ -30,9 +35,4 @@ const TodayButton = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
TodayButton.propTypes = {
|
||||
children: PropTypes.node,
|
||||
onClick: PropTypes.func,
|
||||
};
|
||||
|
||||
export default TodayButton;
|
||||
@ -7,14 +7,17 @@ import { CalendarWidgetProvider } from '../../../CalendarWidgetContext';
|
||||
|
||||
import YearSelect from './YearSelect.ui';
|
||||
|
||||
import type { YearSelectProps } from './YearSelect.ui';
|
||||
import type { UserEvent } from '@testing-library/user-event';
|
||||
|
||||
describe('Test YearSelect', () => {
|
||||
let user;
|
||||
let user: UserEvent;
|
||||
|
||||
beforeEach(() => {
|
||||
user = userEvent.setup();
|
||||
});
|
||||
|
||||
const setup = (props) => {
|
||||
const setup = (props?: YearSelectProps) => {
|
||||
const YearSelectComponent = () => (
|
||||
<YearSelect {...props} />
|
||||
);
|
||||
@ -1,20 +1,25 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useContext } from 'react';
|
||||
|
||||
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 {
|
||||
onChange,
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
// todo eslint fix
|
||||
const {
|
||||
targetYear, targetMonthIndex, setTargetDate, minDate, maxDate,
|
||||
} = useContext(CalendarWidgetContext);
|
||||
|
||||
const onChangeHandler = (event) => {
|
||||
let newDate = new Date(event.target.value, targetMonthIndex);
|
||||
const onChangeHandler: ChangeEventHandler<HTMLSelectElement> = (event) => {
|
||||
let newDate = new Date(Number(event.target.value), targetMonthIndex);
|
||||
|
||||
if (newDate < minDate) {
|
||||
newDate = minDate;
|
||||
@ -54,8 +59,6 @@ const YearSelect = (props) => {
|
||||
return (
|
||||
<select
|
||||
data-testid="year-select"
|
||||
id=""
|
||||
name="year"
|
||||
value={targetYear}
|
||||
onChange={onChangeHandler}
|
||||
{...restProps}
|
||||
@ -65,8 +68,4 @@ const YearSelect = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
YearSelect.propTypes = {
|
||||
onChange: PropTypes.func,
|
||||
};
|
||||
|
||||
export default YearSelect;
|
||||
Loading…
x
Reference in New Issue
Block a user