diff --git a/front/src/app/hooks.ts b/front/src/app/hooks.ts index c9b7832..9444192 100644 --- a/front/src/app/hooks.ts +++ b/front/src/app/hooks.ts @@ -2,5 +2,5 @@ import { useDispatch, useSelector } from 'react-redux'; import type {TypedUseSelectorHook} from 'react-redux'; import type { RootState, AppDispatch } from './store'; -export const useAppDispatch: () => AppDispatch = useDispatch; +export const useAppDispatch = () => useDispatch(); export const useAppSelector: TypedUseSelectorHook = useSelector; \ No newline at end of file diff --git a/front/src/app/routes.tsx b/front/src/app/routes.tsx index 529bf96..da330c6 100644 --- a/front/src/app/routes.tsx +++ b/front/src/app/routes.tsx @@ -8,7 +8,7 @@ import { Route } from "react-router"; function AppRoutes() { return ( - {/*} />*/} + } /> }> } /> } /> diff --git a/front/src/features/auth/authSlice.ts b/front/src/features/auth/authSlice.ts index 052e03a..68a9f3b 100644 --- a/front/src/features/auth/authSlice.ts +++ b/front/src/features/auth/authSlice.ts @@ -22,7 +22,10 @@ const authSlice = createSlice({ state.token = null; state.error = null; localStorage.removeItem("token"); - } + }, + clearError: (state) => { + state.error = null; + }, }, extraReducers: builder => { builder @@ -34,6 +37,7 @@ const authSlice = createSlice({ state.loading = false; state.token = action.payload.token; state.error = null; + localStorage.setItem('token', action.payload.token); }) .addCase(loginThunk.rejected, (state, action) => { state.loading = false; @@ -42,5 +46,5 @@ const authSlice = createSlice({ } }); -export const { logout } = authSlice.actions; +export const { logout, clearError } = authSlice.actions; export default authSlice.reducer; \ No newline at end of file diff --git a/front/src/pages/Layout/Layout.tsx b/front/src/pages/Layout/Layout.tsx index d14827e..84a558e 100644 --- a/front/src/pages/Layout/Layout.tsx +++ b/front/src/pages/Layout/Layout.tsx @@ -1,16 +1,23 @@ import Header from "../../widgets/Header/Header"; import { Outlet } from "react-router"; +import { useAppDispatch, useAppSelector } from '../../app/hooks'; +import type { RootState } from "../../app/store"; +import { Navigate } from "react-router"; const Layout = () =>{ + + const { token } = useAppSelector((state: RootState) => state.auth) + return( -
+ token ?
-
+
: + ); }; diff --git a/front/src/pages/LoginPage/LoginPage.tsx b/front/src/pages/LoginPage/LoginPage.tsx index 35d8243..9e34c3a 100644 --- a/front/src/pages/LoginPage/LoginPage.tsx +++ b/front/src/pages/LoginPage/LoginPage.tsx @@ -1,9 +1,150 @@ -const LoginPage = () =>{ - return( - <> +import React, { useEffect, useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { Form, Input, Button, Checkbox, Alert, Card, Spin, Image } from 'antd'; +import { UserOutlined, LockOutlined } from '@ant-design/icons'; +import { useAppDispatch, useAppSelector } from '../../app/hooks'; +import { loginThunk } from "../../features/auth/authThunks"; +import { clearError } from '../../features/auth/authSlice'; - - ) +interface LoginForm { + email: string; + password: string; + rememberMe: boolean; } +const LoginPage: React.FC = () => { + const navigate = useNavigate(); + const dispatch = useAppDispatch(); + const { loading, error, token } = useAppSelector((state) => state.auth); + + const [form] = Form.useForm(); + + useEffect(() => { + if (token) { + navigate('/'); + } + }, [token, navigate]); + + const handleSubmit = async (values: LoginForm) => { + try { + const result = await dispatch(loginThunk(values)).unwrap(); + + if (result.token) { + navigate('/data-collection'); + } + } catch (error) { + console.error('Login error:', error); + } + }; + + const handleForgotPassword = () => { + console.log('Forgot password clicked'); + }; + + return ( +
+
+ Company Logo +
+ + +

+ Вход в систему +

+ + {error && ( + dispatch(clearError())} + className="login-error-alert" + /> + )} + +
+ + } + placeholder="Введите email" + size="large" + /> + + + + } + placeholder="Введите пароль" + size="large" + /> + + + + Запомнить меня + + + + + +
+ +
+ +
+
+
+ ); +}; + export default LoginPage; \ No newline at end of file diff --git a/front/src/widgets/Header/Header.tsx b/front/src/widgets/Header/Header.tsx index 612b2b6..65201ba 100644 --- a/front/src/widgets/Header/Header.tsx +++ b/front/src/widgets/Header/Header.tsx @@ -1,12 +1,17 @@ import { NavLink } from "react-router"; +import { useAppDispatch, useAppSelector } from '../../app/hooks'; +import { logout } from "../../features/auth/authSlice"; const Header = () =>{ + + const dispatch = useAppDispatch(); + return( )