From 35d6c27063d7694db40ae38902be62f7bdb960af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Rodrigues?= Date: Fri, 26 Apr 2024 18:33:53 -0300 Subject: [PATCH] withAuth HOC in Private Page layout (#27) --- src/contexts/AuthContext.tsx | 18 +++++++++++++----- src/hooks/useAuth.ts | 8 ++++++++ src/layouts/PrivatePage.tsx | 29 +++++++++++++++++++++++++++-- src/pages/index.tsx | 19 ------------------- 4 files changed, 48 insertions(+), 26 deletions(-) create mode 100644 src/hooks/useAuth.ts diff --git a/src/contexts/AuthContext.tsx b/src/contexts/AuthContext.tsx index 46c2301..4294c44 100644 --- a/src/contexts/AuthContext.tsx +++ b/src/contexts/AuthContext.tsx @@ -5,6 +5,7 @@ import Router from "next/router"; type AuthContextType = { isAuthenticated: boolean; + isLoading: boolean; user: User | null; signIn: (data: SigninValues) => Promise; logout: () => void; @@ -33,15 +34,20 @@ type User = { export function AuthProvider({ children }: Props) { const [user, setUser] = useState(null); + const [isLoading, setIsLoading] = useState(true); const isAuthenticated = !!user; useEffect(() => { const { "nextjs-boilerplate-advanced.token": token } = parseCookies(); - if (token) { - api.get("me").then(({ data }) => { - setUser(data); - }); + + if (!token) { + return setIsLoading(false); } + + api.get("me").then(({ data }) => { + setUser(data); + setIsLoading(false); + }); }, []); async function signIn(values: SigninValues) { @@ -66,7 +72,9 @@ export function AuthProvider({ children }: Props) { } return ( - + {children} ); diff --git a/src/hooks/useAuth.ts b/src/hooks/useAuth.ts new file mode 100644 index 0000000..20ae9e1 --- /dev/null +++ b/src/hooks/useAuth.ts @@ -0,0 +1,8 @@ +import { AuthContext } from "@/contexts/AuthContext"; +import { useContext } from "react"; + +export default function useAuth() { + const authContext = useContext(AuthContext); + + return authContext; +} diff --git a/src/layouts/PrivatePage.tsx b/src/layouts/PrivatePage.tsx index b44bf71..b607a9c 100644 --- a/src/layouts/PrivatePage.tsx +++ b/src/layouts/PrivatePage.tsx @@ -1,10 +1,12 @@ import { Box, IconButton, Stack } from "@chakra-ui/react"; import Image from "next/image"; -import React, { ReactNode, useCallback, useState } from "react"; +import React, { ReactNode, useCallback, useEffect, useState } from "react"; import logo from "@/assets/logo.svg"; import { MdMenu } from "react-icons/md"; import MainDrawer from "@/components/MainDrawer"; import Link from "next/link"; +import { useRouter } from "next/router"; +import useAuth from "@/hooks/useAuth"; type Props = { children: ReactNode; @@ -60,4 +62,27 @@ function PrivatePage({ children, title = "" }: Props) { ); } -export default PrivatePage; +const withAuth = (Component: typeof PrivatePage) => { + const AuthenticatedComponent = (props: Props) => { + const router = useRouter(); + const { user, isLoading } = useAuth(); + const [renderPage, setRenderPage] = useState(false); + + useEffect(() => { + if (isLoading) return; + + if (!user?.id) { + router.replace("/login"); + return; + } + + setRenderPage(true); + }, [router, user, isLoading]); + + return renderPage ? : null; + }; + + return AuthenticatedComponent; +}; + +export default withAuth(PrivatePage); diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 92a3866..e509573 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -3,8 +3,6 @@ import PrivatePage from "@/layouts/PrivatePage"; import { Container, Text } from "@chakra-ui/react"; import React, { ReactElement, useContext } from "react"; import type { NextPageWithLayout } from "./_app"; -import { GetServerSideProps } from "next"; -import { parseCookies } from "nookies"; const Index: NextPageWithLayout = () => { const { user } = useContext(AuthContext); @@ -19,23 +17,6 @@ const Index: NextPageWithLayout = () => { ); }; -export const getServerSideProps: GetServerSideProps = async (ctx) => { - const { "nextjs-boilerplate-advanced.token": token } = parseCookies(ctx); - - if (!token) { - return { - redirect: { - destination: "/login", - permanent: false, - }, - }; - } - - return { - props: {}, - }; -}; - Index.getLayout = function getLayout(page: ReactElement) { return {page}; };