Ott 106 login (#19)
parent
332249e29d
commit
714de076b7
@ -1,4 +1,5 @@ |
||||
export const PAGES = { |
||||
home: '/home', |
||||
login: '/login', |
||||
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 { |
||||
Router, |
||||
Route, |
||||
Redirect, |
||||
Switch, |
||||
} from 'react-router-dom' |
||||
import { Router } from 'react-router-dom' |
||||
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 { 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 Main = () => { |
||||
const { token } = useAuthStore() |
||||
return ( |
||||
<Background> |
||||
{ |
||||
token |
||||
? <AuthenticatedApp /> |
||||
: <UnauthenticatedApp /> |
||||
} |
||||
</Background> |
||||
) |
||||
} |
||||
|
||||
export const App = () => ( |
||||
<Router history={history}> |
||||
<Theme> |
||||
<GlobalStyles /> |
||||
|
||||
<Switch> |
||||
<Route path={PAGES.login}> |
||||
<Login /> |
||||
</Route> |
||||
|
||||
<Route path={PAGES.register}> |
||||
<Register /> |
||||
</Route> |
||||
|
||||
<Redirect to={PAGES.login} /> |
||||
</Switch> |
||||
<GlobalStores> |
||||
<Main /> |
||||
</GlobalStores> |
||||
</Theme> |
||||
</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/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