@s-chat/form-manager
Version:
150 lines • 5.49 kB
JavaScript
// External
import { useContext, useState, useRef, useMemo, useEffect } from 'react';
import { Validator } from 'livr';
import extraRules from 'livr-extra-rules';
// Internal
import { FormManagerContext } from '../context/FormManager';
export const useFormManager = (fields, hookOptions = {}) => {
const formManagerCTX = useContext(FormManagerContext);
const options = { ...formManagerCTX.options, ...hookOptions };
Validator.defaultAutoTrim(true);
Validator.registerDefaultRules(extraRules);
Validator.registerDefaultRules(formManagerCTX.customValidationRules);
const [timeStamp, setTimeStamp] = useState(Date.now());
const formFieldsData = Object.keys(fields).map((fieldName) => {
const key = fieldName;
const field = fields[key];
const originalType = field.type;
const valueRef = useRef(field.defaultValue);
const [value, setValue] = useState(field.defaultValue);
const [type, setType] = useState(field.type);
const [errorMessage, setErrorMessage] = useState('');
const isError = useMemo(() => !!errorMessage.length, [errorMessage]);
const onChange = (...props) => {
const valueSelector = (formManagerCTX.fieldValueSelector || {})[originalType] || (formManagerCTX.fieldValueSelector || {}).default;
const newValue = valueSelector(...props);
if (field.onBeforeChange) {
field.onBeforeChange(newValue);
}
setValue(newValue);
valueRef.current = newValue;
if (field.onAfterChange) {
field.onAfterChange(newValue);
}
};
useEffect(() => {
setErrorMessage('');
if (options.isValidateOnChange) {
validateForm();
}
setTimeStamp(Date.now());
}, [value, type]);
return {
field,
name: key,
label: field.label,
value,
valueRef,
isError,
errorMessage,
setValue,
setType,
setErrorMessage,
originalType,
bind: {
name: key,
id: key,
type,
onChange,
...field.htmlAttr,
},
};
});
const getFieldType = (field, fields) => {
if (!field.field.showIf) {
return field.originalType;
}
const result = Object.keys(field.field.showIf).some(showIfKey => {
const searchedField = fields.find(field => field.name === showIfKey);
const fieldConditionValues = (field.field.showIf || {})[showIfKey];
if (!searchedField) {
return false;
}
if (Array.isArray(fieldConditionValues)) {
return fieldConditionValues.includes(`${searchedField.valueRef.current}`);
}
return `${searchedField.valueRef.current}` === fieldConditionValues;
});
return !result ? 'hidden' : field.originalType;
};
const formFieldObject = formFieldsData.reduce((acc, field) => {
// @ts-ignore
acc[field.name] = field.valueRef.current;
return acc;
}, {});
const validateForm = () => {
const validatorData = formFieldsData
.reduce((acc, fieldData) => {
if (fieldData.bind.type === 'hidden') {
return acc;
}
acc.rules[fieldData.name] = fieldData.field.validationRules;
// @ts-ignore
acc.data[fieldData.name] = fieldData.value;
return acc;
}, {
rules: {},
data: {},
});
const validator = new Validator(validatorData.rules);
const validData = validator.validate(validatorData.data);
const errors = validator.getErrors();
formFieldsData.forEach((field) => {
field.setErrorMessage('');
});
if (!errors) {
setTimeStamp(Date.now());
return {
...validatorData.data,
...validData,
};
}
formFieldsData.forEach((field) => {
if (!errors[field.name]) {
return;
}
field.setErrorMessage(field.field.errorMessages && field.field.errorMessages[errors[field.name]]
|| (formManagerCTX.errorMessages || {})[errors[field.name]]
|| (formManagerCTX.errorMessages || {}).default);
});
setTimeStamp(Date.now());
return;
};
const bulkUpdateForm = (updateData) => {
formFieldsData.forEach((field) => {
if (typeof updateData[field.name] !== 'undefined') {
field.setValue(updateData[field.name]);
field.valueRef.current = updateData[field.name];
}
});
};
const resetForm = () => {
formFieldsData.forEach((field) => {
field.setValue(field.field.defaultValue);
field.setErrorMessage('');
});
};
return {
fields: useMemo(() => {
return formFieldsData.map((field, _, array) => {
field.setType(getFieldType(field, array));
return field;
});
}, [timeStamp]),
formFieldObject,
validateForm,
resetForm,
bulkUpdateForm,
};
};
//# sourceMappingURL=useFormManager.js.map