I have these AuthButton done in server and client-side:
Client
'use client';
import { Session, createClientComponentClient } from '@supabase/auth-helpers-nextjs';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
export default function AuthButtonClient({ session } : {session: Session | null}) {
const supabase = createClientComponentClient();
const router = useRouter();
const handleSignOut = async () => {
const { error } = await supabase.auth.signOut();
router.refresh();
if (error) {
// eslint-disable-next-line no-console
console.error('ERROR:', error);
}
}
return session ? (
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full" type="button" onClick={handleSignOut} >
Sign Out
</button>
) : (
<Link href="/login">
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full" type="button" onClick={handleSignOut} >
Login
</button>
</Link>
)
}
Server
import { createServerComponentClient } from "@supabase/auth-helpers-nextjs";
import { cookies } from "next/headers";
import AuthButtonClient from "./AuthButtonClient";
//for server component
export default async function AuthButtonServer(){
const supabase = createServerComponentClient({cookies});
const {data: {session}} = await supabase.auth.getSession();
return <AuthButtonClient session={session}/>
}
And this is the navbar
that I have done:
import AuthButtonServer from "@/app/auth/AuthButton/AuthButtonServer";
import Link from "next/link";
import NavbarComponent from "./NavBarComponent";
const NavBar = async ({ session} : {session: any}) => {
return (
<div>
{/* Links here */}
{session ? <>
<NavbarComponent/>
</>: <>You must login first</>}
{/* Button for Login and Logout */}
<AuthButtonServer/>
</div>
);
}
export default NavBar;
And the NavBarComponent
that I would like to put the Logout
button at the right side of the navbar:
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">
<button
type="button"
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"
>
Logout
</button>
</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>
)
}
Now, I am quite lost on how I can approach this. I cannot use the AuthButtonServer
inside the NavBarComponent
because this is a client component. Any suggestions would be greatly appreciated!
The following pattern is supported. You can pass Server Components as a prop to a Client Component.
A common pattern is to use the React children prop to create a "slot" in your Client Component.
In the example below, accepts a children prop:
'use client'
import { useState } from 'react'
export default function ClientComponent({
children,
}: {
children: React.ReactNode
}) {
const [count, setCount] = useState(0)
return (
<>
<button onClick={() => setCount(count + 1)}>{count}</button>
{children}
</>
)
}
ClientComponent doesn't know that children will eventually be filled in by the result of a Server Component. The only responsibility ClientComponent has is to decide where children will eventually be placed.
In a parent Server Component, you can import both the ClientComponent and ServerComponent and pass ServerComponent as a child of ClientComponent
// This pattern works:
// You can pass a Server Component as a child or prop of a
// Client Component.
import ClientComponent from './client-component'
import ServerComponent from './server-component'
// Pages in Next.js are Server Components by default
export default function Page() {
return (
<ClientComponent>
<ServerComponent />
</ClientComponent>
)
}