frontPanel/src/pages/auth/RecoverPassword.tsx

203 lines
5.6 KiB
TypeScript
Raw Normal View History

2023-12-31 02:53:25 +00:00
import {
Box,
Dialog,
IconButton,
Link,
Typography,
useMediaQuery,
useTheme,
Button,
2023-12-31 02:53:25 +00:00
} from "@mui/material";
import CloseIcon from "@mui/icons-material/Close";
import { useLocation, useNavigate } from "react-router-dom";
2023-12-16 13:02:27 +00:00
import { useFormik } from "formik";
import InputTextfield from "@ui_kit/InputTextfield";
import PenaLogo from "../Landing/images/icons/QuizLogo";
import { enqueueSnackbar } from "notistack";
import { object, string } from "yup";
import { useEffect, useState } from "react";
import { useUserStore } from "@root/user";
2023-12-16 13:02:27 +00:00
2025-07-23 05:06:30 +00:00
import { makeRequest } from "@frontend/kitui";
import { setAuthToken } from "@frontend/kitui";
import { parseAxiosError } from "@utils/parse-error";
2024-05-15 11:44:10 +00:00
import { recoverUser } from "@api/user";
2023-12-16 13:02:27 +00:00
interface Values {
2023-12-31 02:53:25 +00:00
password: string;
2023-12-16 13:02:27 +00:00
}
const initialValues: Values = {
2023-12-31 02:53:25 +00:00
password: "",
2023-12-16 13:02:27 +00:00
};
const validationSchema = object({
2023-12-31 02:53:25 +00:00
password: string()
.min(8, "Минимум 8 символов")
2024-04-16 13:43:22 +00:00
.matches(
/^[.,:;\-_+!&()*<>\[\]\{\}`@"#$\%\^\=?\d\w]+$/,
"Некорректные символы",
)
2023-12-31 02:53:25 +00:00
.required("Поле обязательно"),
2023-12-16 13:02:27 +00:00
});
export default function RecoverPassword() {
2023-12-31 02:53:25 +00:00
const [isDialogOpen, setIsDialogOpen] = useState<boolean>(true);
const [tokenUser, setTokenUser] = useState<string>("");
const user = useUserStore((state) => state.user);
2023-12-31 02:53:25 +00:00
const theme = useTheme();
const upMd = useMediaQuery(theme.breakpoints.up("md"));
const isMobile = useMediaQuery(theme.breakpoints.down(450));
const navigate = useNavigate();
2023-12-31 02:53:25 +00:00
const location = useLocation();
const formik = useFormik<Values>({
initialValues,
validationSchema,
onSubmit: async (values, formikHelpers) => {
if (tokenUser) {
setAuthToken(tokenUser || "");
2024-05-15 11:44:10 +00:00
const [_, recoverError] = await recoverUser(values.password);
if (recoverError) {
setAuthToken("");
enqueueSnackbar(
2024-05-15 11:44:10 +00:00
`Извините, произошла ошибка, попробуйте повторить позже. ${recoverError}`,
);
2024-05-15 11:44:10 +00:00
} else {
setIsDialogOpen(false);
navigate("/");
enqueueSnackbar("Пароль успешно сменён");
}
} else {
enqueueSnackbar("Неверный url-адрес");
}
},
2023-12-31 02:53:25 +00:00
});
useEffect(() => {
const params = new URLSearchParams(window.location.search);
const authToken = params.get("auth");
setTokenUser(authToken);
history.pushState(null, document.title, "/changepwd");
return () => {
setAuthToken("");
};
}, []);
2023-12-16 13:02:27 +00:00
2023-12-31 02:53:25 +00:00
function handleClose() {
setIsDialogOpen(false);
setTimeout(() => navigate("/"), theme.transitions.duration.leavingScreen);
}
2023-12-16 13:02:27 +00:00
2023-12-31 02:53:25 +00:00
return (
<Dialog
open={isDialogOpen}
onClose={handleClose}
PaperProps={{
sx: {
width: isMobile ? "100%" : "600px",
maxWidth: isMobile ? "100%" : "600px",
margin: isMobile ? "0" : "32px",
maxHeight: isMobile ? "100%" : "-moz-initial",
height: isMobile ? "100%" : "-moz-initial",
2023-12-31 02:53:25 +00:00
},
}}
slotProps={{
backdrop: {
style: {
backgroundColor: "rgb(0 0 0 / 0.7)",
},
},
}}
>
<Box
component="form"
onSubmit={formik.handleSubmit}
noValidate
sx={{
height: isMobile ? "100%" : "-moz-initial",
2023-12-31 02:53:25 +00:00
position: "relative",
backgroundColor: "white",
display: "flex",
alignItems: "center",
flexDirection: "column",
p: upMd ? "50px" : "18px",
pb: upMd ? "40px" : "30px",
gap: "15px",
borderRadius: "12px",
"& .MuiFormHelperText-root.Mui-error, & .MuiFormHelperText-root.Mui-error.MuiFormHelperText-filled":
{
position: "absolute",
top: "46px",
margin: "0",
},
}}
>
<IconButton
onClick={handleClose}
sx={{
position: "absolute",
right: "7px",
top: "7px",
}}
>
<CloseIcon sx={{ transform: "scale(1.5)" }} />
</IconButton>
<Box>
<PenaLogo width={upMd ? 233 : 196} color="black" />
2023-12-31 02:53:25 +00:00
</Box>
<Typography
sx={{
color: "#4D4D4D",
mt: "5px",
mb: upMd ? "10px" : "33px",
2023-12-31 02:53:25 +00:00
}}
>
Введите новый пароль
2023-12-31 02:53:25 +00:00
</Typography>
<InputTextfield
TextfieldProps={{
value: formik.values.password,
placeholder: "введите пароль",
2023-12-31 02:53:25 +00:00
onBlur: formik.handleBlur,
error: formik.touched.password && Boolean(formik.errors.password),
helperText: formik.touched.password && formik.errors.password,
}}
onChange={formik.handleChange}
color="#F2F3F7"
id="password"
label="Новый пароль"
2023-12-31 02:53:25 +00:00
gap={upMd ? "10px" : "10px"}
/>
<Button
variant="contained"
fullWidth
type="submit"
disabled={formik.isSubmitting}
sx={{
py: "12px",
"&:hover": {
backgroundColor: "#581CA7",
},
"&:active": {
color: "white",
backgroundColor: "black",
},
}}
>
Восстановить
</Button>
<Box
2023-12-31 02:53:25 +00:00
sx={{
display: "flex",
flexDirection: "column",
alignItems: "center",
gap: "10px",
2023-12-31 02:53:25 +00:00
mt: "auto",
}}
></Box>
2023-12-31 02:53:25 +00:00
</Box>
</Dialog>
);
}