diff --git a/bloques.xml b/bloques.xml
deleted file mode 100644
index ba9b109..0000000
--- a/bloques.xml
+++ /dev/null
@@ -1,354 +0,0 @@
-
-
- The page you're looking for doesn't exist or has been moved. + {t("error_page.description")}
{
@@ -56,7 +55,7 @@ export const LoginPageWithLanguageSelector = () => {
onSuccess: (data) => {
const { success, error } = data;
if (!success && error) {
- form.setError("root", error);
+ form.setError("root", { type: error.name, message: error.message });
}
if (success) {
@@ -76,19 +75,17 @@ export const LoginPageWithLanguageSelector = () => {
email: "",
password: "",
},
- resolver: joiResolver(
- Joi.object({
- email: Joi.string()
- .email({ tlds: { allow: false } })
- .required(),
- password: Joi.string().min(4).alphanum().required(),
- }),
- {
- messages: SpanishJoiMessages,
- }
- ),
+ resolver: joiResolver(createLoginSchema(t)),
});
+ const { getFieldState, trigger } = form;
+ useEffect(() => {
+ const invalidFields = (["email", "password"] as const).filter(
+ (field) => getFieldState(field).invalid
+ );
+ if (invalidFields.length) void trigger(invalidFields);
+ }, [i18n.resolvedLanguage, getFieldState, trigger]);
+
const onSubmit: SubmitHandler
{
+ it.each(["es", "en", "fr", "ca"])("uses %s for every login validation rule", async (lng) => {
+ const i18n = createInstance();
+ await i18n.init({ lng, fallbackLng: false, resources: { es, en, fr, ca } });
+ const schema = createLoginSchema(i18n.t);
+ const valid = { email: "dealer@example.com", password: "abcd1234" };
+ const cases = [
+ { data: { ...valid, email: "" }, key: "email_required" },
+ { data: { password: valid.password }, key: "email_required" },
+ { data: { ...valid, email: "invalid" }, key: "email_invalid" },
+ { data: { ...valid, password: "" }, key: "password_required" },
+ { data: { email: valid.email }, key: "password_required" },
+ { data: { ...valid, password: "abc" }, key: "password_min" },
+ { data: { ...valid, password: "abcd!" }, key: "password_alphanum" },
+ ];
+
+ expect(schema.validate(valid).error).toBeUndefined();
+ for (const { data, key } of cases) {
+ const message = schema.validate(data).error?.details[0].message;
+ expect(message).toBe(i18n.t(`login_page.validation.${key}`, { count: 4 }));
+ expect(message).not.toContain("{{");
+ }
+ });
+
+ it("uses the new language when the resolver schema is rebuilt", async () => {
+ const i18n = createInstance();
+ await i18n.init({ lng: "es", resources: { es, fr } });
+ const invalid = { email: "invalid", password: "abcd1234" };
+ expect(createLoginSchema(i18n.t).validate(invalid).error?.message)
+ .toBe(es.translation.login_page.validation.email_invalid);
+ await i18n.changeLanguage("fr");
+ expect(createLoginSchema(i18n.t).validate(invalid).error?.message)
+ .toBe(fr.translation.login_page.validation.email_invalid);
+ });
+});
diff --git a/client/src/app/auth/loginSchema.ts b/client/src/app/auth/loginSchema.ts
new file mode 100644
index 0000000..fb15ef9
--- /dev/null
+++ b/client/src/app/auth/loginSchema.ts
@@ -0,0 +1,26 @@
+import { TFunction } from "i18next";
+import Joi from "joi";
+
+export const createLoginSchema = (t: TFunction) =>
+ Joi.object({
+ email: Joi.string()
+ .email({ tlds: { allow: false } })
+ .required()
+ .messages({
+ "any.required": t("login_page.validation.email_required"),
+ "string.empty": t("login_page.validation.email_required"),
+ "string.base": t("login_page.validation.email_invalid"),
+ "string.email": t("login_page.validation.email_invalid"),
+ }),
+ password: Joi.string()
+ .min(4)
+ .alphanum()
+ .required()
+ .messages({
+ "any.required": t("login_page.validation.password_required"),
+ "string.empty": t("login_page.validation.password_required"),
+ "string.base": t("login_page.validation.password_alphanum"),
+ "string.min": t("login_page.validation.password_min", { count: 4 }),
+ "string.alphanum": t("login_page.validation.password_alphanum"),
+ }),
+ });
diff --git a/client/src/app/catalog/components/useCatalogTableColumns.tsx b/client/src/app/catalog/components/useCatalogTableColumns.tsx
index 4f0cca5..13570dc 100644
--- a/client/src/app/catalog/components/useCatalogTableColumns.tsx
+++ b/client/src/app/catalog/components/useCatalogTableColumns.tsx
@@ -4,10 +4,12 @@ import { ColumnDef } from "@tanstack/react-table";
import { DataTablaRowActionFunction, DataTableRowActions } from "@/components";
import { Badge } from "@/ui";
import { useMemo } from "react";
+import { useTranslation } from "react-i18next";
export const useCatalogTableColumns = (
actions: DataTablaRowActionFunctionError: {JSON.stringify(error)}
} + {error &&{t("quotes.downloading_dialog.error")}
}${escapeHtml(labels.javascript_required)}
` + ) + .join("\n") + ); + }, + }, { name: "app-build-version", apply: "build", diff --git a/package.json b/package.json index d175b07..b355c69 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "uecko-presupuestador", - "version": "1.2.4", + "version": "1.2.5", "author": "Rodax Software