Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
H
hw92
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
5
Issues
5
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Болатов Ален
hw92
Commits
6e4507e8
Commit
6e4507e8
authored
Apr 03, 2023
by
Болатов Ален
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
27
parent
48c958d0
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
241 additions
and
154 deletions
+241
-154
user.ts
backend/src/routes/user.ts
+7
-1
App.tsx
frontend/src/App.tsx
+2
-2
Layout.tsx
frontend/src/components/Layout.tsx
+29
-6
HomePage.tsx
frontend/src/containers/HomePage.tsx
+10
-0
Login.tsx
frontend/src/containers/Login.tsx
+93
-0
Register.tsx
frontend/src/containers/Register.tsx
+0
-136
users.slice.ts
frontend/src/store/users/users.slice.ts
+100
-9
No files found.
backend/src/routes/user.ts
View file @
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
};
frontend/src/App.tsx
View file @
6e4507e8
...
...
@@ -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
>
...
...
frontend/src/components/Layout.tsx
View file @
6e4507e8
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
>
...
...
frontend/src/containers/HomePage.tsx
View file @
6e4507e8
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
...
...
frontend/src/containers/Login.tsx
0 → 100644
View file @
6e4507e8
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"
>
©
2020 Acme Corp. All rights reserved.
</
p
>
</
div
>
);
};
export
default
Login
;
frontend/src/containers/Register.tsx
deleted
100644 → 0
View file @
48c958d0
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
;
frontend/src/store/users/users.slice.ts
View file @
6e4507e8
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
;
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment