diff --git a/package.json b/package.json index 8f13f298..c0d4f201 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "simulator", - "version": "2.0.1", + "version": "2.0.2", "sideEffects": false, "main": "dist/index.js", "author": "KISS Institute for Practical Robotics", diff --git a/src/components/interface/Form.tsx b/src/components/interface/Form.tsx index 78df8f85..be7c6368 100644 --- a/src/components/interface/Form.tsx +++ b/src/components/interface/Form.tsx @@ -230,12 +230,26 @@ namespace Form { } export const IDENTITY_FINALIZER = (value: string) => value; + export const DATE_FINALIZER = (value: string) => { + let valueParts: string[] = []; + const validDelimters = ['/', '-']; + for (const delimiter of validDelimters) { + valueParts = value.split(delimiter); + if (valueParts.length === 3) { + break; + } + } + + const [mm, dd, yyyy] = valueParts; + return `${mm}/${dd}/${yyyy}`; + }; + export const EMAIL_VALIDATOR = (value: string) => Validators.validate(value, Validators.Types.Email); export const PASSWORD_VALIDATOR = (value: string) => Validators.validatePassword(value); export const DATE_VALIDATOR = (value: string) => Validators.validate(value, Validators.Types.Date); export const NON_EMPTY_VALIDATOR = (value: string) => Validators.validate(value, Validators.Types.Length, 1); - + export const email = (id: string, text: string, tooltip?: string, assist?: () => void, assistText?: string): Item => ({ id, text, @@ -262,7 +276,7 @@ namespace Form { text, tooltip, validator: DATE_VALIDATOR, - finalizer: IDENTITY_FINALIZER, + finalizer: DATE_FINALIZER, assist, assistText, }); diff --git a/src/util/Validator.ts b/src/util/Validator.ts index 9081959d..20f8f2a4 100644 --- a/src/util/Validator.ts +++ b/src/util/Validator.ts @@ -150,9 +150,20 @@ export namespace Validators { return value.length >= length; case Types.Email: return /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(value); - case Types.Date: - // TODO: validate that it's a real date (e.g. 02/30/2000 should not pass) - return /^(0[1-9]|1[012])(\/|-)(0[1-9]|[12][0-9]|3[01])(\/|-)(19|20)\d{2}$/.test(value); + case Types.Date: { + // Ensure it matches the expected format + const regexRes = /^(0[1-9]|1[012])(?:\/|-)(0[1-9]|[12][0-9]|3[01])(?:\/|-)((?:19|20)\d{2})$/.exec(value); + if (regexRes === null) return false; + + // Ensure it's a valid date + // Date constructor will rollover invalid dates, like 2024-02-30 to 2024-03-01, so ensure the individual parts didn't change + const [m, d, y] = regexRes.slice(1).map(s => parseInt(s)); + const dateObj = new Date(Date.UTC(y, m - 1, d)); + return !isNaN(dateObj.getTime()) && + dateObj.getUTCFullYear() === y && + (dateObj.getUTCMonth() + 1) === m && + dateObj.getUTCDate() === d; + } default: return false; }