diff --git a/spec/coffeescripts/util/coupleTimeFieldsSpec.js b/spec/coffeescripts/util/coupleTimeFieldsSpec.js index 361b5437ec8..3ad1b37a625 100644 --- a/spec/coffeescripts/util/coupleTimeFieldsSpec.js +++ b/spec/coffeescripts/util/coupleTimeFieldsSpec.js @@ -19,7 +19,7 @@ import london from 'timezone/Europe/London' import * as tz from '@canvas/datetime' import coupleTimeFields from '@canvas/calendar/jquery/coupleTimeFields' -import DatetimeField from '@canvas/datetime/jquery/DatetimeField' +import DatetimeField, {PARSE_RESULTS} from '@canvas/datetime/jquery/DatetimeField' import $ from 'jquery' import 'jquery-migrate' import fakeENV from 'helpers/fakeENV' @@ -80,7 +80,7 @@ test('leaves invalid start alone', function () { this.end.setTime(fixed) coupleTimeFields(this.$start, this.$end) equal(this.$start.val(), 'invalid') - equal(this.start.invalid, true) + equal(this.start.valid, PARSE_RESULTS.ERROR) }) test('leaves invalid end alone', function () { @@ -89,7 +89,7 @@ test('leaves invalid end alone', function () { this.end.setFromValue() coupleTimeFields(this.$start, this.$end) equal(this.$end.val(), 'invalid') - equal(this.end.invalid, true) + equal(this.end.valid, PARSE_RESULTS.ERROR) }) test('interprets time as occurring on date', function () { @@ -156,7 +156,7 @@ test('leaves invalid start alone', function () { this.end.setTime(fixed) this.$end.trigger('blur') equal(this.$start.val(), 'invalid') - equal(this.start.invalid, true) + equal(this.start.valid, PARSE_RESULTS.ERROR) }) test('leaves invalid end alone', function () { @@ -165,7 +165,7 @@ test('leaves invalid end alone', function () { this.end.setFromValue() this.$start.trigger('blur') equal(this.$end.val(), 'invalid') - equal(this.end.invalid, true) + equal(this.end.valid, PARSE_RESULTS.ERROR) }) test('does not rewrite blurred input', function () { diff --git a/spec/coffeescripts/widgets/DatetimeFieldSpec.js b/spec/coffeescripts/widgets/DatetimeFieldSpec.js index 417663286b0..c43d87e1145 100644 --- a/spec/coffeescripts/widgets/DatetimeFieldSpec.js +++ b/spec/coffeescripts/widgets/DatetimeFieldSpec.js @@ -20,6 +20,7 @@ import DatetimeField, { DATE_FORMAT_OPTIONS, DATETIME_FORMAT_OPTIONS, TIME_FORMAT_OPTIONS, + PARSE_RESULTS, } from '@canvas/datetime/jquery/DatetimeField' import '@canvas/datetime/jquery' import $ from 'jquery' @@ -32,8 +33,8 @@ import juneau from 'timezone/America/Juneau' import fakeENV from 'helpers/fakeENV' import moment from 'moment' -const moonwalk = new Date('1969-07-21T02:56:00Z') -const john_glenn = new Date('1962-02-20T14:47:39') +const challenger = new Date('1986-01-28T16:39:00Z') +const columbia = new Date('2003-02-01T13:59:00Z') QUnit.module('processTimeOptions', { setup() { @@ -222,9 +223,9 @@ test('should add hidden input when requested', function () { }) test('should initialize from the inputdate data', function () { - this.$field.data('inputdate', '1969-07-21T02:56:00Z') + this.$field.data('inputdate', '1986-01-28T16:39:00Z') const field = new DatetimeField(this.$field, {}) - equal(field.$suggest.text(), 'Sun, Jul 20, 1969, 9:56 PM') + equal(field.$suggest.text(), 'Tue, Jan 28, 1986, 11:39 AM') }) test('should initialize from the initial value attribute if present, and then remove it', function () { @@ -239,8 +240,8 @@ test('should initialize from the initial value attribute if present, and then re test('should tie it to update on keyup only', function () { const field = new DatetimeField(this.$field, {}) - this.$field.val('Jul 21, 1969 5:56am').trigger('keyup') - equal(field.$suggest.text(), 'Mon, Jul 21, 1969, 5:56 AM') + this.$field.val('Jan 28, 1986 5:56am').trigger('keyup') + equal(field.$suggest.text(), 'Tue, Jan 28, 1986, 5:56 AM') }) QUnit.module('setFromValue', { @@ -269,9 +270,9 @@ test('should set data fields', function () { }) test('should set suggest text', function () { - this.$field.val('Jul 21, 1969 at 2:56am') + this.$field.val('Jan 28, 1986 at 2:56am') this.field.setFromValue() - equal(this.field.$suggest.text(), 'Mon, Jul 21, 1969, 2:56 AM') + equal(this.field.$suggest.text(), 'Tue, Jan 28, 1986, 2:56 AM') }) QUnit.module('parseValue', { @@ -282,15 +283,15 @@ QUnit.module('parseValue', { }) test('sets @fudged according to browser (fudged) timezone', function () { - this.$field.val(tz.format(moonwalk, '%b %-e, %Y at %-l:%M%P')).change() + this.$field.val(tz.format(challenger, '%b %-e, %Y at %-l:%M%P')).change() this.field.parseValue() - equal(+this.field.fudged, +$.fudgeDateForProfileTimezone(moonwalk)) + equal(+this.field.fudged, +$.fudgeDateForProfileTimezone(challenger)) }) test('sets @datetime according to profile timezone', function () { - this.$field.val(tz.format(moonwalk, '%b %-e, %Y at %-l:%M%P')).change() + this.$field.val(tz.format(challenger, '%b %-e, %Y at %-l:%M%P')).change() this.field.parseValue() - equal(+this.field.datetime, +moonwalk) + equal(+this.field.datetime, +challenger) }) test('sets @showTime true by default', function () { @@ -300,14 +301,14 @@ test('sets @showTime true by default', function () { }) test('sets @showTime false when value is midnight in profile timezone', function () { - this.$field.val('Jan 1, 1970 at 12:00am').change() + this.$field.val('Jan 1, 1990 at 12:00am').change() this.field.parseValue() equal(this.field.showTime, false) }) test('sets @showTime true for midnight if @alwaysShowTime', function () { this.field.alwaysShowTime = true - this.$field.val('Jan 1, 1970 at 12:00am').change() + this.$field.val('Jan 1, 1990 at 12:00am').change() this.field.parseValue() equal(this.field.showTime, true) }) @@ -320,17 +321,17 @@ test('sets @showTime false for non-midnight if not @allowTime', function () { }) test('sets not @blank and not @invalid on valid input', function () { - this.$field.val('Jan 1, 1970 at 12:00am').change() + this.$field.val('Jan 1, 1990 at 12:00am').change() this.field.parseValue() equal(this.field.blank, false) - equal(this.field.invalid, false) + equal(this.field.valid, PARSE_RESULTS.VALID) }) test('sets @blank and not @invalid and null dates when no input', function () { this.$field.val('').change() this.field.parseValue() equal(this.field.blank, true) - equal(this.field.invalid, false) + equal(this.field.valid, PARSE_RESULTS.VALID) equal(this.field.datetime, null) equal(this.field.fudged, null) }) @@ -339,7 +340,7 @@ test('sets @invalid and not @blank and null dates when invalid input', function this.$field.val('invalid').change() this.field.parseValue() equal(this.field.blank, false) - equal(this.field.invalid, true) + equal(this.field.valid, PARSE_RESULTS.ERROR) equal(this.field.datetime, null) equal(this.field.fudged, null) }) @@ -363,18 +364,18 @@ test('interprets bare numbers >= 8 in time-only fields as 24-hour', function () test('interprets time-only fields as occurring on implicit date if set', function () { this.field.showDate = false - this.field.setDate(moonwalk) + this.field.setDate(challenger) this.$field.val('12PM').change() this.field.parseValue() - equal(tz.format(this.field.datetime, '%F %T'), `${tz.format(moonwalk, '%F ')}12:00:00`) + equal(tz.format(this.field.datetime, '%F %T'), `${tz.format(challenger, '%F ')}12:00:00`) }) test('setDate changes the date of an existing time field', function () { this.field.showDate = false - this.field.setDate(moonwalk) + this.field.setDate(challenger) this.$field.val('12PM').change() - this.field.setDate(john_glenn) - equal(tz.format(this.field.datetime, '%F %T'), `${tz.format(john_glenn, '%F ')}12:00:00`) + this.field.setDate(columbia) + equal(tz.format(this.field.datetime, '%F %T'), `${tz.format(columbia, '%F ')}12:00:00`) }) QUnit.module('updateData', { @@ -388,10 +389,10 @@ QUnit.module('updateData', { fakeENV.setup({TIMEZONE: 'America/Detroit'}) this.$field = $('') - this.$field.val('Jan 1, 1970 at 12:01am') + this.$field.val('Jan 1, 1990 at 12:01am') this.field = new DatetimeField(this.$field, {}) - this.field.datetime = moonwalk - this.field.fudged = $.fudgeDateForProfileTimezone(moonwalk) + this.field.datetime = challenger + this.field.fudged = $.fudgeDateForProfileTimezone(challenger) }, teardown() { @@ -407,7 +408,7 @@ test('sets date field to fudged time', function () { test('sets unfudged-date field to actual time', function () { this.field.updateData() - equal(+this.$field.data('unfudged-date'), +moonwalk) + equal(+this.$field.data('unfudged-date'), +challenger) }) test('sets invalid field', function () { @@ -428,16 +429,16 @@ test('sets value of hiddenInput, if present, to fudged time as ISO8601', functio test('sets time-* to fudged, 12-hour values', function () { this.field.updateData() - equal(this.$field.data('time-hour'), '9') - equal(this.$field.data('time-minute'), '56') - equal(this.$field.data('time-ampm'), 'PM') + equal(this.$field.data('time-hour'), '11') + equal(this.$field.data('time-minute'), '39') + equal(this.$field.data('time-ampm'), 'AM') }) test('sets time-* to fudged, 24-hour values', function () { ENV.LOCALE = 'pt-BR' this.field.updateData() - equal(this.$field.data('time-hour'), '21') - equal(this.$field.data('time-minute'), '56') + equal(this.$field.data('time-hour'), '11') + equal(this.$field.data('time-minute'), '39') equal(this.$field.data('time-ampm'), null) }) @@ -458,7 +459,7 @@ test('clear time-* to null if blank', function () { }) test('clear time-* to null if invalid', function () { - this.field.invalid = true + this.field.valid = PARSE_RESULTS.ERROR this.field.updateData() equal(this.$field.data('time-hour'), null) }) @@ -510,7 +511,7 @@ test('omits course suggest text if formatSuggestContext is empty', function () { test('adds invalid_datetime class to suggest if invalid', function () { this.field.updateSuggest() ok(!this.field.$suggest.hasClass('invalid_datetime')) - this.field.invalid = true + this.field.valid = PARSE_RESULTS.ERROR this.field.updateSuggest() ok(this.field.$suggest.hasClass('invalid_datetime')) }) @@ -533,6 +534,12 @@ test('should alert screenreader on an invalid parse no matter what', function () ok(this.field.debouncedSRFME.withArgs("That's not a date!").called) }) +test('should alert on an impossible year entered', function () { + this.$field.val('Jul 19 1964') + this.$field.change() + ok(this.field.debouncedSRFME.withArgs('Year is too far in the past.').called) +}) + test('flashes suggest text to screenreader on typed input', function () { const value = 'suggested value' this.field.formatSuggest = () => value @@ -573,7 +580,7 @@ QUnit.module('formatSuggest', { }) fakeENV.setup({TIMEZONE: 'America/Detroit'}) this.$field = $('') - this.$field.val('Jul 20, 1969 at 9:56pm') + this.$field.val('Jan 28, 1986 at 11:39am') this.field = new DatetimeField(this.$field, {}) }, @@ -584,7 +591,7 @@ QUnit.module('formatSuggest', { }) test('returns result formatted in profile timezone', function () { - equal(this.field.formatSuggest(), 'Sun, Jul 20, 1969, 9:56 PM') + equal(this.field.formatSuggest(), 'Tue, Jan 28, 1986, 11:39 AM') }) test('returns "" if @blank', function () { @@ -593,23 +600,23 @@ test('returns "" if @blank', function () { }) test('returns error message if @invalid', function () { - this.field.invalid = true + this.field.valid = PARSE_RESULTS.ERROR equal(this.field.formatSuggest(), this.field.parseError) }) test('returns date only if @showTime false', function () { this.field.showTime = false - equal(this.field.formatSuggest(), 'Sun, Jul 20, 1969') + equal(this.field.formatSuggest(), 'Tue, Jan 28, 1986') }) test('returns time only if @showDate false', function () { this.field.showDate = false - equal(this.field.formatSuggest(), '9:56 PM') + equal(this.field.formatSuggest(), '11:39 AM') }) test('localizes formatting of dates and times', function () { ENV.LOCALE = 'pt-BR' - equal(this.field.formatSuggest(), 'dom., 20 de jul. de 1969, 21:56') + equal(this.field.formatSuggest(), 'ter., 28 de jan. de 1986, 11:39') }) QUnit.module('formatSuggestContext', { @@ -623,7 +630,7 @@ QUnit.module('formatSuggestContext', { }) fakeENV.setup({TIMEZONE: 'America/Detroit', CONTEXT_TIMEZONE: 'America/Juneau'}) this.$field = $('') - this.$field.val('Jul 20, 1969 at 9:56pm') + this.$field.val('Jan 28, 1986 at 11:39am') this.field = new DatetimeField(this.$field, {}) }, @@ -634,7 +641,7 @@ QUnit.module('formatSuggestContext', { }) test('returns result formatted in course timezone', function () { - equal(this.field.formatSuggestContext(), 'Sun, Jul 20, 1969, 7:56 PM') + equal(this.field.formatSuggestContext(), 'Tue, Jan 28, 1986, 7:39 AM') }) test('returns "" if @blank', function () { @@ -643,7 +650,7 @@ test('returns "" if @blank', function () { }) test('returns "" if @invalid', function () { - this.field.invalid = true + this.field.valid = PARSE_RESULTS.ERROR equal(this.field.formatSuggestContext(), '') }) @@ -654,7 +661,7 @@ test('returns "" if @showTime false', function () { test('returns time only if @showDate false', function () { this.field.showDate = false - equal(this.field.formatSuggestContext(), '7:56 PM') + equal(this.field.formatSuggestContext(), '7:39 AM') }) QUnit.module('normalizeValue', { @@ -740,30 +747,30 @@ test('sets to blank with null value', function () { equal(this.field.datetime, null) equal(this.field.fudged, null) equal(this.field.blank, true) - equal(this.field.invalid, false) + equal(this.field.valid, PARSE_RESULTS.VALID) equal(this.$field.val(), '') }) test('treats value as unfudged', function () { - this.field.setFormattedDatetime(moonwalk, DATETIME_FORMAT_OPTIONS) - equal(+this.field.datetime, +moonwalk) - equal(+this.field.fudged, +$.fudgeDateForProfileTimezone(moonwalk)) + this.field.setFormattedDatetime(challenger, DATETIME_FORMAT_OPTIONS) + equal(+this.field.datetime, +challenger) + equal(+this.field.fudged, +$.fudgeDateForProfileTimezone(challenger)) equal(this.field.blank, false) - equal(this.field.invalid, false) - equal(this.$field.val(), 'Sun, Jul 20, 1969, 9:56 PM') + equal(this.field.valid, PARSE_RESULTS.VALID) + equal(this.$field.val(), 'Tue, Jan 28, 1986, 11:39 AM') }) test('formats value into val() according to date/time requests', function () { - this.field.setFormattedDatetime(moonwalk, DATE_FORMAT_OPTIONS) - equal(this.$field.val(), 'Sun, Jul 20, 1969') - this.field.setFormattedDatetime(moonwalk, TIME_FORMAT_OPTIONS) - equal(this.$field.val(), '9:56 PM') + this.field.setFormattedDatetime(challenger, DATE_FORMAT_OPTIONS) + equal(this.$field.val(), 'Tue, Jan 28, 1986') + this.field.setFormattedDatetime(challenger, TIME_FORMAT_OPTIONS) + equal(this.$field.val(), '11:39 AM') }) test('localizes value', function () { ENV.LOCALE = 'de' - this.field.setFormattedDatetime(moonwalk, DATETIME_FORMAT_OPTIONS) - equal(this.$field.val(), 'So., 20. Juli 1969, 21:56') + this.field.setFormattedDatetime(challenger, DATETIME_FORMAT_OPTIONS) + equal(this.$field.val(), 'Di., 28. Jan. 1986, 11:39') }) QUnit.module('setDate/setTime/setDatetime', { @@ -786,16 +793,16 @@ QUnit.module('setDate/setTime/setDatetime', { }) test('setDate formats into val() with just date', function () { - this.field.setDate(moonwalk) - equal(this.$field.val(), 'Sun, Jul 20, 1969') + this.field.setDate(challenger) + equal(this.$field.val(), 'Tue, Jan 28, 1986') }) test('setTime formats into val() with just time', function () { - this.field.setTime(moonwalk) - equal(this.$field.val(), '9:56 PM') + this.field.setTime(challenger) + equal(this.$field.val(), '11:39 AM') }) test('setDatetime formats into val() with full date and time', function () { - this.field.setDatetime(moonwalk) - equal(this.$field.val(), 'Sun, Jul 20, 1969, 9:56 PM') + this.field.setDatetime(challenger) + equal(this.$field.val(), 'Tue, Jan 28, 1986, 11:39 AM') }) diff --git a/ui/features/course_settings/react/components/CourseAvailabilityOptions.jsx b/ui/features/course_settings/react/components/CourseAvailabilityOptions.jsx index 426957220fa..687887283aa 100644 --- a/ui/features/course_settings/react/components/CourseAvailabilityOptions.jsx +++ b/ui/features/course_settings/react/components/CourseAvailabilityOptions.jsx @@ -79,9 +79,9 @@ export default function CourseAvailabilityOptions({canManage, viewPastLocked, vi const formatDate = date => tz.format(date, 'date.formats.full') - const parseDate = (date, tz) => { + const parseDate = (date, originTZ) => { const dateObj = new Date(date) - const parsedDate = changeTimezone(dateObj, {originTZ: tz, desiredTZ: ENV.TIMEZONE}) + const parsedDate = changeTimezone(dateObj, {originTZ, desiredTZ: ENV.TIMEZONE}) return formatDate(parsedDate) } diff --git a/ui/shared/datetime/jquery/DatetimeField.js b/ui/shared/datetime/jquery/DatetimeField.js index 291bdf55e47..1d80fa9a3fd 100644 --- a/ui/shared/datetime/jquery/DatetimeField.js +++ b/ui/shared/datetime/jquery/DatetimeField.js @@ -40,14 +40,23 @@ const DATE_FORMAT_OPTIONS = { year: 'numeric', } +const EARLIEST_YEAR = 1980 // do not allow any manually entered year before this + +const PARSE_RESULTS = { + VALID: 0, + ERROR: 1, + BAD_YEAR: 2, +} + const DATETIME_FORMAT_OPTIONS = {...DATE_FORMAT_OPTIONS, ...TIME_FORMAT_OPTIONS} Object.freeze(TIME_FORMAT_OPTIONS) Object.freeze(DATE_FORMAT_OPTIONS) Object.freeze(DATETIME_FORMAT_OPTIONS) +Object.freeze(PARSE_RESULTS) // for tests only -export {TIME_FORMAT_OPTIONS, DATE_FORMAT_OPTIONS, DATETIME_FORMAT_OPTIONS} +export {TIME_FORMAT_OPTIONS, DATE_FORMAT_OPTIONS, DATETIME_FORMAT_OPTIONS, PARSE_RESULTS} function formatter(zone, formatOptions = DATETIME_FORMAT_OPTIONS) { const options = {...formatOptions} @@ -149,6 +158,10 @@ export default class DatetimeField { } } + invalid() { + return this.valid !== PARSE_RESULTS.VALID + } + processTimeOptions(options) { // default undefineds to false let {timeOnly, dateOnly} = options @@ -285,26 +298,29 @@ export default class DatetimeField { } parseValue(val) { + const previousDate = this.datetime if (typeof val === 'undefined' && this.$field.data('inputdate')) { const inputdate = this.$field.data('inputdate') this.datetime = inputdate instanceof Date ? inputdate : new Date(inputdate) this.blank = false - this.invalid = this.datetime === null + this.valid = PARSE_RESULTS.VALID + if (this.datetime === null) this.valid = PARSE_RESULTS.ERROR + if (this.datetime && this.datetime.getFullYear() < EARLIEST_YEAR) + this.valid = PARSE_RESULTS.BAD_YEAR this.$field.data('inputdate', null) } else { - const previousDate = this.datetime - if (val) { - this.setFormattedDatetime(val, TIME_FORMAT_OPTIONS) - } + if (val) this.setFormattedDatetime(val, this.intlFormatType()) const value = this.normalizeValue(this.$field.val()) this.datetime = tz.parse(value) this.blank = !value - this.invalid = !this.blank && this.datetime === null - // If the date is invalid, revert to the previous date - if (this.invalid) { - this.datetime = previousDate - } + this.valid = PARSE_RESULTS.VALID + if (!this.blank && this.datetime === null) this.valid = PARSE_RESULTS.ERROR + if (this.datetime && this.datetime.getFullYear() < EARLIEST_YEAR) + this.valid = PARSE_RESULTS.BAD_YEAR } + // If the date is invalid, revert to the previous date + if (this.invalid()) this.datetime = previousDate + if (this.datetime && !this.showDate && this.implicitDate) { this.datetime = tz.mergeTimeAndDate(this.datetime, this.implicitDate) } @@ -326,7 +342,7 @@ export default class DatetimeField { this.fudged = null this.$field.val('') } - this.invalid = false + this.valid = PARSE_RESULTS.VALID this.showTime = this.alwaysShowTime || (this.allowTime && !tz.isMidnight(this.datetime)) this.update() this.updateSuggest(false) @@ -344,7 +360,7 @@ export default class DatetimeField { date: this.fudged, iso8601, blank: this.blank, - invalid: this.invalid, + invalid: this.invalid(), }) if (this.$hiddenInput) { @@ -354,7 +370,7 @@ export default class DatetimeField { // date_fields and time_fields don't have timepicker data fields if (!(this.showDate && this.allowTime)) return - if (this.invalid || this.blank || !this.showTime) { + if (this.invalid() || this.blank || !this.showTime) { this.$field.data({ 'time-hour': null, 'time-minute': null, @@ -384,8 +400,8 @@ export default class DatetimeField { } this.$contextSuggest.text(contextText).show() } - this.$suggest.toggleClass('invalid_datetime', this.invalid).text(localText) - if (show || this.$contextSuggest || this.invalid) { + this.$suggest.toggleClass('invalid_datetime', this.invalid()).text(localText) + if (show || this.$contextSuggest || this.invalid()) { this.$suggest.show() return } @@ -407,7 +423,7 @@ export default class DatetimeField { } updateAria() { - this.$field.attr('aria-invalid', !!this.invalid) + this.$field.attr('aria-invalid', this.invalid()) } intlFormatType() { @@ -417,13 +433,13 @@ export default class DatetimeField { } formatSuggest() { - if (this.invalid) return this.parseError + if (this.invalid()) return this.parseError if (this.blank) return '' return formatter(ENV.TIMEZONE, this.intlFormatType()).format(this.datetime) } formatSuggestContext() { - if (this.invalid || !this.showTime || this.blank) return '' + if (this.invalid() || !this.showTime || this.blank) return '' return formatter(this.contextTimezone, this.intlFormatType()).format(this.datetime) } @@ -438,6 +454,7 @@ export default class DatetimeField { } get parseError() { + if (this.valid === PARSE_RESULTS.BAD_YEAR) return I18n.t('Year is too far in the past.') return I18n.t('errors.not_a_date', "That's not a date!") } } diff --git a/ui/shared/datetime/react/components/DateInput.tsx b/ui/shared/datetime/react/components/DateInput.tsx index a2fa7f00405..839fd99f42f 100644 --- a/ui/shared/datetime/react/components/DateInput.tsx +++ b/ui/shared/datetime/react/components/DateInput.tsx @@ -49,6 +49,8 @@ type BlurReturn = SyntheticEvent | KeyboardEvent const I18n = useI18nScope('app_shared_components_canvas_date_time') +const EARLIEST_YEAR = 1980 // do not allow any manually entered year before this + export type CanvasDateInputProps = { /** * Represents the initial date to be selected. May be `undefined` for no selected date. @@ -288,10 +290,22 @@ export default function CanvasDateInput({ if (isShowingCalendar && withRunningValue) handleHideCalendar() const newDate = tz.parse(value, timezone) if (newDate) { + const year = newDate.getFullYear() + if (year < EARLIEST_YEAR) { + setInternalMessages([ + { + type: 'error', + text: I18n.t('Year %{year} is too far in the past', {year: String(year)}), + }, + ]) + return + } const msgs: Messages = withRunningValue ? [{type: 'success', text: formatDate(newDate)}] : [] setRenderedMoment(moment.tz(newDate, timezone)) setInternalMessages(msgs) - } else if (value === '') { + return + } + if (value === '') { setInternalMessages([]) } else { const text = invalidText(value)