Skip to content

Commit 0190fc5

Browse files
committed
Fix isValid state expression
1 parent 38d349c commit 0190fc5

File tree

3 files changed

+54
-24
lines changed

3 files changed

+54
-24
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@programmer_network/use-ajv-form",
3-
"version": "1.0.13",
3+
"version": "1.0.14",
44
"description": "Custom React Hook that integrates with Ajv JSON Schema Validator",
55
"main": "dist/use-ajv-form.es.js",
66
"author": "Aleksandar Grbic",

src/index.ts

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
import { useState, useEffect, useMemo, useRef } from 'react';
2-
import { getInitial, getValue, getErrors, addUserDefinedKeywords } from './utils';
1+
import { useEffect, useMemo, useRef, useState } from 'react';
2+
import { addUserDefinedKeywords, getErrors, getInitial, getValue } from './utils';
33
import { ajv } from './utils/validation';
44

5+
import { ErrorObject, JSONSchemaType, KeywordDefinition } from 'ajv';
6+
import { useDebounce } from './Hooks/useDebounce';
57
import {
68
AJVMessageFunction,
79
FormField,
810
IState,
9-
useFormErrors,
1011
UseFormReturn,
12+
useFormErrors,
1113
} from './utils/types';
12-
import { ErrorObject, JSONSchemaType, KeywordDefinition } from 'ajv';
13-
import { useDebounce } from './Hooks/useDebounce';
1414

1515
const useAJVForm = <T extends Record<string, any>>(
1616
initial: T,
@@ -41,17 +41,7 @@ const useAJVForm = <T extends Record<string, any>>(
4141
const AJVValidate = ajv.compile(schema);
4242

4343
const resetForm = () => {
44-
setState(
45-
Object.keys(state).reduce((acc, name) => {
46-
return {
47-
...acc,
48-
[name]: {
49-
value: '',
50-
error: '',
51-
},
52-
};
53-
}, {} as IState<T>),
54-
);
44+
setState(initialStateRef.current);
5545
};
5646

5747
const validateField = (fieldName: keyof T) => {
@@ -93,6 +83,7 @@ const useAJVForm = <T extends Record<string, any>>(
9383
name: Object.keys(form)[0] as keyof T,
9484
editId: editCounter,
9585
});
86+
9687
setEditCounter(editCounter + 1);
9788

9889
return newState;
@@ -144,6 +135,11 @@ const useAJVForm = <T extends Record<string, any>>(
144135

145136
return { isValid: false, data: null };
146137
}
138+
139+
if (!isFormValid(state, initialStateRef.current)) {
140+
return { isValid: false, data: null };
141+
}
142+
147143
return { isValid: true, data };
148144
} catch (error) {
149145
return { isValid: false, data: null };
@@ -159,10 +155,23 @@ const useAJVForm = <T extends Record<string, any>>(
159155
);
160156
};
161157

162-
const isFormValid = (currentState: IState<T>): boolean => {
163-
return !Object.keys(currentState).some((key) => currentState[key].error !== '');
158+
const isFormValid = (
159+
currentState: IState<T>,
160+
initialState: IState<T>,
161+
): boolean => {
162+
const hasErrors = Object.keys(currentState).some(
163+
(key) => currentState[key].error !== '',
164+
);
165+
166+
const formIsDirty = isFormDirty(currentState, initialState);
167+
168+
return !hasErrors && formIsDirty;
164169
};
165170

171+
const isValid = useMemo(() => {
172+
return isFormValid(state, initialStateRef.current);
173+
}, [state]);
174+
166175
const isDirty = useMemo(
167176
() => isFormDirty(state, initialStateRef.current),
168177
[state],
@@ -172,8 +181,6 @@ const useAJVForm = <T extends Record<string, any>>(
172181
setState(_setErrors(getErrors(errors, options?.userDefinedMessages)));
173182
};
174183

175-
const isValid = useMemo(() => isFormValid(state), [state]);
176-
177184
useEffect(() => {
178185
if (options?.shouldDebounceAndValidate === false || !debouncedField) {
179186
return;

src/useAjvForm.test.tsx

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { act, renderHook } from '@testing-library/react-hooks';
2-
import useAJVForm from '.';
32
import { JSONSchemaType } from 'ajv';
43
import { vi } from 'vitest';
4+
import useAJVForm from '.';
55

66
// @ts-expect-error - Currently, there is no type definition for this package.
77
import programmerNetworkAjv from 'programmer-network-ajv';
@@ -106,7 +106,7 @@ describe('useAJVForm', () => {
106106

107107
result.current.reset();
108108

109-
expect(result.current.state.title.value).toBe('');
109+
expect(result.current.state.title.value).toBe('Hello');
110110
});
111111

112112
it('validates the form correctly', () => {
@@ -121,13 +121,36 @@ describe('useAJVForm', () => {
121121

122122
const { result } = renderHook(() => useAJVForm(initialData, schema));
123123

124-
result.current.set({ title: '' });
124+
result.current.set({ title: 'Foo' });
125125

126126
const validation = result.current.validate();
127127

128128
expect(validation.isValid).toBe(true);
129129
});
130130

131+
it('isValid should be false when the initial state is set or when reset is called', () => {
132+
const initialData = { title: 'Foo' };
133+
const schema: JSONSchemaType<{ title: string }> = {
134+
type: 'object',
135+
required: ['title'],
136+
properties: {
137+
title: { type: 'string' },
138+
},
139+
};
140+
141+
const { result } = renderHook(() => useAJVForm(initialData, schema));
142+
143+
expect(result.current.validate().isValid).toBe(false);
144+
145+
result.current.set({ title: 'Bar' });
146+
147+
expect(result.current.validate().isValid).toBe(true);
148+
149+
result.current.reset();
150+
151+
expect(result.current.validate().isValid).toBe(false);
152+
});
153+
131154
it('validates minLength and maxLength for title', () => {
132155
const initialData = { title: '' };
133156
const schema: JSONSchemaType<{

0 commit comments

Comments
 (0)