customize date picker, flexible can set max and min date and also handle react-hook-form
This commit is contained in:
parent
c85d21ad0c
commit
cb009c77a4
@ -1,39 +1,71 @@
|
|||||||
import React, { useEffect, useRef } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
|
import { useController } from "react-hook-form";
|
||||||
|
|
||||||
const DatePicker = ({ onDateChange }) => {
|
|
||||||
|
const DatePicker = ({
|
||||||
|
name,
|
||||||
|
control,
|
||||||
|
placeholder = "DD-MM-YYYY",
|
||||||
|
className = "",
|
||||||
|
allowText = false,
|
||||||
|
maxDate=new Date(),
|
||||||
|
minDate,
|
||||||
|
...rest
|
||||||
|
}) => {
|
||||||
const inputRef = useRef(null);
|
const inputRef = useRef(null);
|
||||||
|
|
||||||
useEffect(() => {
|
const {
|
||||||
const fp = flatpickr(inputRef.current, {
|
field: { onChange, value, ref }
|
||||||
dateFormat: "Y-m-d",
|
} = useController({
|
||||||
defaultDate: new Date(),
|
name,
|
||||||
onChange: (selectedDates, dateStr) => {
|
control
|
||||||
if (onDateChange) {
|
});
|
||||||
onDateChange(dateStr); // Pass selected date to parent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
useEffect(() => {
|
||||||
// Cleanup flatpickr instance
|
if (inputRef.current) {
|
||||||
fp.destroy();
|
flatpickr(inputRef.current, {
|
||||||
};
|
dateFormat: "d-m-Y",
|
||||||
}, [onDateChange]);
|
allowInput: allowText,
|
||||||
|
defaultDate: value
|
||||||
|
? flatpickr.parseDate(value, "Y-m-d")
|
||||||
|
: null,
|
||||||
|
maxDate:maxDate,
|
||||||
|
minDate:new Date(minDate?.split("T")[0]) ?? undefined,
|
||||||
|
onChange: function (selectedDates, dateStr) {
|
||||||
|
onChange(dateStr);
|
||||||
|
},
|
||||||
|
...rest
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [inputRef]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container mt-3">
|
<div className={` position-relative ${className}`}>
|
||||||
<div className="mb-3">
|
<input
|
||||||
{/* <label htmlFor="flatpickr-single" className="form-label">
|
type="text"
|
||||||
Select Date
|
className="form-control form-control-sm "
|
||||||
</label> */}
|
placeholder={placeholder}
|
||||||
<input
|
defaultValue={
|
||||||
type="text"
|
value ? flatpickr.formatDate(flatpickr.parseDate(value, "Y-m-d"), "d-m-Y") : ""
|
||||||
id="flatpickr-single"
|
}
|
||||||
className="form-control"
|
ref={(el) => {
|
||||||
placeholder="YYYY-MM-DD"
|
inputRef.current = el;
|
||||||
ref={inputRef}
|
ref(el);
|
||||||
/>
|
}}
|
||||||
</div>
|
readOnly={!allowText}
|
||||||
|
autoComplete="off"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<span
|
||||||
|
className="position-absolute top-50 end-0 pe-1 translate-middle-y cursor-pointer"
|
||||||
|
onClick={() => {
|
||||||
|
if (inputRef.current && inputRef.current._flatpickr) {
|
||||||
|
inputRef.current._flatpickr.open();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<i className="bx bx-calendar bx-sm fs-5 text-muted"></i>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import React, { useEffect, useRef } from "react";
|
import React, { useEffect, useRef } from "react";
|
||||||
|
import { useController, useFormContext, useWatch } from "react-hook-form";
|
||||||
const DateRangePicker = ({
|
const DateRangePicker = ({
|
||||||
|
md,
|
||||||
|
sm,
|
||||||
onRangeChange,
|
onRangeChange,
|
||||||
DateDifference = 7,
|
DateDifference = 7,
|
||||||
endDateMode = "yesterday",
|
endDateMode = "yesterday",
|
||||||
@ -25,11 +27,12 @@ const DateRangePicker = ({
|
|||||||
altInput: true,
|
altInput: true,
|
||||||
altFormat: "d-m-Y",
|
altFormat: "d-m-Y",
|
||||||
defaultDate: [startDate, endDate],
|
defaultDate: [startDate, endDate],
|
||||||
static: true,
|
static: false,
|
||||||
|
// appendTo: document.body,
|
||||||
clickOpens: true,
|
clickOpens: true,
|
||||||
maxDate: endDate, // ✅ Disable future dates
|
maxDate: endDate,
|
||||||
onChange: (selectedDates, dateStr) => {
|
onChange: (selectedDates, dateStr) => {
|
||||||
const [startDateString, endDateString] = dateStr.split(" to ");
|
const [startDateString, endDateString] = dateStr.split(" To ");
|
||||||
onRangeChange?.({ startDate: startDateString, endDate: endDateString });
|
onRangeChange?.({ startDate: startDateString, endDate: endDateString });
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -45,14 +48,129 @@ const DateRangePicker = ({
|
|||||||
}, [onRangeChange, DateDifference, endDateMode]);
|
}, [onRangeChange, DateDifference, endDateMode]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<input
|
<div className={`col-${sm} col-sm-${md} px-1 position-relative`}>
|
||||||
type="text"
|
<input
|
||||||
className="form-control form-control-sm ms-1"
|
type="text"
|
||||||
placeholder="From to End"
|
className="form-control form-control-sm ps-2 pe-5 me-4"
|
||||||
id="flatpickr-range"
|
placeholder="From to End"
|
||||||
ref={inputRef}
|
id="flatpickr-range"
|
||||||
/>
|
ref={inputRef}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<i
|
||||||
|
className="bx bx-calendar calendar-icon cursor-pointer position-absolute top-50 translate-middle-y "
|
||||||
|
style={{ right: "12px" }}
|
||||||
|
></i>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DateRangePicker;
|
export default DateRangePicker;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const DateRangePicker1 = ({
|
||||||
|
startField = "startDate",
|
||||||
|
endField = "endDate",
|
||||||
|
placeholder = "Select date range",
|
||||||
|
className = "",
|
||||||
|
allowText = false,
|
||||||
|
resetSignal, // <- NEW prop
|
||||||
|
...rest
|
||||||
|
}) => {
|
||||||
|
const inputRef = useRef(null);
|
||||||
|
const { control, setValue, getValues } = useFormContext();
|
||||||
|
|
||||||
|
const {
|
||||||
|
field: { ref },
|
||||||
|
} = useController({ name: startField, control });
|
||||||
|
|
||||||
|
const applyDefaultDates = () => {
|
||||||
|
const today = new Date();
|
||||||
|
const past = new Date();
|
||||||
|
past.setDate(today.getDate() - 6);
|
||||||
|
|
||||||
|
const format = (d) => flatpickr.formatDate(d, "d-m-Y");
|
||||||
|
const formattedStart = format(past);
|
||||||
|
const formattedEnd = format(today);
|
||||||
|
|
||||||
|
setValue(startField, formattedStart, { shouldValidate: true });
|
||||||
|
setValue(endField, formattedEnd, { shouldValidate: true });
|
||||||
|
|
||||||
|
if (inputRef.current?._flatpickr) {
|
||||||
|
inputRef.current._flatpickr.setDate([past, today]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!inputRef.current || inputRef.current._flatpickr) return;
|
||||||
|
|
||||||
|
const instance = flatpickr(inputRef.current, {
|
||||||
|
mode: "range",
|
||||||
|
dateFormat: "d-m-Y",
|
||||||
|
allowInput: allowText,
|
||||||
|
onChange: (selectedDates) => {
|
||||||
|
if (selectedDates.length === 2) {
|
||||||
|
const [start, end] = selectedDates;
|
||||||
|
const format = (d) => flatpickr.formatDate(d, "d-m-Y");
|
||||||
|
setValue(startField, format(start), { shouldValidate: true });
|
||||||
|
setValue(endField, format(end), { shouldValidate: true });
|
||||||
|
} else {
|
||||||
|
setValue(startField, "", { shouldValidate: true });
|
||||||
|
setValue(endField, "", { shouldValidate: true });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
...rest,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Apply default if empty
|
||||||
|
const currentStart = getValues(startField);
|
||||||
|
const currentEnd = getValues(endField);
|
||||||
|
if (!currentStart && !currentEnd) {
|
||||||
|
applyDefaultDates();
|
||||||
|
} else if (currentStart && currentEnd) {
|
||||||
|
instance.setDate([
|
||||||
|
flatpickr.parseDate(currentStart, "d-m-Y"),
|
||||||
|
flatpickr.parseDate(currentEnd, "d-m-Y"),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => instance.destroy();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Reapply default range on resetSignal change
|
||||||
|
useEffect(() => {
|
||||||
|
if (resetSignal !== undefined) {
|
||||||
|
applyDefaultDates();
|
||||||
|
}
|
||||||
|
}, [resetSignal]);
|
||||||
|
|
||||||
|
const start = getValues(startField);
|
||||||
|
const end = getValues(endField);
|
||||||
|
const formattedValue = start && end ? `${start} To ${end}` : "";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={`position-relative ${className}`}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="form-control form-control-sm"
|
||||||
|
placeholder={placeholder}
|
||||||
|
defaultValue={formattedValue}
|
||||||
|
ref={(el) => {
|
||||||
|
inputRef.current = el;
|
||||||
|
ref(el);
|
||||||
|
}}
|
||||||
|
readOnly={!allowText}
|
||||||
|
autoComplete="off"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
className="position-absolute top-50 end-0 pe-1 translate-middle-y cursor-pointer"
|
||||||
|
onClick={() => inputRef.current?._flatpickr?.open()}
|
||||||
|
>
|
||||||
|
<i className="bx bx-calendar bx-sm fs-5 text-muted"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user