Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance User Dropdown Menu UI and Improve Component Structure #670

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 78 additions & 49 deletions apps/web/components/UserAccountDropDown.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
"use client";

import { useState, useEffect } from "react";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
Button,
} from "@repo/ui";
import { signOut } from "next-auth/react";
import { useSession } from "next-auth/react";
import { signOut, useSession } from "next-auth/react";
import { LogOut, UserRound } from "lucide-react";
import { useRouter } from "next/navigation";
import UserImage from "./UserImage";
import { motion, AnimatePresence } from "framer-motion";

const dropDownData = [
{
Expand All @@ -22,66 +25,92 @@ const dropDownData = [
];

export default function UserAccountDropDown() {
const session = useSession();
const user = session.data?.user;
const { data: session, status } = useSession();
const user = session?.user;
const router = useRouter();
return (
<>
{user && (
<DropdownMenu>
<DropdownMenuTrigger className="w-[2rem] flex items-center p-[0.2rem] justify-center h-[2rem]">
{!user.image ? (
<div className="p-1 border-2 rounded-md border-[#1a1a1a]">
<UserRound />
</div>
) : (
<UserImage image={user.image} />
)}
</DropdownMenuTrigger>
const [isOpen, setIsOpen] = useState(false);
const [mounted, setMounted] = useState(false);

<DropdownMenuContent className="!w-[15rem] dark:shadow-[#030712] translate-y-8 scale-110 -translate-x-10 shadow-lg">
<DropdownMenuLabel className="flex gap-4 items-center">
<div className="!w-[2rem] flex items-center p-[0.2rem] justify-center !h-[2rem]">
{!user.image ? (
<div className="p-1 border-2 rounded-full border-[#1a1a1a]">
<UserRound />
</div>
) : (
<UserImage image={user.image} />
)}
</div>
useEffect(() => {
setMounted(true);
}, []);

<div className="flex flex-col">
<span className="max-w-[200px]">{user?.name}</span>
<span className="text-[0.8rem] max-w-[200px] text-gray-400">{user?.email}</span>
if (!mounted || status === "loading") return null;
if (!user) return null;

return (
<DropdownMenu onOpenChange={setIsOpen}>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
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"
>
<div className="border-primary/20 h-8 w-8 overflow-hidden rounded-full border-2">
{user.image ? (
<UserImage image={user.image} />
) : (
<div className="from-primary-400 to-primary-600 flex h-full w-full items-center justify-center bg-gradient-to-br text-white">
<UserRound size={16} />
</div>
</DropdownMenuLabel>
<DropdownMenuSeparator />
)}
</div>
</Button>
</DropdownMenuTrigger>

{dropDownData.map((item, index) => {
return (
<DropdownMenuItem className="flex gap-2" onClick={() => router.push("/profile")} key={index}>
<span>{item.icon}</span>
<span>{item.name}</span>
<AnimatePresence>
{isOpen && (
<DropdownMenuContent
forceMount
className="bg-secondary/15 border-primary/10 rounded-2xl border p-2 shadow-lg shadow-neutral-600/5 backdrop-blur-lg"
align="end"
>
<motion.div
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
transition={{ duration: 0.2 }}
>
<DropdownMenuLabel className="flex items-center space-x-3 p-3">
<div className="border-primary/20 h-12 w-12 overflow-hidden rounded-full border-2">
{user.image ? (
<UserImage image={user.image} />
) : (
<div className="from-primary-400 to-primary-600 flex h-full w-full items-center justify-center bg-gradient-to-br text-white">
<UserRound size={24} />
</div>
)}
</div>
<div className="flex flex-col">
<span className="text-foreground font-semibold">{user.name}</span>
<span className="text-muted-foreground max-w-[150px] truncate text-xs">{user.email}</span>
</div>
</DropdownMenuLabel>
<DropdownMenuSeparator className="bg-primary/10 my-2" />
{dropDownData.map((item, index) => (
<DropdownMenuItem
key={index}
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"
onClick={() => router.push(item.href)}
>
<span className="text-foreground">{item.icon}</span>
<span className="text-foreground">{item.name}</span>
</DropdownMenuItem>
);
})}
<DropdownMenuSeparator />
{user && (
))}
<DropdownMenuSeparator className="bg-primary/10 my-2" />
<DropdownMenuItem
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"
onClick={async () => {
await signOut();
router.push("/");
}}
className=" flex gap-2 focus:bg-[#f34e4e]"
>
<LogOut size={15} />
Logout
<LogOut size={15} className="text-destructive" />
<span className="text-destructive">Logout</span>
</DropdownMenuItem>
)}
</motion.div>
</DropdownMenuContent>
</DropdownMenu>
)}
</>
)}
</AnimatePresence>
</DropdownMenu>
);
}
Loading