From 60519a171a8d70ed3ce5b9a5dbe946372a478d09 Mon Sep 17 00:00:00 2001 From: vchikalkin Date: Sun, 14 Jul 2024 15:26:32 +0300 Subject: [PATCH] web: split components into hooks & files --- apps/web/components/Form/Form.module.scss | 56 ---------- apps/web/components/Form/base-form.tsx | 2 +- apps/web/components/Form/default-form.tsx | 38 +------ apps/web/components/Form/hooks/default.ts | 24 ++++ apps/web/components/Form/hooks/index.ts | 2 + .../{ => components/Form}/hooks/socket.tsx | 0 apps/web/components/Form/hooks/telegram.ts | 99 +++++++++++++++++ apps/web/components/Form/hooks/token.ts | 28 +++++ .../components/Form/lib/buttons.module.scss | 55 +++++++++ .../web/components/Form/{ => lib}/buttons.tsx | 6 +- apps/web/components/Form/{ => lib}/types.ts | 0 apps/web/components/Form/{ => lib}/utils.ts | 0 apps/web/components/Form/telegram-form.tsx | 104 ++---------------- .../{components/Form => constants}/errors.ts | 0 14 files changed, 227 insertions(+), 187 deletions(-) create mode 100644 apps/web/components/Form/hooks/default.ts create mode 100644 apps/web/components/Form/hooks/index.ts rename apps/web/{ => components/Form}/hooks/socket.tsx (100%) create mode 100644 apps/web/components/Form/hooks/telegram.ts create mode 100644 apps/web/components/Form/hooks/token.ts create mode 100644 apps/web/components/Form/lib/buttons.module.scss rename apps/web/components/Form/{ => lib}/buttons.tsx (88%) rename apps/web/components/Form/{ => lib}/types.ts (100%) rename apps/web/components/Form/{ => lib}/utils.ts (100%) rename apps/web/{components/Form => constants}/errors.ts (100%) diff --git a/apps/web/components/Form/Form.module.scss b/apps/web/components/Form/Form.module.scss index 29cc229..e26d4bb 100644 --- a/apps/web/components/Form/Form.module.scss +++ b/apps/web/components/Form/Form.module.scss @@ -7,59 +7,3 @@ margin: 7px 0; } } - -.button-submit { - display: flex; - justify-content: center; - align-items: center; -} - -.button-telegram { - @extend .button-submit; - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - text-transform: none; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - - animation: colorTransition 1s cubic-bezier(0.16, 1, 0.3, 1) forwards; -} - -.button-telegram { - img { - margin: 0; - margin-right: 10px; - } -} - -@keyframes colorTransition { - 0% { - background-color: var(--color-primary); - } - 100% { - background-color: #54a9eb; - } -} - -.button-telegram-icon { - filter: brightness(0) invert(1); - margin: 0 !important; - margin-right: 13px !important; - margin-left: none !important; -} - -.spinner-icon { - filter: brightness(0) invert(1); - fill: var(--color-primary); - margin: 0 !important; - margin-right: 6px !important; -} - -.loading-wrapper { - display: flex; - justify-content: center; - align-items: center; -} diff --git a/apps/web/components/Form/base-form.tsx b/apps/web/components/Form/base-form.tsx index cb3ea5a..27ab531 100644 --- a/apps/web/components/Form/base-form.tsx +++ b/apps/web/components/Form/base-form.tsx @@ -1,5 +1,5 @@ import styles from './Form.module.scss'; -import type { FormData, FormProps } from './types'; +import type { FormData, FormProps } from './lib/types'; import { publicRuntimeConfig } from '@/config/runtime'; import { FormStateContext } from '@/context/form-state'; import type { PropsWithChildren } from 'react'; diff --git a/apps/web/components/Form/default-form.tsx b/apps/web/components/Form/default-form.tsx index 6421c8f..a470ba8 100644 --- a/apps/web/components/Form/default-form.tsx +++ b/apps/web/components/Form/default-form.tsx @@ -1,48 +1,22 @@ import { BaseForm } from './base-form'; -import { ButtonLoading, ButtonLogin } from './buttons'; -import { ERROR_INVALID_CREDENTIALS, ERROR_SERVER } from './errors'; -import type { FormData } from './types'; -import { redirect } from '@/components/Form/utils'; +import { useLogin } from './hooks/default'; +import { useRefreshToken } from './hooks/token'; +import { ButtonLoading, ButtonLogin } from './lib/buttons'; import { FormStateContext } from '@/context/form-state'; -import axios from 'axios'; import { useContext } from 'react'; export function DefaultForm() { + useRefreshToken(); + const { handleLogin } = useLogin(); + const { - dispatch, state: { step, user }, } = useContext(FormStateContext); - function handleRefreshToken() { - axios - .get('/refresh-token') - .then(() => redirect()) - .catch(() => - dispatch({ - payload: { error: ERROR_SERVER, user: undefined }, - type: 'set-error', - }) - ); - } - if (step === 'login' && user) { - handleRefreshToken(); - return ; } - function handleLogin(data: FormData) { - return axios - .post('/login', data) - .then(() => redirect()) - .catch(() => - dispatch({ - payload: { error: ERROR_INVALID_CREDENTIALS }, - type: 'set-error', - }) - ); - } - return ( handleLogin(data)}> diff --git a/apps/web/components/Form/hooks/default.ts b/apps/web/components/Form/hooks/default.ts new file mode 100644 index 0000000..71950ba --- /dev/null +++ b/apps/web/components/Form/hooks/default.ts @@ -0,0 +1,24 @@ +import type { FormData } from '../lib/types'; +import { redirect } from '@/components/Form/lib/utils'; +import { ERROR_INVALID_CREDENTIALS } from '@/constants/errors'; +import { FormStateContext } from '@/context/form-state'; +import axios from 'axios'; +import { useContext } from 'react'; + +export function useLogin() { + 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 { handleLogin }; +} diff --git a/apps/web/components/Form/hooks/index.ts b/apps/web/components/Form/hooks/index.ts new file mode 100644 index 0000000..6dd28b6 --- /dev/null +++ b/apps/web/components/Form/hooks/index.ts @@ -0,0 +1,2 @@ +export * from './socket'; +export * from './token'; diff --git a/apps/web/hooks/socket.tsx b/apps/web/components/Form/hooks/socket.tsx similarity index 100% rename from apps/web/hooks/socket.tsx rename to apps/web/components/Form/hooks/socket.tsx diff --git a/apps/web/components/Form/hooks/telegram.ts b/apps/web/components/Form/hooks/telegram.ts new file mode 100644 index 0000000..2e8c00f --- /dev/null +++ b/apps/web/components/Form/hooks/telegram.ts @@ -0,0 +1,99 @@ +import type { FormData } from '../lib/types'; +import { useSocket } from './socket'; +import { redirect } from '@/components/Form/lib/utils'; +import { ERROR_INVALID_CREDENTIALS, ERROR_SERVER } from '@/constants/errors'; +import { FormStateContext } from '@/context/form-state'; +import type { TelegramUrlResponse } from '@/types/error'; +import type { LdapUser } from '@/types/user'; +import axios, { isAxiosError } from 'axios'; +import { useContext, useEffect } from 'react'; + +export function useLogin() { + const { dispatch } = 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', + }) + ); + } + + return { handleLogin }; +} + +export function useTelegramLogin() { + const { dispatch } = useContext(FormStateContext); + + function handleTelegramLogin() { + axios + .post('/login-telegram') + .then(() => { + dispatch({ + payload: { + step: 'telegram-login', + }, + type: 'set-step', + }); + }) + .catch((error_) => { + let error = ERROR_SERVER; + + if (isAxiosError(error_) && error_.response?.data?.message) { + error = error_.response?.data?.message; + } + + return dispatch({ + payload: { error }, + type: 'set-error', + }); + }); + } + + return { handleTelegramLogin }; +} + +export function useTelegramConfirm() { + const { + dispatch, + state: { step }, + } = 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]); +} diff --git a/apps/web/components/Form/hooks/token.ts b/apps/web/components/Form/hooks/token.ts new file mode 100644 index 0000000..057823c --- /dev/null +++ b/apps/web/components/Form/hooks/token.ts @@ -0,0 +1,28 @@ +import { redirect } from '@/components/Form/lib/utils'; +import { ERROR_SERVER } from '@/constants/errors'; +import { FormStateContext } from '@/context/form-state'; +import axios from 'axios'; +import { useContext, useEffect } from 'react'; + +export function useRefreshToken() { + const { + dispatch, + state: { step, user }, + } = useContext(FormStateContext); + + function handleRefreshToken() { + axios + .get('/refresh-token') + .then(() => redirect()) + .catch(() => + dispatch({ + payload: { error: ERROR_SERVER, user: undefined }, + type: 'set-error', + }) + ); + } + + useEffect(() => { + if (step === 'login' && user) handleRefreshToken(); + }, []); +} diff --git a/apps/web/components/Form/lib/buttons.module.scss b/apps/web/components/Form/lib/buttons.module.scss new file mode 100644 index 0000000..da4bfdf --- /dev/null +++ b/apps/web/components/Form/lib/buttons.module.scss @@ -0,0 +1,55 @@ +.button-submit { + display: flex; + justify-content: center; + align-items: center; +} + +.button-telegram { + @extend .button-submit; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + text-transform: none; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + + animation: colorTransition 1s cubic-bezier(0.16, 1, 0.3, 1) forwards; +} + +.button-telegram { + img { + margin: 0; + margin-right: 10px; + } +} + +@keyframes colorTransition { + 0% { + background-color: var(--color-primary); + } + 100% { + background-color: #54a9eb; + } +} + +.button-telegram-icon { + filter: brightness(0) invert(1); + margin: 0 !important; + margin-right: 13px !important; + margin-left: none !important; +} + +.spinner-icon { + filter: brightness(0) invert(1); + fill: var(--color-primary); + margin: 0 !important; + margin-right: 6px !important; +} + +.loading-wrapper { + display: flex; + justify-content: center; + align-items: center; +} diff --git a/apps/web/components/Form/buttons.tsx b/apps/web/components/Form/lib/buttons.tsx similarity index 88% rename from apps/web/components/Form/buttons.tsx rename to apps/web/components/Form/lib/buttons.tsx index edf46df..2e17b24 100644 --- a/apps/web/components/Form/buttons.tsx +++ b/apps/web/components/Form/lib/buttons.tsx @@ -1,6 +1,6 @@ -import Spinner from '../../public/assets/animated/90-ring.svg'; -import TelegramIcon from '../../public/assets/images/telegram.svg?url'; -import styles from './Form.module.scss'; +import styles from './buttons.module.scss'; +import Spinner from '@/public/assets/animated/90-ring.svg'; +import TelegramIcon from '@/public/assets/images/telegram.svg?url'; import Image from 'next/image'; import type { ButtonHTMLAttributes } from 'react'; diff --git a/apps/web/components/Form/types.ts b/apps/web/components/Form/lib/types.ts similarity index 100% rename from apps/web/components/Form/types.ts rename to apps/web/components/Form/lib/types.ts diff --git a/apps/web/components/Form/utils.ts b/apps/web/components/Form/lib/utils.ts similarity index 100% rename from apps/web/components/Form/utils.ts rename to apps/web/components/Form/lib/utils.ts diff --git a/apps/web/components/Form/telegram-form.tsx b/apps/web/components/Form/telegram-form.tsx index 5876cb2..2b43c2b 100644 --- a/apps/web/components/Form/telegram-form.tsx +++ b/apps/web/components/Form/telegram-form.tsx @@ -1,107 +1,21 @@ import { BaseForm } from './base-form'; -import { ButtonLoading, ButtonLogin, ButtonTelegram, ButtonTelegramLogin } from './buttons'; -import { ERROR_INVALID_CREDENTIALS, ERROR_SERVER } from './errors'; -import type { FormData } from './types'; -import { redirect } from '@/components/Form/utils'; +import { useLogin, useTelegramConfirm, useTelegramLogin } from './hooks/telegram'; +import { useRefreshToken } from './hooks/token'; +import { ButtonLoading, ButtonLogin, ButtonTelegram, ButtonTelegramLogin } from './lib/buttons'; 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 { useContext, useEffect } from 'react'; +import { useContext } from 'react'; export function TelegramForm() { + useRefreshToken(); + const { handleLogin } = useLogin(); + const { handleTelegramLogin } = useTelegramLogin(); + useTelegramConfirm(); + 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('/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(() => { - dispatch({ - payload: { - step: 'telegram-login', - }, - type: 'set-step', - }); - }) - .catch((error_) => { - let error = ERROR_SERVER; - - if (isAxiosError(error_) && error_.response?.data?.message) { - error = error_.response?.data?.message; - } - - return dispatch({ - payload: { error }, - type: 'set-error', - }); - }); - } - - function handleRefreshToken() { - axios - .get('/refresh-token') - .then(() => redirect()) - .catch(() => - dispatch({ - payload: { error: ERROR_SERVER }, - type: 'set-error', - }) - ); - } - if (step === 'login' && user) { - handleRefreshToken(); - return ; } diff --git a/apps/web/components/Form/errors.ts b/apps/web/constants/errors.ts similarity index 100% rename from apps/web/components/Form/errors.ts rename to apps/web/constants/errors.ts