From 63eda4adc95c3c82f577d1e33113bbe4422dbfe6 Mon Sep 17 00:00:00 2001 From: Samir Kamal <1954121+skamril@users.noreply.github.com> Date: Thu, 16 May 2024 12:39:13 +0200 Subject: [PATCH 1/3] feat(ui-utils): add overload signatures for `validateNumber` function in validationUtils --- webapp/src/utils/validationUtils.ts | 44 ++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/webapp/src/utils/validationUtils.ts b/webapp/src/utils/validationUtils.ts index 5b3f60091d..5760f285ae 100644 --- a/webapp/src/utils/validationUtils.ts +++ b/webapp/src/utils/validationUtils.ts @@ -4,6 +4,11 @@ import { t } from "i18next"; // Types //////////////////////////////////////////////////////////////// +interface NumberValidationOptions { + min?: number; + max?: number; +} + interface ValidationOptions { existingValues?: string[]; excludedValues?: string[]; @@ -153,22 +158,47 @@ export function validatePassword(password: string): string | true { /** * Validates a number against specified numerical limits. * + * @example + * validateNumber(5, { min: 0, max: 10 }); // true + * validateNumber(9, { min: 10, max: 20 }); // Error message + * + * + * @example With currying. + * const fn = validateNumber({ min: 0, max: 10 }); + * fn(5); // true + * fn(11); // Error message + * * @param value - The number to validate. - * @param options - Configuration options for validation including min and max values. (Optional) - * @param [options.min=Number.MIN_SAFE_INTEGER] - Minimum allowed value for the number. - * @param [options.max=Number.MAX_SAFE_INTEGER] - Maximum allowed value for the number. + * @param [options] - Configuration options for validation. + * @param [options.min=Number.MIN_SAFE_INTEGER] - Minimum allowed value. + * @param [options.max=Number.MAX_SAFE_INTEGER] - Maximum allowed value. * @returns True if validation is successful, or a localized error message if it fails. */ export function validateNumber( value: number, - options?: ValidationOptions, -): string | true { - if (typeof value !== "number" || isNaN(value) || !isFinite(value)) { + options?: NumberValidationOptions, +): string | true; + +export function validateNumber( + options?: NumberValidationOptions, +): (value: number) => string | true; + +export function validateNumber( + valueOrOpts?: number | NumberValidationOptions, + options: NumberValidationOptions = {}, +): (string | true) | ((value: number) => string | true) { + if (typeof valueOrOpts !== "number") { + return (v: number) => validateNumber(v, valueOrOpts); + } + + const value = valueOrOpts; + + if (!isFinite(value)) { return t("form.field.invalidNumber", { value }); } const { min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER } = - options || {}; + options; if (value < min) { return t("form.field.minValue", { 0: min }); From 430d88bad3f488162fc08a298195a9d20c6d4e2c Mon Sep 17 00:00:00 2001 From: Samir Kamal <1954121+skamril@users.noreply.github.com> Date: Wed, 15 May 2024 14:07:19 +0200 Subject: [PATCH 2/3] style(ui-thermals): use curry version of `validateNumber` --- .../Modelization/Areas/Thermal/Fields.tsx | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/webapp/src/components/App/Singlestudy/explore/Modelization/Areas/Thermal/Fields.tsx b/webapp/src/components/App/Singlestudy/explore/Modelization/Areas/Thermal/Fields.tsx index 15f67cdb41..b553152ab8 100644 --- a/webapp/src/components/App/Singlestudy/explore/Modelization/Areas/Thermal/Fields.tsx +++ b/webapp/src/components/App/Singlestudy/explore/Modelization/Areas/Thermal/Fields.tsx @@ -74,7 +74,7 @@ function Fields() { name="unitCount" control={control} rules={{ - validate: (v) => validateNumber(v, { min: 1 }), + validate: validateNumber({ min: 1 }), setValueAs: Math.floor, }} /> @@ -83,7 +83,7 @@ function Fields() { name="nominalCapacity" control={control} rules={{ - validate: (v) => validateNumber(v, { min: 0 }), + validate: validateNumber({ min: 0 }), }} /> validateNumber(v, { min: 0, max: 100 }), + validate: validateNumber({ min: 0, max: 100 }), }} /> validateNumber(v, { min: 1, max: 168 }), + validate: validateNumber({ min: 1, max: 168 }), setValueAs: Math.floor, }} /> @@ -113,7 +113,7 @@ function Fields() { name="minDownTime" control={control} rules={{ - validate: (v) => validateNumber(v, { min: 1, max: 168 }), + validate: validateNumber({ min: 1, max: 168 }), setValueAs: Math.floor, }} /> @@ -134,7 +134,7 @@ function Fields() { name="efficiency" control={control} rules={{ - validate: (v) => validateNumber(v, { min: 0 }), + validate: validateNumber({ min: 0 }), }} disabled={!isTSCost} /> @@ -143,7 +143,7 @@ function Fields() { name="marginalCost" control={control} rules={{ - validate: (v) => validateNumber(v, { min: 0 }), + validate: validateNumber({ min: 0 }), }} /> @@ -152,7 +152,7 @@ function Fields() { name="startupCost" control={control} rules={{ - validate: (v) => validateNumber(v, { min: 0 }), + validate: validateNumber({ min: 0 }), }} /> validateNumber(v, { min: 0 }), + validate: validateNumber({ min: 0 }), }} /> validateNumber(v, { min: 0 }), + validate: validateNumber({ min: 0 }), }} /> validateNumber(v, { min: 0 }), + validate: validateNumber({ min: 0 }), }} disabled={!isTSCost} /> @@ -196,7 +196,7 @@ function Fields() { name={name} control={control} rules={{ - validate: (v) => validateNumber(v, { min: 0 }), + validate: validateNumber({ min: 0 }), }} /> ), @@ -218,7 +218,7 @@ function Fields() { name="volatilityForced" control={control} rules={{ - validate: (v) => validateNumber(v, { min: 0, max: 1 }), + validate: validateNumber({ min: 0, max: 1 }), }} inputProps={{ step: 0.1 }} /> @@ -227,7 +227,7 @@ function Fields() { name="volatilityPlanned" control={control} rules={{ - validate: (v) => validateNumber(v, { min: 0, max: 1 }), + validate: validateNumber({ min: 0, max: 1 }), }} inputProps={{ step: 0.1 }} /> From 6afb77cfd697b901073e0fc979a52cd50e22e05b Mon Sep 17 00:00:00 2001 From: Samir Kamal <1954121+skamril@users.noreply.github.com> Date: Thu, 16 May 2024 12:18:17 +0200 Subject: [PATCH 3/3] fix(ui-utils): change error message for string length in validationUtils --- webapp/public/locales/en/main.json | 3 +- webapp/public/locales/fr/main.json | 3 +- .../BindingConstraints/AddDialog.tsx | 2 +- .../BindingConstView/ConstraintFields.tsx | 2 +- webapp/src/utils/validationUtils.ts | 28 +++++++++---------- 5 files changed, 20 insertions(+), 18 deletions(-) diff --git a/webapp/public/locales/en/main.json b/webapp/public/locales/en/main.json index 49ed4ce172..ccfac647f2 100644 --- a/webapp/public/locales/en/main.json +++ b/webapp/public/locales/en/main.json @@ -123,7 +123,8 @@ "form.asyncDefaultValues.error": "Failed to get values", "form.field.required": "Field required", "form.field.duplicate": "Value already exists", - "form.field.minLength": "{{0}} character(s) minimum", + "form.field.minLength": "{{length}} character(s) minimum", + "form.field.maxLength": "{{length}} character(s) maximum", "form.field.minValue": "The minimum value is {{0}}", "form.field.maxValue": "The maximum value is {{0}}", "form.field.invalidNumber": "Invalid number", diff --git a/webapp/public/locales/fr/main.json b/webapp/public/locales/fr/main.json index 21085ed4bd..ef12be54ec 100644 --- a/webapp/public/locales/fr/main.json +++ b/webapp/public/locales/fr/main.json @@ -123,7 +123,8 @@ "form.asyncDefaultValues.error": "Impossible d'obtenir les valeurs", "form.field.required": "Champ requis", "form.field.duplicate": "Cette valeur existe déjà", - "form.field.minLength": "{{0}} caractère(s) minimum", + "form.field.minLength": "{{length}} caractère(s) minimum", + "form.field.maxLength": "{{length}} caractère(s) maximum", "form.field.minValue": "La valeur minimum est {{0}}", "form.field.maxValue": "La valeur maximum est {{0}}", "form.field.invalidNumber": "Nombre invalide", diff --git a/webapp/src/components/App/Singlestudy/explore/Modelization/BindingConstraints/AddDialog.tsx b/webapp/src/components/App/Singlestudy/explore/Modelization/BindingConstraints/AddDialog.tsx index f1af440491..6891123b8c 100644 --- a/webapp/src/components/App/Singlestudy/explore/Modelization/BindingConstraints/AddDialog.tsx +++ b/webapp/src/components/App/Singlestudy/explore/Modelization/BindingConstraints/AddDialog.tsx @@ -157,7 +157,7 @@ function AddDialog({ rules={{ validate: (v) => validateString(v, { - max: 20, + maxLength: 20, specialChars: "-", }), }} diff --git a/webapp/src/components/App/Singlestudy/explore/Modelization/BindingConstraints/BindingConstView/ConstraintFields.tsx b/webapp/src/components/App/Singlestudy/explore/Modelization/BindingConstraints/BindingConstView/ConstraintFields.tsx index 3405540a6e..7677a78c4f 100644 --- a/webapp/src/components/App/Singlestudy/explore/Modelization/BindingConstraints/BindingConstView/ConstraintFields.tsx +++ b/webapp/src/components/App/Singlestudy/explore/Modelization/BindingConstraints/BindingConstView/ConstraintFields.tsx @@ -90,7 +90,7 @@ function Fields({ study, constraintId }: Props) { rules={{ validate: (v) => validateString(v, { - max: 20, + maxLength: 20, specialChars: "-", }), }} diff --git a/webapp/src/utils/validationUtils.ts b/webapp/src/utils/validationUtils.ts index 5760f285ae..86fb294d8b 100644 --- a/webapp/src/utils/validationUtils.ts +++ b/webapp/src/utils/validationUtils.ts @@ -9,7 +9,7 @@ interface NumberValidationOptions { max?: number; } -interface ValidationOptions { +interface StringValidationOptions { existingValues?: string[]; excludedValues?: string[]; isCaseSensitive?: boolean; @@ -17,8 +17,8 @@ interface ValidationOptions { specialChars?: string; allowSpaces?: boolean; editedValue?: string; - min?: number; - max?: number; + minLength?: number; + maxLength?: number; } //////////////////////////////////////////////////////////////// @@ -40,13 +40,13 @@ interface ValidationOptions { * @param [options.specialChars="&()_-"] - A string representing additional allowed characters outside the typical alphanumeric scope. * @param [options.allowSpaces=true] - Flags if spaces are allowed in the value. * @param [options.editedValue=""] - The current value being edited, to exclude it from duplicate checks. - * @param [options.min=0] - Minimum length required for the string. Defaults to 0. - * @param [options.max=255] - Maximum allowed length for the string. Defaults to 255. + * @param [options.minLength=0] - Minimum length required for the string. Defaults to 0. + * @param [options.maxLength=255] - Maximum allowed length for the string. Defaults to 255. * @returns True if validation is successful, or a localized error message if it fails. */ export function validateString( value: string, - options?: ValidationOptions, + options?: StringValidationOptions, ): string | true { const { existingValues = [], @@ -56,8 +56,8 @@ export function validateString( allowSpaces = true, specialChars = "&()_-", editedValue = "", - min = 0, - max = 255, + minLength = 0, + maxLength = 255, } = options || {}; const trimmedValue = value.trim(); @@ -70,12 +70,12 @@ export function validateString( return t("form.field.spacesNotAllowed"); } - if (trimmedValue.length < min) { - return t("form.field.minValue", { 0: min }); + if (trimmedValue.length < minLength) { + return t("form.field.minLength", { length: minLength }); } - if (trimmedValue.length > max) { - return t("form.field.maxValue", { 0: max }); + if (trimmedValue.length > maxLength) { + return t("form.field.maxLength", { length: maxLength }); } // Compiles a regex pattern based on allowed characters and flags. @@ -129,11 +129,11 @@ export function validatePassword(password: string): string | true { } if (trimmedPassword.length < 8) { - return t("form.field.minValue", { 0: 8 }); + return t("form.field.minLength", { length: 8 }); } if (trimmedPassword.length > 50) { - return t("form.field.maxValue", { 0: 50 }); + return t("form.field.maxLength", { length: 50 }); } if (!/[a-z]/.test(trimmedPassword)) {