2024-06-06 12:36:07 +03:00

218 lines
5.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* eslint-disable react/jsx-curly-newline */
/* eslint-disable sonarjs/no-small-switch */
import TelegramIcon from '../public/assets/images/telegram.svg';
import styles from './Form.module.scss';
import { publicRuntimeConfig } from '@/config/runtime';
import { FormStateContext } from '@/context/form-state';
import { useSocket } from '@/hooks/socket';
import type { TelegramUrlResponse } from '@/types/error';
import type { LdapUser } from '@/types/user';
import axios, { isAxiosError } from 'axios';
import Image from 'next/image';
import type { PropsWithChildren } from 'react';
import { useContext, useEffect } from 'react';
import { useForm } from 'react-hook-form';
const ERROR_INVALID_CREDENTIALS = 'Неверный логин или пароль';
const ERROR_SERVER = 'Не удалось войти. Повторите попытку позже';
const { APP_BASE_PATH, TELEGRAM_BOT_URL } = publicRuntimeConfig;
type FormData = {
readonly login: string;
readonly password: string;
};
type FormProps = {
readonly onSubmit: (data: FormData) => void;
};
function redirect() {
const redirectUrl =
(window.location.pathname.replace(APP_BASE_PATH, '') || '/') + (window.location.search || '');
window.location.replace(redirectUrl);
}
function BaseForm({ children, onSubmit }: FormProps & PropsWithChildren) {
const { handleSubmit, register } = useForm<FormData>();
const {
state: { error, step },
} = useContext(FormStateContext);
return (
<form className={styles.form} onSubmit={handleSubmit(onSubmit)}>
<input
disabled={step !== 'login'}
type="text"
placeholder="Логин"
required
autoComplete="on"
{...register('login', { required: true })}
/>
<input
disabled={step !== 'login'}
type="password"
placeholder="Пароль"
required
autoComplete="on"
{...register('password', { required: true })}
/>
{step === 'telegram-login' ? (
<a target="_blank" className="info" href={TELEGRAM_BOT_URL} rel="noreferrer">
Открыть чат с ботом
</a>
) : null}
{error ? <span className="error">{error}</span> : null}
{children}
</form>
);
}
export const Form = {
Default() {
const { dispatch } = useContext(FormStateContext);
function handleLogin(data: FormData) {
return axios
.post('/login', data)
.then(() => redirect())
.catch(() =>
dispatch({
payload: { error: ERROR_INVALID_CREDENTIALS },
type: 'set-error',
})
);
}
return (
<BaseForm onSubmit={(data) => handleLogin(data)}>
<button className={styles['button-submit']} type="submit">
Войти
</button>
</BaseForm>
);
},
Telegram() {
const {
dispatch,
state: { step, user },
} = useContext(FormStateContext);
const { socket } = useSocket();
useEffect(() => {
if (step === 'telegram-login') {
socket.open();
socket.on('connect', () => {});
socket.on('auth-allow', () => {
socket.off('connect');
axios
.get('/login-confirm')
.then(() => redirect())
.catch(() =>
dispatch({
payload: { error: ERROR_SERVER },
type: 'set-error',
})
);
});
}
return () => {
socket.off('connect');
};
}, [dispatch, socket, step]);
function handleLogin(data: FormData) {
axios
.post<LdapUser>('/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() {
// window.open(TELEGRAM_BOT_URL);
axios
.post<LdapUser>('/login-telegram')
.then(() => {
dispatch({
payload: {
step: 'telegram-login',
},
type: 'set-step',
});
})
.catch((error_) => {
let error = ERROR_SERVER;
if (isAxiosError<TelegramUrlResponse>(error_) && error_.response?.data?.message) {
error = error_.response?.data?.message;
}
return dispatch({
payload: { error },
type: 'set-error',
});
});
}
if (step === 'telegram') {
return (
<BaseForm onSubmit={() => handleTelegramLogin()}>
<button type="submit" className={styles['button-telegram']}>
<Image
className={styles['button-telegram-icon']}
src={TelegramIcon}
width={24}
height={22}
alt="Telegram icon"
/>
Войти как &nbsp; <b>{user?.displayName}</b>
</button>
</BaseForm>
);
}
if (step === 'telegram-login') {
return (
<BaseForm onSubmit={() => {}}>
<button disabled type="submit" className={styles['button-telegram']}>
<Image
className={styles['button-telegram-icon']}
src={TelegramIcon}
width={24}
height={22}
alt="Telegram icon"
/>
Ожидаем подтверждения...
</button>
</BaseForm>
);
}
return (
<BaseForm onSubmit={(data) => handleLogin(data)}>
<button className={styles['button-submit']} type="submit">
Войти
</button>
</BaseForm>
);
},
};