Skip to content

Commit 83e5583

Browse files
authored
Fix/datepicker decade picker unclickable (#1452)
1 parent 3217f88 commit 83e5583

File tree

5 files changed

+120
-11
lines changed

5 files changed

+120
-11
lines changed

packages/ui/src/components/Datepicker/Datepicker.spec.tsx

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,114 @@ describe("Components / Datepicker", () => {
7878
await userEvent.click(document.body);
7979
});
8080

81+
it("should render 1990 - 2100 year range when selecting decade", async () => {
82+
const testDate = new Date(2024, 6, 20);
83+
render(<Datepicker value={testDate.getTime()} />);
84+
85+
const textBox = screen.getByRole("textbox");
86+
await userEvent.click(textBox);
87+
88+
const titleButton = screen.getByText("July 2024");
89+
await userEvent.click(titleButton);
90+
expect(titleButton.textContent).toBe("2024");
91+
await userEvent.click(titleButton);
92+
expect(titleButton.textContent).toBe("2020 - 2031");
93+
await userEvent.click(titleButton);
94+
expect(titleButton.textContent).toBe("1990 - 2100");
95+
});
96+
97+
it("should allow selecting earlier decades when setting max date", async () => {
98+
const testDate = new Date(2024, 6, 20);
99+
render(<Datepicker value={testDate.getTime()} maxDate={testDate} />);
100+
101+
const textBox = screen.getByRole("textbox");
102+
await userEvent.click(textBox);
103+
104+
const titleButton = screen.getByText("July 2024");
105+
await userEvent.click(titleButton);
106+
await userEvent.click(titleButton);
107+
await userEvent.click(titleButton);
108+
109+
const earlierDecadeButton = screen.getByText("2010");
110+
expect(earlierDecadeButton).instanceOf(HTMLButtonElement);
111+
expect(earlierDecadeButton).toBeEnabled();
112+
});
113+
114+
it("should disallow selecting later decades when setting max date", async () => {
115+
const testDate = new Date(2024, 6, 20);
116+
render(<Datepicker value={testDate.getTime()} maxDate={testDate} />);
117+
118+
const textBox = screen.getByRole("textbox");
119+
await userEvent.click(textBox);
120+
121+
const titleButton = screen.getByText("July 2024");
122+
await userEvent.click(titleButton);
123+
await userEvent.click(titleButton);
124+
await userEvent.click(titleButton);
125+
126+
const laterDecadeButton = screen.getByText("2030");
127+
expect(laterDecadeButton).instanceOf(HTMLButtonElement);
128+
expect(laterDecadeButton).toBeDisabled();
129+
});
130+
131+
it("should disallow selecting earlier decades when setting min date", async () => {
132+
const testDate = new Date(2024, 6, 20);
133+
render(<Datepicker value={testDate.getTime()} minDate={testDate} />);
134+
135+
const textBox = screen.getByRole("textbox");
136+
await userEvent.click(textBox);
137+
138+
const titleButton = screen.getByText("July 2024");
139+
await userEvent.click(titleButton);
140+
await userEvent.click(titleButton);
141+
await userEvent.click(titleButton);
142+
143+
const earlierDecadeButton = screen.getByText("2010");
144+
expect(earlierDecadeButton).instanceOf(HTMLButtonElement);
145+
expect(earlierDecadeButton).toBeDisabled();
146+
});
147+
148+
it("should allow selecting later decades when setting min date", async () => {
149+
const testDate = new Date(2024, 6, 20);
150+
render(<Datepicker value={testDate.getTime()} minDate={testDate} />);
151+
152+
const textBox = screen.getByRole("textbox");
153+
await userEvent.click(textBox);
154+
155+
const titleButton = screen.getByText("July 2024");
156+
await userEvent.click(titleButton);
157+
await userEvent.click(titleButton);
158+
await userEvent.click(titleButton);
159+
160+
const laterDecadeButton = screen.getByText("2030");
161+
expect(laterDecadeButton).instanceOf(HTMLButtonElement);
162+
expect(laterDecadeButton).toBeEnabled();
163+
});
164+
165+
it("should allow selecting decades within the range set by max date and min date and disallow selecting outside the range", async () => {
166+
const minDate = new Date(2010, 1, 1);
167+
const maxDate = new Date(2030, 1, 1);
168+
const testDate = new Date(2024, 6, 1);
169+
170+
render(<Datepicker value={testDate.getTime()} minDate={minDate} maxDate={maxDate} />);
171+
172+
const textBox = screen.getByRole("textbox");
173+
await userEvent.click(textBox);
174+
175+
const titleButton = screen.getByText("July 2024");
176+
await userEvent.click(titleButton);
177+
await userEvent.click(titleButton);
178+
await userEvent.click(titleButton);
179+
180+
const inRange = screen.getByText("2010");
181+
expect(inRange).instanceOf(HTMLButtonElement);
182+
expect(inRange).toBeEnabled();
183+
184+
const outsideRange = screen.getByText("2000");
185+
expect(outsideRange).instanceOf(HTMLButtonElement);
186+
expect(outsideRange).toBeDisabled();
187+
});
188+
81189
it("should focus the input when ref.current.focus is called", () => {
82190
const {
83191
result: { current: ref },

packages/ui/src/components/Datepicker/Datepicker.stories.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ const Template: StoryFn<DatepickerProps> = (args) => {
4040
// update defaultDate based on the range
4141
if (args.minDate && args.maxDate) {
4242
if (args.defaultDate) {
43-
args.defaultDate = getFirstDateInRange(args.defaultDate, args.minDate, args.maxDate);
43+
// https://github.com/storybookjs/storybook/issues/11822
44+
args.defaultDate = getFirstDateInRange(new Date(args.defaultDate), args.minDate, args.maxDate);
4445
}
4546
}
4647

packages/ui/src/components/Datepicker/Datepicker.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,9 +197,9 @@ const DatepickerRender: ForwardRefRenderFunction<DatepickerRef, DatepickerProps>
197197
const getViewTitle = (): string => {
198198
switch (view) {
199199
case Views.Decades:
200-
return `${startOfYearPeriod(viewDate, 100)} - ${startOfYearPeriod(viewDate, 100) + 90}`;
200+
return `${startOfYearPeriod(viewDate, 100) - 10} - ${startOfYearPeriod(viewDate, 100) + 100}`;
201201
case Views.Years:
202-
return `${startOfYearPeriod(viewDate, 10)} - ${startOfYearPeriod(viewDate, 10) + 9}`;
202+
return `${startOfYearPeriod(viewDate, 10)} - ${startOfYearPeriod(viewDate, 10) + 11}`;
203203
case Views.Months:
204204
return getFormattedDate(language, viewDate, { year: "numeric" });
205205
case Views.Days:

packages/ui/src/components/Datepicker/Views/Decades.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,21 @@ export interface DatepickerViewsDecadesProps {
2020
}
2121

2222
export const DatepickerViewsDecades: FC<DatepickerViewsDecadesProps> = ({ theme: customTheme = {} }) => {
23-
const { theme: rootTheme, selectedDate, viewDate, setViewDate, setView } = useDatePickerContext();
23+
const { theme: rootTheme, viewDate, selectedDate, minDate, maxDate, setViewDate, setView } = useDatePickerContext();
2424

2525
const theme = mergeDeep(rootTheme.views.decades, customTheme);
26-
26+
const first = startOfYearPeriod(viewDate, 100);
2727
return (
2828
<div className={theme.items.base}>
2929
{[...Array(12)].map((_year, index) => {
30-
const first = startOfYearPeriod(viewDate, 100);
3130
const year = first - 10 + index * 10;
31+
const newDate = new Date(viewDate.getTime());
32+
newDate.setFullYear(year + (viewDate.getFullYear() % 10));
3233
const firstDate = new Date(year, 0, 1);
3334
const lastDate = addYears(firstDate, 9);
3435

35-
const isSelected = isDateInDecade(viewDate, year);
36-
const isDisabled = !isDateInRange(viewDate, firstDate, lastDate);
36+
const isSelected = isDateInDecade(selectedDate, year);
37+
const isDisabled = !isDateInRange(firstDate, minDate, maxDate) && !isDateInRange(lastDate, minDate, maxDate);
3738

3839
return (
3940
<button
@@ -47,8 +48,7 @@ export const DatepickerViewsDecades: FC<DatepickerViewsDecadesProps> = ({ theme:
4748
)}
4849
onClick={() => {
4950
if (isDisabled) return;
50-
51-
setViewDate(addYears(viewDate, year - selectedDate.getFullYear()));
51+
setViewDate(newDate);
5252
setView(Views.Years);
5353
}}
5454
>

packages/ui/src/components/Datepicker/Views/Years.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export const DatepickerViewsYears: FC<DatepickerViewsYearsProps> = ({ theme: cus
3030
<div className={theme.items.base}>
3131
{[...Array(12)].map((_year, index) => {
3232
const first = startOfYearPeriod(viewDate, 10);
33-
const year = first - 1 + index * 1;
33+
const year = first + index;
3434
const newDate = new Date(viewDate.getTime());
3535
newDate.setFullYear(year);
3636

0 commit comments

Comments
 (0)