Commit f182237d authored by Болатов Ален's avatar Болатов Ален

Merge branch '27' into 'dev'

27

See merge request !30
parents 5cd3529a 6e4507e8
import {Router} from 'express';
import {Router, Request, Response} from 'express';
import * as userController from '../controllers/user';
import UserModel from '../models/User';
const router: Router = Router();
router.post('/register', userController.registerOne);
router.post('/login', userController.loginOne);
router.post('/getToken', async (req: Request, res: Response) => {
const user = await UserModel.find({token: req.body.token});
res.send(user);
});
export {router as UsersRouter};
......@@ -2,7 +2,7 @@ import React from 'react';
import {BrowserRouter, Routes, Route} from 'react-router-dom';
import Layout from './components/Layout';
import HomePage from './containers/HomePage';
import Register from './containers/Register';
import Login from './containers/Login';
const App: React.FunctionComponent = (): React.ReactElement => {
return (
......@@ -10,7 +10,7 @@ const App: React.FunctionComponent = (): React.ReactElement => {
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<HomePage />} />
<Route path="register" element={<Register />} />
<Route path="register" element={<Login />} />
</Route>
</Routes>
</BrowserRouter>
......
import React, {FunctionComponent, ReactElement} from 'react';
import {NavLink, Outlet} from 'react-router-dom';
import {useAppDispatch, useAppSelector} from '../store/hooks';
import {setInitialUser} from '../store/users/users.slice';
import {useDispatch} from 'react-redux';
const Layout: FunctionComponent = (): ReactElement => {
const {user} = useAppSelector((state) => state.user);
const dispatch = useAppDispatch();
return (
<div className="bg-gray-50 dark:bg-gray-900">
<div className="flex justify-between container mx-auto">
<a href="#">Add Post</a>
<div>
<NavLink className={'mr-3'} to={'register'}>
Register
</NavLink>
</div>
<p>Forum</p>
{!user.username ? (
<div>
<NavLink className={'mr-3'} to={'register'}>
Register
</NavLink>
</div>
) : (
<div className="flex items-center">
<p>{user.username}</p>
<NavLink className={'mx-4'} to={'/'}>
Add new Post
</NavLink>
<NavLink
onClick={() => {
window.sessionStorage.setItem('token', '');
dispatch(setInitialUser());
}}
to={'/'}
>
Log out
</NavLink>
</div>
)}
</div>
<Outlet />
</div>
......
import {FunctionComponent, ReactElement, useEffect} from 'react';
import {shallowEqual, useDispatch} from 'react-redux';
import {useAppDispatch, useAppSelector} from '../store/hooks';
import {getUser} from '../store/users/users.slice';
const HomePage: FunctionComponent = (): ReactElement => {
const dispatch = useAppDispatch();
useEffect(() => {
const token = window.sessionStorage.getItem('token');
if (token) {
dispatch(getUser(token));
}
});
return (
<div className="bg-gray-50 dark:bg-gray-900 h-screen w-full container mx-auto">
homepage
......
import React, {useEffect, useState} from 'react';
import {Navigate, useNavigate} from 'react-router-dom';
import IUser from '../interfaces/IUser';
import {useAppDispatch, useAppSelector} from '../store/hooks';
import {createUser, loginUser} from '../store/users/users.slice';
const Login = () => {
const dispatch = useAppDispatch();
const navigate = useNavigate();
const [user, setUser] = useState({} as IUser);
const {userLoggedIn} = useAppSelector((state) => state.user);
const handleRegister = async () => {
await dispatch(createUser(user));
};
const handleUserInput = (e: React.ChangeEvent<HTMLInputElement>) => {
setUser((prevState) => ({...prevState, [e.target.name]: e.target.value}));
};
const handleSubmit = async (e: React.ChangeEvent<HTMLFormElement>) => {
e.preventDefault();
await dispatch(loginUser(user));
};
if (userLoggedIn) {
return <Navigate to={'/'} />;
}
return (
<div className="w-full max-w-xs m-auto h-screen mt-[200px]">
<form
onSubmit={handleSubmit}
className="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4"
>
<div className="mb-4">
<label
className="block text-gray-700 text-sm font-bold mb-2"
htmlFor="username"
>
Username
</label>
<input
onChange={handleUserInput}
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
id="username"
type="text"
placeholder="Username"
name="username"
/>
</div>
<div className="mb-6">
<label
className="block text-gray-700 text-sm font-bold mb-2"
htmlFor="password"
>
Password
</label>
<input
onChange={handleUserInput}
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 mb-3 leading-tight focus:outline-none focus:shadow-outline"
id="password"
type="password"
placeholder="Password"
name="password"
/>
</div>
<div className="flex items-center justify-between">
<button
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
type="submit"
>
Sign In
</button>
<a
className="inline-block align-baseline font-bold text-sm text-blue-500 hover:text-blue-800"
href="#"
type="button"
onClick={handleRegister}
>
Register
</a>
</div>
</form>
<p className="text-center text-gray-500 text-xs">
&copy;2020 Acme Corp. All rights reserved.
</p>
</div>
);
};
export default Login;
import React, {useEffect, useState} from 'react';
import {FieldValues, useForm} from 'react-hook-form';
import {Navigate, useNavigate} from 'react-router-dom';
import {useSelector} from 'react-redux';
import IUser from '../interfaces/IUser';
import {useAppDispatch, useAppSelector} from '../store/hooks';
import {selectUser} from '../store/users/users.slice';
import IUserCreateDto from '../interfaces/IUserCreateDto';
const Register = () => {
const {
register,
handleSubmit,
formState: {errors},
} = useForm();
const dispatch = useAppDispatch();
const navigate = useNavigate();
const [user, setUser] = useState({} as IUserCreateDto);
// const {userLoggedIn} = useSelector((state) => state.user);
const handleRegister = async () => {
// await dispatch(createUser(user));
//asdfdsa
};
const handleUserInput = (e: React.ChangeEvent<HTMLInputElement>) => {
setUser((prevState) => ({...prevState, [e.target.name]: e.target.value}));
};
return (
<div className="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
<div className="w-full bg-white rounded-lg shadow dark:border md:mt-0 sm:max-w-md xl:p-0 dark:bg-gray-800 dark:border-gray-700">
<div className="p-6 space-y-4 md:space-y-6 sm:p-8">
<h1 className="text-xl font-bold leading-tight tracking-tight text-gray-900 md:text-2xl dark:text-white">
Create an account
</h1>
<form
onSubmit={handleSubmit((data: FieldValues) => console.log(data))}
className="space-y-4 md:space-y-6"
action="#"
>
<div>
<label
htmlFor="username"
className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
>
Your username
</label>
<input
{...register('username', {required: true})}
type="text"
className="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
placeholder="username"
required
/>
</div>
<div>
<label
htmlFor="password"
className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
>
Password
</label>
<input
{...register('password', {required: true})}
type="password"
placeholder="••••••••"
className="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
required
/>
</div>
<div>
<label
htmlFor="confirm-password"
className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
>
Confirm password
</label>
<input
{...register('password', {required: true})}
type="confirm-password"
name="confirm-password"
id="confirm-password"
placeholder="••••••••"
className="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
required
/>
</div>
<div className="flex items-start">
<div className="flex items-center h-5">
<input
id="terms"
aria-describedby="terms"
type="checkbox"
className="w-4 h-4 border border-gray-300 rounded bg-gray-50 focus:ring-3 focus:ring-primary-300 dark:bg-gray-700 dark:border-gray-600 dark:focus:ring-primary-600 dark:ring-offset-gray-800"
required
/>
</div>
<div className="ml-3 text-sm">
<label
htmlFor="terms"
className="font-light text-gray-500 dark:text-gray-300"
>
I accept the{' '}
<a
className="font-medium text-primary-600 hover:underline dark:text-primary-500"
href="#"
>
Terms and Conditions
</a>
</label>
</div>
</div>
<button
type="submit"
className="w-full text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800"
>
Create an account
</button>
<p className="text-sm font-light text-gray-500 dark:text-gray-400">
Already have an account?{' '}
<a
href="#"
className="font-medium text-primary-600 hover:underline dark:text-primary-500"
>
Login here
</a>
</p>
</form>
</div>
</div>
</div>
);
};
export default Register;
import {createSlice, PayloadAction} from '@reduxjs/toolkit';
import {RootState} from '../store';
import {createAsyncThunk, createSlice} from '@reduxjs/toolkit';
import type {PayloadAction} from '@reduxjs/toolkit';
import axios from 'axios';
import IUser from '../../interfaces/IUser';
import {useNavigate} from 'react-router';
interface UserState {
username: string;
user: IUser;
loading: boolean;
userLoggedIn: boolean;
}
const initialState: UserState = {
username: '',
user: {} as IUser,
loading: false,
userLoggedIn: false,
};
export const createUser = createAsyncThunk(
'createUser',
async (user: IUser) => {
try {
await axios.post(`${import.meta.env.VITE_BASE_URL}/users/register`, {
username: user.username,
password: user.password,
});
} catch (err: any) {
console.log(err);
}
}
);
export const loginUser = createAsyncThunk('loginUser', async (user: IUser) => {
try {
const response = await axios.post(
`${import.meta.env.VITE_BASE_URL}/users/login`,
{
username: user.username,
password: user.password,
}
);
return response.data;
} catch (err: any) {
throw new Error(err);
}
});
export const getUser = createAsyncThunk('getUser', async (token: string) => {
try {
const response = await axios.post(
`${import.meta.env.VITE_BASE_URL}/users/getToken`,
{token}
);
return response.data;
} catch (err: any) {
throw new Error(err);
}
});
export const userSlice = createSlice({
name: 'user',
initialState,
reducers: {},
extraReducers: {},
reducers: {
setInitialUser: (state) => {
state.user = {_id: '', username: '', password: '', token: ''};
state.userLoggedIn = false;
},
},
extraReducers: (builder) => {
builder
.addCase(createUser.pending, (state, action) => {
state.loading = true;
})
.addCase(createUser.rejected, (state, action) => {
state.loading = false;
})
.addCase(createUser.fulfilled, (state, action) => {
state.loading = false;
})
.addCase(loginUser.pending, (state, action) => {
state.loading = true;
})
.addCase(loginUser.rejected, (state, action) => {
state.loading = false;
console.log(action.error);
state.userLoggedIn = false;
})
.addCase(
loginUser.fulfilled,
(state, {payload}: PayloadAction<{token: string}>) => {
state.loading = false;
state.userLoggedIn = true;
window.sessionStorage.setItem('token', payload.token);
}
)
.addCase(getUser.pending, (state, action) => {
state.loading = true;
})
.addCase(getUser.rejected, (state, action) => {
state.loading = false;
state.userLoggedIn = false;
})
.addCase(getUser.fulfilled, (state, action) => {
state.user.username = action.payload[0].username;
state.loading = false;
state.userLoggedIn = true;
});
},
});
export const {} = userSlice.actions;
export const selectUser = (state: RootState) => state.user.username;
export const {setInitialUser} = userSlice.actions;
export default userSlice.reducer;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment