Skip to content

Commit

Permalink
[SOK-16]
Browse files Browse the repository at this point in the history
*update backendApi
*change reducer for async/await
*redirects with router (spa)
+add toast for error message
  • Loading branch information
gloginov committed Oct 1, 2024
1 parent d993cc1 commit 9960d7c
Show file tree
Hide file tree
Showing 12 changed files with 1,422 additions and 783 deletions.
1,365 changes: 966 additions & 399 deletions package-lock.json

Large diffs are not rendered by default.

16 changes: 9 additions & 7 deletions packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@
},
"dependencies": {
"dotenv": "^16.0.2",
"esbuild-linux-64": "^0.15.18",
"eslint-config-prettier": "^8.5.0",
"prettier": "^2.7.1",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react-dom": "^18.2.0",
"react-toastify": "^10.0.5"
},
"devDependencies": {
"react-redux": "^9.1.2",
"axios": "^1.7.7",
"@reduxjs/toolkit": "^2.2.7",
"@testing-library/react": "^13.3.0",
"@types/jest": "^28.1.8",
Expand All @@ -28,17 +28,19 @@
"@typescript-eslint/eslint-plugin": "^5.35.1",
"@typescript-eslint/parser": "^5.35.1",
"@vitejs/plugin-react": "^2.0.1",
"axios": "^1.7.7",
"eslint": "^8.23.0",
"jest": "^28",
"jest-environment-jsdom": "^29.0.1",
"lefthook": "^1.7.15",
"normalize": "^0.3.1",
"prettier": "^2.7.1",
"react-redux": "^9.1.2",
"react-router-dom": "^6.26.2",
"sass": "^1.79.1",
"ts-jest": "^28.0.8",
"typescript": "^4.8.2",
"vite": "^3.0.7",
"normalize": "^0.3.1",
"react-router-dom": "^6.26.2",
"sass": "^1.79.1"
"vite": "^3.0.7"
},
"license": "MIT"
}
20 changes: 1 addition & 19 deletions packages/client/src/api/backendApi.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import axios, { AxiosError, AxiosResponse } from 'axios'
import axios from 'axios'

const instance = axios.create({
baseURL: import.meta.env.VITE_AUTH_URL,
Expand All @@ -8,22 +8,4 @@ const instance = axios.create({
withCredentials: true,
})

instance.interceptors.response.use(
function (response: AxiosResponse) {
return response
},
function (error: AxiosError) {
// if app get response code 401 (died token), redirect user to sign-in form
if (error.response?.status === 401) {
localStorage.removeItem('user')
// save page where we get 401 and redirect after login
window.location.href = '/sign-in?redirectUrl=' + window.location.pathname
}

if (axios.isCancel(error)) return Promise.reject(error)

return Promise.reject(error)
}
)

export default instance
26 changes: 7 additions & 19 deletions packages/client/src/components/ui/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,12 @@ export const Button = (props: {
}) => {
const { text, className, useFixWidth = false, href = '/', onClick } = props
return (
<>
{onClick && typeof onClick === 'function' ? (
<button
className={`custom-button ${className} ${
useFixWidth ? 'custom-button_fix-width' : ''
}`}
onClick={onClick}>
<span>{text}</span>
</button>
) : (
<Link
to={href}
className={`custom-button ${className} ${
useFixWidth ? 'custom-button_fix-width' : ''
}`}>
<span>{text}</span>
</Link>
)}
</>
<button
className={`custom-button ${className} ${
useFixWidth ? 'custom-button_fix-width' : ''
}`}
onClick={onClick}>
<span>{text}</span>
</button>
)
}
21 changes: 20 additions & 1 deletion packages/client/src/layouts/AuthLayout/AuthLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
import { Outlet } from 'react-router-dom'
import { Outlet, useNavigate } from 'react-router-dom'
import {useSelector} from "react-redux";
import {RootState, useAppDispatch} from "@/store";
import {actions, getUser, UserType} from "@/store/reducers/auth-reducer";
import { toast } from 'react-toastify';
import {useEffect} from "react";

export default function AuthLayout() {
const user = useSelector<RootState, UserType>(state => state.AuthReducer.user)
const navigate = useNavigate();

useEffect(() => {
if (window.sessionStorage.getItem('userIsLogged') === '1') {
toast.success('Вы уже авторизованы', {
autoClose: 1500,
onClose: () => {
navigate('/game')
}
})
}
}, [user])

return <Outlet />
}
35 changes: 26 additions & 9 deletions packages/client/src/layouts/private-layout.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,39 @@
import { useSelector } from 'react-redux'
import { Outlet } from 'react-router-dom'
import { RootState } from '@/store'
import { getUser, UserType } from '@/store/reducers/auth-reducer'
import {Outlet, useNavigate} from 'react-router-dom'
import {RootState, useAppDispatch} from '@/store'
import {actions, getUser, UserType} from '@/store/reducers/auth-reducer'
import { useEffect } from 'react'
import { useAppDispatch } from '@/store'
import {toast} from "react-toastify";

export default function PrivateLayout() {
// get user from store
const user = useSelector<RootState, UserType>(state => state.AuthReducer.user)
const navigate = useNavigate();
const userIsLogged = window.sessionStorage.getItem('userIsLogged') === '1';
const dispatch = useAppDispatch()

useEffect(() => {
// if user is empty call backend
if (user === null) {
if (!userIsLogged) {
dispatch(getUser())
.unwrap()
.then((data) => {
dispatch(actions.setUser(data.data))
window.sessionStorage.setItem('userIsLogged', '1') // 0
})
.catch(() => {
window.sessionStorage.setItem('userIsLogged', '0') // 0

toast.error('Необходимо авторизоваться', {
autoClose: 1500,
onClose: () => {
navigate('/sign-in')
}
})
})
}
}, [user])
}, [])

// if the user is full, show page
if (userIsLogged) {
return <Outlet />
}
return user === null ? <h1>Загрузка...</h1> : <Outlet />
}
4 changes: 3 additions & 1 deletion packages/client/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ import React from 'react'
import ReactDOM from 'react-dom/client'
import { Provider } from 'react-redux'
import { store } from '@/store'

import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import App from './app/App'
import '@/scss/styles.scss'

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<Provider store={store}>
<App />
<ToastContainer />
</Provider>
</React.StrictMode>
)
11 changes: 10 additions & 1 deletion packages/client/src/pages/Profile/Profile.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
import { logoutUser } from '@/store/reducers/auth-reducer'
import { useAppDispatch } from '@/store'
import {useNavigate} from "react-router-dom";

export const Profile = () => {
const dispatch = useAppDispatch()
const navigate = useNavigate();

const onLogoutUser = () => {
dispatch(logoutUser())
.then(() => {
window.sessionStorage.setItem('userIsLogged', '0') // 0
navigate('/')
})
}
return (
<>
Страница профиля
<button onClick={() => dispatch(logoutUser())}>Выйти</button>
<button onClick={() => onLogoutUser()}>Выйти</button>
</>
)
}
22 changes: 20 additions & 2 deletions packages/client/src/pages/SignIn/SignIn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,30 @@ import { useAppDispatch } from '@/store'
import { signInUser } from '@/store/reducers/auth-reducer'
import { Button } from '@/components/ui/Button/Button'
import { useSearchParams } from 'react-router-dom'
import { useNavigate } from "react-router-dom";
import { toast } from 'react-toastify';

export const SignIn = () => {
const [form, setForm] = useState({ login: '', password: '' })
const [searchParams] = useSearchParams()
const [query] = useState(searchParams.get('redirectUrl'))
const navigate = useNavigate();
const dispatch = useAppDispatch()

const handleForm = (name: string, value: string) => {
setForm({ ...form, [name]: value })
}

const handleSubmit = () => dispatch(signInUser(form, query))
const handleSubmit = () => {
dispatch(signInUser({form: form, query: query}))
.unwrap()
.then((response: any) => {
navigate('/game')
})
.catch((error?: any, code?: any) => {
toast.error(error.reason)
})
}

return (
<>
Expand All @@ -28,6 +40,7 @@ export const SignIn = () => {
onChange={e => handleForm('login', e.target.value)}
type="text"
name={'login'}
value={form.login}
/>
</label>
<label>
Expand All @@ -36,6 +49,7 @@ export const SignIn = () => {
onChange={e => handleForm('password', e.target.value)}
type="password"
name={'password'}
value={form.password}
/>
</label>
<Button
Expand All @@ -44,7 +58,11 @@ export const SignIn = () => {
onClick={() => handleSubmit()}
/>
</form>
<Button text={'Регистрация'} useFixWidth={true} href={'/sign-up'} />
<Button
text={'Регистрация'}
useFixWidth={true}
onClick={() => { navigate('/sign-up') }}
/>
</>
)
}
21 changes: 19 additions & 2 deletions packages/client/src/pages/SignUp/SignUp.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { useState } from 'react'
import { signUpUser } from '@/store/reducers/auth-reducer'
import { useAppDispatch } from '@/store'
import {useNavigate} from "react-router-dom";
import {toast} from "react-toastify";
import {Button} from "@/components/ui/Button/Button";

export const SignUp = () => {
const [form, setForm] = useState({
Expand All @@ -12,12 +15,22 @@ export const SignUp = () => {
phone: '',
})
const dispatch = useAppDispatch()
const navigate = useNavigate();

const handleForm = (name: string, value: string) => {
setForm({ ...form, [name]: value })
}

const handleSubmit = () => dispatch(signUpUser(form))
const handleSubmit = () => {
dispatch(signUpUser({form: form}))
.unwrap()
.then(() => {
navigate('/sign-in')
})
.catch((error) => {
toast.error(error.reason)
})
}

return (
<>
Expand Down Expand Up @@ -73,7 +86,11 @@ export const SignUp = () => {
name={'phone'}
/>
</label>
<button onClick={() => handleSubmit()}>зарегистрироваться</button>
<Button
text={'зарегистрироваться'}
useFixWidth={true}
onClick={() => handleSubmit()}
/>
</form>
</>
)
Expand Down
Loading

0 comments on commit 9960d7c

Please sign in to comment.