11"use client" ;
2+
3+ import { useState , useEffect } from "react" ;
24import {
35 DropdownMenu ,
46 DropdownMenuContent ,
57 DropdownMenuItem ,
68 DropdownMenuLabel ,
79 DropdownMenuSeparator ,
810 DropdownMenuTrigger ,
11+ Button ,
912} from "@repo/ui" ;
10- import { signOut } from "next-auth/react" ;
11- import { useSession } from "next-auth/react" ;
13+ import { signOut , useSession } from "next-auth/react" ;
1214import { LogOut , UserRound } from "lucide-react" ;
1315import { useRouter } from "next/navigation" ;
1416import UserImage from "./UserImage" ;
17+ import { motion , AnimatePresence } from "framer-motion" ;
1518
1619const dropDownData = [
1720 {
@@ -22,66 +25,92 @@ const dropDownData = [
2225] ;
2326
2427export default function UserAccountDropDown ( ) {
25- const session = useSession ( ) ;
26- const user = session . data ?. user ;
28+ const { data : session , status } = useSession ( ) ;
29+ const user = session ?. user ;
2730 const router = useRouter ( ) ;
28- return (
29- < >
30- { user && (
31- < DropdownMenu >
32- < DropdownMenuTrigger className = "w-[2rem] flex items-center p-[0.2rem] justify-center h-[2rem]" >
33- { ! user . image ? (
34- < div className = "p-1 border-2 rounded-md border-[#1a1a1a]" >
35- < UserRound />
36- </ div >
37- ) : (
38- < UserImage image = { user . image } />
39- ) }
40- </ DropdownMenuTrigger >
31+ const [ isOpen , setIsOpen ] = useState ( false ) ;
32+ const [ mounted , setMounted ] = useState ( false ) ;
4133
42- < DropdownMenuContent className = "!w-[15rem] dark:shadow-[#030712] translate-y-8 scale-110 -translate-x-10 shadow-lg" >
43- < DropdownMenuLabel className = "flex gap-4 items-center" >
44- < div className = "!w-[2rem] flex items-center p-[0.2rem] justify-center !h-[2rem]" >
45- { ! user . image ? (
46- < div className = "p-1 border-2 rounded-full border-[#1a1a1a]" >
47- < UserRound />
48- </ div >
49- ) : (
50- < UserImage image = { user . image } />
51- ) }
52- </ div >
34+ useEffect ( ( ) => {
35+ setMounted ( true ) ;
36+ } , [ ] ) ;
5337
54- < div className = "flex flex-col" >
55- < span className = "max-w-[200px]" > { user ?. name } </ span >
56- < span className = "text-[0.8rem] max-w-[200px] text-gray-400" > { user ?. email } </ span >
38+ if ( ! mounted || status === "loading" ) return null ;
39+ if ( ! user ) return null ;
40+
41+ return (
42+ < DropdownMenu onOpenChange = { setIsOpen } >
43+ < DropdownMenuTrigger asChild >
44+ < Button
45+ variant = "ghost"
46+ className = "bg-secondary/15 hover:bg-secondary/25 flex items-center gap-2 rounded-xl px-3 py-2 shadow-sm transition-all duration-200 hover:shadow-md"
47+ >
48+ < div className = "border-primary/20 h-8 w-8 overflow-hidden rounded-full border-2" >
49+ { user . image ? (
50+ < UserImage image = { user . image } />
51+ ) : (
52+ < div className = "from-primary-400 to-primary-600 flex h-full w-full items-center justify-center bg-gradient-to-br text-white" >
53+ < UserRound size = { 16 } />
5754 </ div >
58- </ DropdownMenuLabel >
59- < DropdownMenuSeparator />
55+ ) }
56+ </ div >
57+ </ Button >
58+ </ DropdownMenuTrigger >
6059
61- { dropDownData . map ( ( item , index ) => {
62- return (
63- < DropdownMenuItem className = "flex gap-2" onClick = { ( ) => router . push ( "/profile" ) } key = { index } >
64- < span > { item . icon } </ span >
65- < span > { item . name } </ span >
60+ < AnimatePresence >
61+ { isOpen && (
62+ < DropdownMenuContent
63+ forceMount
64+ className = "bg-secondary/15 border-primary/10 rounded-2xl border p-2 shadow-lg shadow-neutral-600/5 backdrop-blur-lg"
65+ align = "end"
66+ >
67+ < motion . div
68+ initial = { { opacity : 0 , y : - 10 } }
69+ animate = { { opacity : 1 , y : 0 } }
70+ exit = { { opacity : 0 , y : - 10 } }
71+ transition = { { duration : 0.2 } }
72+ >
73+ < DropdownMenuLabel className = "flex items-center space-x-3 p-3" >
74+ < div className = "border-primary/20 h-12 w-12 overflow-hidden rounded-full border-2" >
75+ { user . image ? (
76+ < UserImage image = { user . image } />
77+ ) : (
78+ < div className = "from-primary-400 to-primary-600 flex h-full w-full items-center justify-center bg-gradient-to-br text-white" >
79+ < UserRound size = { 24 } />
80+ </ div >
81+ ) }
82+ </ div >
83+ < div className = "flex flex-col" >
84+ < span className = "text-foreground font-semibold" > { user . name } </ span >
85+ < span className = "text-muted-foreground max-w-[150px] truncate text-xs" > { user . email } </ span >
86+ </ div >
87+ </ DropdownMenuLabel >
88+ < DropdownMenuSeparator className = "bg-primary/10 my-2" />
89+ { dropDownData . map ( ( item , index ) => (
90+ < DropdownMenuItem
91+ key = { index }
92+ className = "focus:bg-secondary/25 hover:bg-secondary/25 flex cursor-pointer items-center space-x-3 rounded-lg p-3 transition-all duration-200 hover:shadow-md"
93+ onClick = { ( ) => router . push ( item . href ) }
94+ >
95+ < span className = "text-foreground" > { item . icon } </ span >
96+ < span className = "text-foreground" > { item . name } </ span >
6697 </ DropdownMenuItem >
67- ) ;
68- } ) }
69- < DropdownMenuSeparator />
70- { user && (
98+ ) ) }
99+ < DropdownMenuSeparator className = "bg-primary/10 my-2" />
71100 < DropdownMenuItem
101+ className = "focus:bg-secondary/25 hover:bg-destructive/15 flex cursor-pointer items-center space-x-3 rounded-lg p-3 transition-all duration-200 hover:shadow-md"
72102 onClick = { async ( ) => {
73103 await signOut ( ) ;
74104 router . push ( "/" ) ;
75105 } }
76- className = " flex gap-2 focus:bg-[#f34e4e]"
77106 >
78- < LogOut size = { 15 } />
79- Logout
107+ < LogOut size = { 15 } className = "text-destructive" />
108+ < span className = "text-destructive" > Logout</ span >
80109 </ DropdownMenuItem >
81- ) }
110+ </ motion . div >
82111 </ DropdownMenuContent >
83- </ DropdownMenu >
84- ) }
85- </ >
112+ ) }
113+ </ AnimatePresence >
114+ </ DropdownMenu >
86115 ) ;
87116}
0 commit comments