авторизация с подвязкой к беку

This commit is contained in:
krokodilka 2023-03-12 05:32:56 +03:00
parent 00ae7fb567
commit 45c7262dbd
12 changed files with 361 additions and 64 deletions

101
package-lock.json generated

@ -27,11 +27,13 @@
"@types/react": "^18.0.18",
"@types/react-dom": "^18.0.6",
"@types/react-router-dom": "^5.3.3",
"axios": "^1.3.4",
"craco": "^0.0.3",
"dayjs": "^1.11.5",
"formik": "^2.2.9",
"moment": "^2.29.4",
"nanoid": "^4.0.1",
"notistack": "^3.0.1",
"numeral": "^2.0.6",
"react": "^18.2.0",
"react-dom": "^18.2.0",
@ -6217,6 +6219,29 @@
"node": ">=4"
}
},
"node_modules/axios": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz",
"integrity": "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==",
"dependencies": {
"follow-redirects": "^1.15.0",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/axios/node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/axobject-query": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz",
@ -11767,6 +11792,14 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/goober": {
"version": "2.1.12",
"resolved": "https://registry.npmjs.org/goober/-/goober-2.1.12.tgz",
"integrity": "sha512-yXHAvO08FU1JgTXX6Zn6sYCUFfB/OJSX8HHjDSgerZHZmFKAb08cykp5LBw5QnmyMcZyPRMqkdyHUSSzge788Q==",
"peerDependencies": {
"csstype": "^3.0.10"
}
},
"node_modules/gopd": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
@ -15225,6 +15258,27 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/notistack": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/notistack/-/notistack-3.0.1.tgz",
"integrity": "sha512-ntVZXXgSQH5WYfyU+3HfcXuKaapzAJ8fBLQ/G618rn3yvSzEbnOB8ZSOwhX+dAORy/lw+GC2N061JA0+gYWTVA==",
"dependencies": {
"clsx": "^1.1.0",
"goober": "^2.0.33"
},
"engines": {
"node": ">=12.0.0",
"npm": ">=6.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/notistack"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/npm-run-path": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
@ -17482,6 +17536,11 @@
"node": ">= 0.10"
}
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"node_modules/prr": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
@ -26416,6 +26475,28 @@
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.6.3.tgz",
"integrity": "sha512-/BQzOX780JhsxDnPpH4ZiyrJAzcd8AfzFPkv+89veFSr1rcMjuq2JDCwypKaPeB6ljHp9KjXhPpjgCvQlWYuqg=="
},
"axios": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz",
"integrity": "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==",
"requires": {
"follow-redirects": "^1.15.0",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
},
"dependencies": {
"form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
}
}
}
},
"axobject-query": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz",
@ -30511,6 +30592,12 @@
"slash": "^3.0.0"
}
},
"goober": {
"version": "2.1.12",
"resolved": "https://registry.npmjs.org/goober/-/goober-2.1.12.tgz",
"integrity": "sha512-yXHAvO08FU1JgTXX6Zn6sYCUFfB/OJSX8HHjDSgerZHZmFKAb08cykp5LBw5QnmyMcZyPRMqkdyHUSSzge788Q==",
"requires": {}
},
"gopd": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
@ -32979,6 +33066,15 @@
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
"integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A=="
},
"notistack": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/notistack/-/notistack-3.0.1.tgz",
"integrity": "sha512-ntVZXXgSQH5WYfyU+3HfcXuKaapzAJ8fBLQ/G618rn3yvSzEbnOB8ZSOwhX+dAORy/lw+GC2N061JA0+gYWTVA==",
"requires": {
"clsx": "^1.1.0",
"goober": "^2.0.33"
}
},
"npm-run-path": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
@ -34351,6 +34447,11 @@
}
}
},
"proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"prr": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",

@ -22,11 +22,13 @@
"@types/react": "^18.0.18",
"@types/react-dom": "^18.0.6",
"@types/react-router-dom": "^5.3.3",
"axios": "^1.3.4",
"craco": "^0.0.3",
"dayjs": "^1.11.5",
"formik": "^2.2.9",
"moment": "^2.29.4",
"nanoid": "^4.0.1",
"notistack": "^3.0.1",
"numeral": "^2.0.6",
"react": "^18.2.0",
"react-dom": "^18.2.0",

@ -1,8 +1,9 @@
import * as React from "react";
import CssBaseline from "@mui/material/CssBaseline";
import { SnackbarProvider } from 'notistack';
import { ThemeProvider } from '@mui/material/styles';
import { createRoot } from 'react-dom/client';
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { BrowserRouter, Routes, Route, Outlet, Navigate } from "react-router-dom";
import theme from "./theme";
import PublicRoute from "@kitUI/publicRoute";
import PrivateRoute from "@kitUI/privateRoute";
@ -10,7 +11,7 @@ import Signin from "@pages/Authorization/signin";
import Signup from "@pages/Authorization/signup";
import Restore from "@pages/Authorization/restore";
import Sections from "@pages/Sections";
import LoggedIn from "@pages/dashboard";
import Dashboard from "@pages/dashboard";
import Error404 from "@pages/Error404";
import Users from "@pages/dashboard/Content/Users";
import Entities from "@pages/dashboard/Content/Entities";
@ -34,23 +35,27 @@ root.render(
<React.StrictMode>
<CssBaseline />
<ThemeProvider theme={theme}>
<BrowserRouter>
<Routes>
<Route path="/" element={<PublicRoute><Signin /></PublicRoute> } />
<Route path="/signin" element={ <PublicRoute><Signin /></PublicRoute> } />
<Route path="/signup" element={ <PublicRoute><Signup /></PublicRoute> } />
<Route path="/restore" element={ <PublicRoute><Restore /></PublicRoute> } />
<Route path="/dispatch" element={ <PublicRoute><Sections /></PublicRoute> } />
{componentsArray.map((e:any, i) => (
<Route key={i} path={e[0]} element={ <PrivateRoute>{e[1]}</PrivateRoute> } />
))}
<SnackbarProvider>
<BrowserRouter>
<Routes>
<Route path="/" element={<PublicRoute><Signin /></PublicRoute> } />
<Route path="/signin" element={ <PublicRoute><Signin /></PublicRoute> } />
<Route path="/signup" element={ <PublicRoute><Signup /></PublicRoute> } />
<Route path="/restore" element={ <PublicRoute><Restore /></PublicRoute> } />
<Route path="/dispatch" element={ <PublicRoute><Sections /></PublicRoute> } />
<Route element={<PrivateRoute><Dashboard/></PrivateRoute>}>
{componentsArray.map((e:any, i) => (
<Route key={i} path={e[0]} element={e[1]} />
))}
</Route>
<Route
path="*"
element={ <Error404 /> }
/>
</Routes>
</BrowserRouter>
<Route
path="*"
element={ <Error404 /> }
/>
</Routes>
</BrowserRouter>
</SnackbarProvider>
</ThemeProvider>
</React.StrictMode>
);

65
src/kitUI/makeRequest.ts Normal file

@ -0,0 +1,65 @@
import axios from 'axios'
interface MakeRequest {
method?: string
url: string
body?: unknown
useToken?: boolean
contentType?: boolean
}
export default (props: MakeRequest) => {
return (
new Promise(async (resolve, reject) => {
await makeRequest(props)
.then(r => resolve(r))
.catch(r => reject(r))
})
)
}
function makeRequest({
method = "post",
url,
body,
useToken = true,
contentType = false
}: MakeRequest) {
//В случае 401 рефреш должен попробовать вызваться 1 раз
let counterRefresh = true
let headers: any = {}
if (useToken) headers["Authorization"] = localStorage.getItem('AT')
if (contentType) headers["Content-Type"] = "application/json"
return axios({
url: url,
method: method,
headers: headers,
data: body
})
.then(response => {
if (response.data && response.data.accessToken) {
localStorage.setItem('AT', response.data.accessToken)
}
return response
})
.catch(error => {
if (error.response.status == 401 && counterRefresh) {
refresh().then(response => {
if (response.data && response.data.accessToken) localStorage.setItem('AT', response.data.accessToken)
counterRefresh = false
})
} else {
throw error
}
throw error
})
}
function refresh() {
return axios("https://hub.pena.digital/auth/refresh", {
headers: {
"Authorization": localStorage.getItem('AT'),
"Content-Type": "application/json"
}
})
}

@ -2,13 +2,11 @@ import * as React from "react";
import { useLocation, Navigate } from 'react-router-dom'
export default ({ children }: any) => {
console.log("проверяю")
const auth = true
const location = useLocation()
if (!auth) {
//Если пользователь авторизован, перенаправляем его на нужный путь. Иначе выкидываем в регистрацию
if (localStorage.getItem('AT')) {
return children
}
return <Navigate to="/users" state={{from: location}} />
return <Navigate to="/" state={{from: location}} />
}

@ -2,13 +2,11 @@ import * as React from "react";
import { useLocation, Navigate } from 'react-router-dom'
export default ({ children }: any) => {
console.log("проверяю")
const auth = true
const location = useLocation()
if (!auth) {
return <Navigate to="/signin" state={{from: location}} />
//Если пользователь авторизован, перенаправляем его в приложение. Иначе пускаем куда хотел
if (localStorage.getItem('AT')) {
return <Navigate to="/users" state={{from: location}} />
}
return children
}

@ -1,16 +1,19 @@
import * as React from "react";
import { useNavigate } from "react-router-dom";
import { Formik, Field, Form } from 'formik';
import {useTheme} from "@mui/material/styles";
import { Link } from "react-router-dom"
import {Box, Button, Checkbox, TextField, Typography} from "@mui/material";
import {Box, Typography} from "@mui/material";
import Logo from "@pages/Logo";
import CleverButton from "@kitUI/cleverButton"
import MakeRequest from "@kitUI/makeRequest";
import EmailOutlinedIcon from "@mui/icons-material/EmailOutlined";
import LockOutlinedIcon from "@mui/icons-material/LockOutlined";
import OutlinedInput from "@kitUI/outlinedInput";
export default () => {
const theme = useTheme()
const navigate = useNavigate();
const [restore, setRestore] = React.useState(true)
const [isReady, setIsReady] = React.useState(true)
if (restore) {

@ -1,4 +1,6 @@
import * as React from "react"
import { useNavigate } from "react-router-dom";
import { enqueueSnackbar } from 'notistack';
import {useTheme} from "@mui/material/styles"
import { Formik, Field, Form } from 'formik'
import { Link } from "react-router-dom"
@ -6,21 +8,56 @@ import { Box, Checkbox, TextField, Typography, FormControlLabel} from "@mui/mate
import Logo from "@pages/Logo"
import CleverButton from "@kitUI/cleverButton"
import OutlinedInput from "@kitUI/outlinedInput"
import makeRequest from "@kitUI/makeRequest";
import EmailOutlinedIcon from "@mui/icons-material/EmailOutlined";
import LockOutlinedIcon from "@mui/icons-material/LockOutlined"
interface Values {
email: string;
password: string;
}
function validate(values: Values) {
const errors = {} as any;
if (!values.email) {
errors.email = "Required";
}
if (!values.password) {
errors.password = "Required";
} else if (!/^[\w-]{8,25}$/i.test(values.password)) {
errors.password = "Invalid password";
}
return errors;
}
export default () => {
const theme = useTheme()
const navigate = useNavigate();
const [isReady, setIsReady] = React.useState(true)
return(
<Formik
initialValues={{
login: "",
pass: ""
email: "",
password: ""
}}
validate={validate}
onSubmit={(values) => {
makeRequest({
url: "https://hub.pena.admin/auth/login",
body: {
"email": values.email,
"password": values.password
},
useToken: false
})
.then((e) => {
console.log(e)
navigate("/users")
})
.catch((e) => {
console.log(e)
enqueueSnackbar(e.message ? e.message : `Unknown error`)
})
}}
>
<Form>
@ -55,11 +92,11 @@ export default () => {
</Box>
<Box sx={{display:"flex", alignItems:"center",marginTop:"15px","> *": {marginRight:"10px"}}}>
<EmailOutlinedIcon htmlColor={theme.palette.golden.main}/>
<Field as={OutlinedInput} name="login" variant="filled" label="Эл. почта"/>
<Field as={OutlinedInput} name="email" variant="filled" label="Эл. почта"/>
</Box>
<Box sx={{display:"flex", alignItems:"center",marginTop:"15px","> *": {marginRight:"10px"}}}>
<LockOutlinedIcon htmlColor={theme.palette.golden.main}/>
<Field as={OutlinedInput} type="password" name="pass" variant="filled" label="Пароль"/>
<Field as={OutlinedInput} type="password" name="password" variant="filled" label="Пароль"/>
</Box>
<Box component="article"
sx={{

@ -1,26 +1,67 @@
import * as React from "react"
import { enqueueSnackbar } from 'notistack';
import { useNavigate } from "react-router-dom";
import { useTheme } from "@mui/material/styles"
import { Formik, Field, Form } from "formik"
import { Link } from "react-router-dom"
import {Box, TextField, Typography} from "@mui/material"
import {Box, Typography} from "@mui/material"
import CleverButton from "@kitUI/cleverButton"
import OutlinedInput from "@kitUI/outlinedInput";
import makeRequest from "@kitUI/makeRequest";
import Logo from "@pages/Logo/index"
import EmailOutlinedIcon from "@mui/icons-material/EmailOutlined"
import LockOutlinedIcon from "@mui/icons-material/LockOutlined"
interface Values {
email: string;
password: string;
repeatPassword: string;
}
function validate(values: Values) {
const errors = {} as any;
if (!values.email) {
errors.login = "Required";
}
if (!values.password) {
errors.password = "Required";
} else if (!/^[\w-]{8,25}$/i.test(values.password)) {
errors.password = "Invalid password";
}
if (values.password !== values.repeatPassword) {
errors.repeatPassword = "Passwords do not match";
}
return errors;
}
export default () => {
const navigate = useNavigate();
const theme = useTheme()
const [isReady, setIsReady] = React.useState(true)
return(
<Formik
initialValues={{
login: "",
first: "",
second: ""
email: "",
password: "",
repeatPassword: ""
}}
validate={validate}
onSubmit={(values) => {
makeRequest({
url: "https://hub.pena.admin/auth/register",
body: {
"login": "login",
"email": values.email,
"password": values.repeatPassword,
"phoneNumber": "+89999999999"
},
useToken: false
})
.then((e) => {
navigate("/users")
})
.catch((e) => {
console.log(e)
enqueueSnackbar(e.response && e.response.data && e.response.data.message ? e.response.data.message : `Unknown error`)
})
}}
>
<Form>
@ -57,15 +98,15 @@ export default () => {
</Box>
<Box sx={{display:"flex", alignItems:"center",marginTop:"15px","> *": {marginRight:"10px"}}}>
<EmailOutlinedIcon htmlColor={theme.palette.golden.main}/>
<Field as={OutlinedInput} name="login" variant="filled" label="Эл. почта"/>
<Field as={OutlinedInput} name="email" variant="filled" label="Эл. почта"/>
</Box>
<Box sx={{display:"flex", alignItems:"center",marginTop:"15px","> *": {marginRight:"10px"}}}>
<LockOutlinedIcon htmlColor={theme.palette.golden.main}/>
<Field as={OutlinedInput} type="password" name="first" variant="filled" label="Пароль"/>
<Field as={OutlinedInput} type="password" name="password" variant="filled" label="Пароль"/>
</Box>
<Box sx={{display:"flex", alignItems:"center",marginTop:"15px","> *": {marginRight:"10px"}}}>
<LockOutlinedIcon htmlColor={theme.palette.golden.main}/>
<Field as={OutlinedInput} type="password" name="second" variant="filled" label="Повторите пароль"/>
<Field as={OutlinedInput} type="password" name="repeatPassword" variant="filled" label="Повторите пароль"/>
</Box>
<CleverButton type="submit" text="Отправить" isReady={isReady}/>
<Link to="/signin" style={{textDecoration: "none"}} ><Typography color={theme.palette.golden.main}>У меня уже есть аккаунт</Typography></Link>

@ -1,8 +1,9 @@
import * as React from "react";
import { Box, Typography } from "@mui/material";
import {Box, IconButton, Typography} from "@mui/material";
import theme from "../../../theme";
import ExitToAppOutlinedIcon from '@mui/icons-material/ExitToAppOutlined';
import Logo from "../../Logo";
import makeRequest from "@kitUI/makeRequest";
const Header: React.FC = () => {
@ -43,7 +44,15 @@ const Header: React.FC = () => {
Добро пожаловать, Администратор сервиса
</Typography>
<Box sx={{
<IconButton
onClick={()=>{
makeRequest({
url: "https://hub.pena.admin/auth/logout",
contentType: true
})
.then(()=>localStorage.setItem('AT', ""))
}}
sx={{
display: "flex",
flexDirection: "column",
justifyContent: "center",
@ -55,7 +64,7 @@ const Header: React.FC = () => {
color: theme.palette.golden.main,
transform: "scale(1.3)"
}} />
</Box>
</IconButton>
</Box>
</Box>
</React.Fragment>

@ -1,5 +1,5 @@
import * as React from "react";
import { Outlet } from 'react-router-dom'
import {Outlet} from 'react-router-dom'
import {useTheme} from '@mui/material/styles';
import {Box} from "@mui/material";
import {ThemeProvider} from "@mui/material";
@ -11,12 +11,7 @@ import ModalUser from "./ModalUser";
import ModalEntities from "./ModalEntities";
import {useMatch} from "react-router-dom";
export interface MWProps {
section: number
}
const LoggedIn: React.FC<MWProps> = ({section}) => {
export default () => {
const theme = useTheme()
return (
<React.Fragment>
@ -41,7 +36,18 @@ const LoggedIn: React.FC<MWProps> = ({section}) => {
justifyContent: "space-between",
alignItems: "center"
}}>
<Outlet />
<Box sx={{
width: "100%",
height: "100vh",
display: "flex",
flexDirection: "column",
alignItems: "center",
overflow: "auto",
overflowY: "auto",
padding: "160px 5px"
}}>
<Outlet/>
</Box>
</Box>
</Box>
</Box>
@ -49,10 +55,6 @@ const LoggedIn: React.FC<MWProps> = ({section}) => {
<ModalAdmin open={useMatch('/modalAdmin') !== null}/>
<ModalUser open={useMatch('/modalUser') !== null}/>
<ModalEntities open={useMatch('/modalEntities') !== null}/>
</React.Fragment>
)
;
</React.Fragment>
)
}
export default LoggedIn;

@ -3416,6 +3416,15 @@
"resolved" "https://registry.npmjs.org/axe-core/-/axe-core-4.6.3.tgz"
"version" "4.6.3"
"axios@^1.3.4":
"integrity" "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ=="
"resolved" "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz"
"version" "1.3.4"
dependencies:
"follow-redirects" "^1.15.0"
"form-data" "^4.0.0"
"proxy-from-env" "^1.1.0"
"axobject-query@^3.1.1":
"integrity" "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg=="
"resolved" "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz"
@ -4173,7 +4182,7 @@
"process-nextick-args" "^2.0.0"
"readable-stream" "^2.3.5"
"clsx@^1.0.2", "clsx@^1.2.1":
"clsx@^1.0.2", "clsx@^1.1.0", "clsx@^1.2.1":
"integrity" "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg=="
"resolved" "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz"
"version" "1.2.1"
@ -4742,7 +4751,7 @@
dependencies:
"cssom" "~0.3.6"
"csstype@^3.0.2", "csstype@^3.1.1":
"csstype@^3.0.10", "csstype@^3.0.2", "csstype@^3.1.1":
"integrity" "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw=="
"resolved" "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz"
"version" "3.1.1"
@ -6041,7 +6050,7 @@
"inherits" "^2.0.3"
"readable-stream" "^2.3.6"
"follow-redirects@^1.0.0":
"follow-redirects@^1.0.0", "follow-redirects@^1.15.0":
"integrity" "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA=="
"resolved" "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz"
"version" "1.15.2"
@ -6086,6 +6095,15 @@
"combined-stream" "^1.0.8"
"mime-types" "^2.1.12"
"form-data@^4.0.0":
"integrity" "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww=="
"resolved" "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz"
"version" "4.0.0"
dependencies:
"asynckit" "^0.4.0"
"combined-stream" "^1.0.8"
"mime-types" "^2.1.12"
"formik@^2.2.9":
"integrity" "sha512-LQLcISMmf1r5at4/gyJigGn0gOwFbeEAlji+N9InZF6LIMXnFNkO42sCI8Jt84YZggpD4cPWObAZaxpEFtSzNA=="
"resolved" "https://registry.npmjs.org/formik/-/formik-2.2.9.tgz"
@ -6336,6 +6354,11 @@
"merge2" "^1.4.1"
"slash" "^3.0.0"
"goober@^2.0.33":
"integrity" "sha512-yXHAvO08FU1JgTXX6Zn6sYCUFfB/OJSX8HHjDSgerZHZmFKAb08cykp5LBw5QnmyMcZyPRMqkdyHUSSzge788Q=="
"resolved" "https://registry.npmjs.org/goober/-/goober-2.1.12.tgz"
"version" "2.1.12"
"gopd@^1.0.1":
"integrity" "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA=="
"resolved" "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz"
@ -8593,6 +8616,14 @@
"resolved" "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz"
"version" "6.1.0"
"notistack@^3.0.1":
"integrity" "sha512-ntVZXXgSQH5WYfyU+3HfcXuKaapzAJ8fBLQ/G618rn3yvSzEbnOB8ZSOwhX+dAORy/lw+GC2N061JA0+gYWTVA=="
"resolved" "https://registry.npmjs.org/notistack/-/notistack-3.0.1.tgz"
"version" "3.0.1"
dependencies:
"clsx" "^1.1.0"
"goober" "^2.0.33"
"npm-run-path@^4.0.1":
"integrity" "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="
"resolved" "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz"
@ -9717,6 +9748,11 @@
"forwarded" "0.2.0"
"ipaddr.js" "1.9.1"
"proxy-from-env@^1.1.0":
"integrity" "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
"resolved" "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz"
"version" "1.1.0"
"prr@~1.0.1":
"integrity" "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw=="
"resolved" "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz"
@ -9895,7 +9931,7 @@
"strip-ansi" "^6.0.1"
"text-table" "^0.2.0"
"react-dom@^16.8.0 || ^17.0.0", "react-dom@^17.0.0 || ^18.0.0", "react-dom@^17.0.2 || ^18.0.0", "react-dom@^18.0.0", "react-dom@^18.2.0", "react-dom@>= 16.8.0", "react-dom@>=16.6.0", "react-dom@>=16.8":
"react-dom@^16.8.0 || ^17.0.0", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom@^17.0.0 || ^18.0.0", "react-dom@^17.0.2 || ^18.0.0", "react-dom@^18.0.0", "react-dom@^18.2.0", "react-dom@>= 16.8.0", "react-dom@>=16.6.0", "react-dom@>=16.8":
"integrity" "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g=="
"resolved" "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz"
"version" "18.2.0"