diff --git a/apps/web/src/components/day-picker/index.tsx b/apps/web/src/components/day-picker/index.tsx index d9004ccf3..6253a1d3d 100644 --- a/apps/web/src/components/day-picker/index.tsx +++ b/apps/web/src/components/day-picker/index.tsx @@ -16,6 +16,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ + import { useDatePicker } from "@rehookify/datepicker"; import { Box, Button, Flex, Text } from "@theme-ui/components"; import { useState } from "react"; @@ -31,6 +32,7 @@ type DayPickerProps = { export function DayPicker(props: DayPickerProps) { const { selected, sx, maxDate, minDate, onSelect } = props; const [selectedDates, onDatesChange] = useState([selected]); + const { data: { weekDays, months, years, calendars }, propGetters: { dayButton, addOffset, subtractOffset, setOffset } @@ -52,6 +54,24 @@ export function DayPicker(props: DayPickerProps) { const { month, year, days } = calendars[0]; + const currentMonthDate = months.find((m) => m.month === month)?.$date; + const isNextMonthBeyondMax = + maxDate && currentMonthDate + ? new Date( + currentMonthDate.getFullYear(), + currentMonthDate.getMonth() + 1, + 1 + ) > stripTime(maxDate) + : false; + const isPrevMonthBeforeMin = + minDate && currentMonthDate + ? new Date( + currentMonthDate.getFullYear(), + currentMonthDate.getMonth(), + 1 + ) <= stripTime(minDate) + : false; + return ( @@ -83,9 +103,12 @@ export function DayPicker(props: DayPickerProps) { value={month} onChange={(e) => { const selectedOption = e.target.selectedOptions[0]; - setOffset(new Date(selectedOption.dataset.date || ""))?.onClick?.( - e + const d = clampDate( + new Date(selectedOption.dataset.date || ""), + minDate, + maxDate ); + setOffset(d)?.onClick?.(e as any); }} > {months.map((month) => ( @@ -112,9 +135,12 @@ export function DayPicker(props: DayPickerProps) { value={year} onChange={(e) => { const selectedOption = e.target.selectedOptions[0]; - setOffset(new Date(selectedOption.dataset.date || ""))?.onClick?.( - e + const d = clampDate( + new Date(selectedOption.dataset.date || ""), + minDate, + maxDate ); + setOffset(d)?.onClick?.(e as any); }} > {years.map((year) => ( @@ -129,7 +155,16 @@ export function DayPicker(props: DayPickerProps) { ))} - @@ -195,3 +230,24 @@ export function DayPicker(props: DayPickerProps) { ); } + +function clampDate(d: Date, minDate?: Date, maxDate?: Date) { + /** + * Strip time for accurate comparison + */ + const normalizedMaxDate = maxDate ? stripTime(maxDate) : null; + const normalizedMinDate = minDate ? stripTime(minDate) : null; + + if (normalizedMaxDate && d > normalizedMaxDate) { + return normalizedMaxDate; + } + if (normalizedMinDate && d < normalizedMinDate) { + return normalizedMinDate; + } + + return d; +} + +function stripTime(date: Date) { + return new Date(date.getFullYear(), date.getMonth(), date.getDate()); +}