-
-
Save fernandops26/da681c4b12e52191803b4fcb040cdebb to your computer and use it in GitHub Desktop.
import * as React from 'react'; | |
import { DateTime } from 'luxon'; | |
import { Calendar as CalendarIcon } from 'lucide-react'; | |
import { Button } from '@/components/ui/Button'; | |
import { Calendar } from '@/components/ui/Calendar'; | |
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/Popover'; | |
import { cn } from '@/lib/utils'; | |
import { SelectSingleEventHandler } from 'react-day-picker'; | |
import { Label } from '@/components/ui/Label'; | |
import { Input } from '@/components/ui/Input'; | |
interface DateTimePickerProps { | |
date: Date; | |
setDate: (date: Date) => void; | |
} | |
export function DateTimePicker({ date, setDate }: DateTimePickerProps) { | |
const [selectedDateTime, setSelectedDateTime] = React.useState<DateTime>( | |
DateTime.fromJSDate(date) | |
); | |
const handleSelect: SelectSingleEventHandler = (day, selected) => { | |
const selectedDay = DateTime.fromJSDate(selected); | |
const modifiedDay = selectedDay.set({ | |
hour: selectedDateTime.hour, | |
minute: selectedDateTime.minute, | |
}); | |
setSelectedDateTime(modifiedDay); | |
setDate(modifiedDay.toJSDate()); | |
}; | |
const handleTimeChange: React.ChangeEventHandler<HTMLInputElement> = (e) => { | |
const { value } = e.target; | |
const hours = Number.parseInt(value.split(':')[0] || '00', 10); | |
const minutes = Number.parseInt(value.split(':')[1] || '00', 10); | |
const modifiedDay = selectedDateTime.set({ hour: hours, minute: minutes }); | |
setSelectedDateTime(modifiedDay); | |
setDate(modifiedDay.toJSDate()); | |
}; | |
const footer = ( | |
<> | |
<div className="px-4 pt-0 pb-4"> | |
<Label>Time</Label> | |
<Input | |
type="time" | |
onChange={handleTimeChange} | |
value={selectedDateTime.toFormat('HH:mm')} | |
/> | |
</div> | |
{!selectedDateTime && <p>Please pick a day.</p>} | |
</> | |
); | |
return ( | |
<Popover> | |
<PopoverTrigger asChild className="z-10"> | |
<Button | |
variant={'outline'} | |
className={cn( | |
'w-[280px] justify-start text-left font-normal', | |
!date && 'text-muted-foreground' | |
)} | |
> | |
<CalendarIcon className="mr-2 h-4 w-4" /> | |
{date ? ( | |
selectedDateTime.toFormat('DDD HH:mm') | |
) : ( | |
<span>Pick a date</span> | |
)} | |
</Button> | |
</PopoverTrigger> | |
<PopoverContent className="w-auto p-0"> | |
<Calendar | |
mode="single" | |
selected={selectedDateTime.toJSDate()} | |
onSelect={handleSelect} | |
initialFocus | |
/> | |
{footer} | |
</PopoverContent> | |
</Popover> | |
); | |
} |
Thanks @fernandops26 !
how to add date range picker using mode="range"?
it's a version to use in a dialog. add modal props on popover.
otherwise you will lose focus on the element and the popover will disappear
import * as React from "react";
import { DateTime } from "luxon";
import { Calendar as CalendarIcon } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { cn } from "@/lib/utils";
import { SelectSingleEventHandler } from "react-day-picker";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
interface DateTimePickerProps {
date: Date;
setDate: (date: Date) => void;
locale: any;
}
export function DateTimePicker({ date, setDate, locale }: DateTimePickerProps) {
const [selectedDateTime, setSelectedDateTime] = React.useState(
DateTime.fromJSDate(date),
);
React.useEffect(() => {
setSelectedDateTime(DateTime.fromJSDate(date));
}, [date]);
const handleSelect: SelectSingleEventHandler = (day, selected) => {
if (!selected) return;
const selectedDay = DateTime.fromJSDate(selected);
const modifiedDay = selectedDay.set({
hour: selectedDateTime.hour,
minute: selectedDateTime.minute,
});
setSelectedDateTime(modifiedDay);
setDate(modifiedDay.toJSDate());
};
const handleTimeChange: React.ChangeEventHandler = (e) => {
e.stopPropagation();
const { value } = e.target;
const hours = Number.parseInt(value.split(":")[0], 10);
const minutes = Number.parseInt(value.split(":")[1], 10);
const modifiedDay = selectedDateTime.set({ hour: hours, minute: minutes });
setSelectedDateTime(modifiedDay);
setDate(modifiedDay.toJSDate());
};
const footer = (
Heure
<Input
type="time"
onChange={handleTimeChange}
value={selectedDateTime.toFormat("HH:mm")}
/>
);
return (
<Button
variant={"outline"}
className={cn(
"w-full justify-start text-left font-normal",
!date && "text-muted-foreground",
)}
>
{date ? selectedDateTime.toFormat("DDD HH:mm") : Selectionne une date}
{footer}
);
}
Hello @fernandops26 and every one, thank you for the tutorial on creating dateTimePicker with shadcn ui. I have applied, everything is fine on windows and android, but I have a problem when it displays on IOS, I have searched everywhere to solve the problem but still can't solve it, do you have any way to solve it? solve my problem? Thanks a lot!
Thanks @fernandops26!
Amazing! Thanks @fernandops26 🚀.
When using Nextjs, I had to use
suppressHydrationWarning
on the button as server and client dates are differently!