|
2 | 2 | import { Dashboard } from "@/components/dashboard"; |
3 | 3 | import { ThemeToggle } from "@/components/theme-toggle"; |
4 | 4 | import { Button } from "@/components/ui/button"; |
| 5 | +import { |
| 6 | + DropdownMenu, |
| 7 | + DropdownMenuContent, |
| 8 | + DropdownMenuItem, |
| 9 | + DropdownMenuLabel, |
| 10 | + DropdownMenuSeparator, |
| 11 | + DropdownMenuTrigger, |
| 12 | +} from "@/components/ui/dropdown-menu"; |
| 13 | +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; |
5 | 14 | import { useIsMobile } from "@/hooks/use-mobile"; |
6 | 15 | import { cn } from "@/lib/utils"; |
7 | 16 | import { FloatingChatbot } from "@/components/floating-chatbot"; |
8 | 17 | import { StockVisionErrorBoundary } from "../../lib/error-handling"; |
9 | 18 | import { |
10 | 19 | BarChart2, ChevronLeft, ChevronRight, Home, LineChart, |
11 | | - Settings, Wallet,BriefcaseBusiness , ChartNoAxesCombined |
| 20 | + Settings, Wallet, BriefcaseBusiness, ChartNoAxesCombined, LogOut, User |
12 | 21 | } from "lucide-react"; |
13 | 22 | import { useRouter } from "next/navigation"; |
14 | 23 | import { useEffect, useState } from "react"; |
| 24 | +import { useSession, signOut } from "next-auth/react"; |
15 | 25 |
|
16 | 26 | export default function DashboardPage() { |
17 | 27 | const [sidebarCollapsed, setSidebarCollapsed] = useState(false); |
18 | 28 | const isMobile = useIsMobile(); |
19 | 29 | const router = useRouter(); |
20 | 30 | const [activeSection, setActiveSection] = useState("overview"); |
| 31 | + const { data: session } = useSession(); |
| 32 | + |
| 33 | + const handleSignOut = async () => { |
| 34 | + await signOut({ redirect: false }); |
| 35 | + router.push('/'); |
| 36 | + }; |
| 37 | + |
| 38 | + const getUsernameFromEmail = (email?: string | null) => { |
| 39 | + if (!email) return 'User'; |
| 40 | + const username = email.split('@')[0]; |
| 41 | + // Capitalize first letter |
| 42 | + return username.charAt(0).toUpperCase() + username.slice(1); |
| 43 | + }; |
| 44 | + |
| 45 | + const getInitials = (name?: string | null, email?: string | null) => { |
| 46 | + if (name) { |
| 47 | + return name |
| 48 | + .split(' ') |
| 49 | + .map(n => n[0]) |
| 50 | + .join('') |
| 51 | + .toUpperCase() |
| 52 | + .slice(0, 2); |
| 53 | + } |
| 54 | + if (email) { |
| 55 | + const username = email.split('@')[0]; |
| 56 | + return username.slice(0, 2).toUpperCase(); |
| 57 | + } |
| 58 | + return 'U'; |
| 59 | + }; |
21 | 60 |
|
22 | 61 | useEffect(() => { |
23 | 62 | if (isMobile) { |
@@ -209,7 +248,81 @@ export default function DashboardPage() { |
209 | 248 | </Button> |
210 | 249 | </div> |
211 | 250 | <h1 className="text-xl font-extrabold">Dashboard</h1> |
212 | | - <ThemeToggle /> |
| 251 | + <div className="flex items-center gap-3"> |
| 252 | + <ThemeToggle /> |
| 253 | + {session && ( |
| 254 | + <DropdownMenu> |
| 255 | + <DropdownMenuTrigger asChild> |
| 256 | + <Button |
| 257 | + variant="ghost" |
| 258 | + className="relative h-10 w-10 rounded-full p-0 ring-2 ring-primary/30 hover:ring-primary/60 transition-all duration-300 hover:scale-105" |
| 259 | + > |
| 260 | + <Avatar className="h-10 w-10"> |
| 261 | + <AvatarImage |
| 262 | + src={session.user?.image || undefined} |
| 263 | + alt={session.user?.name || getUsernameFromEmail(session.user?.email)} |
| 264 | + className="object-cover" |
| 265 | + /> |
| 266 | + <AvatarFallback className="bg-gradient-to-br from-blue-500 via-purple-500 to-pink-500 text-white font-bold shadow-lg"> |
| 267 | + {getInitials(session.user?.name, session.user?.email)} |
| 268 | + </AvatarFallback> |
| 269 | + </Avatar> |
| 270 | + {/* Active indicator dot */} |
| 271 | + <span className="absolute bottom-0 right-0 h-2.5 w-2.5 rounded-full bg-green-500 border-2 border-background shadow-sm" /> |
| 272 | + </Button> |
| 273 | + </DropdownMenuTrigger> |
| 274 | + <DropdownMenuContent className="w-64" align="end" forceMount> |
| 275 | + <DropdownMenuLabel className="font-normal"> |
| 276 | + <div className="flex flex-col space-y-2 p-2"> |
| 277 | + <div className="flex items-center gap-3"> |
| 278 | + <Avatar className="h-12 w-12"> |
| 279 | + <AvatarImage |
| 280 | + src={session.user?.image || undefined} |
| 281 | + alt={session.user?.name || getUsernameFromEmail(session.user?.email)} |
| 282 | + className="object-cover" |
| 283 | + /> |
| 284 | + <AvatarFallback className="bg-gradient-to-br from-blue-500 via-purple-500 to-pink-500 text-white font-bold shadow-lg"> |
| 285 | + {getInitials(session.user?.name, session.user?.email)} |
| 286 | + </AvatarFallback> |
| 287 | + </Avatar> |
| 288 | + <div className="flex flex-col space-y-1 flex-1 min-w-0"> |
| 289 | + <p className="text-sm font-semibold leading-none truncate"> |
| 290 | + {session.user?.name || getUsernameFromEmail(session.user?.email)} |
| 291 | + </p> |
| 292 | + <p className="text-xs leading-none text-muted-foreground truncate"> |
| 293 | + {session.user?.email} |
| 294 | + </p> |
| 295 | + </div> |
| 296 | + </div> |
| 297 | + </div> |
| 298 | + </DropdownMenuLabel> |
| 299 | + <DropdownMenuSeparator /> |
| 300 | + <DropdownMenuItem |
| 301 | + onClick={() => handleSectionChange("settings")} |
| 302 | + className="cursor-pointer" |
| 303 | + > |
| 304 | + <Settings className="mr-2 h-4 w-4" /> |
| 305 | + <span>Settings</span> |
| 306 | + </DropdownMenuItem> |
| 307 | + <DropdownMenuItem |
| 308 | + onClick={handleHomeClick} |
| 309 | + className="cursor-pointer" |
| 310 | + > |
| 311 | + <Home className="mr-2 h-4 w-4" /> |
| 312 | + <span>Home</span> |
| 313 | + </DropdownMenuItem> |
| 314 | + <DropdownMenuSeparator /> |
| 315 | + <DropdownMenuItem |
| 316 | + className="cursor-pointer text-red-600 focus:text-red-600 focus:bg-red-50 dark:focus:bg-red-950" |
| 317 | + onClick={handleSignOut} |
| 318 | + > |
| 319 | + <LogOut className="mr-2 h-4 w-4" /> |
| 320 | + <span>Log out</span> |
| 321 | + </DropdownMenuItem> |
| 322 | + </DropdownMenuContent> |
| 323 | + </DropdownMenu> |
| 324 | + )} |
| 325 | + </div> |
213 | 326 | </header> |
214 | 327 | <main className="flex-1 overflow-y-auto"> |
215 | 328 | <Dashboard activeSection={activeSection} onSectionChange={handleSectionChange} /> |
|
0 commit comments