запросы для восстановления пароля(не закончено)
This commit is contained in:
parent
8496c5d273
commit
8d1192c8bc
@ -15,7 +15,7 @@
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.10.5",
|
||||
"@emotion/styled": "^11.10.5",
|
||||
"@frontend/kitui": "1.0.58",
|
||||
"@frontend/kitui": "1.0.60",
|
||||
"@mui/icons-material": "^5.10.14",
|
||||
"@mui/material": "^5.10.14",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
|
@ -10,7 +10,7 @@ import type {
|
||||
} from "@frontend/kitui";
|
||||
|
||||
const apiUrl = process.env.REACT_APP_DOMAIN + "/auth";
|
||||
console.log("переменная", apiUrl);
|
||||
|
||||
export async function register(
|
||||
login: string,
|
||||
password: string,
|
||||
@ -61,8 +61,9 @@ export async function recover(
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append("email", email);
|
||||
formData.append("RedirectionURL", process.env.REACT_APP_DOMAIN + "/changepwd")
|
||||
const recoverResponse = await makeRequest<unknown, unknown>({
|
||||
url: process.env.REACT_APP_DOMAIN + "/recover",
|
||||
url: process.env.REACT_APP_DOMAIN + "/codeword/recover",
|
||||
body: formData,
|
||||
useToken: false,
|
||||
withCredentials: true,
|
||||
|
@ -30,6 +30,8 @@ import PPofData from "@root/docs/PPofData"
|
||||
import Docs from "@root/docs/docs"
|
||||
import Oferta from "@root/docs/content/oferta"
|
||||
import PrivacyPolicy from "@root/docs/content/PrivacyPolicy"
|
||||
import RecoverPassword from "@root/pages/auth/RecoverPassword"
|
||||
import OutdatedLink from "@root/pages/auth/OutdatedLink"
|
||||
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = new URL("pdfjs-dist/build/pdf.worker.min.js", import.meta.url).toString()
|
||||
|
||||
@ -78,6 +80,9 @@ const App = () => {
|
||||
<Route path="/signin" element={<SigninDialog />} />
|
||||
<Route path="/signup" element={<SignupDialog />} />
|
||||
<Route path="/recover" element={<RecoverDialog />} />
|
||||
<Route path="/chengepwd" element={<RecoverPassword />} />
|
||||
<Route path="/changepwd/expired" element={<OutdatedLink />} />
|
||||
|
||||
</Routes>
|
||||
)}
|
||||
<Routes location={location.state?.backgroundLocation || location}>
|
||||
@ -85,6 +90,8 @@ const App = () => {
|
||||
<Route path="/signin" element={<Navigate to="/" replace state={{ redirectTo: "/signin" }} />} />
|
||||
<Route path="/signup" element={<Navigate to="/" replace state={{ redirectTo: "/signup" }} />} />
|
||||
<Route path="/recover" element={<Navigate to="/" replace state={{ redirectTo: "/recover" }} />} />
|
||||
<Route path="/chengepwd" element={<Navigate to="/" replace state={{ redirectTo: "/chengepwd" }} />} />
|
||||
<Route path="/changepwd/expired" element={<Navigate to="/" replace state={{ redirectTo: "/changepwd/expired" }} />} />
|
||||
<Route element={<PrivateRoute />}>
|
||||
<Route element={<ProtectedLayout />}>
|
||||
<Route path="/tariffs" element={<Tariffs />} />
|
||||
|
@ -7,7 +7,7 @@ interface Props {
|
||||
icon: ReactNode;
|
||||
headerText: string;
|
||||
discount?: string;
|
||||
text: string | string[];
|
||||
text?: any;
|
||||
sx?: SxProps<Theme>;
|
||||
buttonProps?: {
|
||||
sx?: SxProps<Theme>;
|
||||
@ -78,7 +78,7 @@ export default function TariffCard({ icon, headerText, text, sx, price, buttonPr
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
{/* <Tooltip title={<Typography>{headerText}</Typography>} placement="top">
|
||||
<Tooltip title={<Typography>{headerText}</Typography>} placement="top">
|
||||
<Typography
|
||||
variant="h5"
|
||||
sx={{
|
||||
@ -92,8 +92,8 @@ export default function TariffCard({ icon, headerText, text, sx, price, buttonPr
|
||||
>
|
||||
{headerText}
|
||||
</Typography>
|
||||
</Tooltip> */}
|
||||
{/* <Tooltip
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
title={text.map((line, index) => (
|
||||
<Typography key={index}>{line}</Typography>
|
||||
))}
|
||||
@ -111,7 +111,7 @@ export default function TariffCard({ icon, headerText, text, sx, price, buttonPr
|
||||
</Typography>
|
||||
))}
|
||||
</Box>
|
||||
</Tooltip> */}
|
||||
</Tooltip>
|
||||
{buttonProps && (
|
||||
<Button
|
||||
onClick={buttonProps.onClick}
|
||||
|
138
src/pages/auth/OutdatedLink.tsx
Normal file
138
src/pages/auth/OutdatedLink.tsx
Normal file
@ -0,0 +1,138 @@
|
||||
import {
|
||||
Box,
|
||||
Dialog,
|
||||
IconButton,
|
||||
Typography,
|
||||
useMediaQuery,
|
||||
useTheme,
|
||||
Button,
|
||||
} from "@mui/material";
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import PenaLogo from "@components/PenaLogo";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useUserStore } from "@root/stores/user";
|
||||
import { cardShadow } from "@root/utils/theme";
|
||||
|
||||
|
||||
export default function OutdatedLink() {
|
||||
const [isDialogOpen, setIsDialogOpen] = useState<boolean>(true);
|
||||
const user = useUserStore((state) => state.user);
|
||||
const theme = useTheme();
|
||||
const upMd = useMediaQuery(theme.breakpoints.up("md"));
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
|
||||
useEffect(
|
||||
function redirectIfSignedIn() {
|
||||
if (user) navigate("/tariffs", { replace: true });
|
||||
},
|
||||
[navigate, user]
|
||||
);
|
||||
|
||||
function handleClose() {
|
||||
setIsDialogOpen(false);
|
||||
setTimeout(() => navigate("/"), theme.transitions.duration.leavingScreen);
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={isDialogOpen}
|
||||
onClose={handleClose}
|
||||
PaperProps={{
|
||||
sx: {
|
||||
width: "600px",
|
||||
maxWidth: "600px",
|
||||
},
|
||||
}}
|
||||
slotProps={{
|
||||
backdrop: {
|
||||
style: {
|
||||
backgroundColor: "rgb(0 0 0 / 0.7)",
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
component="form"
|
||||
sx={{
|
||||
position: "relative",
|
||||
backgroundColor: "white",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
p: upMd ? "50px" : "18px",
|
||||
pb: upMd ? "40px" : "30px",
|
||||
gap: "15px",
|
||||
borderRadius: "12px",
|
||||
boxShadow: cardShadow,
|
||||
"& .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" />
|
||||
</Box>
|
||||
<Typography
|
||||
sx={{
|
||||
color: theme.palette.gray.dark,
|
||||
mt: "5px",
|
||||
mb: upMd ? "10px" : "33px",
|
||||
}}
|
||||
>
|
||||
Внимание! Ссылка устарела!
|
||||
</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
color: theme.palette.gray.dark,
|
||||
mt: "5px",
|
||||
mb: upMd ? "10px" : "33px",
|
||||
}}
|
||||
>
|
||||
Срок действия ссылки истёк, пожалуйста повторите попытку восстановления пароля
|
||||
</Typography>
|
||||
<Button
|
||||
variant="pena-contained-dark"
|
||||
fullWidth
|
||||
onClick={()=> navigate("/")}
|
||||
sx={{
|
||||
py: "12px",
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.purple.dark,
|
||||
},
|
||||
"&:active": {
|
||||
color: "white",
|
||||
backgroundColor: "black",
|
||||
},
|
||||
}}
|
||||
>
|
||||
На главную
|
||||
</Button>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
gap: "10px",
|
||||
mt: "auto",
|
||||
}}
|
||||
>
|
||||
</Box>
|
||||
</Box>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
@ -56,6 +56,8 @@ export default function RecoverDialog() {
|
||||
if (recoverError) {
|
||||
return enqueueSnackbar(recoverError);
|
||||
}
|
||||
navigate("/")
|
||||
enqueueSnackbar("Письмо прийдёт Вам на почту")
|
||||
},
|
||||
});
|
||||
|
||||
|
184
src/pages/auth/RecoverPassword.tsx
Normal file
184
src/pages/auth/RecoverPassword.tsx
Normal file
@ -0,0 +1,184 @@
|
||||
import {
|
||||
Box,
|
||||
Dialog,
|
||||
IconButton,
|
||||
Link,
|
||||
Typography,
|
||||
useMediaQuery,
|
||||
useTheme,
|
||||
Button,
|
||||
} from "@mui/material";
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import { useFormik } from "formik";
|
||||
import InputTextfield from "@components/InputTextfield";
|
||||
import PenaLogo from "@components/PenaLogo";
|
||||
import { enqueueSnackbar } from "notistack";
|
||||
import { Link as RouterLink } from "react-router-dom";
|
||||
import { object, string } from "yup";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useUserStore } from "@root/stores/user";
|
||||
import { cardShadow } from "@root/utils/theme";
|
||||
|
||||
import { recover } from "@root/api/auth";
|
||||
import axios, {AxiosResponse} from "axios"
|
||||
import {getAuthToken, setAuthToken} from "@frontend/kitui"
|
||||
interface Values {
|
||||
password: string;
|
||||
}
|
||||
|
||||
const initialValues: Values = {
|
||||
password: "",
|
||||
};
|
||||
|
||||
const validationSchema = object({
|
||||
password: string()
|
||||
.min(8, "Минимум 8 символов")
|
||||
.matches(/^[.,:;-_+\d\w]+$/, "Некорректные символы")
|
||||
.required("Поле обязательно"),
|
||||
});
|
||||
|
||||
export default function RecoverPassword() {
|
||||
const [isDialogOpen, setIsDialogOpen] = useState<boolean>(true);
|
||||
const user = useUserStore((state) => state.user);
|
||||
const theme = useTheme();
|
||||
const upMd = useMediaQuery(theme.breakpoints.up("md"));
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const formik = useFormik<Values>({
|
||||
initialValues,
|
||||
validationSchema,
|
||||
onSubmit: async (values, formikHelpers) => {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
const authToken = params.get("auth")
|
||||
if (authToken) {
|
||||
try {
|
||||
const response = await axios<unknown, unknown>({
|
||||
url: process.env.REACT_APP_DOMAIN + "/user",
|
||||
method: "PATCH",
|
||||
headers: {"Authorization": "Bearer " + authToken},
|
||||
data: {password: values.password},
|
||||
});
|
||||
|
||||
} catch (error) { enqueueSnackbar("Извините, произошла ошибка, попробуйте повторить позже")}
|
||||
|
||||
} else {
|
||||
enqueueSnackbar("Неверный url-адрес")
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
function handleClose() {
|
||||
setIsDialogOpen(false);
|
||||
setTimeout(() => navigate("/"), theme.transitions.duration.leavingScreen);
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={isDialogOpen}
|
||||
onClose={handleClose}
|
||||
PaperProps={{
|
||||
sx: {
|
||||
width: "600px",
|
||||
maxWidth: "600px",
|
||||
},
|
||||
}}
|
||||
slotProps={{
|
||||
backdrop: {
|
||||
style: {
|
||||
backgroundColor: "rgb(0 0 0 / 0.7)",
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
component="form"
|
||||
onSubmit={formik.handleSubmit}
|
||||
noValidate
|
||||
sx={{
|
||||
position: "relative",
|
||||
backgroundColor: "white",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
p: upMd ? "50px" : "18px",
|
||||
pb: upMd ? "40px" : "30px",
|
||||
gap: "15px",
|
||||
borderRadius: "12px",
|
||||
boxShadow: cardShadow,
|
||||
"& .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" />
|
||||
</Box>
|
||||
<Typography
|
||||
sx={{
|
||||
color: theme.palette.gray.dark,
|
||||
mt: "5px",
|
||||
mb: upMd ? "10px" : "33px",
|
||||
}}
|
||||
>
|
||||
Введите новый пароль
|
||||
</Typography>
|
||||
<InputTextfield
|
||||
TextfieldProps={{
|
||||
value: formik.values.password,
|
||||
placeholder: "введите пароль",
|
||||
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="Новый пароль"
|
||||
gap={upMd ? "10px" : "10px"}
|
||||
/>
|
||||
<Button
|
||||
variant="pena-contained-dark"
|
||||
fullWidth
|
||||
type="submit"
|
||||
disabled={formik.isSubmitting}
|
||||
sx={{
|
||||
py: "12px",
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.purple.dark,
|
||||
},
|
||||
"&:active": {
|
||||
color: "white",
|
||||
backgroundColor: "black",
|
||||
},
|
||||
}}
|
||||
>
|
||||
Восстановить
|
||||
</Button>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
gap: "10px",
|
||||
mt: "auto",
|
||||
}}
|
||||
>
|
||||
</Box>
|
||||
</Box>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
@ -1420,10 +1420,10 @@
|
||||
resolved "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.6.tgz"
|
||||
integrity sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==
|
||||
|
||||
"@frontend/kitui@1.0.58":
|
||||
version "1.0.58"
|
||||
resolved "https://penahub.gitlab.yandexcloud.net/api/v4/projects/21/packages/npm/@frontend/kitui/-/@frontend/kitui-1.0.58.tgz"
|
||||
integrity sha1-b/p7hJXG35suzyplPXAIBcBJ6s4=
|
||||
"@frontend/kitui@1.0.60":
|
||||
version "1.0.60"
|
||||
resolved "https://penahub.gitlab.yandexcloud.net/api/v4/projects/21/packages/npm/@frontend/kitui/-/@frontend/kitui-1.0.60.tgz#159980acd53fdf47ab3c4328f5a88850f2675a36"
|
||||
integrity sha1-FZmArNU/30erPEMo9aiIUPJnWjY=
|
||||
dependencies:
|
||||
immer "^10.0.2"
|
||||
reconnecting-eventsource "^1.6.2"
|
||||
|
Loading…
Reference in New Issue
Block a user