2023-04-10 07:14:06 +00:00
|
|
|
import React, { useRef, useState } from "react";
|
2023-04-18 10:19:24 +00:00
|
|
|
import PropTypes from "prop-types";
|
2023-04-17 17:13:59 +00:00
|
|
|
import moment from "moment";
|
2023-05-15 16:10:29 +00:00
|
|
|
import styled, { css } from "styled-components";
|
2023-04-10 07:14:06 +00:00
|
|
|
|
|
|
|
import { TextInput } from "@docspace/components";
|
|
|
|
|
|
|
|
const TimeInput = styled.div`
|
|
|
|
width: 57px;
|
|
|
|
height: 32px;
|
|
|
|
box-sizing: border-box;
|
|
|
|
padding: 6px 8px;
|
|
|
|
|
|
|
|
border: 1px solid #d0d5da;
|
|
|
|
border-radius: 3px;
|
|
|
|
|
|
|
|
transition: "all 0.2s ease 0s";
|
|
|
|
|
|
|
|
display: flex;
|
|
|
|
|
2023-05-01 08:17:16 +00:00
|
|
|
border-color: ${(props) => (props.hasError ? "#f21c0e" : "#d0d5da")};
|
|
|
|
|
2023-05-15 16:10:29 +00:00
|
|
|
${(props) =>
|
|
|
|
props.isFocused &&
|
|
|
|
css`
|
|
|
|
border-color: #4781d1;
|
|
|
|
`}
|
|
|
|
|
2023-04-10 07:14:06 +00:00
|
|
|
:focus {
|
|
|
|
border-color: #4781d1;
|
|
|
|
}
|
|
|
|
|
|
|
|
input {
|
|
|
|
padding: 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
input:last-of-type {
|
|
|
|
text-align: end;
|
|
|
|
}
|
|
|
|
`;
|
|
|
|
|
2023-05-15 16:10:29 +00:00
|
|
|
const TimePicker = ({
|
|
|
|
date,
|
|
|
|
setDate,
|
|
|
|
onChange,
|
|
|
|
className,
|
|
|
|
hasError,
|
|
|
|
tabIndex,
|
|
|
|
}) => {
|
2023-04-10 07:14:06 +00:00
|
|
|
const hoursInputRef = useRef(null);
|
|
|
|
const minutesInputRef = useRef(null);
|
|
|
|
const timeInputRef = useRef(null);
|
|
|
|
|
2023-05-15 16:10:29 +00:00
|
|
|
const [isInputFocused, setIsInputFocused] = useState(false);
|
|
|
|
|
2023-04-17 17:13:59 +00:00
|
|
|
const [hours, setHours] = useState(moment(date, "HH:mm").format("HH"));
|
2023-04-10 07:14:06 +00:00
|
|
|
|
2023-04-17 17:13:59 +00:00
|
|
|
const [minutes, setMinutes] = useState(moment(date, "HH:mm").format("mm"));
|
|
|
|
|
|
|
|
const handleHoursChange = (time) => {
|
|
|
|
setHours(time);
|
2023-04-18 10:19:24 +00:00
|
|
|
setDate(moment(date.format("YYYY-MM-DD") + " " + time + ":" + minutes));
|
2023-04-17 17:13:59 +00:00
|
|
|
onChange(time);
|
|
|
|
};
|
|
|
|
const handleMinutesChange = (time) => {
|
|
|
|
setMinutes(time);
|
2023-04-18 10:19:24 +00:00
|
|
|
setDate(moment(date.format("YYYY-MM-DD") + " " + hours + ":" + time));
|
2023-04-17 17:13:59 +00:00
|
|
|
onChange(time);
|
|
|
|
};
|
2023-04-10 07:14:06 +00:00
|
|
|
|
|
|
|
const handleChangeHours = (e) => {
|
2023-04-17 17:13:59 +00:00
|
|
|
const hours = e.target.value;
|
|
|
|
|
|
|
|
if (hours === "") {
|
|
|
|
handleHoursChange("00");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!/^\d+$/.test(hours)) return;
|
|
|
|
|
|
|
|
if (hours > 23) {
|
|
|
|
focusMinutesInput();
|
|
|
|
hours.length === 2 && handleHoursChange("0" + hours[0]);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hours.length === 1 && hours > 2) {
|
|
|
|
handleHoursChange("0" + hours);
|
|
|
|
focusMinutesInput();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
hours.length === 2 && focusMinutesInput();
|
|
|
|
|
|
|
|
handleHoursChange(hours);
|
2023-04-10 07:14:06 +00:00
|
|
|
};
|
2023-04-17 17:13:59 +00:00
|
|
|
|
2023-04-10 07:14:06 +00:00
|
|
|
const handleChangeMinutes = (e) => {
|
2023-04-17 17:13:59 +00:00
|
|
|
const minutes = e.target.value;
|
|
|
|
|
|
|
|
if (minutes === "") {
|
|
|
|
handleMinutesChange("00");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!/^\d+$/.test(minutes)) return;
|
|
|
|
|
|
|
|
if (minutes > 59) return;
|
|
|
|
|
|
|
|
if (minutes.length === 1 && minutes > 5) {
|
|
|
|
handleMinutesChange("0" + minutes);
|
|
|
|
blurMinutesInput();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
minutes.length === 2 && blurMinutesInput();
|
|
|
|
|
|
|
|
handleMinutesChange(minutes);
|
2023-04-10 07:14:06 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const focusHoursInput = (e) => {
|
|
|
|
const target = e.target;
|
2023-05-14 22:35:00 +00:00
|
|
|
if (!minutesInputRef.current.contains(target))
|
|
|
|
hoursInputRef.current.select();
|
2023-04-17 17:13:59 +00:00
|
|
|
};
|
|
|
|
const focusMinutesInput = () => {
|
|
|
|
minutesInputRef.current.select();
|
|
|
|
};
|
|
|
|
const blurMinutesInput = () => {
|
|
|
|
minutesInputRef.current.blur();
|
2023-04-10 07:14:06 +00:00
|
|
|
};
|
|
|
|
|
2023-04-17 17:13:59 +00:00
|
|
|
const onHoursBlur = (e) => {
|
|
|
|
e.target.value.length === 1 && handleHoursChange("0" + e.target.value);
|
2023-05-15 16:10:29 +00:00
|
|
|
setIsInputFocused(false);
|
2023-04-17 17:13:59 +00:00
|
|
|
};
|
|
|
|
const onMinutesBlur = (e) => {
|
|
|
|
e.target.value.length === 1 && handleMinutesChange("0" + e.target.value);
|
2023-05-15 16:10:29 +00:00
|
|
|
setIsInputFocused(false);
|
2023-04-17 17:13:59 +00:00
|
|
|
};
|
2023-04-10 07:14:06 +00:00
|
|
|
|
|
|
|
return (
|
2023-05-01 08:17:16 +00:00
|
|
|
<TimeInput
|
|
|
|
ref={timeInputRef}
|
|
|
|
onClick={focusHoursInput}
|
|
|
|
className={className}
|
2023-05-14 22:35:00 +00:00
|
|
|
hasError={hasError}
|
2023-05-15 16:10:29 +00:00
|
|
|
isFocused={isInputFocused}
|
2023-05-14 22:35:00 +00:00
|
|
|
>
|
2023-04-17 17:13:59 +00:00
|
|
|
<TextInput
|
|
|
|
withBorder={false}
|
|
|
|
forwardedRef={hoursInputRef}
|
|
|
|
value={hours}
|
|
|
|
onChange={handleChangeHours}
|
|
|
|
onBlur={onHoursBlur}
|
2023-05-15 16:10:29 +00:00
|
|
|
tabIndex={tabIndex}
|
|
|
|
onFocus={() => setIsInputFocused(true)}
|
2023-04-17 17:13:59 +00:00
|
|
|
/>
|
|
|
|
:
|
|
|
|
<TextInput
|
|
|
|
withBorder={false}
|
|
|
|
forwardedRef={minutesInputRef}
|
|
|
|
value={minutes}
|
|
|
|
onChange={handleChangeMinutes}
|
|
|
|
onClick={focusMinutesInput}
|
|
|
|
onBlur={onMinutesBlur}
|
2023-05-15 16:10:29 +00:00
|
|
|
onFocus={() => setIsInputFocused(true)}
|
2023-04-17 17:13:59 +00:00
|
|
|
/>
|
2023-04-10 07:14:06 +00:00
|
|
|
</TimeInput>
|
|
|
|
);
|
|
|
|
};
|
2023-04-18 10:19:24 +00:00
|
|
|
|
|
|
|
TimePicker.propTypes = {
|
2023-05-14 22:35:00 +00:00
|
|
|
/** Inital date */
|
2023-04-18 10:19:24 +00:00
|
|
|
date: PropTypes.object,
|
2023-05-14 22:35:00 +00:00
|
|
|
/** State setter function */
|
2023-04-18 10:19:24 +00:00
|
|
|
setDate: PropTypes.func,
|
2023-05-14 22:35:00 +00:00
|
|
|
/** Allows to set classname */
|
2023-04-25 07:06:08 +00:00
|
|
|
className: PropTypes.string,
|
2023-04-18 10:19:24 +00:00
|
|
|
/** Allow you to handle changing events of component */
|
|
|
|
onChange: PropTypes.func,
|
2023-05-14 22:35:00 +00:00
|
|
|
/** Indicates error */
|
2023-05-01 08:17:16 +00:00
|
|
|
hasError: PropTypes.bool,
|
2023-05-15 16:10:29 +00:00
|
|
|
/** Tab index allows to make element focusable */
|
|
|
|
hasError: PropTypes.bool,
|
2023-04-18 10:19:24 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
TimePicker.defaultProps = {
|
|
|
|
onChange: () => {},
|
2023-04-25 07:06:08 +00:00
|
|
|
className: "",
|
2023-05-01 08:17:16 +00:00
|
|
|
hasError: false,
|
2023-04-18 10:19:24 +00:00
|
|
|
};
|
2023-05-14 22:35:00 +00:00
|
|
|
|
|
|
|
export default TimePicker;
|