From 2b06fa7c7742abab123027ce5a1b683c675c0894 Mon Sep 17 00:00:00 2001 From: Lee-Dongwook Date: Mon, 21 Oct 2024 09:44:07 +0900 Subject: [PATCH] feat: Navbar --- client/src/app/chat/page.tsx | 7 +++ client/src/app/layout.tsx | 2 + client/src/app/profile/page.tsx | 7 +++ client/src/app/setting/page.tsx | 7 +++ client/src/components/Button/signout.tsx | 19 ++++++++ client/src/components/ModeToggle/index.tsx | 26 +++++++++++ client/src/components/NavLink/index.tsx | 22 ++++++++++ client/src/components/NavLink/main-nav.tsx | 44 +++++++++++++++++++ client/src/components/NavLink/user-avatar.tsx | 27 ++++++++++++ client/src/components/NavLink/user-nav.tsx | 44 +++++++++++++++++++ client/src/constants/index.ts | 9 ++++ client/src/lib/authAction.ts | 7 +++ client/src/middleware.ts | 4 +- 13 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 client/src/app/chat/page.tsx create mode 100644 client/src/app/profile/page.tsx create mode 100644 client/src/app/setting/page.tsx create mode 100644 client/src/components/Button/signout.tsx create mode 100644 client/src/components/ModeToggle/index.tsx create mode 100644 client/src/components/NavLink/index.tsx create mode 100644 client/src/components/NavLink/main-nav.tsx create mode 100644 client/src/components/NavLink/user-avatar.tsx create mode 100644 client/src/components/NavLink/user-nav.tsx create mode 100644 client/src/constants/index.ts diff --git a/client/src/app/chat/page.tsx b/client/src/app/chat/page.tsx new file mode 100644 index 0000000..a54c709 --- /dev/null +++ b/client/src/app/chat/page.tsx @@ -0,0 +1,7 @@ +import React from "react"; + +const page = () => { + return
page
; +}; + +export default page; diff --git a/client/src/app/layout.tsx b/client/src/app/layout.tsx index 75f4177..22d365c 100644 --- a/client/src/app/layout.tsx +++ b/client/src/app/layout.tsx @@ -4,6 +4,7 @@ import localFont from "next/font/local"; import AuthProvider from "@/providers/auth-provider"; import ThemeProvider from "@/providers/theme-provider"; +import Navbar from "@/components/NavLink"; import { Toaster } from "@/components/ui/toaster"; const geistSans = localFont({ @@ -39,6 +40,7 @@ export default function RootLayout({ enableSystem disableTransitionOnChange > +
{children}
diff --git a/client/src/app/profile/page.tsx b/client/src/app/profile/page.tsx new file mode 100644 index 0000000..a54c709 --- /dev/null +++ b/client/src/app/profile/page.tsx @@ -0,0 +1,7 @@ +import React from "react"; + +const page = () => { + return
page
; +}; + +export default page; diff --git a/client/src/app/setting/page.tsx b/client/src/app/setting/page.tsx new file mode 100644 index 0000000..a54c709 --- /dev/null +++ b/client/src/app/setting/page.tsx @@ -0,0 +1,7 @@ +import React from "react"; + +const page = () => { + return
page
; +}; + +export default page; diff --git a/client/src/components/Button/signout.tsx b/client/src/components/Button/signout.tsx new file mode 100644 index 0000000..da186cf --- /dev/null +++ b/client/src/components/Button/signout.tsx @@ -0,0 +1,19 @@ +"use client"; + +import { signOut } from "next-auth/react"; +import { Button } from "@/components/ui/button"; + +export default function SignOutButton() { + const signout = () => { + signOut({ + redirect: true, + callbackUrl: `${window.location.origin}/signin`, + }); + }; + + return ( + + ); +} diff --git a/client/src/components/ModeToggle/index.tsx b/client/src/components/ModeToggle/index.tsx new file mode 100644 index 0000000..b7040a5 --- /dev/null +++ b/client/src/components/ModeToggle/index.tsx @@ -0,0 +1,26 @@ +"use client"; + +import { useTheme } from "next-themes"; + +import { Button } from "@/components/ui/button"; +import { Moon, Sun } from "lucide-react"; + +export default function ModeToggle() { + const { theme, setTheme } = useTheme(); + + const toggleTheme = () => { + if (theme === "dark") { + setTheme("light"); + } else { + setTheme("dark"); + } + }; + + return ( + + ); +} diff --git a/client/src/components/NavLink/index.tsx b/client/src/components/NavLink/index.tsx new file mode 100644 index 0000000..a0a8a80 --- /dev/null +++ b/client/src/components/NavLink/index.tsx @@ -0,0 +1,22 @@ +import Link from "next/link"; +import MainNav from "@/components/NavLink/main-nav"; +import UserNav from "@/components/NavLink/user-nav"; +import ModeToggle from "@/components/ModeToggle"; +import { Code } from "lucide-react"; + +export default function Navbar() { + return ( +
+ +
+ ); +} diff --git a/client/src/components/NavLink/main-nav.tsx b/client/src/components/NavLink/main-nav.tsx new file mode 100644 index 0000000..6b71a88 --- /dev/null +++ b/client/src/components/NavLink/main-nav.tsx @@ -0,0 +1,44 @@ +"use client"; + +import { useState } from "react"; +import { usePathname } from "next/navigation"; +import Link from "next/link"; +import { Menu } from "lucide-react"; +import { mainNavLinks } from "@/constants"; +import { Button } from "@/components/ui/button"; +import { cn } from "@/lib/utils"; + +export default function MainNav() { + const [menuOpen, setMenuOpen] = useState(false); + const pathName = usePathname(); + + return ( +
+ +
+ {mainNavLinks.map((link) => ( + + {link.title} + + ))} +
+
+ ); +} diff --git a/client/src/components/NavLink/user-avatar.tsx b/client/src/components/NavLink/user-avatar.tsx new file mode 100644 index 0000000..38583dd --- /dev/null +++ b/client/src/components/NavLink/user-avatar.tsx @@ -0,0 +1,27 @@ +"use client"; + +import { useSession } from "next-auth/react"; +import { UserCircle2 } from "lucide-react"; +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; + +export default function UserAvatar() { + const { data: session } = useSession(); + + return ( +
+ {session?.user?.image ? ( + + + CN + + ) : ( + + )} +

{session?.user?.name}

+
+ ); +} diff --git a/client/src/components/NavLink/user-nav.tsx b/client/src/components/NavLink/user-nav.tsx new file mode 100644 index 0000000..e01ea8e --- /dev/null +++ b/client/src/components/NavLink/user-nav.tsx @@ -0,0 +1,44 @@ +import Link from "next/link"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { buttonVariants } from "@/components/ui/button"; +import SignOutButton from "@/components/Button/signout"; +import UserAvatar from "@/components/NavLink/user-avatar"; +import { getUserSession } from "@/lib/authAction"; + +export default async function UserNav() { + const { session } = await getUserSession(); + + return ( +
+ {session ? ( + + + + + + + + + Profile + + + + + + + + ) : ( + + Sign In + + )} +
+ ); +} diff --git a/client/src/constants/index.ts b/client/src/constants/index.ts new file mode 100644 index 0000000..e970500 --- /dev/null +++ b/client/src/constants/index.ts @@ -0,0 +1,9 @@ +export const mainNavLinks = [ + { title: "Home", url: "/" }, + { title: "My Documents", url: "/document" }, + { title: "Create Document", url: "/document/new" }, + { title: "Real-time Collaboration", url: "/document/realtime" }, + { title: "Profile", url: "/profile" }, + { title: "settings", url: "/setting" }, + { title: "Chat", url: "/chat" }, +]; diff --git a/client/src/lib/authAction.ts b/client/src/lib/authAction.ts index b6bcccf..6769620 100644 --- a/client/src/lib/authAction.ts +++ b/client/src/lib/authAction.ts @@ -1,8 +1,10 @@ "use server"; +import { getServerSession } from "next-auth"; import { redirect } from "next/navigation"; import bcrypt from "bcryptjs"; import connectDB from "@/lib/mongoDBConnect"; +import { nextAuthOptions } from "@/lib/nextAuthOptions"; import User from "@/models/user.model"; interface SignUpWithCredentialsParams { @@ -19,6 +21,11 @@ interface GetUserByEmailParams { email: string; } +export async function getUserSession() { + const session = await getServerSession(nextAuthOptions); + return { session }; +} + export async function signUpWithCredentials({ name, email, diff --git a/client/src/middleware.ts b/client/src/middleware.ts index 21cfba8..c304343 100644 --- a/client/src/middleware.ts +++ b/client/src/middleware.ts @@ -17,4 +17,6 @@ export default withAuth( } ); -export const config = { matcher: ["/document/:path*"] }; +export const config = { + matcher: ["/document/:path*", "/profile", "/setting", "/chat"], +};