Skip to content
This repository has been archived by the owner on Oct 14, 2023. It is now read-only.

Добавила OAuth авторизацию #13

Merged
merged 4 commits into from
Dec 21, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions packages/client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,16 @@ import NotFound from '@pages/not-found/NotFound'
import ServerError from '@pages/server-error/ServerError'

function App() {
useEffect(() => {
const fetchServerData = async () => {
const url = `http://localhost:${__SERVER_PORT__}`
const response = await fetch(url)
const data = await response.json()
console.log(data)
}
// useEffect(() => {
// const fetchServerData = async () => {
// const url = `http://localhost:${__SERVER_PORT__}`
// const response = await fetch(url)
// const data = await response.json()
// console.log(data)
// }

fetchServerData()
}, [])
// fetchServerData()
// }, [])
return (
<div className="App">
<Router>
Expand Down
4 changes: 4 additions & 0 deletions packages/client/src/assets/RU.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added packages/client/src/assets/ya-btn.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions packages/client/src/components/YandexIcon/YandexIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import icon from '@assets/RU.svg'
export const YandexIcon = () => {
return <img src={icon}/>

}
8 changes: 4 additions & 4 deletions packages/client/src/hooks/useAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ export const useAuth = () => {
user.id
? navigate('/game/start')
: dispatch(fetchUser()).then(res => {
if (res.type === 'auth/fetch/rejected') {
return navigate('/auth')
}
})
if (res.type === 'auth/fetch/rejected') {
return navigate('/auth')
}
})
}
}
23 changes: 23 additions & 0 deletions packages/client/src/hooks/useOAuth.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { oauthYandex, fetchUser } from '@store/actions/AuthActionCreators'
import { useAppDispatch } from '@store/index'
import { OauthData } from '@store/types'

export const useOAuth = () => {
const REDIRECT_URI = 'http://localhost:3000'
const dispatch = useAppDispatch()
const url = document.location.href
const code = url.split('=').pop();
return () => {
if (/code/.test(url)) {
dispatch(oauthYandex({
code: code,
redirect_uri: REDIRECT_URI
} as OauthData))
.then(res => {
if (res.payload === 'OK') {
dispatch(fetchUser())
}
})
}
}
}
16 changes: 16 additions & 0 deletions packages/client/src/hooks/useServiceId.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { getServiceId } from "@store/actions/AuthActionCreators"
import { useAppDispatch } from "@store/index"

export const useServiceId = () => {
const dispatch = useAppDispatch()
const REDIRECT_URI = 'http://localhost:3000';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В 9м спринте понадобится подставлять продовый или дев-адрес в зависимости от окружения. Это будет сложно сделать, если константа дублируюется в нескольких местах

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Когда настроим докер контейнер и впишем авторизацию в серверный рендеринг - поправлю этот момент

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В целом можно было бы сразу вынести общую константу, но не настаиваю


return () => {
dispatch(getServiceId())
.then(res => {
if (res.payload.service_id) {
document.location = `https://oauth.yandex.ru/authorize?response_type=code&client_id=${res.payload.service_id}&redirect_uri=${REDIRECT_URI}`
}
})
}
}
30 changes: 15 additions & 15 deletions packages/client/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,21 @@ import './index.css'

const store = setupStore()

window.addEventListener('load', () => {
if ('serviceWorker' in navigator) {
navigator.serviceWorker
.register('/sw.js')
.then(registration => {
console.log(
'ServiceWorker registration successful with scope: ',
registration.scope
)
})
.catch((error: string) => {
console.log('ServiceWorker registration failed: ', error)
})
}
})
// window.addEventListener('load', () => {
// if ('serviceWorker' in navigator) {
// navigator.serviceWorker
// .register('/sw.js')
// .then(registration => {
// console.log(
// 'ServiceWorker registration successful with scope: ',
// registration.scope
// )
// })
// .catch((error: string) => {
// console.log('ServiceWorker registration failed: ', error)
// })
// }
// })

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
Expand Down
30 changes: 27 additions & 3 deletions packages/client/src/pages/LoginPage/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,42 @@ import {
Stack,
} from '@mui/material'
import { Link, useNavigate } from 'react-router-dom'
import { createTheme, ThemeProvider } from '@mui/material/styles'
import { createTheme, styled, ThemeProvider } from '@mui/material/styles'
import { LoginData } from '@store/types'
import { useLogin } from '../../hooks/useLogin'
import { useUser } from '../../hooks/useUser'
import { useEffect } from 'react'
import { fetchUser } from '@store/actions/AuthActionCreators'
import { useAppDispatch } from '@store/index'
import { YandexIcon } from '@components/YandexIcon/YandexIcon'
import { useServiceId } from '../../hooks/useServiceId'

export default function Login() {
const user = useUser()
const dispatch = useAppDispatch()
const navigate = useNavigate()
const login = useLogin()
const location = useServiceId()

const YandexIdButton = styled(Button)({
color: ' white',
width: '100%',
height: '44px',
backgroundColor: 'black',
textTransform: 'none',
'&:hover': {
backgroundColor: 'black',
borderColor: '#0062cc',
boxShadow: 'none',
},
})

useEffect(() => {
dispatch(fetchUser())
if (user.id) {
navigate('/')
}
}, [navigate, user])
dispatch(fetchUser())
}, [user.id])

const theme = createTheme({
typography: {
Expand All @@ -42,6 +58,7 @@ export default function Login() {
} as LoginData
login(authData)
}


return (
<ThemeProvider theme={theme}>
Expand Down Expand Up @@ -89,6 +106,13 @@ export default function Login() {
{' '}
Войти
</Button>
<Typography component="p" sx={{ textAlign: 'center', fontSize: '12px' }}>
или
</Typography>
<YandexIdButton
onClick={()=>location()}
startIcon={<YandexIcon/>}
>Войти c Яндекс ID</YandexIdButton>
<Stack spacing={2} sx={{ textAlign: 'center' }}>
<Typography>Еще не зарегистрированы?</Typography>
<Link
Expand Down
12 changes: 1 addition & 11 deletions packages/client/src/pages/game/GameStart/MenuList/MenuList.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import { Box, Button } from '@mui/material'
import { Box } from '@mui/material'

import userIcon from '../../../../assets/user-icon.svg'
import chatIcon from '../../../../assets/chat-icon.svg'
import ratingIcon from '../../../../assets/rating-icon.svg'
import questionIcon from '../../../../assets/question-icon.svg'
import exitIcon from '../../../../assets/exit-icon.svg'
import MenuItem from '../MenuItem'
import { logout } from '@store/actions/AuthActionCreators'
import { useAppDispatch } from '@store/index'
import { useNavigate } from 'react-router-dom'

const links = [
{ title: 'Профиль игрока', src: userIcon, alt: 'профиль', to: '/profile' },
Expand All @@ -19,13 +16,7 @@ const links = [
]

export default function MenuList() {
const dispatch = useAppDispatch()
const navigate = useNavigate()

const logOut = () => {
dispatch(logout())
navigate('/auth')
}
return (
<Box
component="ul"
Expand All @@ -43,7 +34,6 @@ export default function MenuList() {
{links.map(props => (
<MenuItem key={props.title} {...props} />
))}
<Button onClick={logOut}>Выйти</Button>
</Box>
)
}
11 changes: 6 additions & 5 deletions packages/client/src/pages/intro/Intro.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import { Box, Container, Button, Typography } from '@mui/material'
import { fetchUser } from '@store/actions/AuthActionCreators'
import { useAppDispatch } from '@store/index'
import { useOAuth } from '../../hooks/useOAuth'
import { useEffect } from 'react'
import { useAuth } from '../../hooks/useAuth'
import styles from './styles'

export default function Intro() {
const isOAuth = useOAuth()
const isAuth = useAuth()
const dispatch = useAppDispatch()

useEffect(() => {
isOAuth()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: функции обычно именуют с глагола, а is/has/... используются для булевых значений

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Поправила

dispatch(fetchUser())
}, [])
const isAuth = useAuth()
const handleClick = () => {
isAuth()
}

return (
<Box sx={{ ...styles.page }}>
Expand All @@ -29,7 +30,7 @@ export default function Intro() {
alignItems: 'flex-start',
}}>
<Button
onClick={handleClick}
onClick={() => isAuth()}
sx={{ marginBottom: '1rem' }}
variant="contained"
size="large"
Expand Down
4 changes: 2 additions & 2 deletions packages/client/src/pages/profile/Profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,8 @@ const Profile = () => {
marginTop: 1,
}}
onClick={() => {
dispatch(logout())
navigate('/auth')
dispatch(logout()).then(()=>navigate('/auth'))

}}>
Выйти из профиля
</RB.Button>
Expand Down
26 changes: 25 additions & 1 deletion packages/client/src/store/actions/AuthActionCreators.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createAsyncThunk } from '@reduxjs/toolkit'
import { LoginData, UserData } from '@store/types'
import { LoginData, OauthData, UserData } from '@store/types'
import axiosInstance from '../../services/BaseApi'

export const register = createAsyncThunk(
Expand Down Expand Up @@ -45,3 +45,27 @@ export const logout = createAsyncThunk('auth/logout', async (_, thunkApi) => {
return thunkApi.rejectWithValue('Не удалось выйти из приложения')
}
})

export const getServiceId = createAsyncThunk(
'auth/serviceid',
async (_, thunkApi) => {
try {
const response = await axiosInstance.get('oauth/yandex/service-id')
return response.data
} catch (e) {
return thunkApi.rejectWithValue('No such redirect_uri refistered')
}
}
)

export const oauthYandex = createAsyncThunk(
'auth/yandex',
async (data: OauthData, thunkApi) => {
try {
const response = await axiosInstance.post('oauth/yandex', data)
return response.data
} catch (e) {
return thunkApi.rejectWithValue('Пользователь не авторизован в системе')
}
}
)
25 changes: 25 additions & 0 deletions packages/client/src/store/slices/AuthSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ import {
login,
fetchUser,
logout,
getServiceId,
oauthYandex,
} from '@store/actions/AuthActionCreators'
import {
StatusLoading,
RequestDataState,
RequestData,
UserData,
OauthData,
} from '../types'

export interface AuthState {
Expand All @@ -32,6 +35,8 @@ const initialState: AuthState = {
signIn: {} as RequestDataState,
getUserInfo: {} as RequestDataState<UserData>,
logout: {} as RequestDataState,
getServiceId: {} as RequestDataState,
oauth: {} as RequestDataState<OauthData>,
},
}

Expand Down Expand Up @@ -85,6 +90,26 @@ export const authSlice = createSlice({
state.requestData.logout.errorMessage = payload
state.requestData.logout.status = StatusLoading.ERROR
},
[getServiceId.fulfilled.type]: state => {
state.requestData.getServiceId.status = StatusLoading.SUCCESS
},
[getServiceId.pending.type]: state => {
state.requestData.getServiceId.status = StatusLoading.IN_PROGRESS
},
[getServiceId.rejected.type]: (state, { payload }: PayloadAction<string>) => {
state.requestData.getServiceId.errorMessage = payload
state.requestData.getServiceId.status = StatusLoading.ERROR
},
[oauthYandex.fulfilled.type]: state => {
state.requestData.oauth.status = StatusLoading.SUCCESS
},
[oauthYandex.pending.type]: state => {
state.requestData.oauth.status = StatusLoading.IN_PROGRESS
},
[oauthYandex.rejected.type]: (state, { payload }: PayloadAction<string>) => {
state.requestData.oauth.errorMessage = payload
state.requestData.oauth.status = StatusLoading.ERROR
},
},
})

Expand Down
5 changes: 5 additions & 0 deletions packages/client/src/store/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,8 @@ export interface PassWord {
oldPassword: string
newPassword: string
}

export interface OauthData {
code: string
redirect_uri: string
}
1 change: 0 additions & 1 deletion packages/client/sw.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
const CACHE_NAME = 'my-site-cache-v1'

const URLS = [
// '/',
'./src/main.tsx',
]

Expand Down