From 8ddb4da1fdb2e4193b70f28fed1615c2c59d47eb Mon Sep 17 00:00:00 2001 From: Antonio Date: Sat, 4 Mar 2023 23:45:31 +0100 Subject: [PATCH] feat: use auth check --- components/Form.tsx | 7 ++++--- components/layout/Sidebar.tsx | 10 +++++---- components/layout/SidebarItem.tsx | 22 +++++++++++++------- components/layout/SidebarTweetButton.tsx | 15 +++++++++++++- components/modals/LoginModal.tsx | 6 ++++-- components/modals/RegisterModal.tsx | 2 +- components/posts/PostItem.tsx | 9 ++++++-- components/profiles/ProfileBio.tsx | 13 +++++++++++- hooks/useCurrentUser.ts | 16 +++++++++++++++ libs/fetcher.ts | 5 +++++ libs/serverAuth.ts | 26 ++++++++++++++++++++++++ package-lock.json | 23 +++++++++++++++++++++ package.json | 1 + pages/_app.tsx | 5 +++-- pages/api/current.ts | 18 ++++++++++++++++ pages/notifications.tsx | 21 +++++++++++++++++++ 16 files changed, 176 insertions(+), 23 deletions(-) create mode 100644 hooks/useCurrentUser.ts create mode 100644 libs/fetcher.ts create mode 100644 libs/serverAuth.ts create mode 100644 pages/api/current.ts diff --git a/components/Form.tsx b/components/Form.tsx index f5f8e51..5b69b52 100644 --- a/components/Form.tsx +++ b/components/Form.tsx @@ -4,12 +4,11 @@ import { IoLocationSharp } from 'react-icons/io5'; import useLoginModal from '@/hooks/useLoginModal'; import useRegisterModal from '@/hooks/useRegisterModal'; +import useCurrentUser from '@/hooks/useCurrentUser'; import Avatar from './Avatar'; import Button from './Button'; -const isLoggedIn = false; - interface FormProps { placeholder: string; } @@ -18,9 +17,11 @@ const Form: React.FC = ({ placeholder }) => { const registerModal = useRegisterModal(); const loginModal = useLoginModal(); + const { data: currentUser } = useCurrentUser(); + return (
- {isLoggedIn ? ( + {currentUser ? (
diff --git a/components/layout/Sidebar.tsx b/components/layout/Sidebar.tsx index 76e22e2..1739c32 100644 --- a/components/layout/Sidebar.tsx +++ b/components/layout/Sidebar.tsx @@ -1,13 +1,12 @@ -import { useMemo } from 'react'; -import { BsHouseFill, BsBellFill, BsEnvelopeFill } from 'react-icons/bs'; +import { signOut, useSession } from 'next-auth/react'; +import { BiLogOut } from 'react-icons/bi'; +import { BsHouseFill, BsBellFill } from 'react-icons/bs'; import { FaHashtag, FaUser } from 'react-icons/fa'; import SidebarItem from './SidebarItem'; import SidebarLogo from './SidebarLogo'; import SidebarTweetButton from './SidebarTweetButton'; -const isLoggedIn = false; - const items = [ { icon: BsHouseFill, @@ -34,6 +33,8 @@ const items = [ ] const Sidebar = () => { + const session = useSession(); + return (
@@ -48,6 +49,7 @@ const Sidebar = () => { label={item.label} /> ))} + {session.data && signOut()} icon={BiLogOut} label="Logout" />}
diff --git a/components/layout/SidebarItem.tsx b/components/layout/SidebarItem.tsx index 9eb2536..e4c9240 100644 --- a/components/layout/SidebarItem.tsx +++ b/components/layout/SidebarItem.tsx @@ -3,28 +3,36 @@ import { IconType } from "react-icons"; import { useRouter } from 'next/router'; import useLoginModal from '@/hooks/useLoginModal'; +import useCurrentUser from '@/hooks/useCurrentUser'; interface SidebarItemProps { label: string; icon: IconType; - href: string; + href?: string; + onClick?: () => void; auth?: boolean; } -const SidebarItem: React.FC = ({ label, icon: Icon, href, auth }) => { +const SidebarItem: React.FC = ({ label, icon: Icon, href, auth, onClick }) => { const router = useRouter(); const loginModal = useLoginModal(); - const onClick = useCallback(() => { - if (auth) { + const { data: currentUser } = useCurrentUser(); + + const handleClick = useCallback(() => { + if (onClick) { + return onClick(); + } + + if (auth && !currentUser) { loginModal.onOpen(); - } else { + } else if (href) { router.push(href); } - }, [router, href, auth, loginModal]); + }, [router, href, auth, loginModal, onClick, currentUser]); return ( -
+
{ + const router = useRouter(); const loginModal = useLoginModal(); + const { data: currentUser } = useCurrentUser(); + + const onClick = useCallback(() => { + if (!currentUser) { + return loginModal.onOpen(); + } + + router.push('/'); + }, [loginModal, router, currentUser]); return ( -
+
{ const loginModal = useLoginModal(); + const { data: currentUser } = useCurrentUser(); + + const onFollow = useCallback(() => { + if (!currentUser) { + return loginModal.onOpen(); + } + + return; + }, [currentUser, loginModal]); return (
-
diff --git a/hooks/useCurrentUser.ts b/hooks/useCurrentUser.ts new file mode 100644 index 0000000..5b2fc8a --- /dev/null +++ b/hooks/useCurrentUser.ts @@ -0,0 +1,16 @@ +import useSWR from 'swr'; + +import fetcher from '@/libs/fetcher'; + +const useCurrentUser = () => { + const { data, error, isLoading, mutate } = useSWR('/api/current', fetcher); + + return { + data, + error, + isLoading, + mutate + } +}; + +export default useCurrentUser; diff --git a/libs/fetcher.ts b/libs/fetcher.ts new file mode 100644 index 0000000..868c9a1 --- /dev/null +++ b/libs/fetcher.ts @@ -0,0 +1,5 @@ +import axios from 'axios'; + +const fetcher = (url: string) => axios.get(url).then((res) => res.data); + +export default fetcher; diff --git a/libs/serverAuth.ts b/libs/serverAuth.ts new file mode 100644 index 0000000..cddff9b --- /dev/null +++ b/libs/serverAuth.ts @@ -0,0 +1,26 @@ +import { NextApiRequest } from 'next'; +import { getSession } from 'next-auth/react'; + +import prisma from '@/libs/prismadb'; + +const serverAuth = async (req: NextApiRequest) => { + const session = await getSession({ req }); + + if (!session?.user?.email) { + throw new Error('Not signed in'); + } + + const currentUser = await prisma.user.findUnique({ + where: { + email: session.user.email, + } + }); + + if (!currentUser) { + throw new Error('Not signed in'); + } + + return { currentUser }; +}; + +export default serverAuth; diff --git a/package-lock.json b/package-lock.json index 37f436e..be0ea87 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "react-hot-toast": "^2.4.0", "react-icons": "^4.7.1", "react-toastify": "^9.1.1", + "swr": "^2.0.4", "typescript": "4.9.5", "zustand": "^4.3.5" }, @@ -4216,6 +4217,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/swr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.0.4.tgz", + "integrity": "sha512-4GUiTjknRUVuw4MWUHR7mzJ9G/DWL+yZz/TgWDfiA0OZ9tL6qyrTkN2wPeboBpL3OJTkej3pexh3mWCnv8cFkQ==", + "dependencies": { + "use-sync-external-store": "^1.2.0" + }, + "engines": { + "pnpm": "7" + }, + "peerDependencies": { + "react": "^16.11.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/synckit": { "version": "0.8.5", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", @@ -7459,6 +7474,14 @@ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" }, + "swr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.0.4.tgz", + "integrity": "sha512-4GUiTjknRUVuw4MWUHR7mzJ9G/DWL+yZz/TgWDfiA0OZ9tL6qyrTkN2wPeboBpL3OJTkej3pexh3mWCnv8cFkQ==", + "requires": { + "use-sync-external-store": "^1.2.0" + } + }, "synckit": { "version": "0.8.5", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", diff --git a/package.json b/package.json index 301f446..a77eced 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "react-hot-toast": "^2.4.0", "react-icons": "^4.7.1", "react-toastify": "^9.1.1", + "swr": "^2.0.4", "typescript": "4.9.5", "zustand": "^4.3.5" }, diff --git a/pages/_app.tsx b/pages/_app.tsx index b3907c6..010129e 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -1,5 +1,6 @@ import type { AppProps } from 'next/app' import { Toaster } from 'react-hot-toast'; +import { SessionProvider } from 'next-auth/react'; import Layout from '@/components/Layout' import LoginModal from '@/components/modals/LoginModal' @@ -8,13 +9,13 @@ import '@/styles/globals.css' export default function App({ Component, pageProps }: AppProps) { return ( - <> + - + ) } diff --git a/pages/api/current.ts b/pages/api/current.ts new file mode 100644 index 0000000..18430a4 --- /dev/null +++ b/pages/api/current.ts @@ -0,0 +1,18 @@ +import { NextApiRequest, NextApiResponse } from 'next'; + +import serverAuth from '@/libs/serverAuth'; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + if (req.method !== 'GET') { + return res.status(405).end(); + } + + try { + const { currentUser } = await serverAuth(req); + + return res.status(200).json(currentUser); + } catch (error) { + console.log(error); + return res.status(400).end(); + } +} diff --git a/pages/notifications.tsx b/pages/notifications.tsx index 5ed428f..a8869e2 100644 --- a/pages/notifications.tsx +++ b/pages/notifications.tsx @@ -1,4 +1,25 @@ import Header from "@/components/Header"; +import { NextPageContext } from "next"; +import { getSession } from "next-auth/react"; + +export async function getServerSideProps(context: NextPageContext) { + const session = await getSession(context); + + if (!session) { + return { + redirect: { + destination: '/', + permanent: false, + } + } + } + + return { + props: { + session + } + } +} const Notifications = () => { return (