1
1
"use client" ;
2
+
3
+ import { useState , useEffect } from "react" ;
2
4
import {
3
5
DropdownMenu ,
4
6
DropdownMenuContent ,
5
7
DropdownMenuItem ,
6
8
DropdownMenuLabel ,
7
9
DropdownMenuSeparator ,
8
10
DropdownMenuTrigger ,
11
+ Button ,
9
12
} 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" ;
12
14
import { LogOut , UserRound } from "lucide-react" ;
13
15
import { useRouter } from "next/navigation" ;
14
16
import UserImage from "./UserImage" ;
17
+ import { motion , AnimatePresence } from "framer-motion" ;
15
18
16
19
const dropDownData = [
17
20
{
@@ -22,66 +25,92 @@ const dropDownData = [
22
25
] ;
23
26
24
27
export default function UserAccountDropDown ( ) {
25
- const session = useSession ( ) ;
26
- const user = session . data ?. user ;
28
+ const { data : session , status } = useSession ( ) ;
29
+ const user = session ?. user ;
27
30
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 ) ;
41
33
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
+ } , [ ] ) ;
53
37
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 } />
57
54
</ div >
58
- </ DropdownMenuLabel >
59
- < DropdownMenuSeparator />
55
+ ) }
56
+ </ div >
57
+ </ Button >
58
+ </ DropdownMenuTrigger >
60
59
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 >
66
97
</ DropdownMenuItem >
67
- ) ;
68
- } ) }
69
- < DropdownMenuSeparator />
70
- { user && (
98
+ ) ) }
99
+ < DropdownMenuSeparator className = "bg-primary/10 my-2" />
71
100
< 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"
72
102
onClick = { async ( ) => {
73
103
await signOut ( ) ;
74
104
router . push ( "/" ) ;
75
105
} }
76
- className = " flex gap-2 focus:bg-[#f34e4e]"
77
106
>
78
- < LogOut size = { 15 } />
79
- Logout
107
+ < LogOut size = { 15 } className = "text-destructive" />
108
+ < span className = "text-destructive" > Logout</ span >
80
109
</ DropdownMenuItem >
81
- ) }
110
+ </ motion . div >
82
111
</ DropdownMenuContent >
83
- </ DropdownMenu >
84
- ) }
85
- </ >
112
+ ) }
113
+ </ AnimatePresence >
114
+ </ DropdownMenu >
86
115
) ;
87
116
}
0 commit comments