запросы для восстановления пароля(не закончено)
This commit is contained in:
parent
8496c5d273
commit
8d1192c8bc
@ -15,7 +15,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.10.5",
|
"@emotion/react": "^11.10.5",
|
||||||
"@emotion/styled": "^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/icons-material": "^5.10.14",
|
||||||
"@mui/material": "^5.10.14",
|
"@mui/material": "^5.10.14",
|
||||||
"@popperjs/core": "^2.11.8",
|
"@popperjs/core": "^2.11.8",
|
||||||
|
@ -10,7 +10,7 @@ import type {
|
|||||||
} from "@frontend/kitui";
|
} from "@frontend/kitui";
|
||||||
|
|
||||||
const apiUrl = process.env.REACT_APP_DOMAIN + "/auth";
|
const apiUrl = process.env.REACT_APP_DOMAIN + "/auth";
|
||||||
console.log("переменная", apiUrl);
|
|
||||||
export async function register(
|
export async function register(
|
||||||
login: string,
|
login: string,
|
||||||
password: string,
|
password: string,
|
||||||
@ -61,8 +61,9 @@ export async function recover(
|
|||||||
try {
|
try {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("email", email);
|
formData.append("email", email);
|
||||||
|
formData.append("RedirectionURL", process.env.REACT_APP_DOMAIN + "/changepwd")
|
||||||
const recoverResponse = await makeRequest<unknown, unknown>({
|
const recoverResponse = await makeRequest<unknown, unknown>({
|
||||||
url: process.env.REACT_APP_DOMAIN + "/recover",
|
url: process.env.REACT_APP_DOMAIN + "/codeword/recover",
|
||||||
body: formData,
|
body: formData,
|
||||||
useToken: false,
|
useToken: false,
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
|
@ -30,6 +30,8 @@ import PPofData from "@root/docs/PPofData"
|
|||||||
import Docs from "@root/docs/docs"
|
import Docs from "@root/docs/docs"
|
||||||
import Oferta from "@root/docs/content/oferta"
|
import Oferta from "@root/docs/content/oferta"
|
||||||
import PrivacyPolicy from "@root/docs/content/PrivacyPolicy"
|
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()
|
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="/signin" element={<SigninDialog />} />
|
||||||
<Route path="/signup" element={<SignupDialog />} />
|
<Route path="/signup" element={<SignupDialog />} />
|
||||||
<Route path="/recover" element={<RecoverDialog />} />
|
<Route path="/recover" element={<RecoverDialog />} />
|
||||||
|
<Route path="/chengepwd" element={<RecoverPassword />} />
|
||||||
|
<Route path="/changepwd/expired" element={<OutdatedLink />} />
|
||||||
|
|
||||||
</Routes>
|
</Routes>
|
||||||
)}
|
)}
|
||||||
<Routes location={location.state?.backgroundLocation || location}>
|
<Routes location={location.state?.backgroundLocation || location}>
|
||||||
@ -85,6 +90,8 @@ const App = () => {
|
|||||||
<Route path="/signin" element={<Navigate to="/" replace state={{ redirectTo: "/signin" }} />} />
|
<Route path="/signin" element={<Navigate to="/" replace state={{ redirectTo: "/signin" }} />} />
|
||||||
<Route path="/signup" element={<Navigate to="/" replace state={{ redirectTo: "/signup" }} />} />
|
<Route path="/signup" element={<Navigate to="/" replace state={{ redirectTo: "/signup" }} />} />
|
||||||
<Route path="/recover" element={<Navigate to="/" replace state={{ redirectTo: "/recover" }} />} />
|
<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={<PrivateRoute />}>
|
||||||
<Route element={<ProtectedLayout />}>
|
<Route element={<ProtectedLayout />}>
|
||||||
<Route path="/tariffs" element={<Tariffs />} />
|
<Route path="/tariffs" element={<Tariffs />} />
|
||||||
|
@ -7,7 +7,7 @@ interface Props {
|
|||||||
icon: ReactNode;
|
icon: ReactNode;
|
||||||
headerText: string;
|
headerText: string;
|
||||||
discount?: string;
|
discount?: string;
|
||||||
text: string | string[];
|
text?: any;
|
||||||
sx?: SxProps<Theme>;
|
sx?: SxProps<Theme>;
|
||||||
buttonProps?: {
|
buttonProps?: {
|
||||||
sx?: SxProps<Theme>;
|
sx?: SxProps<Theme>;
|
||||||
@ -78,7 +78,7 @@ export default function TariffCard({ icon, headerText, text, sx, price, buttonPr
|
|||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
{/* <Tooltip title={<Typography>{headerText}</Typography>} placement="top">
|
<Tooltip title={<Typography>{headerText}</Typography>} placement="top">
|
||||||
<Typography
|
<Typography
|
||||||
variant="h5"
|
variant="h5"
|
||||||
sx={{
|
sx={{
|
||||||
@ -92,8 +92,8 @@ export default function TariffCard({ icon, headerText, text, sx, price, buttonPr
|
|||||||
>
|
>
|
||||||
{headerText}
|
{headerText}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Tooltip> */}
|
</Tooltip>
|
||||||
{/* <Tooltip
|
<Tooltip
|
||||||
title={text.map((line, index) => (
|
title={text.map((line, index) => (
|
||||||
<Typography key={index}>{line}</Typography>
|
<Typography key={index}>{line}</Typography>
|
||||||
))}
|
))}
|
||||||
@ -111,7 +111,7 @@ export default function TariffCard({ icon, headerText, text, sx, price, buttonPr
|
|||||||
</Typography>
|
</Typography>
|
||||||
))}
|
))}
|
||||||
</Box>
|
</Box>
|
||||||
</Tooltip> */}
|
</Tooltip>
|
||||||
{buttonProps && (
|
{buttonProps && (
|
||||||
<Button
|
<Button
|
||||||
onClick={buttonProps.onClick}
|
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) {
|
if (recoverError) {
|
||||||
return enqueueSnackbar(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"
|
resolved "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.6.tgz"
|
||||||
integrity sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==
|
integrity sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==
|
||||||
|
|
||||||
"@frontend/kitui@1.0.58":
|
"@frontend/kitui@1.0.60":
|
||||||
version "1.0.58"
|
version "1.0.60"
|
||||||
resolved "https://penahub.gitlab.yandexcloud.net/api/v4/projects/21/packages/npm/@frontend/kitui/-/@frontend/kitui-1.0.58.tgz"
|
resolved "https://penahub.gitlab.yandexcloud.net/api/v4/projects/21/packages/npm/@frontend/kitui/-/@frontend/kitui-1.0.60.tgz#159980acd53fdf47ab3c4328f5a88850f2675a36"
|
||||||
integrity sha1-b/p7hJXG35suzyplPXAIBcBJ6s4=
|
integrity sha1-FZmArNU/30erPEMo9aiIUPJnWjY=
|
||||||
dependencies:
|
dependencies:
|
||||||
immer "^10.0.2"
|
immer "^10.0.2"
|
||||||
reconnecting-eventsource "^1.6.2"
|
reconnecting-eventsource "^1.6.2"
|
||||||
|
Loading…
Reference in New Issue
Block a user