skip to Main Content

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


  1. 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.

    import NavbarComponent from "./NavBarComponent";
    
    const NavBar = async ({ session} : {session: any}) => {  
        return ( 
            <div>
                {/* Links here */}
                
                {session ? <NavbarComponent/> : <NotAuthenticatedNavBar />}
                {/* Button for Login and Logout */}
            </div>
         );
    }
     
    export default NavBar;
    
    
    Login or Signup to reply.
  2. You can pass your session to your NavbarComponent as well and inside make the links change, something like this

    export default function NavbarComponent(props: { session: any }) {
      const authenticatedNavigationItems = [
        { name: 'Home', href: '/', },
        { name: 'Profile', href: '/Profile'},
      ];
      const notAuthenticatedNavigationItems = [
        { name: 'View all stores', href: '/stores', } // I'm just making this out as example
      ];
      const navigationItems = session ? authenticatedNavigationItems : notAuthenticatedNavigationItems
     ...
    }
    

    Then in your NavBar change it like this

    import NavbarComponent from "./NavBarComponent";
    
    const NavBar = async ({ session} : {session: any}) => {  
        return ( 
            <div>
                {/* Links here */}
                
                <NavbarComponent session={session} />
                {/* Button for Login and Logout */}
            </div>
         );
    }
     
    export default NavBar;
    

    This way only the items will change but the navbar will always be visible

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search