"use client"; import { ChevronDownIcon, CalendarIcon } from "lucide-react"; import { Button } from "@app/components/ui/button"; import { Calendar } from "@app/components/ui/calendar"; import { Input } from "@app/components/ui/input"; import { Label } from "@app/components/ui/label"; import { Popover, PopoverContent, PopoverTrigger } from "@app/components/ui/popover"; import { cn } from "@app/lib/cn"; import { ChangeEvent, useEffect, useState } from "react"; export interface DateTimeValue { date?: Date; time?: string; } export interface DateTimePickerProps { label?: string; value?: DateTimeValue; onChange?: (value: DateTimeValue) => void; placeholder?: string; className?: string; disabled?: boolean; showTime?: boolean; } export function DateTimePicker({ label, value, onChange, placeholder = "Select date & time", className, disabled = false, showTime = true }: DateTimePickerProps) { const [open, setOpen] = useState(false); const [internalDate, setInternalDate] = useState( value?.date ); const [internalTime, setInternalTime] = useState(value?.time || ""); // Sync internal state with external value prop useEffect(() => { setInternalDate(value?.date); setInternalTime(value?.time || ""); }, [value?.date, value?.time]); const handleDateChange = (date: Date | undefined) => { setInternalDate(date); const newValue = { date, time: internalTime }; onChange?.(newValue); }; const handleTimeChange = (event: ChangeEvent) => { const time = event.target.value; setInternalTime(time); const newValue = { date: internalDate, time }; onChange?.(newValue); }; const getDisplayText = () => { if (!internalDate) return placeholder; const dateStr = internalDate.toLocaleDateString(); if (!showTime || !internalTime) return dateStr; // Parse time and format in local timezone const [hours, minutes, seconds] = internalTime.split(":"); const timeDate = new Date(); timeDate.setHours( parseInt(hours, 10), parseInt(minutes, 10), parseInt(seconds || "0", 10) ); const timeStr = timeDate.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }); return `${dateStr} ${timeStr}`; }; const hasValue = internalDate || (showTime && internalTime); return (
{label && }
{showTime ? (
{ handleDateChange(date); if (!showTime) { setOpen(false); } }} className="grow w-[250px]" />
) : ( { handleDateChange(date); setOpen(false); }} /> )}
); } export interface DateRangePickerProps { startLabel?: string; endLabel?: string; startValue?: DateTimeValue; endValue?: DateTimeValue; onStartChange?: (value: DateTimeValue) => void; onEndChange?: (value: DateTimeValue) => void; onRangeChange?: (start: DateTimeValue, end: DateTimeValue) => void; className?: string; disabled?: boolean; showTime?: boolean; } export function DateRangePicker({ // startLabel = "From", // endLabel = "To", startValue, endValue, onStartChange, onEndChange, onRangeChange, className, disabled = false, showTime = true }: DateRangePickerProps) { const handleStartChange = (value: DateTimeValue) => { onStartChange?.(value); if (onRangeChange && endValue) { onRangeChange(value, endValue); } }; const handleEndChange = (value: DateTimeValue) => { onEndChange?.(value); if (onRangeChange && startValue) { onRangeChange(startValue, value); } }; return (
); }