diff --git a/src/index.ts b/src/index.ts index 2bf02cb..95f6b21 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ export { createForm } from "./factory" +export { createErrorsMap } from "./utils" export { useForm, useField } from "./react-hooks" export { AnyFormValues, @@ -13,5 +14,5 @@ export { ValidationEvent, ValidationResult, FormValues, - Form + Form, } from "./types" diff --git a/src/utils.spec.ts b/src/utils.spec.ts new file mode 100644 index 0000000..fdb7771 --- /dev/null +++ b/src/utils.spec.ts @@ -0,0 +1,79 @@ +import { createEvent } from "effector" +import { createField } from "./field" +import { createErrorsMap } from "./utils" +import { ValidationError } from "./types" + +test("createErrorsMap with field with errors", () => { + const field = createField("email", { + init: "value", + }) + const addError = createEvent() + const resetErrors = createEvent() + field.$errors.on(addError, (errors, error) => [...errors, error]) + field.$errors.on(resetErrors, () => []) + + const error = { + rule: "email", + value: "value", + } + const error2 = { + rule: "email2", + value: "value", + } + + const errorsMap = createErrorsMap({ email: field }) + expect(errorsMap.getState()).toEqual({ email: [] }) + + addError(error) + addError(error2) + + expect(errorsMap.getState()).toEqual({ email: [error, error2] }) + + resetErrors() + expect(errorsMap.getState()).toEqual({ email: [] }) +}) + +test("createErrorsMap with multiple fields", () => { + const field1 = createField("email", { + init: "value", + }) + const field2 = createField("password", { + init: "value", + }) + + const addField1Error = createEvent() + const addField2Error = createEvent() + + const resetErrors = createEvent() + field1.$errors.on(addField1Error, (errors, error) => [...errors, error]) + field2.$errors.on(addField2Error, (errors, error) => [...errors, error]) + field1.$errors.on(resetErrors, () => []) + field2.$errors.on(resetErrors, () => []) + + const errorsMap = createErrorsMap({ email: field1, password: field2 }) + + expect(errorsMap.getState()).toEqual({ email: [], password: [] }) + + const field1Error = { + rule: "email", + value: "value", + } + const field2Error = { + rule: "password", + value: "value", + } + + addField1Error(field1Error) + addField1Error(field1Error) + addField1Error(field1Error) + addField1Error(field1Error) + addField2Error(field2Error) + + expect(errorsMap.getState()).toEqual({ + email: [field1Error, field1Error, field1Error, field1Error], + password: [field2Error], + }) + + resetErrors() + expect(errorsMap.getState()).toEqual({ email: [], password: [] }) +}) diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..e63bba7 --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,21 @@ +import { combine, Store, StoreWritable } from "effector" +import { AnyFormValues, FormFields, ValidationError } from "./types" + +type ErrorsMap = { + [K in keyof Values]: ValidationError[] +} + +export function createErrorsMap( + fields: FormFields +): Store> { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const shape: Record[]>> = {} + + for (const fieldName in fields) { + // eslint-disable-next-line no-prototype-builtins + if (!fields.hasOwnProperty(fieldName)) continue + shape[fieldName] = fields[fieldName].$errors + } + + return combine(shape) as Store> +}