I’m working on a Next.js project where I want to conditionally render navigation links in the header based on user authentication. I have a NavBar that handles the rendering of links.
For authenticated users, I want to display the links Home
,Profile
, and Sign out
. For non-authenticated users, the links should be Login
and View All Stores
.
Currently, I’m using the session
to determine whether a user is authenticated or not. However, when the user is not authenticated, the entire navbar is hidden. I want to modify this behavior so that the navbar is always visible, but only the links are conditionally displayed based on authentication status.
Layout.tsx
export const inter = Inter({ subsets: ['latin'] });
//tried adding this
export const revalidate = 0;
export const dynamic = "force-dynamic";
export const metadata = {
title: 'Water Refilling Station',
description: 'Generated by Next.js',
}
export default async function RootLayout({
children,
}: {
children: React.ReactNode
}) {
const supabase = createServerComponentClient({cookies});
const {
data: { session },
} = await supabase.auth.getSession();
const accessToken = session?.access_token || null;
return (
<html lang="en">
<body className={`${inter.className} antialiased`}>
<NavBar session={session}/>
<AuthProvider accessToken={accessToken}>{children}</AuthProvider>
</body>
</html>
)
}
NavBarComponent
‘use client’
const navigation = [
{ name: 'Home', href: '/', },
{ name: 'Profile', href: '/Profile'},
]
function classNames(...classes: string[]) {
return classes.filter(Boolean).join(' ')
}
export default function NavbarComponent() {
const pathname = usePathname()
return (
<Disclosure as="nav" className="bg-gray-800">
{({ open }) => (
<>
<div className="mx-auto max-w-7xl px-2 sm:px-6 lg:px-8">
<div className="relative flex h-16 items-center justify-between">
<div className="absolute inset-y-0 left-0 flex items-center sm:hidden">
{/* Mobile menu button*/}
<Disclosure.Button className="relative inline-flex items-center justify-center rounded-md p-2 text-gray-400 hover:bg-gray-700 hover:text-white focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white">
<span className="absolute -inset-0.5" />
<span className="sr-only">Open main menu</span>
{open ? (
<XMarkIcon className="block h-6 w-6" aria-hidden="true" />
) : (
<Bars3Icon className="block h-6 w-6" aria-hidden="true" />
)}
</Disclosure.Button>
</div>
<div className="flex flex-1 items-center justify-center sm:items-stretch sm:justify-start">
<div className="flex flex-shrink-0 items-center">
<img
className="h-8 w-auto"
src="https://tailwindui.com/img/logos/mark.svg?color=indigo&shade=500"
alt="Your Company"
/>
</div>
<div className="hidden sm:ml-6 sm:block">
<div className="flex space-x-4">
{navigation.map((item) => (
<Link
key={item.name}
href={item.href}
className={
item.href === pathname
? 'bg-gray-900 text-white rounded-md px-3 py-2 text-sm font-medium'
: 'text-gray-300 hover:bg-gray-700 hover:text-white rounded-md px-3 py-2 text-sm font-medium'
}
aria-current={item.href === pathname ? 'page' : undefined}
>
{item.name}
</Link>
))}
</div>
</div>
</div>
<div className="absolute inset-y-0 right-0 flex items-center pr-2 sm:static sm:inset-auto sm:ml-6 sm:pr-0">
<form action="/auth/signout" method="post">
<button type="submit"
className="relative rounded-full bg-gray-800 p-1 text-gray-400 hover:text-white focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-800"
>
Sign out
</button>
</form>
</div>
</div>
</div>
<Disclosure.Panel className="sm:hidden">
<div className="space-y-1 px-2 pb-3 pt-2">
{navigation.map((item) => (
<Disclosure.Button
key={item.name}
as="a"
href={item.href}
className={classNames(
item.href === pathname ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white',
'block rounded-md px-3 py-2 text-base font-medium'
)}
aria-current={item.href === pathname ? 'page' : undefined}
>
{item.name}
</Disclosure.Button>
))}
</div>
</Disclosure.Panel>
</>
)}
</Disclosure>
)
}
To be able to use the session
, I added this component and this is the one that is being imported to the Layout.tsx
. I am using this component because I cannot directly use the session
on the NavBarComponent
because session
is from a server. Hence, it will cause an error if I try to use the session
on the NavBarComponent
import NavbarComponent from "./NavBarComponent";
const NavBar = async ({ session} : {session: any}) => {
return (
<div>
{/* Links here */}
{session && <NavbarComponent/>}
{/* Button for Login and Logout */}
</div>
);
}
export default NavBar;
I want to ensure that the navbar is always visible and only the links are conditionally displayed based on the user’s authentication status. What modifications should I make to achieve this behavior?
Any help or suggestions would be greatly appreciated. Thank you!
2
Answers
You can achieve this by modifying your Navbar component and adding a new component
NotAuthenticatedNavBar
using the ternary operator to show a NavBar for a user that is not authenticated.You can pass your
session
to yourNavbarComponent
as well and inside make the links change, something like thisThen in your NavBar change it like this
This way only the items will change but the navbar will always be visible