сделал авторизацию
@ -3,7 +3,27 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<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>
|
||||
<body>
|
||||
<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 PrivateRoute from "./components/PrivateRoute.jsx";
|
||||
import LoginPage from "./pages/LoginPage.jsx";
|
||||
|
||||
|
||||
const AppRouter = () => (
|
||||
<Routes>
|
||||
<Route path="/login"/>
|
||||
<Route path="/login" element={<LoginPage/>}/>
|
||||
|
||||
<Route element={<PrivateRoute/>}>
|
||||
|
||||
<Route path={"/"} element={<p>1234</p>}/>
|
||||
</Route>
|
||||
</Routes>
|
||||
)
|
||||
|
||||
@ -18,9 +18,10 @@ export const AuthProvider = ({children}) => {
|
||||
try {
|
||||
const token = await loginUser(loginData);
|
||||
localStorage.setItem("access_token", token);
|
||||
setUser({ token });
|
||||
setUser({token});
|
||||
} catch (error) {
|
||||
console.error("Login failed", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -2,12 +2,17 @@ import axios from "axios";
|
||||
import CONFIG from "../core/Config.jsx";
|
||||
|
||||
export const loginUser = async (loginData) => {
|
||||
console.log(loginData)
|
||||
try {
|
||||
const response = await axios.post(`${CONFIG.BASE_URL}/login/`, loginData, {
|
||||
withCredentials: true,
|
||||
});
|
||||
return response.data.access_token;
|
||||
} 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 = {
|
||||
BASE_URL: 'http://localhost:8080/api/v1/',
|
||||
BASE_URL: 'http://localhost:8000/api/v1',
|
||||
};
|
||||
|
||||
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;
|
||||