diff --git a/src/hooks/useAsync.ts b/src/hooks/useAsync.ts new file mode 100644 index 0000000..6fdc0da --- /dev/null +++ b/src/hooks/useAsync.ts @@ -0,0 +1,41 @@ +import { useCallback, useEffect, useState } from 'react'; +import useIsMountedRef from './useIsMountedRef'; + +type StateType = { + status: 'idle' | 'pending' | 'success' | 'error'; + error: any; + data: DataResultT | null; + isLoading: boolean; +}; + +const useAsync = (callback: (...params: P) => Promise) => { + const [state, setState] = useState>({ status: 'idle', error: null, data: null, isLoading: false }); + const isMountedRef = useIsMountedRef(); + + const execute = useCallback( + async (...params: P) => { + try { + setState(s => ({ ...s, isLoading: true, status: 'pending', data: null, error: null })); + const res = await callback(...params); + if (isMountedRef.current) { + setState(s => ({ ...s, status: 'success', data: res })); + } + return res; + } catch (error: any) { + if (isMountedRef.current) { + setState(s => ({ ...s, status: 'error', error })); + } + throw error; + } finally { + if (isMountedRef.current) { + setState(s => ({ ...s, isLoading: false })); + } + } + }, + [callback] + ); + + return { execute, ...state }; +}; + +export default useAsync; diff --git a/src/hooks/useLoginQuery.ts b/src/hooks/useLoginQuery.ts index 09de884..249f7dc 100644 --- a/src/hooks/useLoginQuery.ts +++ b/src/hooks/useLoginQuery.ts @@ -1,27 +1,16 @@ import { useToast } from '@chakra-ui/react'; import { IApiRespose, IToken } from '@educt/interfaces'; -import { useState } from 'react'; import { useErrorHandler } from 'react-error-boundary'; -import useIsMountedRef from './useIsMountedRef'; +import useAsync from './useAsync'; import { useRootStore } from './useRootStore'; -type LoginStateType = { - result: IApiRespose | null; - error: any; - loading: boolean; - fetched: boolean; -}; - const useLoginQuery = () => { - const isMountedRef = useIsMountedRef(); const { authStore } = useRootStore(); - const [state, setState] = useState({ result: null, error: null, loading: false, fetched: false }); const toast = useToast(); const handleError = useErrorHandler(); const login = async (login: string, password: string) => { try { - setState(s => ({ ...s, loading: true })); const result = await authStore.login(login, password); toast({ title: `👋 Welcome back!`, @@ -29,14 +18,8 @@ const useLoginQuery = () => { isClosable: true, status: 'success', }); - - if (isMountedRef.current) { - setState(s => ({ ...s, result })); - } + return result; } catch (error: any) { - if (isMountedRef.current) { - setState(s => ({ ...s, error })); - } if (error.response) { /** * Handle response error @@ -44,26 +27,23 @@ const useLoginQuery = () => { switch (error.response.status) { case 404: toast({ title: 'User not found in a system.', status: 'error', duration: 2000 }); - break; + throw error; case 401: toast({ title: 'Invalid password.', status: 'error', duration: 2000 }); - break; + throw error; default: handleError(error); break; } } else { - console.error(error); handleError(error); } - } finally { - if (isMountedRef.current) { - setState(s => ({ ...s, loading: false, fetched: true })); - } } }; - return { ...state, login }; + const { execute, ...state } = useAsync | undefined, Parameters>(login); + + return { login: execute, ...state }; }; export default useLoginQuery; diff --git a/src/interfaces/index.ts b/src/interfaces/index.ts index 96881c3..92b277c 100644 --- a/src/interfaces/index.ts +++ b/src/interfaces/index.ts @@ -27,6 +27,7 @@ export interface ICourse { category: ICategory; lessons: ILesson[]; students: Array>; + color: ColorType | null; students_count: string; likes_count: string; lessons_count: string; diff --git a/src/pages/auth/components/AuthForm/AuthForm.tsx b/src/pages/auth/components/AuthForm/AuthForm.tsx index fa71e79..b20c5c2 100644 --- a/src/pages/auth/components/AuthForm/AuthForm.tsx +++ b/src/pages/auth/components/AuthForm/AuthForm.tsx @@ -44,14 +44,12 @@ const AuthForm: React.FC = () => { } = useForm({ resolver: yupResolver(LoginSchema), }); - const { login, loading } = useLoginQuery(); + const { login, isLoading } = useLoginQuery(); /** * Login handler */ - const onSubmit: SubmitHandler = data => { - login(data.login, data.password).finally(() => reset()); - }; + const onSubmit: SubmitHandler = data => login(data.login, data.password).finally(() => reset()); return ( @@ -87,7 +85,7 @@ const AuthForm: React.FC = () => {