"use client"; import { ChevronDownIcon, CalendarIcon } from "lucide-react"; import { Button } from "@app/components/ui/button"; 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; return `${dateStr} ${internalTime}`; }; const hasValue = internalDate || (showTime && internalTime); return (
{label && ( )}
{ let dateValue = undefined; if (e.target.value) { // Create date in local timezone to avoid offset issues const parts = e.target.value.split('-'); dateValue = new Date(parseInt(parts[0]), parseInt(parts[1]) - 1, parseInt(parts[2])); } handleDateChange(dateValue); }} className="mt-1" />
{showTime && (
)}
); } 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 (
); }