75 lines
2.6 KiB
TypeScript
75 lines
2.6 KiB
TypeScript
"use client";
|
|
|
|
import { format } from "date-fns";
|
|
import { zhCN as dateFnsZhCN } from "date-fns/locale";
|
|
import { CalendarIcon } from "lucide-react";
|
|
import { useId, useState } from "react";
|
|
import { zhCN } from "react-day-picker/locale";
|
|
|
|
import { Button } from "@/components/ui/button";
|
|
import { Calendar } from "@/components/ui/calendar";
|
|
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
|
import { formatBirthDate, parseBirthDate } from "@/lib/birth-time-intake-model";
|
|
|
|
type BirthDatePickerProps = {
|
|
readonly value: string;
|
|
readonly disabled: boolean;
|
|
readonly onChange: (value: string) => void;
|
|
};
|
|
|
|
const emptyDefaultMonth = new Date(1997, 0, 1);
|
|
|
|
export function BirthDatePicker({ value, disabled, onChange }: BirthDatePickerProps) {
|
|
const labelId = useId();
|
|
const valueId = useId();
|
|
const [open, setOpen] = useState(false);
|
|
const selected = parseBirthDate(value);
|
|
const today = new Date();
|
|
today.setHours(0, 0, 0, 0);
|
|
|
|
return (
|
|
<div className="grid gap-2">
|
|
<span id={labelId}>出生日期</span>
|
|
<Popover open={open} onOpenChange={setOpen}>
|
|
<PopoverTrigger
|
|
render={<Button
|
|
type="button"
|
|
variant="outline"
|
|
disabled={disabled}
|
|
aria-labelledby={`${labelId} ${valueId}`}
|
|
data-empty={selected === undefined}
|
|
className="w-full justify-start px-3 text-left font-normal data-[empty=true]:text-muted-foreground"
|
|
/>}
|
|
>
|
|
<CalendarIcon aria-hidden="true" />
|
|
<span id={valueId}>
|
|
{selected === undefined
|
|
? "选择出生日期"
|
|
: format(selected, "PPP", { locale: dateFnsZhCN })}
|
|
</span>
|
|
</PopoverTrigger>
|
|
<PopoverContent align="start" className="w-auto p-0" aria-label="选择出生日期">
|
|
<Calendar
|
|
key={value || "empty"}
|
|
mode="single"
|
|
className="[--cell-size:2.75rem] [&_button[data-selected-single=true]]:text-primary-foreground!"
|
|
locale={zhCN}
|
|
selected={selected}
|
|
defaultMonth={selected ?? emptyDefaultMonth}
|
|
captionLayout="dropdown"
|
|
startMonth={new Date(1900, 0)}
|
|
endMonth={today}
|
|
reverseYears
|
|
disabled={{ before: new Date(1900, 0, 1), after: today }}
|
|
onSelect={(nextDate) => {
|
|
if (nextDate === undefined) return;
|
|
onChange(formatBirthDate(nextDate));
|
|
setOpen(false);
|
|
}}
|
|
/>
|
|
</PopoverContent>
|
|
</Popover>
|
|
</div>
|
|
);
|
|
}
|