132 lines
3.1 KiB
TypeScript
132 lines
3.1 KiB
TypeScript
"use client"
|
||
|
||
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 { Calendar } from "@/components/ui/calendar"
|
||
import {
|
||
Popover,
|
||
PopoverContent,
|
||
PopoverTrigger,
|
||
} from "@/components/ui/popover"
|
||
|
||
interface DatePickerProps {
|
||
value?: Date
|
||
onChange?: (date: Date | undefined) => void
|
||
placeholder?: string
|
||
disabled?: boolean
|
||
className?: string
|
||
fromDate?: Date
|
||
toDate?: Date
|
||
}
|
||
|
||
function DatePicker({
|
||
value,
|
||
onChange,
|
||
placeholder = "Pick a date",
|
||
disabled = false,
|
||
className,
|
||
fromDate,
|
||
toDate,
|
||
}: DatePickerProps) {
|
||
return (
|
||
<Popover>
|
||
<PopoverTrigger
|
||
render={
|
||
<Button
|
||
variant="outline"
|
||
disabled={disabled}
|
||
className={cn(
|
||
"h-10 w-full justify-start text-left font-normal sm:w-60",
|
||
!value && "text-muted-foreground",
|
||
className
|
||
)}
|
||
/>
|
||
}
|
||
>
|
||
<CalendarIcon className="mr-2 size-4 shrink-0" />
|
||
<span className="truncate">
|
||
{value ? format(value, "PPP") : placeholder}
|
||
</span>
|
||
</PopoverTrigger>
|
||
<PopoverContent className="w-auto p-0" align="start">
|
||
<Calendar
|
||
mode="single"
|
||
selected={value}
|
||
onSelect={onChange}
|
||
disabled={(date) => {
|
||
if (fromDate && date < fromDate) return true
|
||
if (toDate && date > toDate) return true
|
||
return false
|
||
}}
|
||
autoFocus
|
||
/>
|
||
</PopoverContent>
|
||
</Popover>
|
||
)
|
||
}
|
||
|
||
interface DateRangePickerProps {
|
||
value?: { from: Date | undefined; to?: Date | undefined }
|
||
onChange?: (range: { from: Date | undefined; to?: Date | undefined } | undefined) => void
|
||
placeholder?: string
|
||
disabled?: boolean
|
||
className?: string
|
||
}
|
||
|
||
function DateRangePicker({
|
||
value,
|
||
onChange,
|
||
placeholder = "Pick a date range",
|
||
disabled = false,
|
||
className,
|
||
}: DateRangePickerProps) {
|
||
return (
|
||
<Popover>
|
||
<PopoverTrigger
|
||
render={
|
||
<Button
|
||
variant="outline"
|
||
disabled={disabled}
|
||
className={cn(
|
||
"h-10 w-full justify-start text-left font-normal sm:w-75",
|
||
!value?.from && "text-muted-foreground",
|
||
className
|
||
)}
|
||
/>
|
||
}
|
||
>
|
||
<CalendarIcon className="mr-2 size-4 shrink-0" />
|
||
<span className="truncate">
|
||
{value?.from ? (
|
||
value.to ? (
|
||
<>
|
||
{format(value.from, "LLL dd, y")} –{" "}
|
||
{format(value.to, "LLL dd, y")}
|
||
</>
|
||
) : (
|
||
format(value.from, "LLL dd, y")
|
||
)
|
||
) : (
|
||
placeholder
|
||
)}
|
||
</span>
|
||
</PopoverTrigger>
|
||
<PopoverContent className="w-auto p-0" align="start">
|
||
<Calendar
|
||
mode="range"
|
||
selected={value}
|
||
onSelect={onChange as (range: unknown) => void}
|
||
numberOfMonths={2}
|
||
autoFocus
|
||
/>
|
||
</PopoverContent>
|
||
</Popover>
|
||
)
|
||
}
|
||
|
||
export { DatePicker, DateRangePicker }
|