84 lines
2.1 KiB
TypeScript
84 lines
2.1 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from 'react';
|
|
import { format } from 'date-fns';
|
|
|
|
interface DateRange {
|
|
from: Date;
|
|
to: Date;
|
|
}
|
|
|
|
interface DateRangePickerProps {
|
|
value: DateRange;
|
|
onChange: (value: DateRange) => void;
|
|
className?: string;
|
|
}
|
|
|
|
export function DateRangePicker({
|
|
value,
|
|
onChange,
|
|
className
|
|
}: DateRangePickerProps) {
|
|
// Internal date state for validation
|
|
const [from, setFrom] = useState<string>(
|
|
value.from ? format(value.from, 'yyyy-MM-dd') : ''
|
|
);
|
|
const [to, setTo] = useState<string>(
|
|
value.to ? format(value.to, 'yyyy-MM-dd') : ''
|
|
);
|
|
|
|
const handleFromChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
const newFrom = e.target.value;
|
|
setFrom(newFrom);
|
|
|
|
if (newFrom) {
|
|
onChange({
|
|
from: new Date(newFrom),
|
|
to: value.to
|
|
});
|
|
}
|
|
};
|
|
|
|
const handleToChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
const newTo = e.target.value;
|
|
setTo(newTo);
|
|
|
|
if (newTo) {
|
|
onChange({
|
|
from: value.from,
|
|
to: new Date(newTo)
|
|
});
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className={`flex flex-col space-y-2 sm:flex-row sm:space-y-0 sm:space-x-4 ${className}`}>
|
|
<div>
|
|
<label htmlFor="from" className="block text-sm font-medium text-gray-500 mb-1">
|
|
Start Date
|
|
</label>
|
|
<input
|
|
type="date"
|
|
id="from"
|
|
value={from}
|
|
onChange={handleFromChange}
|
|
max={to}
|
|
className="block w-full px-3 py-2 bg-white border border-gray-300 rounded-md text-sm text-gray-900 focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label htmlFor="to" className="block text-sm font-medium text-gray-500 mb-1">
|
|
End Date
|
|
</label>
|
|
<input
|
|
type="date"
|
|
id="to"
|
|
value={to}
|
|
onChange={handleToChange}
|
|
min={from}
|
|
className="block w-full px-3 py-2 bg-white border border-gray-300 rounded-md text-sm text-gray-900 focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
|
/>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|