import TabPanel from "@mui/lab/TabPanel"; import { useState } from "react"; import { useTheme } from "@emotion/react"; import { Box, Stack, Typography, Button } from "@mui/material"; import { PasswordEndAdornment } from "@/Components/v1/Inputs/TextInput/Adornments/index.jsx"; import TextInput from "@/Components/v1/Inputs/TextInput/index.jsx"; import { newOrChangedCredentials } from "../../../Validation/validation.js"; import Alert from "@/Components/v1/Alert/index.jsx"; import { update } from "../../../Features/Auth/authSlice.js"; import { useDispatch, useSelector } from "react-redux"; import { createToast } from "../../../Utils/toastUtils.jsx"; import { getTouchedFieldErrors } from "../../../Validation/error.js"; import { useTranslation } from "react-i18next"; import { useNavigate, useLocation } from "react-router-dom"; import { clearAuthState } from "../../../Features/Auth/authSlice.js"; import TextLink from "@/Components/v1/TextLink/index.jsx"; const defaultPasswordsState = { password: "", newPassword: "", confirm: "", }; /** * PasswordPanel component manages the form for editing password. * * @returns {JSX.Element} */ const PasswordPanel = () => { const theme = useTheme(); const dispatch = useDispatch(); const { t } = useTranslation(); const navigate = useNavigate(); const location = useLocation(); const SPACING_GAP = theme.spacing(12); //redux state const { isLoading, authToken } = useSelector((state) => state.auth); const idToName = { "edit-current-password": "password", "edit-new-password": "newPassword", "edit-confirm-password": "confirm", }; const [localData, setLocalData] = useState(defaultPasswordsState); const [errors, setErrors] = useState(defaultPasswordsState); const [touchedFields, setTouchedFields] = useState({ password: false, newPassword: false, confirm: false, }); const handleChange = (event) => { const { value, id } = event.target; const name = idToName[id]; const updatedData = { ...localData, [name]: value, }; const updatedTouchedFields = { ...touchedFields, [name]: true, }; const validation = newOrChangedCredentials.validate( { ...updatedData }, { abortEarly: false, context: { password: updatedData.newPassword } } ); const updatedErrors = getTouchedFieldErrors(validation, updatedTouchedFields); if (!touchedFields[name]) { setTouchedFields(updatedTouchedFields); } setLocalData(updatedData); setErrors(updatedErrors); }; const handleSubmit = async (event) => { event.preventDefault(); // Check for expired/invalid token before submitting if (!authToken) { createToast({ body: "Your session has expired. Please log in again.", }); dispatch(clearAuthState()); navigate("/login"); return; } const { error } = newOrChangedCredentials.validate(localData, { abortEarly: false, context: { password: localData.newPassword }, }); if (error) { const newErrors = {}; error.details.forEach((err) => { newErrors[err.path[0]] = err.message; }); setErrors(newErrors); } else { const action = await dispatch(update({ localData })); if (action.payload.success) { createToast({ body: t( "passwordPanel.passwordChangedSuccess", "Your password was changed successfully." ), }); setLocalData({ password: "", newPassword: "", confirm: "", }); } else { // TODO: Check for other errors? createToast({ body: t( "passwordPanel.passwordInputIncorrect", "Your password input was incorrect." ), }); setErrors({ password: "*" + action.payload.msg + "." }); } } }; return ( ); }; PasswordPanel.propTypes = { // No props are being passed to this component, hence no specific PropTypes are defined. }; export default PasswordPanel;