From deb5c5322fbc4104e9a195480b8f9456c46b41d5 Mon Sep 17 00:00:00 2001 From: christof-wittreich Date: Tue, 25 Jul 2023 15:48:58 -0500 Subject: [PATCH] Converted to functional component --- .../components/date-selector/date-selector.js | 357 +++++++++--------- 1 file changed, 170 insertions(+), 187 deletions(-) diff --git a/web/js/components/date-selector/date-selector.js b/web/js/components/date-selector/date-selector.js index e8b53812b5..3265736891 100644 --- a/web/js/components/date-selector/date-selector.js +++ b/web/js/components/date-selector/date-selector.js @@ -1,9 +1,10 @@ /* eslint-disable react/jsx-props-no-spreading */ -import React, { Component } from 'react'; +import React, { useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import DateInputColumn from './date-input-column'; import util from '../../util/util'; import { MONTH_STRING_ARRAY } from '../../modules/date/constants'; +import usePrevious from '../../util/customHooks'; /* * DateSelector used within Timeline and AnimationWidget. @@ -11,51 +12,57 @@ import { MONTH_STRING_ARRAY } from '../../modules/date/constants'; * * @class DateSelector */ -class DateSelector extends Component { - constructor(props) { - super(props); - this.state = { - year: null, - month: null, - day: null, - hour: null, - minute: null, - yearValid: true, - monthValid: true, - dayValid: true, - hourValid: true, - minuteValid: true, - }; - } +function DateSelector(props) { + const { + date, + minDate, + maxDate, + isStartDate, + isEndDate, + onDateChange, + fontSize, + idSuffix, + subDailyMode, + isDisabled, + isKioskModeActive, + } = props; - componentDidUpdate(prevProps) { - const { - date, - minDate, - maxDate, - isStartDate, - isEndDate, - } = this.props; + const [focusedUnit, setFocusedUnit] = useState(null); + const [dateObj, setDateObj] = useState({ + year: null, + month: null, + day: null, + hour: null, + minute: null, + yearValid: true, + monthValid: true, + dayValid: true, + hourValid: true, + minuteValid: true, + }); + + const prevDate = usePrevious(date); + + useEffect(() => { + // parent arrow clicks should override any temporary values within date selector + if (!prevDate || prevDate.getTime() !== date.getTime()) { + clearTimeValuesAndValidation(); + } + }, [date]); + + useEffect(() => { const { year, month, day, hour, minute, - } = this.state; - - // parent arrow clicks should override any temporary values within date selector - if (prevProps.date.getTime() !== date.getTime()) { - this.clearTimeValuesAndValidation(); - } - // handle animation start/end date limit changes and pending invalid -> valid dates - const minDateChangeEndUpdate = isEndDate && prevProps.minDate.getTime() !== minDate.getTime(); - const maxDateChangeStartUpdate = isStartDate && prevProps.maxDate.getTime() !== maxDate.getTime(); + } = dateObj; const anyPendingTimeUnits = year || month || day || hour || minute; - if ((minDateChangeEndUpdate || maxDateChangeStartUpdate) && anyPendingTimeUnits) { - this.updateDate(); + if (anyPendingTimeUnits) { + updateDate(); } - } + }, [dateObj.year, dateObj.month, dateObj.day, dateObj.hour, dateObj.minute]); /** * @desc add individual timeunit input @@ -64,14 +71,8 @@ class DateSelector extends Component { * @param {String / Number} input * @returns {void} */ - updateTimeUnitInput = (timeUnit, input) => { - this.setState({ - [timeUnit]: input, - }, this.updateDate); - }; - - setFocus = (type) => { - this.setState({ focusedUnit: type }); + const updateTimeUnitInput = (timeUnit, input) => { + setDateObj({ ...dateObj, [timeUnit]: input }); }; /** @@ -80,47 +81,47 @@ class DateSelector extends Component { * @desc changing to invalid FEB 31 (31 is a valid day, but invalid for FEB), * @desc and changing to valid OCT 31 - temp values are retained until valid date * - * @param {String} date + * @param {String} dateIn * @param {Boolean} isRollDate * @returns {Object Date or Boolean} valid date or false */ - updateDateCheck = (date, isRollDate) => { - const { minDate, maxDate } = this.props; + const updateDateCheck = (dateIn, isRollDate) => { const { - year, month, day, hour, minute, focusedUnit, - } = this.state; + year, month, day, hour, minute, + } = dateObj; const tabToCheck = focusedUnit; - const inputDate = new Date(date); - const tempDay = day || date.getUTCDate(); + const inputDate = new Date(dateIn); + const tempDay = day || dateIn.getUTCDate(); let validDate = true; let triggeredInvalid = false; + let newDate = dateIn; if (isRollDate) { - date = inputDate; + newDate = inputDate; } else { // conditional logic allows temporary place holder values to be validated // in the event other inputs are invalid, temp values remain without date change if (year) { - date = new Date(new Date(date).setUTCFullYear(year)); + newDate = new Date(new Date(newDate).setUTCFullYear(year)); if (tabToCheck === 'year') { - const yearDateWithinRange = date < minDate || date > maxDate; + const yearDateWithinRange = newDate < minDate || newDate > maxDate; triggeredInvalid = yearDateWithinRange; } } if (day && !month) { const maxDayDate = new Date( - date.getUTCFullYear(), - date.getUTCMonth() + 1, + newDate.getUTCFullYear(), + newDate.getUTCMonth() + 1, 0, ).getDate(); let dateCheck; if (day <= maxDayDate) { - date = new Date(new Date(date).setUTCDate(day)); + newDate = new Date(new Date(newDate).setUTCDate(day)); dateCheck = new Date(new Date(inputDate).setUTCDate(day)); } else { validDate = false; - date = new Date(new Date(date).setUTCDate(maxDayDate)); + newDate = new Date(new Date(newDate).setUTCDate(maxDayDate)); dateCheck = new Date(new Date(inputDate).setUTCDate(maxDayDate)); } @@ -133,13 +134,13 @@ class DateSelector extends Component { if (month) { const realMonth = util.stringInArray(MONTH_STRING_ARRAY, month); const maxDatePrev = new Date( - date.getUTCFullYear(), - date.getUTCMonth() + 1, + newDate.getUTCFullYear(), + newDate.getUTCMonth() + 1, 0, ).getDate(); const maxDateNew = new Date( - date.getUTCFullYear(), + newDate.getUTCFullYear(), realMonth + 1, 0, ).getDate(); @@ -150,15 +151,15 @@ class DateSelector extends Component { let dateCheck; if (day && month) { - date = new Date(new Date(date).setUTCDate(1)); - date = new Date(new Date(date).setUTCMonth(realMonth)); + newDate = new Date(new Date(newDate).setUTCDate(1)); + newDate = new Date(new Date(newDate).setUTCMonth(realMonth)); dateCheck = new Date(inputDate); dateCheck = new Date(new Date(dateCheck).setUTCDate(1)); dateCheck = new Date(new Date(dateCheck).setUTCMonth(realMonth)); } else { const maxDayDate = new Date( - date.getUTCFullYear(), - date.getUTCMonth() + 1, + newDate.getUTCFullYear(), + newDate.getUTCMonth() + 1, 0, ).getDate(); @@ -166,7 +167,7 @@ class DateSelector extends Component { validDate = false; } dateCheck = new Date(new Date(inputDate).setUTCMonth(realMonth)); - date = new Date(new Date(date).setUTCMonth(realMonth)); + newDate = new Date(new Date(newDate).setUTCMonth(realMonth)); } if (tabToCheck === 'month') { @@ -177,22 +178,22 @@ class DateSelector extends Component { if (day && month) { const maxDayDate = new Date( - date.getUTCFullYear(), - date.getUTCMonth() + 1, + newDate.getUTCFullYear(), + newDate.getUTCMonth() + 1, 0, ).getDate(); let dateCheck; if (day <= maxDayDate) { const realMonth = util.stringInArray(MONTH_STRING_ARRAY, month); - date = new Date(new Date(date).setUTCDate(day)); + newDate = new Date(new Date(newDate).setUTCDate(day)); dateCheck = new Date(inputDate); - dateCheck = new Date(new Date(date).setUTCDate(1)); + dateCheck = new Date(new Date(newDate).setUTCDate(1)); dateCheck = new Date(new Date(dateCheck).setUTCMonth(realMonth)); dateCheck = new Date(new Date(dateCheck).setUTCDate(day)); } else { validDate = false; - date = new Date(new Date(date).setUTCDate(maxDayDate)); + newDate = new Date(new Date(newDate).setUTCDate(maxDayDate)); dateCheck = new Date(new Date(inputDate).setUTCDate(maxDayDate)); } @@ -206,51 +207,47 @@ class DateSelector extends Component { } if (hour) { - date = new Date(new Date(date).setUTCHours(hour)); + newDate = new Date(new Date(newDate).setUTCHours(hour)); if (tabToCheck === 'hour') { - const hourDateWithinRange = !validDate || (date < minDate || date > maxDate); + const hourDateWithinRange = !validDate || (newDate < minDate || newDate > maxDate); triggeredInvalid = hourDateWithinRange; } } if (minute) { - date = new Date(new Date(date).setUTCMinutes(minute)); + newDate = new Date(new Date(newDate).setUTCMinutes(minute)); if (tabToCheck === 'minute') { - const minuteDateWithinRange = !validDate || (date < minDate || date > maxDate); + const minuteDateWithinRange = !validDate || (newDate < minDate || newDate > maxDate); triggeredInvalid = minuteDateWithinRange; } } } // check if date is within min/max range - const dateTime = date.getTime(); + const dateTime = newDate.getTime(); const minDateTime = minDate.getTime(); const maxDateTime = maxDate.getTime(); const dateWithinRange = dateTime >= minDateTime && dateTime <= maxDateTime; // updateDate at this stage can still be invalid with pending timeunit changes // eslint-disable-next-line react/destructuring-assignment - const updatedDate = date.getTime() !== this.props.date.getTime(); + const updatedDate = newDate.getTime() !== date.getTime(); const newDateWithinRange = dateWithinRange && updatedDate; if (validDate && (isRollDate || newDateWithinRange)) { - return date; + return newDate; } // set invalid if updated and tabToCheck was offending invalid value const timeValid = `${tabToCheck}Valid`; if (updatedDate) { const timeValidation = !triggeredInvalid; // time specific validation (e.g., 'yearValid') for use in inputs - this.setState({ - [timeValid]: timeValidation, - }); + setDateObj({ ...dateObj, [timeValid]: timeValidation }); } else { // input not invalid, but some other input is, so add more invalids - this.setState({ - [timeValid]: false, - }); + setDateObj({ ...dateObj, [timeValid]: false }); // reverting from invalid date back to same valid date edge case if (!triggeredInvalid && validDate) { - return date; + return newDate; } } return false; @@ -259,19 +256,18 @@ class DateSelector extends Component { /** * @desc update date with newDate if valid from check and then reset temp time values * - * @param {String} date + * @param {String} dateIn * @param {Boolean} isRollDate * @returns {void} */ // eslint-disable-next-line react/destructuring-assignment - updateDate = (date = this.props.date, isRollDate = false) => { - const { onDateChange } = this.props; - const newDate = this.updateDateCheck(date, isRollDate); + const updateDate = (dateIn = date, isRollDate = false) => { + const newDate = updateDateCheck(dateIn, isRollDate); if (newDate) { onDateChange(newDate); // clear the pending timeunit inputs and reset validation - this.clearTimeValuesAndValidation(); + clearTimeValuesAndValidation(); } }; @@ -280,8 +276,8 @@ class DateSelector extends Component { * * @returns {void} */ - clearTimeValuesAndValidation = () => { - this.setState({ + const clearTimeValuesAndValidation = () => { + setDateObj({ year: null, month: null, day: null, @@ -295,102 +291,88 @@ class DateSelector extends Component { }); }; - render() { - const { - date, - maxDate, - minDate, - fontSize, - idSuffix, - subDailyMode, - isStartDate, - isEndDate, - isDisabled, - isKioskModeActive, - } = this.props; - const { - year, - month, - day, - hour, - minute, - yearValid, - monthValid, - dayValid, - hourValid, - minuteValid, - } = this.state; - const sharedProps = { - idSuffix, - onFocus: this.setFocus, - subDailyMode, - isStartDate, - isEndDate, - date, - updateDate: this.updateDate, - maxDate, - minDate, - fontSize, - updateTimeUnitInput: this.updateTimeUnitInput, - }; + const { + year, + month, + day, + hour, + minute, + yearValid, + monthValid, + dayValid, + hourValid, + minuteValid, + } = dateObj; + const sharedProps = { + idSuffix, + onFocus: setFocusedUnit, + subDailyMode, + isStartDate, + isEndDate, + date, + updateDate, + maxDate, + minDate, + fontSize, + updateTimeUnitInput, + }; - const yearValue = year || date.getUTCFullYear(); - const monthValue = month || MONTH_STRING_ARRAY[date.getUTCMonth()]; - const dayValue = day || util.pad(date.getUTCDate(), 2, '0'); - const hourValue = hour || util.pad(date.getUTCHours(), 2, '0'); - const minuteValue = minute || util.pad(date.getUTCMinutes(), 2, '0'); + const yearValue = year || date.getUTCFullYear(); + const monthValue = month || MONTH_STRING_ARRAY[date.getUTCMonth()]; + const dayValue = day || util.pad(date.getUTCDate(), 2, '0'); + const hourValue = hour || util.pad(date.getUTCHours(), 2, '0'); + const minuteValue = minute || util.pad(date.getUTCMinutes(), 2, '0'); - return ( -
- - - - { subDailyMode && ( - <> - -
:
- -
Z
- - )} -
- ); - } + return ( +
+ + + + { subDailyMode && ( + <> + +
:
+ +
Z
+ + )} +
+ ); } DateSelector.defaultProps = { fontSize: 15, @@ -406,6 +388,7 @@ DateSelector.propTypes = { minDate: PropTypes.object, onDateChange: PropTypes.func, subDailyMode: PropTypes.bool, + isKioskModeActive: PropTypes.bool, }; export default DateSelector;