Merge pull request #1282 from peterpardo/fix/password-validation-on-account

fix: Password validation on account
This commit is contained in:
Alexander Holliday authored and GitHub committed 2024-12-04 17:44:27 -08:00
commit 95d832e683
2 files changed
+59 -22

No files matched your search

@@ -10,6 +10,13 @@ import Alert from "../../Alert";
import { update } from "../../../Features/Auth/authSlice";
import { useDispatch, useSelector } from "react-redux";
import { createToast } from "../../../Utils/toastUtils";
import { getTouchedFieldErrors } from "../../../Validation/error";
const defaultPasswordsState = {
password: "",
newPassword: "",
confirm: "",
};
/**
* PasswordPanel component manages the form for editing password.
@@ -30,35 +37,40 @@ const PasswordPanel = () => {
"edit-confirm-password": "confirm",
};
const [localData, setLocalData] = useState({
password: "",
newPassword: "",
confirm: "",
const [localData, setLocalData] = useState(defaultPasswordsState);
const [errors, setErrors] = useState(defaultPasswordsState);
const [touchedFields, setTouchedFields] = useState({
password: false,
newPassword: false,
confirm: false,
});
const [errors, setErrors] = useState({});
const handleChange = (event) => {
const { value, id } = event.target;
const name = idToName[id];
setLocalData((prev) => ({
...prev,
const updatedData = {
...localData,
[name]: value,
}));
};
const updatedTouchedFields = {
...touchedFields,
[name]: true,
};
const validation = credentials.validate(
{ [name]: value },
{ abortEarly: false, context: { password: localData.newPassword } }
{ ...updatedData },
{ abortEarly: false, context: { password: updatedData.newPassword } }
);
setErrors((prev) => {
const updatedErrors = { ...prev };
const updatedErrors = getTouchedFieldErrors(validation, updatedTouchedFields);
if (validation.error) {
updatedErrors[name] = validation.error.details[0].message;
} else {
delete updatedErrors[name];
}
return updatedErrors;
});
if (!touchedFields[name]) {
setTouchedFields(updatedTouchedFields);
}
setLocalData(updatedData);
setErrors(updatedErrors);
};
const handleSubmit = async (event) => {
@@ -220,8 +232,8 @@ const PasswordPanel = () => {
loading={isLoading}
loadingIndicator="Saving..."
disabled={
Object.keys(errors).length !== 0 ||
Object.values(localData).filter((value) => value !== "").length === 0
Object.keys(errors).length > 0 ||
Object.values(localData).filter((value) => value === "").length > 0
}
sx={{
px: theme.spacing(12),
+26 -1
View File
@@ -8,6 +8,31 @@ const buildErrors = (prev, id, error) => {
return updatedErrors;
};
/**
* Processes Joi validation errors and returns a filtered object of error messages for fields that have been touched.
*
* @param {Object} validation - The Joi validation result object.
* @param {Object} validation.error - The error property of the validation result containing details of validation failures.
* @param {Object[]} validation.error.details - An array of error details from the Joi validation. Each item contains information about the path and the message.
* @param {Object} touchedErrors - An object representing which fields have been interacted with. Keys are field IDs (field names), and values are booleans indicating whether the field has been touched.
* @returns {Object} - An object where keys are the field IDs (if they exist in `touchedErrors` and are in the error details) and values are their corresponding error messages.
*/
const getTouchedFieldErrors = (validation, touchedErrors) => {
let newErrors = {};
if (validation?.error) {
newErrors = validation.error.details.reduce((errors, detail) => {
const fieldId = detail.path[0];
if (touchedErrors[fieldId] && !(fieldId in errors)) {
errors[fieldId] = detail.message;
}
return errors;
}, {});
}
return newErrors;
};
const hasValidationErrors = (form, validation, setErrors) => {
const { error } = validation.validate(form, {
abortEarly: false,
@@ -53,4 +78,4 @@ const hasValidationErrors = (form, validation, setErrors) => {
}
return false;
};
export { buildErrors, hasValidationErrors };
export { buildErrors, hasValidationErrors, getTouchedFieldErrors };