Skip to content

Commit 35d6c27

Browse files
authored
withAuth HOC in Private Page layout (#27)
1 parent fe590b1 commit 35d6c27

File tree

4 files changed

+48
-26
lines changed

4 files changed

+48
-26
lines changed

src/contexts/AuthContext.tsx

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import Router from "next/router";
55

66
type AuthContextType = {
77
isAuthenticated: boolean;
8+
isLoading: boolean;
89
user: User | null;
910
signIn: (data: SigninValues) => Promise<void>;
1011
logout: () => void;
@@ -33,15 +34,20 @@ type User = {
3334

3435
export function AuthProvider({ children }: Props) {
3536
const [user, setUser] = useState<User | null>(null);
37+
const [isLoading, setIsLoading] = useState(true);
3638
const isAuthenticated = !!user;
3739

3840
useEffect(() => {
3941
const { "nextjs-boilerplate-advanced.token": token } = parseCookies();
40-
if (token) {
41-
api.get("me").then(({ data }) => {
42-
setUser(data);
43-
});
42+
43+
if (!token) {
44+
return setIsLoading(false);
4445
}
46+
47+
api.get("me").then(({ data }) => {
48+
setUser(data);
49+
setIsLoading(false);
50+
});
4551
}, []);
4652

4753
async function signIn(values: SigninValues) {
@@ -66,7 +72,9 @@ export function AuthProvider({ children }: Props) {
6672
}
6773

6874
return (
69-
<AuthContext.Provider value={{ isAuthenticated, signIn, logout, user }}>
75+
<AuthContext.Provider
76+
value={{ isAuthenticated, signIn, logout, user, isLoading }}
77+
>
7078
{children}
7179
</AuthContext.Provider>
7280
);

src/hooks/useAuth.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { AuthContext } from "@/contexts/AuthContext";
2+
import { useContext } from "react";
3+
4+
export default function useAuth() {
5+
const authContext = useContext(AuthContext);
6+
7+
return authContext;
8+
}

src/layouts/PrivatePage.tsx

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { Box, IconButton, Stack } from "@chakra-ui/react";
22
import Image from "next/image";
3-
import React, { ReactNode, useCallback, useState } from "react";
3+
import React, { ReactNode, useCallback, useEffect, useState } from "react";
44
import logo from "@/assets/logo.svg";
55
import { MdMenu } from "react-icons/md";
66
import MainDrawer from "@/components/MainDrawer";
77
import Link from "next/link";
8+
import { useRouter } from "next/router";
9+
import useAuth from "@/hooks/useAuth";
810

911
type Props = {
1012
children: ReactNode;
@@ -60,4 +62,27 @@ function PrivatePage({ children, title = "" }: Props) {
6062
);
6163
}
6264

63-
export default PrivatePage;
65+
const withAuth = (Component: typeof PrivatePage) => {
66+
const AuthenticatedComponent = (props: Props) => {
67+
const router = useRouter();
68+
const { user, isLoading } = useAuth();
69+
const [renderPage, setRenderPage] = useState(false);
70+
71+
useEffect(() => {
72+
if (isLoading) return;
73+
74+
if (!user?.id) {
75+
router.replace("/login");
76+
return;
77+
}
78+
79+
setRenderPage(true);
80+
}, [router, user, isLoading]);
81+
82+
return renderPage ? <Component {...props} /> : null;
83+
};
84+
85+
return AuthenticatedComponent;
86+
};
87+
88+
export default withAuth(PrivatePage);

src/pages/index.tsx

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ import PrivatePage from "@/layouts/PrivatePage";
33
import { Container, Text } from "@chakra-ui/react";
44
import React, { ReactElement, useContext } from "react";
55
import type { NextPageWithLayout } from "./_app";
6-
import { GetServerSideProps } from "next";
7-
import { parseCookies } from "nookies";
86

97
const Index: NextPageWithLayout = () => {
108
const { user } = useContext(AuthContext);
@@ -19,23 +17,6 @@ const Index: NextPageWithLayout = () => {
1917
);
2018
};
2119

22-
export const getServerSideProps: GetServerSideProps = async (ctx) => {
23-
const { "nextjs-boilerplate-advanced.token": token } = parseCookies(ctx);
24-
25-
if (!token) {
26-
return {
27-
redirect: {
28-
destination: "/login",
29-
permanent: false,
30-
},
31-
};
32-
}
33-
34-
return {
35-
props: {},
36-
};
37-
};
38-
3920
Index.getLayout = function getLayout(page: ReactElement) {
4021
return <PrivatePage title="Dashboard">{page}</PrivatePage>;
4122
};

0 commit comments

Comments
 (0)