diff --git a/README.md b/README.md index ba6c353..728a93c 100644 --- a/README.md +++ b/README.md @@ -209,6 +209,11 @@ For Production: }, [fetchUser]); ``` +- How to use Auth feature + - If you want to build an admin page, with authorize full layout, just go to line **50** at `src/layouts/main.tsx` and use the code inside comment. + - **Auth** component is a feature help authorize page by fetching profile each time page rendered. + - You must have a server API to use this feature. This API with simple function like receive a header token, return user profile if token is valid and return 404 if token is expired. + --- ## Tips diff --git a/package.json b/package.json index 9fd19f8..7cc6cb4 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "aldenn", "license": "ISC", "name": "react-webpack-typescript-starter", - "version": "0.0.3", + "version": "0.0.4", "description": "The React-Typescript Boilerplate with Webpack config manual", "main": "index.js", "scripts": { diff --git a/src/components/hoc/withAuth.tsx b/src/components/hoc/withAuth.tsx deleted file mode 100644 index 7555ebb..0000000 --- a/src/components/hoc/withAuth.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { verifyToken } from '@/store/actions/auth'; -import { selectCurrentUser } from '@/store/slices/authSlice'; -import React, { ReactNode, useEffect } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; - -const Empty = () =>
; - -const withAuth: ReactNode = (AuthComponent: React.FC) => { - const AuthenHOC: React.FC = () => { - const dispatch = useDispatch(); - const currentUser = useSelector(selectCurrentUser); - - useEffect(() => { - dispatch(verifyToken()); - }, [dispatch]); - - return currentUser ? : ; - }; - - return AuthenHOC; -}; - -export default withAuth; diff --git a/src/layouts/Auth.tsx b/src/layouts/Auth.tsx new file mode 100644 index 0000000..d762028 --- /dev/null +++ b/src/layouts/Auth.tsx @@ -0,0 +1,43 @@ +import React, { useCallback, useEffect, useState } from 'react'; +import { useDispatch } from 'react-redux'; +import { setAuthenticated, setCurrentUser } from '@/store/slices/authSlice'; +import { getCurrentUser } from '@/apis/auth'; + +import { getToken } from '@/helpers/local-storage'; +import { goURL } from '@/helpers/router'; + +interface IProps { + children: React.ReactElement; +} + +const Auth: React.FC = ({ children }) => { + const [renderRoute, setRenderRoute] = useState(false); + const dispatch = useDispatch(); + + const fetchCurrentUser = useCallback(async () => { + try { + const response = await getCurrentUser(); + if (response && response.data) { + dispatch(setAuthenticated(true)); + dispatch(setCurrentUser(response.data)); + } + } catch (error) { + goURL('/login'); + } + setRenderRoute(true); + }, [dispatch]); + + useEffect(() => { + if (!getToken()) { + goURL('/login'); + setRenderRoute(true); + } else { + fetchCurrentUser(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return renderRoute ? children : null; +}; + +export default Auth; diff --git a/src/layouts/main/index.tsx b/src/layouts/main/index.tsx index 26abef8..67f55f8 100644 --- a/src/layouts/main/index.tsx +++ b/src/layouts/main/index.tsx @@ -44,6 +44,14 @@ const Main: React.FC = () => { path={path} render={props => { updateDisplayLayout(currentLayout, layout); + /** + * Use this for authentication like admin page + */ + // return ( + // + // + // + // ); return ; }} {...rest} diff --git a/src/store/actions/auth.ts b/src/store/actions/auth.ts deleted file mode 100644 index 82e7ffa..0000000 --- a/src/store/actions/auth.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Dispatch } from 'redux'; -import { getCurrentUser } from '@/apis/auth'; -import { history } from '@/store'; -import { getToken } from '@/helpers/local-storage'; -import { setLoading } from '../slices/appSlice'; -import { setCurrentUser, setAuthenticated } from '../slices/authSlice'; - -export const verifyToken = - () => - async (dispatch: Dispatch): Promise => { - if (!getToken()) { - history.push('/login'); - } - try { - dispatch(setLoading(true)); - - dispatch(setCurrentUser(null)); - dispatch(setAuthenticated(false)); - - const { data } = await getCurrentUser(); - - if (data) { - dispatch(setCurrentUser({ ...(data as object) })); - dispatch(setAuthenticated(true)); - } - } catch (error) { - history.push('/login'); - } finally { - dispatch(setLoading(false)); - } - };