-
Notifications
You must be signed in to change notification settings - Fork 0
/
useForm.js
118 lines (98 loc) · 3.17 KB
/
useForm.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import { useState } from "react";
// FormEasy v0.1 - lightning fast
// [ ] TODO feat: spread input attributes in the subscribe function
// [ ] TODO feat: handle errors if validation is not set properly
// [ ] TODO feat: add uncontrolled form option
const useForm = (yup) => {
const [values, setValues] = useState({});
const [errors, setErrors] = useState({});
let schema;
let initialValues;
const _getValidationErrors = async ({ schema, values }) => {
let validationErrors = [];
try {
await yup.object().shape(schema).validate(values, { abortEarly: false });
validationErrors = Object.keys(values).reduce(
(prev, key) => ({ ...prev, [key]: [] }),
{}
);
} catch (err) {
validationErrors = err.inner.reduce(
(prev, curr) => ({
...prev,
[curr.path]: [...(prev[curr.path] || []), curr.message],
}),
{}
);
}
return validationErrors;
};
const _sanitizeFormErrors = (errors) => {
return Object.keys(errors).reduce((prev, fieldName) => {
if (errors[fieldName].length > 0) {
return { ...prev, [fieldName]: errors[fieldName] };
} else {
return { ...prev };
}
}, {});
};
const _handleInputBlur = (e) => {
_validateField(e.target.name, e.target.value);
};
const _handleInputChange = (e) => {
const fieldName = e.target.name;
const fieldValue = e.target.value;
const fieldHasErrors = errors[fieldName] && errors[fieldName].length > 0;
if (fieldHasErrors) _validateField(fieldName, fieldValue);
setValues((prev) => ({ ...prev, [fieldName]: fieldValue }));
};
const _validateField = async (fieldName, fieldValue) => {
const validationErrors = await _getValidationErrors({
schema: { [fieldName]: schema[fieldName] },
values: { [fieldName]: fieldValue },
});
setErrors((prev) => _sanitizeFormErrors({ ...prev, ...validationErrors }));
};
const _validateForm = async () => {
const currentValues = { ...initialValues, ...values };
const validationErrors = await _getValidationErrors({
schema: schema,
values: currentValues,
});
setErrors((prev) => _sanitizeFormErrors({ ...prev, ...validationErrors }));
const formIsValid = Object.keys(validationErrors).reduce(
(prev, fieldName) => validationErrors[fieldName].length === 0,
false
);
return formIsValid;
};
const onSubmit = (handleSubmit) => ({
onSubmit: async (e) => {
e.preventDefault();
const validForm = await _validateForm();
if (!validForm) return;
handleSubmit(e);
},
});
const subscribe = (field) => {
const fieldName = field.attribute.name;
initialValues = { ...initialValues, [fieldName]: field.initialValue || "" };
schema = { ...schema, [fieldName]: field.validation };
return {
name: fieldName,
label: field.attribute.label,
type: field.attribute.type,
value: values[fieldName] || initialValues[fieldName],
onChange: _handleInputChange,
errors: errors[fieldName],
onBlur: _handleInputBlur,
};
};
return {
subscribe,
onSubmit,
values,
errors,
};
};
export default useForm;