diff --git a/src/components/DateTimePicker.jsx b/src/components/DateTimePicker.jsx index be607b9..03fa11e 100644 --- a/src/components/DateTimePicker.jsx +++ b/src/components/DateTimePicker.jsx @@ -1,19 +1,16 @@ -import ReactDatePicker from 'react-datepicker'; -import { de } from 'date-fns/locale'; import { Calendar as CalendarIcon, Clock } from 'lucide-react'; -import { forwardRef, useRef, useCallback } from 'react'; -import 'react-datepicker/dist/react-datepicker.css'; /** - * Custom DateTimePicker that reads the app's CSS variables and - * fully matches whatever theme is active. + * Themed DateTimePicker using native + . + * No popups, no Popper.js, no scroll issues — the browser-native date/time + * pickers handle everything and respect the OS dark/light mode via color-scheme. * * Props: - * value – ISO datetime string (or '') - * onChange – (isoString) => void + * value – local datetime string 'YYYY-MM-DDTHH:mm' (or '') + * onChange – (localDatetimeString) => void * label – string * required – bool - * minDate – Date | null + * minDate – Date | null (only the date part is enforced) * icon – 'calendar' (default) | 'clock' */ export default function DateTimePicker({ @@ -24,126 +21,58 @@ export default function DateTimePicker({ minDate = null, icon = 'calendar', }) { - const selected = value ? new Date(value) : null; + // Split 'YYYY-MM-DDTHH:mm' into date and time parts + const [datePart, timePart] = value ? value.split('T') : ['', '']; - const handleChange = (date) => { - if (!date) { onChange(''); return; } - // Produce local datetime string yyyy-MM-ddTHH:mm - const y = date.getFullYear(); - const mo = String(date.getMonth() + 1).padStart(2, '0'); - const d = String(date.getDate()).padStart(2, '0'); - const h = String(date.getHours()).padStart(2, '0'); - const mi = String(date.getMinutes()).padStart(2, '0'); - onChange(`${y}-${mo}-${d}T${h}:${mi}`); + const handleDateChange = (e) => { + const d = e.target.value; // YYYY-MM-DD + const t = timePart || '09:00'; + onChange(d ? `${d}T${t}` : ''); + }; + + const handleTimeChange = (e) => { + const t = e.target.value; // HH:mm + const d = datePart || new Date().toISOString().slice(0, 10); + onChange(t ? `${d}T${t}` : ''); }; const Icon = icon === 'clock' ? Clock : CalendarIcon; - // react-datepicker calls scrollIntoView on the selected time item when the - // calendar opens. This scrolls the nearest scrollable ancestor (page or - // modal). We capture every scrollable ancestor's position just before open - // and restore it in the next animation frame — after scrollIntoView fires. - const wrapperRef = useRef(null); - const handleCalendarOpen = useCallback(() => { - const snapshots = []; - let el = wrapperRef.current?.parentElement; - while (el && el !== document.body) { - const { overflow, overflowY } = getComputedStyle(el); - if (/(auto|scroll)/.test(overflow + overflowY)) { - snapshots.push({ el, top: el.scrollTop, left: el.scrollLeft }); - } - el = el.parentElement; - } - // also capture window scroll - const winY = window.scrollY; - requestAnimationFrame(() => { - snapshots.forEach(s => { s.el.scrollTop = s.top; s.el.scrollLeft = s.left; }); - window.scrollTo({ top: winY, behavior: 'instant' }); - }); - }, []); + // Format minDate to YYYY-MM-DD for the native input + const minDateStr = minDate + ? `${minDate.getFullYear()}-${String(minDate.getMonth() + 1).padStart(2, '0')}-${String(minDate.getDate()).padStart(2, '0')}` + : undefined; return ( -