refactor: user session management in navbar and user button
This commit is contained in:
parent
21d5faed6e
commit
a8f331b2bb
@ -25,6 +25,7 @@ import { usePathname } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
import React from "react";
|
||||
import { Logo } from "@/components/logo";
|
||||
import { authClient } from "@/lib/auth-client";
|
||||
|
||||
interface NavBarProps {
|
||||
scroll?: boolean;
|
||||
@ -33,13 +34,9 @@ interface NavBarProps {
|
||||
|
||||
export function Navbar({ scroll = false, config }: NavBarProps) {
|
||||
const scrolled = useScroll(50);
|
||||
// const user = useCurrentUser();
|
||||
// console.log(`navbar: user:`, user);
|
||||
const user = {
|
||||
name: "John Doe",
|
||||
email: "john.doe@example.com",
|
||||
image: "https://example.com/john.jpg",
|
||||
};
|
||||
const { data: session, error } = authClient.useSession();
|
||||
const user = session?.user;
|
||||
console.log(`Navbar, user:`, user);
|
||||
|
||||
const pathname = usePathname();
|
||||
// console.log(`Navbar, pathname: ${pathname}`);
|
||||
@ -73,15 +70,15 @@ export function Navbar({ scroll = false, config }: NavBarProps) {
|
||||
scroll ? (scrolled ? "border-b" : "bg-transparent") : "border-b",
|
||||
)}
|
||||
>
|
||||
<Container className="flex h-16 items-center">
|
||||
<Container className="flex h-16 items-center px-4">
|
||||
{/* navbar left show logo and links */}
|
||||
<div className="flex items-center gap-6 md:gap-10">
|
||||
{/* logo */}
|
||||
<Link href="/" className="flex items-center space-x-2">
|
||||
<a href="/" className="flex items-center space-x-2">
|
||||
<Logo />
|
||||
|
||||
<span className="text-xl font-bold">{siteConfig.name}</span>
|
||||
</Link>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{/* links */}
|
||||
@ -119,28 +116,16 @@ export function Navbar({ scroll = false, config }: NavBarProps) {
|
||||
<UserButton />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{/* <LoginWrapper mode="modal" asChild>
|
||||
<Button
|
||||
className="flex gap-2 px-5 rounded-full"
|
||||
variant="default"
|
||||
size="default"
|
||||
>
|
||||
<span>Sign In</span>
|
||||
<ArrowRightIcon className="size-4" />
|
||||
</Button>
|
||||
</LoginWrapper> */}
|
||||
{/* <Button
|
||||
className="rounded-full"
|
||||
<LoginWrapper mode="modal" asChild>
|
||||
<Button
|
||||
className="flex gap-2 px-5 rounded-full"
|
||||
variant="default"
|
||||
size="default"
|
||||
asChild
|
||||
>
|
||||
<Link href="/submit">
|
||||
<span>Submit</span>
|
||||
</Link>
|
||||
</Button> */}
|
||||
</>
|
||||
<span>Sign In</span>
|
||||
<ArrowRightIcon className="size-4" />
|
||||
</Button>
|
||||
</LoginWrapper>
|
||||
)}
|
||||
|
||||
<ModeToggle />
|
||||
@ -167,15 +152,14 @@ export function Navbar({ scroll = false, config }: NavBarProps) {
|
||||
<SheetContent side="left" className="flex flex-col p-0">
|
||||
<div className="flex h-screen flex-col">
|
||||
{/* logo */}
|
||||
<Link
|
||||
href="/"
|
||||
<a href="/"
|
||||
className="flex items-center space-x-2 pl-4 pt-4"
|
||||
onClick={() => setOpen(false)}
|
||||
>
|
||||
<Logo />
|
||||
|
||||
<span className="text-xl font-bold">{siteConfig.name}</span>
|
||||
</Link>
|
||||
</a>
|
||||
|
||||
<nav className="flex flex-1 flex-col gap-2 p-2 pt-8 font-medium">
|
||||
{links.map((item) => {
|
||||
@ -194,7 +178,7 @@ export function Navbar({ scroll = false, config }: NavBarProps) {
|
||||
? "bg-muted text-foreground"
|
||||
: "text-muted-foreground hover:text-foreground",
|
||||
item.disabled &&
|
||||
"cursor-not-allowed opacity-80 hover:bg-transparent hover:text-muted-foreground",
|
||||
"cursor-not-allowed opacity-80 hover:bg-transparent hover:text-muted-foreground",
|
||||
)}
|
||||
>
|
||||
<Icon className="size-5" />
|
||||
@ -208,15 +192,14 @@ export function Navbar({ scroll = false, config }: NavBarProps) {
|
||||
</Sheet>
|
||||
|
||||
{/* logo */}
|
||||
<Link
|
||||
href="/"
|
||||
<a href="/"
|
||||
className="flex items-center space-x-2"
|
||||
onClick={() => setOpen(false)}
|
||||
>
|
||||
<Logo className="size-8" />
|
||||
|
||||
<span className="text-xl font-bold">{siteConfig.name}</span>
|
||||
</Link>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{/* mobile navbar right show sign in or account */}
|
||||
@ -226,28 +209,16 @@ export function Navbar({ scroll = false, config }: NavBarProps) {
|
||||
<UserButton />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{/* <LoginWrapper mode="redirect" asChild>
|
||||
<Button
|
||||
className="flex gap-2 px-5 rounded-full"
|
||||
variant="default"
|
||||
size="default"
|
||||
>
|
||||
<span>Sign In</span>
|
||||
<ArrowRightIcon className="size-4" />
|
||||
</Button>
|
||||
</LoginWrapper> */}
|
||||
{/* <Button
|
||||
className="rounded-full"
|
||||
<LoginWrapper mode="redirect" asChild>
|
||||
<Button
|
||||
className="flex gap-2 px-5 rounded-full"
|
||||
variant="default"
|
||||
size="default"
|
||||
asChild
|
||||
>
|
||||
<Link href="/submit">
|
||||
<span>Submit</span>
|
||||
</Link>
|
||||
</Button> */}
|
||||
</>
|
||||
<span>Sign In</span>
|
||||
<ArrowRightIcon className="size-4" />
|
||||
</Button>
|
||||
</LoginWrapper>
|
||||
)}
|
||||
|
||||
<ModeToggle />
|
||||
|
||||
@ -2,21 +2,6 @@
|
||||
|
||||
import { Icons } from "@/components/icons/icons";
|
||||
import { UserAvatar } from "@/components/shared/user-avatar";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { userButtonConfig } from "@/config/user-button";
|
||||
// import { useCurrentUser } from "@/hooks/use-current-user";
|
||||
import { useMediaQuery } from "@/hooks/use-media-query";
|
||||
import { LogOutIcon } from "lucide-react";
|
||||
// import { signOut } from "next-auth/react";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
Drawer,
|
||||
DrawerTrigger,
|
||||
@ -26,18 +11,47 @@ import {
|
||||
DrawerHeader,
|
||||
DrawerTitle,
|
||||
} from "@/components/ui/drawer";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { userButtonConfig } from "@/config/user-button";
|
||||
import { useMediaQuery } from "@/hooks/use-media-query";
|
||||
import { LogOutIcon } from "lucide-react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
import { authClient } from "@/lib/auth-client";
|
||||
|
||||
export function UserButton() {
|
||||
const router = useRouter();
|
||||
// const user = useCurrentUser();
|
||||
// console.log('UserButton, user:', user);
|
||||
const user = {
|
||||
name: "John Doe",
|
||||
email: "john.doe@example.com",
|
||||
image: "https://example.com/john.jpg",
|
||||
const { data: session, error } = authClient.useSession();
|
||||
const user = session?.user;
|
||||
console.log('UserButton, user:', user);
|
||||
// if (error) {
|
||||
// console.error("UserButton, error:", error);
|
||||
// return (
|
||||
// <div className="size-8 animate-pulse rounded-full border bg-muted" />
|
||||
// );
|
||||
// }
|
||||
|
||||
const handleSignOut = async () => {
|
||||
await authClient.signOut({
|
||||
fetchOptions: {
|
||||
onSuccess: () => {
|
||||
console.log("sign out success");
|
||||
router.push("/");
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error("sign out error:", error);
|
||||
// TODO: show error message
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const router = useRouter();
|
||||
const [open, setOpen] = useState(false);
|
||||
const closeDrawer = () => {
|
||||
setOpen(false);
|
||||
@ -45,20 +59,14 @@ export function UserButton() {
|
||||
|
||||
const { isMobile } = useMediaQuery();
|
||||
|
||||
// if (!user) {
|
||||
// return (
|
||||
// <div className="size-8 animate-pulse rounded-full border bg-muted" />
|
||||
// );
|
||||
// }
|
||||
|
||||
// Mobile View, use Drawer
|
||||
if (isMobile) {
|
||||
return (
|
||||
<Drawer open={open} onClose={closeDrawer}>
|
||||
<DrawerTrigger onClick={() => setOpen(true)}>
|
||||
<UserAvatar
|
||||
name={user.name || undefined}
|
||||
image={user.image || undefined}
|
||||
name={user?.name || undefined}
|
||||
image={user?.image || undefined}
|
||||
className="size-8 border"
|
||||
/>
|
||||
</DrawerTrigger>
|
||||
@ -70,13 +78,13 @@ export function UserButton() {
|
||||
</DrawerHeader>
|
||||
<div className="flex items-center justify-start gap-4 p-2">
|
||||
<UserAvatar
|
||||
name={user.name || undefined}
|
||||
image={user.image || undefined}
|
||||
name={user?.name || undefined}
|
||||
image={user?.image || undefined}
|
||||
className="size-8 border"
|
||||
/>
|
||||
<div className="flex flex-col">
|
||||
{user.name && <p className="font-medium">{user.name}</p>}
|
||||
{user.email && (
|
||||
{user?.name && <p className="font-medium">{user.name}</p>}
|
||||
{user?.email && (
|
||||
<p className="w-[200px] truncate text-muted-foreground">
|
||||
{user?.email}
|
||||
</p>
|
||||
@ -110,19 +118,7 @@ export function UserButton() {
|
||||
onClick={async (event) => {
|
||||
event.preventDefault();
|
||||
closeDrawer();
|
||||
|
||||
await authClient.signOut({
|
||||
fetchOptions: {
|
||||
onSuccess: () => {
|
||||
console.log("sign out success");
|
||||
router.push("/auth/login");
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error("sign out error:", error);
|
||||
// TODO: show error message
|
||||
},
|
||||
},
|
||||
});
|
||||
handleSignOut();
|
||||
}}
|
||||
className="flex w-full items-center gap-3 px-2.5 py-2"
|
||||
>
|
||||
@ -142,16 +138,16 @@ export function UserButton() {
|
||||
<DropdownMenu open={open} onOpenChange={setOpen}>
|
||||
<DropdownMenuTrigger>
|
||||
<UserAvatar
|
||||
name={user.name || undefined}
|
||||
image={user.image || undefined}
|
||||
name={user?.name || undefined}
|
||||
image={user?.image || undefined}
|
||||
className="size-8 border"
|
||||
/>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<div className="flex items-center justify-start gap-2 p-2">
|
||||
<div className="flex flex-col space-y-1 leading-none">
|
||||
{user.name && <p className="font-medium">{user.name}</p>}
|
||||
{user.email && (
|
||||
{user?.name && <p className="font-medium">{user.name}</p>}
|
||||
{user?.email && (
|
||||
<p className="w-[200px] truncate text-sm text-muted-foreground">
|
||||
{user?.email}
|
||||
</p>
|
||||
@ -185,19 +181,8 @@ export function UserButton() {
|
||||
className="cursor-pointer"
|
||||
onSelect={async (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
await authClient.signOut({
|
||||
fetchOptions: {
|
||||
onSuccess: () => {
|
||||
console.log("sign out success");
|
||||
router.push("/auth/login");
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error("sign out error:", error);
|
||||
// TODO: show error message
|
||||
},
|
||||
},
|
||||
});
|
||||
setOpen(false);
|
||||
handleSignOut();
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center space-x-2.5">
|
||||
|
||||
11
src/hooks/use-current-user.ts
Normal file
11
src/hooks/use-current-user.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { authClient } from "@/lib/auth-client";
|
||||
|
||||
export const useCurrentUser = () => {
|
||||
const { data: session, error } = authClient.useSession();
|
||||
// console.log('useCurrentUser, session:', session);
|
||||
if (error) {
|
||||
console.error("useCurrentUser, error:", error);
|
||||
return null;
|
||||
}
|
||||
return session?.user;
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user