Ott 106 login (#19)
parent
332249e29d
commit
714de076b7
@ -1,4 +1,5 @@ |
|||||||
export const PAGES = { |
export const PAGES = { |
||||||
|
home: '/home', |
||||||
login: '/login', |
login: '/login', |
||||||
register: '/register', |
register: '/register', |
||||||
} |
} |
||||||
|
|||||||
@ -0,0 +1,20 @@ |
|||||||
|
import React from 'react' |
||||||
|
import { |
||||||
|
Route, |
||||||
|
Redirect, |
||||||
|
Switch, |
||||||
|
} from 'react-router-dom' |
||||||
|
|
||||||
|
import { PAGES } from 'config' |
||||||
|
|
||||||
|
import { HomePage } from 'features/HomePage' |
||||||
|
|
||||||
|
export const AuthenticatedApp = () => ( |
||||||
|
<Switch> |
||||||
|
<Route path={PAGES.home}> |
||||||
|
<HomePage /> |
||||||
|
</Route> |
||||||
|
|
||||||
|
<Redirect to={PAGES.home} /> |
||||||
|
</Switch> |
||||||
|
) |
||||||
@ -0,0 +1,25 @@ |
|||||||
|
import React from 'react' |
||||||
|
import { |
||||||
|
Route, |
||||||
|
Redirect, |
||||||
|
Switch, |
||||||
|
} from 'react-router-dom' |
||||||
|
|
||||||
|
import { PAGES } from 'config' |
||||||
|
|
||||||
|
import { Login } from 'features/Login' |
||||||
|
import { Register } from 'features/Register' |
||||||
|
|
||||||
|
export const UnauthenticatedApp = () => ( |
||||||
|
<Switch> |
||||||
|
<Route path={PAGES.login}> |
||||||
|
<Login /> |
||||||
|
</Route> |
||||||
|
|
||||||
|
<Route path={PAGES.register}> |
||||||
|
<Register /> |
||||||
|
</Route> |
||||||
|
|
||||||
|
<Redirect to={PAGES.login} /> |
||||||
|
</Switch> |
||||||
|
) |
||||||
@ -1,36 +1,38 @@ |
|||||||
import React from 'react' |
import React from 'react' |
||||||
import { |
import { Router } from 'react-router-dom' |
||||||
Router, |
|
||||||
Route, |
|
||||||
Redirect, |
|
||||||
Switch, |
|
||||||
} from 'react-router-dom' |
|
||||||
import { createBrowserHistory } from 'history' |
import { createBrowserHistory } from 'history' |
||||||
|
|
||||||
import { PAGES } from 'config' |
import { GlobalStores } from 'features/GlobalStores' |
||||||
|
import { useAuthStore } from 'features/AuthStore' |
||||||
|
import { Background } from 'features/Background' |
||||||
import { GlobalStyles } from 'features/GlobalStyles' |
import { GlobalStyles } from 'features/GlobalStyles' |
||||||
import { Theme } from 'features/Theme' |
import { Theme } from 'features/Theme' |
||||||
import { Login } from 'features/Login' |
|
||||||
import { Register } from 'features/Register' |
import { AuthenticatedApp } from './AuthenticatedApp' |
||||||
|
import { UnauthenticatedApp } from './UnauthenticatedApp' |
||||||
|
|
||||||
const history = createBrowserHistory() |
const history = createBrowserHistory() |
||||||
|
|
||||||
|
const Main = () => { |
||||||
|
const { token } = useAuthStore() |
||||||
|
return ( |
||||||
|
<Background> |
||||||
|
{ |
||||||
|
token |
||||||
|
? <AuthenticatedApp /> |
||||||
|
: <UnauthenticatedApp /> |
||||||
|
} |
||||||
|
</Background> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
export const App = () => ( |
export const App = () => ( |
||||||
<Router history={history}> |
<Router history={history}> |
||||||
<Theme> |
<Theme> |
||||||
<GlobalStyles /> |
<GlobalStyles /> |
||||||
|
<GlobalStores> |
||||||
<Switch> |
<Main /> |
||||||
<Route path={PAGES.login}> |
</GlobalStores> |
||||||
<Login /> |
|
||||||
</Route> |
|
||||||
|
|
||||||
<Route path={PAGES.register}> |
|
||||||
<Register /> |
|
||||||
</Route> |
|
||||||
|
|
||||||
<Redirect to={PAGES.login} /> |
|
||||||
</Switch> |
|
||||||
</Theme> |
</Theme> |
||||||
</Router> |
</Router> |
||||||
) |
) |
||||||
|
|||||||
@ -0,0 +1,30 @@ |
|||||||
|
import { useHistory } from 'react-router-dom' |
||||||
|
|
||||||
|
import { PAGES } from 'config' |
||||||
|
import { login } from 'requests' |
||||||
|
import { writeToken } from 'helpers' |
||||||
|
|
||||||
|
type LoginArgs = Parameters<typeof login>[0] |
||||||
|
|
||||||
|
type Args = { |
||||||
|
setToken: (token: string | null) => void, |
||||||
|
} |
||||||
|
|
||||||
|
export const useLogin = ({ setToken }: Args) => { |
||||||
|
const history = useHistory() |
||||||
|
|
||||||
|
const onSuccess = (token: string) => { |
||||||
|
writeToken(token) |
||||||
|
setToken(token) |
||||||
|
history.replace(PAGES.home) |
||||||
|
} |
||||||
|
|
||||||
|
const onError = (message: string) => { |
||||||
|
// eslint-disable-next-line no-alert
|
||||||
|
window.alert(message) |
||||||
|
} |
||||||
|
|
||||||
|
return async ({ email, password }: LoginArgs) => ( |
||||||
|
login({ email, password }).then(onSuccess, onError) |
||||||
|
) |
||||||
|
} |
||||||
@ -0,0 +1,26 @@ |
|||||||
|
import { useHistory } from 'react-router-dom' |
||||||
|
|
||||||
|
import { PAGES } from 'config' |
||||||
|
import { removeToken } from 'helpers' |
||||||
|
// import { logout } from 'requests'
|
||||||
|
|
||||||
|
// временная заглушка запроса
|
||||||
|
const logout = () => Promise.resolve() |
||||||
|
|
||||||
|
type Args = { |
||||||
|
setToken: (token: string | null) => void, |
||||||
|
} |
||||||
|
|
||||||
|
export const useLogout = ({ setToken }: Args) => { |
||||||
|
const history = useHistory() |
||||||
|
|
||||||
|
const onSuccess = () => { |
||||||
|
removeToken() |
||||||
|
setToken(null) |
||||||
|
history.replace(PAGES.login) |
||||||
|
} |
||||||
|
|
||||||
|
return async () => ( |
||||||
|
logout().then(onSuccess) |
||||||
|
) |
||||||
|
} |
||||||
@ -0,0 +1,23 @@ |
|||||||
|
import { useHistory } from 'react-router-dom' |
||||||
|
|
||||||
|
import { PAGES } from 'config' |
||||||
|
import { register } from 'requests' |
||||||
|
|
||||||
|
type Args = Parameters<typeof register>[0] |
||||||
|
|
||||||
|
export const useRegister = () => { |
||||||
|
const history = useHistory() |
||||||
|
|
||||||
|
const goToLoginPage = () => { |
||||||
|
history.replace(PAGES.login) |
||||||
|
} |
||||||
|
|
||||||
|
const showError = (message: string) => { |
||||||
|
// eslint-disable-next-line no-alert
|
||||||
|
window.alert(message) |
||||||
|
} |
||||||
|
|
||||||
|
return async (args: Args) => ( |
||||||
|
register(args).then(goToLoginPage, showError) |
||||||
|
) |
||||||
|
} |
||||||
@ -0,0 +1,43 @@ |
|||||||
|
import type { ReactNode } from 'react' |
||||||
|
import React, { |
||||||
|
createContext, |
||||||
|
useContext, |
||||||
|
useState, |
||||||
|
} from 'react' |
||||||
|
|
||||||
|
import { readToken } from 'helpers' |
||||||
|
|
||||||
|
import { useLogin } from './hooks/useLogin' |
||||||
|
import { useLogout } from './hooks/useLogout' |
||||||
|
import { useRegister } from './hooks/useRegister' |
||||||
|
|
||||||
|
type Auth = { |
||||||
|
login: ReturnType<typeof useLogin>, |
||||||
|
logout: ReturnType<typeof useLogout>, |
||||||
|
register: ReturnType<typeof useRegister>, |
||||||
|
token: string | null, |
||||||
|
} |
||||||
|
|
||||||
|
const AuthContext = createContext({} as Auth) |
||||||
|
|
||||||
|
type Props = { |
||||||
|
children: ReactNode, |
||||||
|
} |
||||||
|
|
||||||
|
export const AuthStore = ({ children }: Props) => { |
||||||
|
const [token, setToken] = useState(readToken()) |
||||||
|
const login = useLogin({ setToken }) |
||||||
|
const logout = useLogout({ setToken }) |
||||||
|
const register = useRegister() |
||||||
|
|
||||||
|
const auth = { |
||||||
|
login, |
||||||
|
logout, |
||||||
|
register, |
||||||
|
token, |
||||||
|
} |
||||||
|
|
||||||
|
return <AuthContext.Provider value={auth}>{children}</AuthContext.Provider> |
||||||
|
} |
||||||
|
|
||||||
|
export const useAuthStore = () => useContext(AuthContext) |
||||||
@ -0,0 +1,14 @@ |
|||||||
|
import React, { ReactNode } from 'react' |
||||||
|
|
||||||
|
import { AuthStore } from 'features/AuthStore' |
||||||
|
|
||||||
|
type Props = { |
||||||
|
children: ReactNode, |
||||||
|
} |
||||||
|
|
||||||
|
// аутентификация, лексики и другие глобальные сторы
|
||||||
|
export const GlobalStores = ({ children }: Props) => ( |
||||||
|
<AuthStore> |
||||||
|
{children} |
||||||
|
</AuthStore> |
||||||
|
) |
||||||
@ -0,0 +1,33 @@ |
|||||||
|
import React from 'react' |
||||||
|
|
||||||
|
import styled from 'styled-components/macro' |
||||||
|
|
||||||
|
import { Logo } from 'features/Logo' |
||||||
|
import { CenterBlock } from 'features/Login/styled' |
||||||
|
import { useAuthStore } from 'features/AuthStore' |
||||||
|
|
||||||
|
// временные компоненты
|
||||||
|
const TempContainer = styled.div` |
||||||
|
margin-top: 50px; |
||||||
|
color: white; |
||||||
|
font-size: 20px; |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
` |
||||||
|
|
||||||
|
const TempPageTitle = styled.span` |
||||||
|
margin: 20px 0; |
||||||
|
` |
||||||
|
|
||||||
|
export const HomePage = () => { |
||||||
|
const { logout } = useAuthStore() |
||||||
|
return ( |
||||||
|
<CenterBlock> |
||||||
|
<Logo /> |
||||||
|
<TempContainer> |
||||||
|
<TempPageTitle>HOME PAGE</TempPageTitle> |
||||||
|
<button type='button' onClick={logout}>Logout</button> |
||||||
|
</TempContainer> |
||||||
|
</CenterBlock> |
||||||
|
) |
||||||
|
} |
||||||
@ -0,0 +1,26 @@ |
|||||||
|
import type { FormEvent } from 'react' |
||||||
|
|
||||||
|
import trim from 'lodash/trim' |
||||||
|
|
||||||
|
import { useAuthStore } from 'features/AuthStore' |
||||||
|
import { formIds } from 'features/Register/components/RegistrationStep/config' |
||||||
|
|
||||||
|
const readFormValue = (event: FormEvent<HTMLFormElement>) => ( |
||||||
|
(fieldName: string) => trim(event.currentTarget[fieldName]?.value) |
||||||
|
) |
||||||
|
|
||||||
|
export const useForm = () => { |
||||||
|
const { login } = useAuthStore() |
||||||
|
|
||||||
|
const handleSubmit = async (event: FormEvent<HTMLFormElement>) => { |
||||||
|
event.preventDefault() |
||||||
|
|
||||||
|
const readFieldValue = readFormValue(event) |
||||||
|
const email = readFieldValue(formIds.email) |
||||||
|
const password = readFieldValue(formIds.password) |
||||||
|
|
||||||
|
login({ email, password }) |
||||||
|
} |
||||||
|
|
||||||
|
return { handleSubmit } |
||||||
|
} |
||||||
@ -1 +0,0 @@ |
|||||||
export const loadIdToken = () => localStorage.getItem('id_token') |
|
||||||
@ -1,2 +1,3 @@ |
|||||||
export * from './callApi' |
export * from './callApi' |
||||||
export * from './callApi/getResponseData' |
export * from './callApi/getResponseData' |
||||||
|
export * from './token' |
||||||
|
|||||||
@ -0,0 +1,13 @@ |
|||||||
|
const TOKEN_KEY = 'token' |
||||||
|
|
||||||
|
export const readToken = () => ( |
||||||
|
localStorage.getItem(TOKEN_KEY) |
||||||
|
) |
||||||
|
|
||||||
|
export const writeToken = (token: string) => ( |
||||||
|
localStorage.setItem(TOKEN_KEY, token) |
||||||
|
) |
||||||
|
|
||||||
|
export const removeToken = () => ( |
||||||
|
localStorage.removeItem(TOKEN_KEY) |
||||||
|
) |
||||||
@ -1 +1,51 @@ |
|||||||
export const login = () => {} |
import { DATA_URL, PROCEDURES } from 'config' |
||||||
|
import { callApi, writeToken } from 'helpers' |
||||||
|
|
||||||
|
const proc = PROCEDURES.auth_user |
||||||
|
|
||||||
|
const statusCodes = { |
||||||
|
ACCOUNT_EXPIRED: 5, |
||||||
|
EMAIL_NOT_FOUND: 2, |
||||||
|
INVALID_CREDENTIALS: 3, |
||||||
|
SUCCESS: 1, |
||||||
|
USER_REMOVED_OR_BLOCKED: 4, |
||||||
|
} as const |
||||||
|
|
||||||
|
type StatusCodes = typeof statusCodes[keyof typeof statusCodes] |
||||||
|
|
||||||
|
type Response = { |
||||||
|
_p_status: StatusCodes, |
||||||
|
_p_token: string, |
||||||
|
} |
||||||
|
|
||||||
|
type Args = { |
||||||
|
email: string, |
||||||
|
password: string, |
||||||
|
} |
||||||
|
|
||||||
|
export const login = async ({ |
||||||
|
email, |
||||||
|
password, |
||||||
|
}: Args) => { |
||||||
|
const config = { |
||||||
|
body: { |
||||||
|
params: { |
||||||
|
_p_email: email, |
||||||
|
_p_password: password, |
||||||
|
}, |
||||||
|
proc, |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
const response: Response = await callApi({ |
||||||
|
config, |
||||||
|
url: DATA_URL, |
||||||
|
}) |
||||||
|
|
||||||
|
if (response._p_status === statusCodes.SUCCESS) { |
||||||
|
writeToken(response._p_token) |
||||||
|
return Promise.resolve(response._p_token) |
||||||
|
} |
||||||
|
|
||||||
|
return Promise.reject(response._p_status) |
||||||
|
} |
||||||
|
|||||||
Loading…
Reference in new issue