diff --git a/packages/ui/src/components/Datepicker/Datepicker.spec.tsx b/packages/ui/src/components/Datepicker/Datepicker.spec.tsx index 7f3b19e0c..81f5814c1 100644 --- a/packages/ui/src/components/Datepicker/Datepicker.spec.tsx +++ b/packages/ui/src/components/Datepicker/Datepicker.spec.tsx @@ -78,6 +78,114 @@ describe("Components / Datepicker", () => { await userEvent.click(document.body); }); + it("should render 1990 - 2100 year range when selecting decade", async () => { + const testDate = new Date(2024, 6, 20); + render(); + + const textBox = screen.getByRole("textbox"); + await userEvent.click(textBox); + + const titleButton = screen.getByText("July 2024"); + await userEvent.click(titleButton); + expect(titleButton.textContent).toBe("2024"); + await userEvent.click(titleButton); + expect(titleButton.textContent).toBe("2020 - 2031"); + await userEvent.click(titleButton); + expect(titleButton.textContent).toBe("1990 - 2100"); + }); + + it("should allow selecting earlier decades when setting max date", async () => { + const testDate = new Date(2024, 6, 20); + render(); + + const textBox = screen.getByRole("textbox"); + await userEvent.click(textBox); + + const titleButton = screen.getByText("July 2024"); + await userEvent.click(titleButton); + await userEvent.click(titleButton); + await userEvent.click(titleButton); + + const earlierDecadeButton = screen.getByText("2010"); + expect(earlierDecadeButton).instanceOf(HTMLButtonElement); + expect(earlierDecadeButton).toBeEnabled(); + }); + + it("should disallow selecting later decades when setting max date", async () => { + const testDate = new Date(2024, 6, 20); + render(); + + const textBox = screen.getByRole("textbox"); + await userEvent.click(textBox); + + const titleButton = screen.getByText("July 2024"); + await userEvent.click(titleButton); + await userEvent.click(titleButton); + await userEvent.click(titleButton); + + const laterDecadeButton = screen.getByText("2030"); + expect(laterDecadeButton).instanceOf(HTMLButtonElement); + expect(laterDecadeButton).toBeDisabled(); + }); + + it("should disallow selecting earlier decades when setting min date", async () => { + const testDate = new Date(2024, 6, 20); + render(); + + const textBox = screen.getByRole("textbox"); + await userEvent.click(textBox); + + const titleButton = screen.getByText("July 2024"); + await userEvent.click(titleButton); + await userEvent.click(titleButton); + await userEvent.click(titleButton); + + const earlierDecadeButton = screen.getByText("2010"); + expect(earlierDecadeButton).instanceOf(HTMLButtonElement); + expect(earlierDecadeButton).toBeDisabled(); + }); + + it("should allow selecting later decades when setting min date", async () => { + const testDate = new Date(2024, 6, 20); + render(); + + const textBox = screen.getByRole("textbox"); + await userEvent.click(textBox); + + const titleButton = screen.getByText("July 2024"); + await userEvent.click(titleButton); + await userEvent.click(titleButton); + await userEvent.click(titleButton); + + const laterDecadeButton = screen.getByText("2030"); + expect(laterDecadeButton).instanceOf(HTMLButtonElement); + expect(laterDecadeButton).toBeEnabled(); + }); + + it("should allow selecting decades within the range set by max date and min date and disallow selecting outside the range", async () => { + const minDate = new Date(2010, 1, 1); + const maxDate = new Date(2030, 1, 1); + const testDate = new Date(2024, 6, 1); + + render(); + + const textBox = screen.getByRole("textbox"); + await userEvent.click(textBox); + + const titleButton = screen.getByText("July 2024"); + await userEvent.click(titleButton); + await userEvent.click(titleButton); + await userEvent.click(titleButton); + + const inRange = screen.getByText("2010"); + expect(inRange).instanceOf(HTMLButtonElement); + expect(inRange).toBeEnabled(); + + const outsideRange = screen.getByText("2000"); + expect(outsideRange).instanceOf(HTMLButtonElement); + expect(outsideRange).toBeDisabled(); + }); + it("should focus the input when ref.current.focus is called", () => { const { result: { current: ref }, diff --git a/packages/ui/src/components/Datepicker/Datepicker.stories.tsx b/packages/ui/src/components/Datepicker/Datepicker.stories.tsx index cb5c052e6..f7cfaaf2d 100644 --- a/packages/ui/src/components/Datepicker/Datepicker.stories.tsx +++ b/packages/ui/src/components/Datepicker/Datepicker.stories.tsx @@ -40,7 +40,8 @@ const Template: StoryFn = (args) => { // update defaultDate based on the range if (args.minDate && args.maxDate) { if (args.defaultDate) { - args.defaultDate = getFirstDateInRange(args.defaultDate, args.minDate, args.maxDate); + // https://github.com/storybookjs/storybook/issues/11822 + args.defaultDate = getFirstDateInRange(new Date(args.defaultDate), args.minDate, args.maxDate); } } diff --git a/packages/ui/src/components/Datepicker/Datepicker.tsx b/packages/ui/src/components/Datepicker/Datepicker.tsx index 5600385f7..87a92557d 100644 --- a/packages/ui/src/components/Datepicker/Datepicker.tsx +++ b/packages/ui/src/components/Datepicker/Datepicker.tsx @@ -197,9 +197,9 @@ const DatepickerRender: ForwardRefRenderFunction const getViewTitle = (): string => { switch (view) { case Views.Decades: - return `${startOfYearPeriod(viewDate, 100)} - ${startOfYearPeriod(viewDate, 100) + 90}`; + return `${startOfYearPeriod(viewDate, 100) - 10} - ${startOfYearPeriod(viewDate, 100) + 100}`; case Views.Years: - return `${startOfYearPeriod(viewDate, 10)} - ${startOfYearPeriod(viewDate, 10) + 9}`; + return `${startOfYearPeriod(viewDate, 10)} - ${startOfYearPeriod(viewDate, 10) + 11}`; case Views.Months: return getFormattedDate(language, viewDate, { year: "numeric" }); case Views.Days: diff --git a/packages/ui/src/components/Datepicker/Views/Decades.tsx b/packages/ui/src/components/Datepicker/Views/Decades.tsx index 350f80c41..82453183e 100644 --- a/packages/ui/src/components/Datepicker/Views/Decades.tsx +++ b/packages/ui/src/components/Datepicker/Views/Decades.tsx @@ -20,20 +20,21 @@ export interface DatepickerViewsDecadesProps { } export const DatepickerViewsDecades: FC = ({ theme: customTheme = {} }) => { - const { theme: rootTheme, selectedDate, viewDate, setViewDate, setView } = useDatePickerContext(); + const { theme: rootTheme, viewDate, selectedDate, minDate, maxDate, setViewDate, setView } = useDatePickerContext(); const theme = mergeDeep(rootTheme.views.decades, customTheme); - + const first = startOfYearPeriod(viewDate, 100); return (
{[...Array(12)].map((_year, index) => { - const first = startOfYearPeriod(viewDate, 100); const year = first - 10 + index * 10; + const newDate = new Date(viewDate.getTime()); + newDate.setFullYear(year + (viewDate.getFullYear() % 10)); const firstDate = new Date(year, 0, 1); const lastDate = addYears(firstDate, 9); - const isSelected = isDateInDecade(viewDate, year); - const isDisabled = !isDateInRange(viewDate, firstDate, lastDate); + const isSelected = isDateInDecade(selectedDate, year); + const isDisabled = !isDateInRange(firstDate, minDate, maxDate) && !isDateInRange(lastDate, minDate, maxDate); return (