website/components/TimePicker.tsx

116 lines
3.3 KiB
TypeScript
Raw Permalink Normal View History

'use client';
import * as React from 'react';
import { Clock } from 'lucide-react';
import { format } from 'date-fns';
import { cn } from '@/lib/utils';
import { Button } from '@/components/ui/button';
import DatePickerLib from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css';
interface TimePickerProps {
time: string; // HH:mm format (e.g., "09:00")
setTime: (time: string) => void;
label?: string;
isDark?: boolean;
}
export function TimePicker({ time, setTime, label, isDark = false }: TimePickerProps) {
const [isOpen, setIsOpen] = React.useState(false);
const wrapperRef = React.useRef<HTMLDivElement>(null);
// Convert HH:mm string to Date object for the time picker
const timeValue = React.useMemo(() => {
if (!time) return null;
const [hours, minutes] = time.split(':').map(Number);
const date = new Date();
date.setHours(hours || 9);
date.setMinutes(minutes || 0);
date.setSeconds(0);
return date;
}, [time]);
// Handle time change from the picker
const handleTimeChange = (date: Date | null) => {
if (date) {
const hours = date.getHours().toString().padStart(2, '0');
const minutes = date.getMinutes().toString().padStart(2, '0');
setTime(`${hours}:${minutes}`);
}
};
// Close picker when clicking outside
React.useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (wrapperRef.current && !wrapperRef.current.contains(event.target as Node)) {
setIsOpen(false);
}
};
if (isOpen) {
document.addEventListener('mousedown', handleClickOutside);
}
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, [isOpen]);
// Format display time
const displayTime = timeValue
? format(timeValue, 'h:mm a') // e.g., "9:00 AM"
: 'Select time';
return (
<div className="space-y-2">
{label && (
<label className={cn(
"text-sm font-medium",
isDark ? "text-gray-300" : "text-gray-700"
)}>
{label}
</label>
)}
<div className="relative" ref={wrapperRef}>
<Button
type="button"
variant="outline"
onClick={() => setIsOpen(!isOpen)}
className={cn(
"w-full justify-start text-left font-normal h-12 text-base",
!timeValue && "text-muted-foreground",
isDark
? "bg-gray-800 border-gray-600 text-white hover:bg-gray-700"
: "bg-white border-gray-300 text-gray-900 hover:bg-gray-50"
)}
>
<Clock className="mr-2 h-5 w-5" />
{displayTime}
</Button>
{isOpen && (
<div className={cn(
"absolute z-[9999] mt-2 rounded-lg shadow-lg border",
isDark
? "bg-gray-800 border-gray-700"
: "bg-white border-gray-200"
)}>
<DatePickerLib
selected={timeValue}
onChange={handleTimeChange}
showTimeSelect
showTimeSelectOnly
timeIntervals={15}
timeCaption="Time"
dateFormat="h:mm aa"
inline
className="time-picker"
wrapperClassName="time-picker-wrapper"
/>
</div>
)}
</div>
</div>
);
}