-
-
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
suppressHydrationWarningon the button as server and client dates are differently!