import { DatePicker, Space, TimePicker } from "antd"; import PropTypes from "prop-types"; import { useCallback, useState } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { selectBodyshop } from "../../redux/user/user.selectors.js"; import dayjs from "../../utils/day"; import { fuzzyMatchDate } from "./formats.js"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop }); const DateTimePicker = ({ value, onChange, onBlur, id, onlyFuture, onlyToday, isDateOnly = false, isSeparatedTime = false, bodyshop, ...restProps }) => { const [isManualInput, setIsManualInput] = useState(false); const { t } = useTranslation(); const handleChange = useCallback( (newDate) => { if (onChange) { onChange(bodyshop?.timezone && newDate ? dayjs(newDate).tz(bodyshop.timezone, true) : newDate); } setIsManualInput(false); }, [onChange, bodyshop?.timezone] ); const handleBlur = useCallback( (e) => { // Bail if this is not a manual input if (!isManualInput) { return; } // Reset manual input flag setIsManualInput(false); const v = e?.target?.value; if (!v) return; let parsedDate = isDateOnly ? fuzzyMatchDate(v)?.startOf("day") : fuzzyMatchDate(v); if (parsedDate && onChange) { onChange(parsedDate); } }, [isManualInput, isDateOnly, onChange] ); const handleKeyDown = useCallback( (e) => { setIsManualInput(true); if (e.key.toLowerCase() === "t" && onChange) { e.preventDefault(); setIsManualInput(false); onChange(dayjs()); } else if (e.key.toLowerCase() === "enter") { handleBlur(e); } }, [onChange, handleBlur] ); const handleDisabledDate = useCallback( (current) => { if (onlyToday) { return !dayjs().isSame(current, "day"); } else if (onlyFuture) { return dayjs().subtract(1, "day").isAfter(current); } return false; }, [onlyToday, onlyFuture] ); return (
{isSeparatedTime && ( { if (dateValue) { // When date changes, preserve the existing time if it exists if (value && dayjs(value).isValid()) { const existingTime = dayjs(value); const newDateTime = dayjs(dateValue) .hour(existingTime.hour()) .minute(existingTime.minute()) .second(existingTime.second()); handleChange(newDateTime); } else { // If no existing time, just set the date without time handleChange(dateValue); } } else { handleChange(dateValue); } }} placeholder={t("general.labels.date")} onBlur={handleBlur} disabledDate={handleDisabledDate} isDateOnly={true} {...restProps} /> {value && ( { if (timeValue) { // When time changes, combine it with the existing date const existingDate = dayjs(value); const newDateTime = existingDate .hour(timeValue.hour()) .minute(timeValue.minute()) .second(0); handleChange(newDateTime); } else { // If time is cleared, just update with null time but keep date handleChange(timeValue); } if (onBlur) onBlur(); }} placeholder={t("general.labels.time")} {...restProps} /> )} )} {!isSeparatedTime && ( )}
); }; DateTimePicker.propTypes = { value: PropTypes.any, onChange: PropTypes.func, onBlur: PropTypes.func, id: PropTypes.string, onlyFuture: PropTypes.bool, onlyToday: PropTypes.bool, isDateOnly: PropTypes.bool, isSeparatedTime: PropTypes.bool }; export default connect(mapStateToProps, null)(DateTimePicker);