Skip to content

Commit 6b56c50

Browse files
committed
Added minDate and maxDate, any dates outside of that are disabled
1 parent beef17d commit 6b56c50

File tree

5 files changed

+1956
-1886
lines changed

5 files changed

+1956
-1886
lines changed

src/components/Calendar/Days.tsx

Lines changed: 83 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@ import React, { useCallback, useContext } from "react";
33

44
import { BG_COLOR } from "../../constants";
55
import DatepickerContext from "../../contexts/DatepickerContext";
6-
import { formatDate, getTextColorByPrimaryColor, nextMonth, previousMonth } from "../../helpers";
6+
import {
7+
formatDate,
8+
getTextColorByPrimaryColor,
9+
nextMonth,
10+
previousMonth,
11+
classNames as cn
12+
} from "../../helpers";
713

814
const isBetween = require("dayjs/plugin/isBetween");
915
dayjs.extend(isBetween);
@@ -29,7 +35,7 @@ const Days: React.FC<Props> = ({
2935
onClickNextDays
3036
}) => {
3137
// Contexts
32-
const { primaryColor, period, changePeriod, dayHover, changeDayHover } =
38+
const { primaryColor, period, changePeriod, dayHover, changeDayHover, minDate, maxDate } =
3339
useContext(DatepickerContext);
3440

3541
// Functions
@@ -139,16 +145,55 @@ const Days: React.FC<Props> = ({
139145
[calendarData.date, currentDateClass, dayHover, period.end, period.start, primaryColor]
140146
);
141147

142-
const buttonCass = useCallback(
143-
(day: number) => {
144-
const baseClass = "flex items-center justify-center w-12 h-12 lg:w-10 lg:h-10";
145-
return `${baseClass}${
146-
!activeDateData(day).active
147-
? ` ${hoverClassByDay(day)}`
148-
: activeDateData(day).className
148+
const isDateTooEarly = useCallback(
149+
(day: number, type: string) => {
150+
if (!minDate) {
151+
return false;
152+
}
153+
const object = {
154+
previous: previousMonth(calendarData.date),
155+
current: calendarData.date,
156+
next: nextMonth(calendarData.date)
157+
};
158+
const newDate = object[type as keyof typeof object];
159+
const newHover = `${newDate.year()}-${newDate.month() + 1}-${
160+
day >= 10 ? day : "0" + day
161+
}`;
162+
163+
return dayjs(newHover).isBefore(dayjs(minDate).subtract(1, "day"));
164+
},
165+
[calendarData.date, minDate]
166+
);
167+
168+
const isDateTooLate = useCallback(
169+
(day: number, type: string) => {
170+
if (!maxDate) {
171+
return false;
172+
}
173+
const object = {
174+
previous: previousMonth(calendarData.date),
175+
current: calendarData.date,
176+
next: nextMonth(calendarData.date)
177+
};
178+
const newDate = object[type as keyof typeof object];
179+
const newHover = `${newDate.year()}-${newDate.month() + 1}-${
180+
day >= 10 ? day : "0" + day
149181
}`;
182+
183+
return dayjs(newHover).isAfter(dayjs(maxDate));
184+
},
185+
[calendarData.date, maxDate]
186+
);
187+
const buttonClass = useCallback(
188+
(day: number, type: string) => {
189+
const baseClass = "flex items-center justify-center w-12 h-12 lg:w-10 lg:h-10";
190+
return cn(
191+
baseClass,
192+
!activeDateData(day).active ? hoverClassByDay(day) : activeDateData(day).className,
193+
(isDateTooEarly(day, type) || isDateTooLate(day, type)) && "text-red-500"
194+
);
150195
},
151-
[activeDateData, hoverClassByDay]
196+
[activeDateData, hoverClassByDay, isDateTooEarly, isDateTooLate]
152197
);
153198

154199
const hoverDay = useCallback(
@@ -163,27 +208,36 @@ const Days: React.FC<Props> = ({
163208
day >= 10 ? day : "0" + day
164209
}`;
165210

166-
if (period.start && !period.end) {
167-
if (dayjs(newHover).isBefore(dayjs(period.start))) {
168-
changePeriod({
169-
start: null,
170-
end: period.start
171-
});
211+
if (!isDateTooEarly(day, type) && !isDateTooLate(day, type)) {
212+
if (period.start && !period.end) {
213+
if (dayjs(newHover).isBefore(dayjs(period.start))) {
214+
changePeriod({
215+
start: null,
216+
end: period.start
217+
});
218+
}
172219
}
173-
changeDayHover(newHover);
174-
}
175220

176-
if (!period.start && period.end) {
177-
if (dayjs(newHover).isAfter(dayjs(period.end))) {
178-
changePeriod({
179-
start: period.end,
180-
end: null
181-
});
221+
if (!period.start && period.end) {
222+
if (dayjs(newHover).isAfter(dayjs(period.end))) {
223+
changePeriod({
224+
start: period.end,
225+
end: null
226+
});
227+
}
182228
}
183229
changeDayHover(newHover);
184230
}
185231
},
186-
[calendarData.date, changeDayHover, changePeriod, period.end, period.start]
232+
[
233+
calendarData.date,
234+
changeDayHover,
235+
changePeriod,
236+
isDateTooEarly,
237+
isDateTooLate,
238+
period.end,
239+
period.start
240+
]
187241
);
188242

189243
return (
@@ -192,6 +246,7 @@ const Days: React.FC<Props> = ({
192246
<button
193247
type="button"
194248
key={index}
249+
disabled={isDateTooEarly(item, "previous") || isDateTooLate(item, "previous")}
195250
className="flex items-center justify-center text-gray-400 h-12 w-12 lg:w-10 lg:h-10"
196251
onClick={() => onClickPreviousDays(item)}
197252
onMouseOver={() => {
@@ -206,7 +261,8 @@ const Days: React.FC<Props> = ({
206261
<button
207262
type="button"
208263
key={index}
209-
className={buttonCass(item)}
264+
disabled={isDateTooEarly(item, "current") || isDateTooLate(item, "current")}
265+
className={`${buttonClass(item, "current")}`}
210266
onClick={() => {
211267
onClickDay(item);
212268
}}
@@ -222,6 +278,7 @@ const Days: React.FC<Props> = ({
222278
<button
223279
type="button"
224280
key={index}
281+
disabled={isDateTooEarly(item, "next") || isDateTooLate(item, "next")}
225282
className="flex items-center justify-center text-gray-400 h-12 w-12 lg:w-10 lg:h-10"
226283
onClick={() => {
227284
onClickNextDays(item);

src/components/Datepicker.tsx

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { COLORS, DEFAULT_COLOR } from "../constants";
99
import DatepickerContext from "../contexts/DatepickerContext";
1010
import { formatDate, nextMonth, previousMonth } from "../helpers";
1111
import useOnClickOutside from "../hooks";
12-
import { Period, DateValueType } from "../types";
12+
import { Period, DateValueType, DateType } from "../types";
1313

1414
import { Arrow, VerticalDash } from "./utils";
1515

@@ -43,6 +43,8 @@ interface Props {
4343
containerClassName?: string | null;
4444
displayFormat?: string;
4545
readOnly?: boolean;
46+
minDate?: DateType | null;
47+
maxDate?: DateType | null;
4648
}
4749

4850
const Datepicker: React.FC<Props> = ({
@@ -62,7 +64,9 @@ const Datepicker: React.FC<Props> = ({
6264
inputClassName = null,
6365
containerClassName = null,
6466
displayFormat = "YYYY-MM-DD",
65-
readOnly = false
67+
readOnly = false,
68+
minDate = null,
69+
maxDate = null
6670
}) => {
6771
// Ref
6872
const containerRef = useRef<HTMLDivElement>(null);
@@ -260,7 +264,9 @@ const Datepicker: React.FC<Props> = ({
260264
inputClassName,
261265
containerClassName,
262266
readOnly,
263-
displayFormat
267+
displayFormat,
268+
minDate,
269+
maxDate
264270
};
265271
}, [
266272
asSingle,
@@ -281,7 +287,9 @@ const Datepicker: React.FC<Props> = ({
281287
containerClassName,
282288
readOnly,
283289
displayFormat,
284-
firstGotoDate
290+
firstGotoDate,
291+
minDate,
292+
maxDate
285293
]);
286294

287295
return (

src/contexts/DatepickerContext.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import dayjs from "dayjs";
22
import React, { createContext } from "react";
33

4-
import { Configs, Period, DateValueType } from "../types";
4+
import { Configs, Period, DateValueType, DateType } from "../types";
55

66
interface DatepickerStore {
77
asSingle?: boolean;
@@ -28,6 +28,8 @@ interface DatepickerStore {
2828
containerClassName?: string | null;
2929
readOnly?: boolean;
3030
displayFormat?: string;
31+
minDate?: DateType | null;
32+
maxDate?: DateType | null;
3133
}
3234

3335
const DatepickerContext = createContext<DatepickerStore>({
@@ -56,7 +58,9 @@ const DatepickerContext = createContext<DatepickerStore>({
5658
inputClassName: "",
5759
containerClassName: "",
5860
readOnly: false,
59-
displayFormat: "YYYY-MM-DD"
61+
displayFormat: "YYYY-MM-DD",
62+
minDate: null,
63+
maxDate: null
6064
});
6165

6266
export default DatepickerContext;

src/helpers/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import dayjs from "dayjs";
22

3+
export function classNames(...classes: (false | null | undefined | string)[]) {
4+
return classes.filter(Boolean).join(" ");
5+
}
6+
37
export function getTextColorByPrimaryColor(color: string) {
48
switch (color) {
59
case "blue":

0 commit comments

Comments
 (0)