Spaces:
Sleeping
Sleeping
| import * as React from "react"; | |
| import { format, parse } from "date-fns"; | |
| import { Calendar as CalendarIcon } from "lucide-react"; | |
| import { cn } from "@/lib/utils"; | |
| import { Button } from "@/components/ui/button"; | |
| import { Calendar } from "@/components/ui/calendar"; | |
| import { | |
| Popover, | |
| PopoverContent, | |
| PopoverTrigger, | |
| } from "@/components/ui/popover"; | |
| interface DateInputProps { | |
| value: string | null; | |
| onChange: (value: string | null) => void; | |
| className?: string; | |
| disabled?: boolean; | |
| placeholder?: string; | |
| } | |
| export function DateInput({ | |
| value, | |
| onChange, | |
| className, | |
| disabled = false, | |
| placeholder = "Pick a date", | |
| }: DateInputProps) { | |
| // Convert string date to Date object for the calendar | |
| const getDateValue = () => { | |
| if (!value) return undefined; | |
| try { | |
| return parse(value, "yyyy-MM-dd", new Date()); | |
| } catch (e) { | |
| console.error("Invalid date format:", value); | |
| return undefined; | |
| } | |
| }; | |
| // Update the date value as string in yyyy-MM-dd format | |
| const handleDateChange = (date: Date | undefined) => { | |
| if (!date) { | |
| onChange(null); | |
| return; | |
| } | |
| try { | |
| const formattedDate = format(date, "yyyy-MM-dd"); | |
| onChange(formattedDate); | |
| } catch (e) { | |
| console.error("Error formatting date:", e); | |
| } | |
| }; | |
| // Format date for display | |
| const getDisplayDate = () => { | |
| if (!value) return null; | |
| try { | |
| const date = parse(value, "yyyy-MM-dd", new Date()); | |
| return format(date, "PPP"); // Human readable format | |
| } catch (e) { | |
| console.error("Error parsing date for display:", e); | |
| return value; | |
| } | |
| }; | |
| return ( | |
| <div className={cn("grid gap-2", className)}> | |
| <Popover> | |
| <PopoverTrigger asChild> | |
| <Button | |
| variant={"outline"} | |
| className={cn( | |
| "w-full justify-start text-left font-normal", | |
| !value && "text-muted-foreground" | |
| )} | |
| disabled={disabled} | |
| > | |
| <CalendarIcon className="mr-2 h-4 w-4" /> | |
| {value ? getDisplayDate() : <span>{placeholder}</span>} | |
| </Button> | |
| </PopoverTrigger> | |
| <PopoverContent | |
| className="w-auto p-0" | |
| align="start" | |
| side="bottom" | |
| sideOffset={4} | |
| alignOffset={0} | |
| style={{ zIndex: 10000 }} | |
| > | |
| <div className="date-picker-wrapper"> | |
| <Calendar | |
| mode="single" | |
| selected={getDateValue()} | |
| onSelect={(date) => handleDateChange(date)} | |
| initialFocus | |
| disabled={(date) => date > new Date('2100-01-01') || date < new Date('1900-01-01')} | |
| /> | |
| </div> | |
| </PopoverContent> | |
| </Popover> | |
| </div> | |
| ); | |
| } |