сделал авторизацию
@ -3,7 +3,27 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Линза+</title>
|
<title>Линза ➕</title>
|
||||||
|
|
||||||
|
<link rel="apple-touch-icon" sizes="57x57" href="/favicons/favicon-57x57.png">
|
||||||
|
<link rel="apple-touch-icon" sizes="60x60" href="/favicons/favicon-60x60.png">
|
||||||
|
<link rel="apple-touch-icon" sizes="72x72" href="/favicons/favicon-72x72.png">
|
||||||
|
<link rel="apple-touch-icon" sizes="76x76" href="/favicons/favicon-76x76.png">
|
||||||
|
<link rel="apple-touch-icon" sizes="114x114" href="/favicons/favicon-114x114.png">
|
||||||
|
<link rel="apple-touch-icon" sizes="120x120" href="/favicons/favicon-120x120.png">
|
||||||
|
<link rel="apple-touch-icon" sizes="144x144" href="/favicons/favicon-144x144.png">
|
||||||
|
<link rel="apple-touch-icon" sizes="152x152" href="/favicons/favicon-152x152.png">
|
||||||
|
<link rel="apple-touch-icon" sizes="180x180" href="/favicons/favicon-180x180.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="16x16" href="/favicons/favicon-16x16.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="/favicons/favicon-32x32.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="96x96" href="/favicons/favicon-96x96.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="192x192" href="/favicons/favicon-192x192.png">
|
||||||
|
<link rel="shortcut icon" type="image/x-icon" href="/favicons/favicon.ico">
|
||||||
|
<link rel="icon" type="image/x-icon" href="/favicons/favicon.ico">
|
||||||
|
<meta name="msapplication-TileColor" content="#ffffff">
|
||||||
|
<meta name="msapplication-TileImage" content="/favicons/favicon-144x144.png">
|
||||||
|
<meta name="msapplication-config" content="/favicons/browserconfig.xml">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
12
web-app/public/favicons/browserconfig.xml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<browserconfig>
|
||||||
|
<msapplication>
|
||||||
|
<tile>
|
||||||
|
<square70x70logo src="/favicon-70x70.png"/>
|
||||||
|
<square150x150logo src="/favicon-150x150.png"/>
|
||||||
|
<square310x310logo src="/favicon-310x310.png"/>
|
||||||
|
<TileColor>#ffffff</TileColor>
|
||||||
|
</tile>
|
||||||
|
</msapplication>
|
||||||
|
</browserconfig>
|
||||||
BIN
web-app/public/favicons/favicon-114x114.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
web-app/public/favicons/favicon-120x120.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
web-app/public/favicons/favicon-144x144.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
web-app/public/favicons/favicon-150x150.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
web-app/public/favicons/favicon-152x152.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
web-app/public/favicons/favicon-16x16.png
Normal file
|
After Width: | Height: | Size: 681 B |
BIN
web-app/public/favicons/favicon-180x180.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
web-app/public/favicons/favicon-192x192.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
web-app/public/favicons/favicon-310x310.png
Normal file
|
After Width: | Height: | Size: 83 KiB |
BIN
web-app/public/favicons/favicon-32x32.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
web-app/public/favicons/favicon-57x57.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
web-app/public/favicons/favicon-60x60.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
web-app/public/favicons/favicon-70x70.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
web-app/public/favicons/favicon-72x72.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
web-app/public/favicons/favicon-76x76.png
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
BIN
web-app/public/favicons/favicon-96x96.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
web-app/public/favicons/favicon.ico
Normal file
|
After Width: | Height: | Size: 364 KiB |
BIN
web-app/public/logo_rounded.png
Normal file
|
After Width: | Height: | Size: 496 KiB |
BIN
web-app/public/logo_with_back.png
Normal file
|
After Width: | Height: | Size: 410 KiB |
@ -1,13 +1,14 @@
|
|||||||
import {Routes, Route} from "react-router-dom";
|
import {Routes, Route} from "react-router-dom";
|
||||||
import PrivateRoute from "./components/PrivateRoute.jsx";
|
import PrivateRoute from "./components/PrivateRoute.jsx";
|
||||||
|
import LoginPage from "./pages/LoginPage.jsx";
|
||||||
|
|
||||||
|
|
||||||
const AppRouter = () => (
|
const AppRouter = () => (
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/login"/>
|
<Route path="/login" element={<LoginPage/>}/>
|
||||||
|
|
||||||
<Route element={<PrivateRoute/>}>
|
<Route element={<PrivateRoute/>}>
|
||||||
|
<Route path={"/"} element={<p>1234</p>}/>
|
||||||
</Route>
|
</Route>
|
||||||
</Routes>
|
</Routes>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -18,9 +18,10 @@ export const AuthProvider = ({children}) => {
|
|||||||
try {
|
try {
|
||||||
const token = await loginUser(loginData);
|
const token = await loginUser(loginData);
|
||||||
localStorage.setItem("access_token", token);
|
localStorage.setItem("access_token", token);
|
||||||
setUser({ token });
|
setUser({token});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Login failed", error);
|
console.error("Login failed", error);
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -2,12 +2,17 @@ import axios from "axios";
|
|||||||
import CONFIG from "../core/Config.jsx";
|
import CONFIG from "../core/Config.jsx";
|
||||||
|
|
||||||
export const loginUser = async (loginData) => {
|
export const loginUser = async (loginData) => {
|
||||||
|
console.log(loginData)
|
||||||
try {
|
try {
|
||||||
const response = await axios.post(`${CONFIG.BASE_URL}/login/`, loginData, {
|
const response = await axios.post(`${CONFIG.BASE_URL}/login/`, loginData, {
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
});
|
});
|
||||||
return response.data.access_token;
|
return response.data.access_token;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error("Login failed: " + error.message);
|
if (error.status === 401) {
|
||||||
|
throw new Error("Неверное имя пользователя или пароль")
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(error.message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
const CONFIG = {
|
const CONFIG = {
|
||||||
BASE_URL: 'http://localhost:8080/api/v1/',
|
BASE_URL: 'http://localhost:8000/api/v1',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CONFIG;
|
export default CONFIG;
|
||||||
69
web-app/src/pages/LoginPage.jsx
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import {Form, Input, Button, Row, Col, Typography} from 'antd';
|
||||||
|
import {useState} from 'react';
|
||||||
|
import {useAuth} from "../AuthContext.jsx";
|
||||||
|
|
||||||
|
const {Title} = Typography;
|
||||||
|
|
||||||
|
const LoginPage = () => {
|
||||||
|
const {login} = useAuth();
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [error, setError] = useState(null);
|
||||||
|
|
||||||
|
const onFinish = async (values) => {
|
||||||
|
setLoading(true);
|
||||||
|
setError(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await login(values);
|
||||||
|
} catch (error) {
|
||||||
|
setError(`Ошибка при входе: ${error.message}`);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Row justify="center" align="middle" style={{minHeight: '100vh'}}>
|
||||||
|
<Col xs={24} sm={18} md={12} lg={8} xl={6}>
|
||||||
|
<div style={{padding: 20, border: '1px solid #ddd', borderRadius: 8}}>
|
||||||
|
<Title level={2} style={{textAlign: 'center'}}>Авторизация</Title>
|
||||||
|
|
||||||
|
{error && <div style={{color: 'red', marginBottom: 15}}>{error}</div>}
|
||||||
|
|
||||||
|
<Form
|
||||||
|
name="login"
|
||||||
|
initialValues={{remember: true}}
|
||||||
|
onFinish={onFinish}
|
||||||
|
>
|
||||||
|
<Form.Item
|
||||||
|
name="login"
|
||||||
|
rules={[{required: true, message: 'Пожалуйста, введите логин'}]}
|
||||||
|
>
|
||||||
|
<Input placeholder="Логин"/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="password"
|
||||||
|
rules={[{required: true, message: 'Пожалуйста, введите пароль'}]}
|
||||||
|
>
|
||||||
|
<Input.Password placeholder="Пароль"/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
htmlType="submit"
|
||||||
|
block
|
||||||
|
loading={loading}
|
||||||
|
>
|
||||||
|
Войти
|
||||||
|
</Button>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LoginPage;
|
||||||