diff --git a/apps/web/components/Form.tsx b/apps/web/components/Form.tsx index 1b17b9a..76c0bcf 100644 --- a/apps/web/components/Form.tsx +++ b/apps/web/components/Form.tsx @@ -3,14 +3,17 @@ import TelegramIcon from '../public/assets/images/telegram.svg'; import styles from './Form.module.scss'; import { publicRuntimeConfig } from '@/config/runtime'; -import { AuthModeContext } from '@/context/auth-mode'; import { FormStateContext } from '@/context/form-state'; import type { LdapUser } from '@/types/user'; import axios from 'axios'; import Image from 'next/image'; -import { useContext, useState } from 'react'; +import type { PropsWithChildren } from 'react'; +import { useContext } from 'react'; import { useForm } from 'react-hook-form'; +const ERROR_INVALID_CREDENTIALS = 'Неверный логин или пароль'; +const ERROR_SERVER = 'Не удалось войти. Повторите попытку позже'; + const { APP_BASE_PATH } = publicRuntimeConfig; type FormData = { @@ -18,45 +21,18 @@ type FormData = { readonly password: string; }; -function handleDefaultLogin(data: FormData) { - const redirectUrl = - (window.location.pathname.replace(APP_BASE_PATH, '') || '/') + (window.location.search || ''); +type FormProps = { + readonly onSubmit: (data: FormData) => void; +}; - return axios.post('/login', data).then(() => { - window.location.replace(redirectUrl); - }); -} - -function handleTelegramLogin(data: FormData) { - return axios.post('/login', data); -} - -export function Form() { - const [hasError, setHasError] = useState(false); +function BaseForm({ children, onSubmit }: FormProps & PropsWithChildren) { const { handleSubmit, register } = useForm(); - const { tfa } = useContext(AuthModeContext); const { - dispatch, - state: { step, user }, + state: { error, step }, } = useContext(FormStateContext); return ( -
{ - if (!tfa) return handleDefaultLogin(data).catch(() => setHasError(true)); - - return handleTelegramLogin(data).then((res) => - dispatch({ - payload: { - step: 'telegram', - user: res.data, - }, - type: 'set-step', - }) - ); - })} - > + - {hasError ? Неверный логин или пароль : null} - + {error ? {error} : null} + {children} ); } -type ButtonSumitProps = { - readonly step: string; - readonly tfa: boolean; - readonly user: LdapUser | undefined; -}; +export const Form = { + Default() { + const { dispatch } = useContext(FormStateContext); + + function handleLogin(data: FormData) { + const redirectUrl = + (window.location.pathname.replace(APP_BASE_PATH, '') || '/') + + (window.location.search || ''); + + return axios + .post('/login', data) + .then(() => window.location.replace(redirectUrl)) + .catch(() => + dispatch({ + payload: { error: ERROR_INVALID_CREDENTIALS }, + type: 'set-error', + }) + ); + } -function ButtonSubmit({ step, tfa, user }: ButtonSumitProps) { - if (!tfa || step === 'login') { return ( - + handleLogin(data)}> + + ); - } + }, - return ( - - ); -} + Telegram() { + const { + dispatch, + state: { step, user }, + } = useContext(FormStateContext); + + function handleLogin(data: FormData) { + axios + .post('/login', data) + .then((res) => { + dispatch({ + payload: { + step: 'telegram', + user: res.data, + }, + type: 'set-step', + }); + }) + .catch(() => + dispatch({ + payload: { error: ERROR_INVALID_CREDENTIALS }, + type: 'set-error', + }) + ); + } + + function handleTelegramLogin() { + axios + .post('/login-telegram') + .then((res) => { + // eslint-disable-next-line no-console + console.log('🚀 ~ .then ~ res:', res); + }) + .catch(() => + dispatch({ + payload: { error: ERROR_SERVER }, + type: 'set-error', + }) + ); + } + + if (step === 'telegram') { + return ( + handleLogin(data)}> + + + ); + } + + return ( + handleTelegramLogin()}> + + + ); + }, +}; diff --git a/apps/web/components/Login.jsx b/apps/web/components/Login.jsx index 0722e04..6e51fa9 100644 --- a/apps/web/components/Login.jsx +++ b/apps/web/components/Login.jsx @@ -2,12 +2,12 @@ import { Form } from './Form'; import styles from './Login.module.scss'; import { Logo } from '@/elements'; -export function Login() { +export function Login({ tfa }) { return (
-
+ {tfa ? : }
); diff --git a/apps/web/context/auth-mode.ts b/apps/web/context/auth-mode.ts deleted file mode 100644 index a7ba3fd..0000000 --- a/apps/web/context/auth-mode.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { createContext } from 'react'; - -type AuthMode = { - tfa: boolean; -}; - -export const AuthModeContext = createContext({ tfa: false }); diff --git a/apps/web/context/form-state.tsx b/apps/web/context/form-state.tsx index 964f08c..7c6aa3c 100644 --- a/apps/web/context/form-state.tsx +++ b/apps/web/context/form-state.tsx @@ -4,22 +4,45 @@ import type { PropsWithChildren } from 'react'; import { createContext, useMemo, useReducer } from 'react'; type State = { + error: string | undefined; step: 'login' | 'telegram'; user: LdapUser | undefined; }; type Action = { - payload: State; - type: 'set-step'; + payload: Partial; + type: 'set-step' | 'set-error' | 'reset-error'; }; const reducer = (state: State, action: Action): State => { switch (action.type) { - case 'set-step': + case 'set-step': { + if (action.payload.step) + return { + ...state, + step: action.payload.step, + }; + + return state; + } + + case 'set-error': { + if (action.payload.error) { + return { + ...state, + error: action.payload.error, + }; + } + + return state; + } + + case 'reset-error': { return { ...state, - ...action.payload, + error: undefined, }; + } default: return state; @@ -35,6 +58,7 @@ export const FormStateContext = createContext({} as Context); export function FormStateProvider({ children }: PropsWithChildren) { const [state, dispatch] = useReducer(reducer, { + error: undefined, step: 'login', user: undefined, }); diff --git a/apps/web/pages/index.jsx b/apps/web/pages/index.jsx index 56f6242..a1b0dd2 100644 --- a/apps/web/pages/index.jsx +++ b/apps/web/pages/index.jsx @@ -1,8 +1,7 @@ import { Login } from '@/components'; import { publicRuntimeConfig } from '@/config/runtime'; -import { AuthModeContext } from '@/context/auth-mode'; +import { FormStateProvider } from '@/context/form-state'; import Head from 'next/head'; -import { useMemo } from 'react'; const { APP_DESCRIPTION } = publicRuntimeConfig; @@ -16,12 +15,10 @@ function PageHead() { } export default function Page() { - const value = useMemo(() => ({ tfa: false }), []); - return ( - + - + ); } diff --git a/apps/web/pages/telegram.jsx b/apps/web/pages/telegram.jsx index da86683..892a1d8 100644 --- a/apps/web/pages/telegram.jsx +++ b/apps/web/pages/telegram.jsx @@ -1,9 +1,7 @@ import { Login } from '@/components'; import { publicRuntimeConfig } from '@/config/runtime'; -import { AuthModeContext } from '@/context/auth-mode'; import { FormStateProvider } from '@/context/form-state'; import Head from 'next/head'; -import { useMemo } from 'react'; const { APP_DESCRIPTION } = publicRuntimeConfig; @@ -17,14 +15,10 @@ function PageHead() { } export default function Page() { - const value = useMemo(() => ({ tfa: true }), []); - return ( - - - - - - + + + + ); }