Files
Checkmate/Client/src/Components/TabPanels/Account/PasswordPanel.jsx
T

219 lines
6.8 KiB
React
Raw Normal View History

2024-06-18 20:16:32 -04:00
import TabPanel from "@mui/lab/TabPanel";
import React, { useState } from "react";
import { useTheme } from "@emotion/react";
2024-06-23 17:41:40 -04:00
import { Box, Divider, Stack, Typography } from "@mui/material";
2024-06-18 20:16:32 -04:00
import ButtonSpinner from "../../ButtonSpinner";
import PasswordTextField from "../../TextFields/Password/PasswordTextField";
2024-06-23 17:41:40 -04:00
import { editPasswordValidation } from "../../../Validation/validation";
2024-07-06 14:33:36 -04:00
import Alert from "../../Alert";
2024-07-10 18:26:05 -04:00
import { update } from "../../../Features/Auth/authSlice";
import { useDispatch, useSelector } from "react-redux";
2024-06-18 20:16:32 -04:00
/**
* PasswordPanel component manages the form for editing password.
*
* @returns {JSX.Element}
*/
const PasswordPanel = () => {
const theme = useTheme();
2024-07-10 18:26:05 -04:00
const dispatch = useDispatch();
//redux state
const { authToken, isLoading } = useSelector((state) => state.auth);
2024-06-18 20:16:32 -04:00
2024-06-23 17:41:40 -04:00
const idToName = {
2024-06-24 11:43:07 -04:00
"edit-current-password": "password",
2024-07-10 18:26:05 -04:00
"edit-new-password": "newPassword",
2024-06-23 17:41:40 -04:00
"edit-confirm-password": "confirm",
};
2024-07-10 18:26:05 -04:00
const [localData, setLocalData] = useState({
2024-06-23 17:41:40 -04:00
password: "",
2024-07-10 18:26:05 -04:00
newPassword: "",
2024-06-23 17:41:40 -04:00
confirm: "",
});
const [errors, setErrors] = useState({});
2024-07-10 18:26:05 -04:00
const [showPassword, setShowPassword] = useState(false); // password visibility
const handleChange = (event) => {
const { value, id } = event.target;
2024-06-23 17:41:40 -04:00
const name = idToName[id];
setLocalData((prev) => ({
...prev,
2024-06-23 17:41:40 -04:00
[name]: value,
}));
2024-06-23 17:41:40 -04:00
const validation = editPasswordValidation.validate(
{ [name]: value },
2024-07-10 18:26:05 -04:00
{ abortEarly: false, context: { newPassword: localData.newPassword } }
2024-06-23 17:41:40 -04:00
);
setErrors((prev) => {
const updatedErrors = { ...prev };
2024-06-23 17:41:40 -04:00
if (validation.error) {
updatedErrors[name] = validation.error.details[0].message;
} else {
2024-06-23 17:41:40 -04:00
delete updatedErrors[name];
}
return updatedErrors;
});
};
2024-07-10 18:26:05 -04:00
const handleSubmit = async (event) => {
2024-06-23 17:41:40 -04:00
event.preventDefault();
const { error } = editPasswordValidation.validate(localData, {
abortEarly: false,
2024-07-10 18:26:05 -04:00
context: { newPassword: localData.newPassword },
2024-06-23 17:41:40 -04:00
});
if (error) {
const newErrors = {};
error.details.forEach((err) => {
newErrors[err.path[0]] = err.message;
});
setErrors(newErrors);
} else {
2024-07-10 18:26:05 -04:00
const action = await dispatch(update({ authToken, localData }));
if (action.payload.success) {
// TODO: Add toast/notification for password update success
setLocalData({
password: "",
newPassword: "",
confirm: "",
});
} else {
// TODO: Add toast/notification for password update rejected
// TODO: Check for other errors?
setErrors({ password: "*" + action.payload.msg + "." });
}
2024-06-23 17:41:40 -04:00
}
2024-06-18 20:16:32 -04:00
};
2024-06-23 17:41:40 -04:00
2024-06-18 20:16:32 -04:00
return (
2024-06-27 19:19:36 -04:00
<TabPanel value="password">
2024-06-23 17:41:40 -04:00
<form
onSubmit={handleSubmit}
className="edit-password-form"
noValidate
spellCheck="false"
>
2024-06-18 20:16:32 -04:00
<div className="edit-password-form__wrapper">
2024-07-06 14:33:36 -04:00
<Alert
variant="info"
title="SSO login"
2024-06-18 20:16:32 -04:00
body="Since you logged in via SSO, you cannot reset or modify your password."
/>
</div>
<div className="edit-password-form__wrapper">
<Stack>
<Typography component="h1">Current password</Typography>
2024-06-18 20:16:32 -04:00
</Stack>
<Stack>
<PasswordTextField
2024-06-18 20:16:32 -04:00
id="edit-current-password"
label={null}
placeholder="Enter your current password"
autoComplete="current-password"
visibility={showPassword}
setVisibility={setShowPassword}
2024-07-10 18:26:05 -04:00
value={localData.password}
2024-06-23 17:41:40 -04:00
onChange={handleChange}
error={errors[idToName["edit-current-password"]] ? true : false}
/>
2024-06-23 17:41:40 -04:00
{errors[idToName["edit-current-password"]] ? (
<Typography component="p" className="input-error">
2024-06-23 17:41:40 -04:00
{errors[idToName["edit-current-password"]]}
</Typography>
) : (
""
)}
</Stack>
2024-06-18 20:16:32 -04:00
</div>
<div className="edit-password-form__wrapper">
<Stack>
<Typography component="h1">New password</Typography>
2024-06-18 20:16:32 -04:00
</Stack>
<Stack>
<PasswordTextField
id="edit-new-password"
label={null}
placeholder="Enter your new password"
autoComplete="new-password"
visibility={showPassword}
setVisibility={setShowPassword}
2024-07-10 18:26:05 -04:00
value={localData.newPassword}
onChange={handleChange}
2024-06-23 17:41:40 -04:00
error={errors[idToName["edit-new-password"]] ? true : false}
/>
2024-06-23 17:41:40 -04:00
{errors[idToName["edit-new-password"]] ? (
<Typography component="p" className="input-error">
2024-06-23 17:41:40 -04:00
{errors[idToName["edit-new-password"]]}
</Typography>
) : (
""
)}
</Stack>
2024-06-18 20:16:32 -04:00
</div>
<div className="edit-password-form__wrapper">
<Stack>
<Typography component="h1">Confirm new password</Typography>
2024-06-18 20:16:32 -04:00
</Stack>
<Stack>
<PasswordTextField
id="edit-confirm-password"
label={null}
placeholder="Reenter your new password"
autoComplete="new-password"
visibility={showPassword}
setVisibility={setShowPassword}
2024-07-10 18:26:05 -04:00
value={localData.confirm}
onChange={handleChange}
2024-06-23 17:41:40 -04:00
error={errors[idToName["edit-confirm-password"]] ? true : false}
/>
2024-06-23 17:41:40 -04:00
{errors[idToName["edit-confirm-password"]] ? (
<Typography component="p" className="input-error">
2024-06-23 17:41:40 -04:00
{errors[idToName["edit-confirm-password"]]}
</Typography>
) : (
""
)}
</Stack>
</div>
<div className="edit-password-form__wrapper">
<Stack></Stack>
<Box sx={{ flex: 1 }}>
2024-07-06 14:33:36 -04:00
<Alert
variant="warning"
2024-06-18 20:16:32 -04:00
body="New password must contain at least 8 characters and must have at least one uppercase letter, one number and one symbol."
/>
</Box>
</div>
<Divider aria-hidden="true" width="0" />
2024-06-18 20:16:32 -04:00
<Stack direction="row" justifyContent="flex-end">
<Box width="fit-content">
<ButtonSpinner
level="primary"
label="Save"
2024-06-23 17:41:40 -04:00
onClick={handleSubmit}
2024-06-18 20:16:32 -04:00
isLoading={isLoading}
loadingText="Saving..."
disabled={Object.keys(errors).length !== 0 && true}
2024-06-18 20:16:32 -04:00
sx={{
2024-07-10 18:26:05 -04:00
paddingX: theme.gap.xl,
2024-06-18 20:16:32 -04:00
}}
/>
</Box>
</Stack>
</form>
</TabPanel>
);
};
PasswordPanel.propTypes = {
// No props are being passed to this component, hence no specific PropTypes are defined.
};
2024-06-18 20:16:32 -04:00
export default PasswordPanel;