mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 16:51:12 -05:00
178 lines
5.0 KiB
TypeScript
178 lines
5.0 KiB
TypeScript
import * as React from "react";
|
|
import { format } from "date-fns";
|
|
import { CalendarIcon } from "lucide-react";
|
|
import { cn } from "@/lib/utils";
|
|
import { Button } from "@/components/ui/button";
|
|
import { DatePicker } from "@/components/ui/date-picker";
|
|
import { MonthYearPicker } from "@/components/ui/month-year-picker";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Label } from "@/components/ui/label";
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from "@/components/ui/select";
|
|
import { toDateOnly, toDateWithPrecision } from "@/lib/dateUtils";
|
|
|
|
export type DatePrecision = 'day' | 'month' | 'year';
|
|
|
|
interface FlexibleDateInputProps {
|
|
value?: Date;
|
|
precision?: DatePrecision;
|
|
onChange: (date: Date | undefined, precision: DatePrecision) => void;
|
|
placeholder?: string;
|
|
disabled?: boolean;
|
|
className?: string;
|
|
disableFuture?: boolean;
|
|
disablePast?: boolean;
|
|
fromYear?: number;
|
|
toYear?: number;
|
|
label?: string;
|
|
}
|
|
|
|
export function FlexibleDateInput({
|
|
value,
|
|
precision = 'day',
|
|
onChange,
|
|
placeholder = "Select date",
|
|
disabled = false,
|
|
className,
|
|
disableFuture = false,
|
|
disablePast = false,
|
|
fromYear = 1800,
|
|
toYear = new Date().getFullYear() + 10,
|
|
label,
|
|
}: FlexibleDateInputProps) {
|
|
const [localPrecision, setLocalPrecision] = React.useState<DatePrecision>(precision);
|
|
const [yearValue, setYearValue] = React.useState<string>(
|
|
value && precision === 'year' ? value.getFullYear().toString() : ''
|
|
);
|
|
|
|
React.useEffect(() => {
|
|
setLocalPrecision(precision);
|
|
}, [precision]);
|
|
|
|
React.useEffect(() => {
|
|
if (value && precision === 'year') {
|
|
setYearValue(value.getFullYear().toString());
|
|
}
|
|
}, [value, precision]);
|
|
|
|
const handlePrecisionChange = (newPrecision: DatePrecision) => {
|
|
setLocalPrecision(newPrecision);
|
|
|
|
// If we have a value, adjust it to the new precision
|
|
if (value) {
|
|
const year = value.getFullYear();
|
|
const month = value.getMonth();
|
|
|
|
let newDate: Date;
|
|
switch (newPrecision) {
|
|
case 'year':
|
|
newDate = new Date(year, 0, 1); // January 1st (local timezone)
|
|
setYearValue(year.toString());
|
|
break;
|
|
case 'month':
|
|
newDate = new Date(year, month, 1); // 1st of month (local timezone)
|
|
break;
|
|
case 'day':
|
|
default:
|
|
newDate = value; // Keep existing date
|
|
break;
|
|
}
|
|
onChange(newDate, newPrecision);
|
|
} else {
|
|
onChange(undefined, newPrecision);
|
|
}
|
|
};
|
|
|
|
const handleYearChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
const yearStr = e.target.value;
|
|
setYearValue(yearStr);
|
|
|
|
const yearNum = parseInt(yearStr, 10);
|
|
if (yearStr && !isNaN(yearNum) && yearNum >= fromYear && yearNum <= toYear) {
|
|
const newDate = new Date(yearNum, 0, 1);
|
|
onChange(newDate, 'year');
|
|
} else if (!yearStr) {
|
|
onChange(undefined, 'year');
|
|
}
|
|
};
|
|
|
|
const getPlaceholderText = () => {
|
|
switch (localPrecision) {
|
|
case 'year':
|
|
return 'Enter year (e.g., 2005)';
|
|
case 'month':
|
|
return 'Select month and year';
|
|
case 'day':
|
|
default:
|
|
return placeholder;
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className={cn("space-y-2", className)}>
|
|
{label && <Label>{label}</Label>}
|
|
|
|
<div className="flex gap-2">
|
|
<div className="flex-1">
|
|
{localPrecision === 'day' && (
|
|
<DatePicker
|
|
date={value}
|
|
onSelect={(date) => onChange(date, 'day')}
|
|
placeholder={getPlaceholderText()}
|
|
disabled={disabled}
|
|
disableFuture={disableFuture}
|
|
disablePast={disablePast}
|
|
fromYear={fromYear}
|
|
toYear={toYear}
|
|
/>
|
|
)}
|
|
|
|
{localPrecision === 'month' && (
|
|
<MonthYearPicker
|
|
date={value}
|
|
onSelect={(date) => onChange(date, 'month')}
|
|
placeholder={getPlaceholderText()}
|
|
disabled={disabled}
|
|
fromYear={fromYear}
|
|
toYear={toYear}
|
|
/>
|
|
)}
|
|
|
|
{localPrecision === 'year' && (
|
|
<Input
|
|
type="number"
|
|
value={yearValue}
|
|
onChange={handleYearChange}
|
|
placeholder={getPlaceholderText()}
|
|
disabled={disabled}
|
|
min={fromYear}
|
|
max={toYear}
|
|
className="w-full"
|
|
/>
|
|
)}
|
|
</div>
|
|
|
|
<Select
|
|
value={localPrecision}
|
|
onValueChange={(value) => handlePrecisionChange(value as DatePrecision)}
|
|
disabled={disabled}
|
|
>
|
|
<SelectTrigger className="w-[160px]">
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="day">Use Full Date</SelectItem>
|
|
<SelectItem value="month">Use Month/Year</SelectItem>
|
|
<SelectItem value="year">Use Year Only</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|