import React, { useState, useEffect, forwardRef, useRef, useCallback } from 'react'; import dayjs from 'dayjs'; import styled from 'styled-components'; import DatePicker from 'react-datepicker'; import _ from 'lodash'; import 'react-datepicker/dist/react-datepicker.css'; import { getYear, getMonth } from 'date-fns'; import { useForm, Controller } from 'react-hook-form'; import NOOP from 'shared/utils/noop'; import { Wrapper, RemoveDueDate, DueDateInput, DueDatePickerWrapper, ConfirmAddDueDate, DateRangeInputs, AddDateRange, ActionIcon, ActionsWrapper, ClearButton, ActionsSeparator, ActionClock, ActionLabel, } from './Styles'; import { Clock, Cross } from 'shared/icons'; import Select from 'react-select/src/Select'; type DueDateManagerProps = { task: Task; onDueDateChange: (task: Task, newDueDate: Date, hasTime: boolean) => void; onRemoveDueDate: (task: Task) => void; onCancel: () => void; }; const Form = styled.form` padding-top: 25px; `; const FormField = styled.div` width: 50%; display: inline-block; `; const HeaderSelectLabel = styled.div` display: inline-block; position: relative; z-index: 9999; border-radius: 3px; cursor: pointer; padding: 6px 10px; text-decoration: underline; margin: 6px 0; font-size: 14px; line-height: 16px; margin-left: 0; margin-right: 0; padding-left: 4px; padding-right: 4px; color: #c2c6dc; &:hover { background: ${(props) => props.theme.colors.primary}; color: #c2c6dc; } `; const HeaderSelect = styled.select` text-decoration: underline; font-size: 14px; text-align: center; background: none; outline: none; border: none; border-radius: 3px; appearance: none; width: 100%; display: inline-block; & option { color: #c2c6dc; background: ${(props) => props.theme.colors.bg.primary}; } & option:hover { background: ${(props) => props.theme.colors.bg.secondary}; border: 1px solid ${(props) => props.theme.colors.primary}; outline: none !important; box-shadow: none; color: #c2c6dc; } &::-ms-expand { display: none; } cursor: pointer; position: absolute; z-index: 9998; margin: 0; left: 0; top: 5px; opacity: 0; `; const HeaderButton = styled.button` cursor: pointer; color: #c2c6dc; text-decoration: underline; font-size: 14px; text-align: center; padding: 6px 10px; margin: 6px 0; background: none; outline: none; border: none; border-radius: 3px; &:hover { background: ${(props) => props.theme.colors.primary}; color: #fff; } `; const HeaderActions = styled.div` position: relative; text-align: center; & > button:first-child { float: left; } & > button:last-child { float: right; } `; const DueDateManager: React.FC = ({ task, onDueDateChange, onRemoveDueDate, onCancel }) => { const currentDueDate = task.dueDate ? dayjs(task.dueDate).toDate() : null; const { register, handleSubmit, setValue, setError, formState: { errors }, control, } = useForm(); const [startDate, setStartDate] = useState(currentDueDate); const [endDate, setEndDate] = useState(currentDueDate); const [hasTime, enableTime] = useState(task.hasTime ?? false); const firstRun = useRef(true); const debouncedFunctionRef = useRef((newDate: Date | null, nowHasTime: boolean) => { if (!firstRun.current) { if (newDate) { onDueDateChange(task, newDate, nowHasTime); } else { onRemoveDueDate(task); enableTime(false); } } else { firstRun.current = false; } }); const debouncedChange = useCallback( _.debounce((newDate, nowHasTime) => debouncedFunctionRef.current(newDate, nowHasTime), 500), [], ); useEffect(() => { debouncedChange(startDate, hasTime); }, [startDate, hasTime]); const years = _.range(2010, getYear(new Date()) + 10, 1); const months = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December', ]; const onChange = (dates: any) => { const [start, end] = dates; setStartDate(start); setEndDate(end); }; const [isRange, setIsRange] = useState(false); const CustomTimeInput = forwardRef(({ value, onClick, onChange, onBlur, onFocus }: any, $ref: any) => { return ( ); }); return ( { if (!Array.isArray(date)) { setStartDate(date); } }} popperClassName="picker-hidden" dateFormat="yyyy-MM-dd" disabledKeyboardNavigation isClearable placeholderText="Select due date" /> {isRange ? ( { if (!Array.isArray(date)) { setStartDate(date); } }} popperClassName="picker-hidden" dateFormat="yyyy-MM-dd" placeholderText="Select from date" /> ) : ( Add date range )} { if (!Array.isArray(date)) { setStartDate(date); } }} startDate={startDate} useWeekdaysShort renderCustomHeader={({ date, changeYear, changeMonth, decreaseMonth, increaseMonth, prevMonthButtonDisabled, nextMonthButtonDisabled, }) => ( Prev {months[date.getMonth()]} changeMonth(months.indexOf(value))} > {months.map((option) => ( ))} {date.getFullYear()} changeYear(parseInt(value, 10))}> {years.map((option) => ( ))} Next )} inline /> {hasTime && ( Due Time { if (!Array.isArray(date)) { setStartDate(date); } }} showTimeSelect showTimeSelectOnly timeIntervals={15} timeCaption="Time" dateFormat="h:mm aa" /> enableTime(false)}> )} {!hasTime && ( { if (startDate === null) { const today = new Date(); today.setHours(12, 30, 0); setStartDate(today); } enableTime(true); }} > )} setStartDate(null)}>{hasTime ? 'Clear all' : 'Clear'} ); }; export default DueDateManager;