Skip to content

Commit

Permalink
fix: min/max date behaviour with month buttons (#55)
Browse files Browse the repository at this point in the history
Co-authored-by: F <[email protected]>
  • Loading branch information
Feshchenko and F authored Mar 20, 2024
1 parent d47a0ea commit a8081d0
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 15 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "datepicker",
"version": "6.6.0",
"version": "6.6.1",
"description": "The ultimate tool to create a date, range and time picker in your React applications.",
"scripts": {
"clean": "rimraf node_modules",
Expand Down
28 changes: 28 additions & 0 deletions packages/datepicker/src/__test__/predicates.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
isBeforeMinYear,
isBetween,
isSame,
isSameOrAfterMaxYear,
isSameOrBeforeMinYear,
maxDateAndAfter,
minDateAndBefore,
} from '../utils/predicates';
Expand Down Expand Up @@ -169,3 +171,29 @@ describe('isAfterMaxYear', () => {
expect(isAfterMaxYear(2024, maxYear)).toBe(true);
});
});

describe('isSameOrAfterMaxYear', () => {
test('should return false if maxDate is not exist', () => {
expect(isSameOrAfterMaxYear(2022)).toBe(false);
});

test('should return true if year >= maxDate year', () => {
const maxYear = newDate(2024, 1, 1);
expect(isSameOrAfterMaxYear(2023, maxYear)).toBe(false);
expect(isSameOrAfterMaxYear(2024, maxYear)).toBe(true);
expect(isSameOrAfterMaxYear(2025, maxYear)).toBe(true);
});
});

describe('isSameOrBeforeMinYear', () => {
test('should return false if minYear is not exist', () => {
expect(isSameOrBeforeMinYear(2024)).toBe(false);
});

test('should return true if year < minYear', () => {
const minYear = newDate(2024, 1, 1);
expect(isSameOrBeforeMinYear(2023, minYear)).toBe(true);
expect(isSameOrBeforeMinYear(2024, minYear)).toBe(true);
expect(isSameOrBeforeMinYear(2025, minYear)).toBe(false);
});
});
10 changes: 4 additions & 6 deletions packages/datepicker/src/utils/create-months.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import type { DPDatesConfig, DPLocaleConfig, DPMonth } from '../types';
import { formatMonthName, getDateParts, newDate } from './date';
import {
isAfterMaxMonth,
isAfterMaxYear,
isBeforeMinMonth,
isBeforeMinYear,
isSameOrAfterMaxYear,
isSameOrBeforeMinYear,
} from './predicates';

export var createMonths = (
Expand Down Expand Up @@ -32,10 +32,8 @@ export var createMonths = (
active: M === i,
now: i === nM && Y === nY,
disabled:
isBeforeMinMonth(i, minDate) ||
isBeforeMinYear(Y, minDate) ||
isAfterMaxMonth(i, maxDate) ||
isAfterMaxYear(Y, maxDate),
(isBeforeMinMonth(i, minDate) && isSameOrBeforeMinYear(Y, minDate)) ||
(isAfterMaxMonth(i, maxDate) && isSameOrAfterMaxYear(Y, maxDate)),
};
});
};
6 changes: 6 additions & 0 deletions packages/datepicker/src/utils/predicates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,9 @@ export const isAfterMaxMonth = (month: number, maxDate?: Date): boolean =>

export const isAfterMaxYear = (year: number, maxDate?: Date): boolean =>
!!maxDate && year > getDateParts(maxDate).Y;

export const isSameOrAfterMaxYear = (year: number, maxDate?: Date): boolean =>
!!maxDate && year >= getDateParts(maxDate).Y;

export const isSameOrBeforeMinYear = (year: number, minDate?: Date): boolean =>
!!minDate && year <= getDateParts(minDate).Y;
10 changes: 7 additions & 3 deletions packages/examples-e2e/test/basic.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { expect, test } from '@playwright/test';

test('test basic month navigation', async ({ page }) => {
test('basic month navigation', async ({ page }) => {
await page.goto('/');

const previousMonthButton = page.getByTestId('previous-month-button');
const nextMonthButton = page.getByTestId('next-month-button');
const previousMonthButton = page.getByRole('button', {
name: /previous month button/i,
});
const nextMonthButton = page.getByRole('button', {
name: /next month button/i,
});

await expect(nextMonthButton).toBeDisabled();
await expect(previousMonthButton).toBeEnabled();
Expand Down
34 changes: 34 additions & 0 deletions packages/examples-e2e/test/min-max-date.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { expect, test } from '@playwright/test';

test('month and years availability with min and max date', async ({ page }) => {
await page.goto('/');

const NOW = new Date();
const Y = NOW.getFullYear();
const M = NOW.getMonth();
const currentMonthName = NOW.toLocaleDateString('en-us', { month: 'long' });

const nextMonth = new Date(Y, M + 1, 1);
const nextMonthName = nextMonth.toLocaleDateString('en-us', {
month: 'long',
});

// Previous year should be enabled since we are defining minDate as new Date(Y - 1, 0, 1)
await expect(page.getByRole('button', { name: `${Y - 1}` })).toBeEnabled();

// Next year is disabled since we are defining maxDate as new Date()
await expect(page.getByRole('button', { name: `${Y + 1}` })).toBeDisabled();

// Current month should be enabled
await expect(
page.getByRole('button', { name: currentMonthName }),
).toBeEnabled();

// Next month should be disabled since we are defining maxDate as new Date()
await expect(
page.getByRole('button', { name: nextMonthName }),
).toBeDisabled();

await page.getByRole('button', { name: `${Y - 1}` }).click();
await expect(page.getByRole('button', { name: /january/i })).toBeEnabled();
});
12 changes: 7 additions & 5 deletions packages/examples/src/pages/home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ export const HomePage = () => {
prefersDark.addEventListener('change', (mQ) => toggleDarkTheme(mQ.matches));
}, []);

const NOW = new Date();

const [selectedDates, onDatesChange] = useState<Date[]>([]);
const {
data: { calendars, weekDays, months, years },
Expand All @@ -59,8 +61,8 @@ export const HomePage = () => {
mode: 'range',
// toggle: true,
// selectSameDate: true,
minDate: new Date(2000, 0, 1),
maxDate: new Date(),
minDate: new Date(NOW.getFullYear() - 1, 0, 1),
maxDate: NOW,
},
calendar: {
offsets: [-1, 1],
Expand All @@ -74,7 +76,7 @@ export const HomePage = () => {
leftButton={
<HeaderButton
{...subtractOffset({ months: 1 })}
data-testid="previous-month-button"
aria-label="previous month button"
>
<ChevronLeft />
</HeaderButton>
Expand All @@ -100,7 +102,7 @@ export const HomePage = () => {
<Calendar>
<CalendarHeader>
<div />
<CalendarHeaderTitle data-testid="main-calendar-title">
<CalendarHeaderTitle aria-label="current month and year">
{calendars[0].month} {calendars[0].year}
</CalendarHeaderTitle>
</CalendarHeader>
Expand All @@ -122,7 +124,7 @@ export const HomePage = () => {
rightButton={
<HeaderButton
{...addOffset({ months: 1 })}
data-testid="next-month-button"
aria-label="next month button"
>
<ChevronRight />
</HeaderButton>
Expand Down

0 comments on commit a8081d0

Please sign in to comment.