103 lines
4.1 KiB
TypeScript
103 lines
4.1 KiB
TypeScript
"use client";
|
|
|
|
import { authClient } from "@/lib/auth-client";
|
|
import { useRouter } from "@/i18n/routing";
|
|
import { Link } from "@/i18n/routing";
|
|
import { useState } from "react";
|
|
import { useTranslations } from "next-intl";
|
|
|
|
export default function DashboardProfile() {
|
|
const t = useTranslations('Profile');
|
|
const { data: session, isPending } = authClient.useSession();
|
|
const router = useRouter();
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
|
|
// If loading, show skeleton
|
|
if (isPending) {
|
|
return (
|
|
<div className="flex items-center space-x-3 animate-pulse">
|
|
<div className="text-right hidden md:block">
|
|
<div className="h-4 w-24 bg-gray-600 rounded"></div>
|
|
<div className="h-3 w-16 bg-gray-600 rounded mt-1"></div>
|
|
</div>
|
|
<div className="w-10 h-10 bg-gray-600 rounded-full"></div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
// If no session, show nothing (or could show login button, but dashboard is protected)
|
|
if (!session) {
|
|
return null;
|
|
}
|
|
|
|
const user = session.user;
|
|
const initials = user.name
|
|
? user.name
|
|
.split(" ")
|
|
.map((n) => n[0])
|
|
.join("")
|
|
.toUpperCase()
|
|
.slice(0, 2)
|
|
: "??";
|
|
|
|
// Attempt to get role from user object if it exists (custom field), or default
|
|
// @ts-ignore - role might not be in the default type definition yet
|
|
const role = user.role || "Member";
|
|
|
|
const handleSignOut = async () => {
|
|
await authClient.signOut();
|
|
router.push("/auth/signin");
|
|
};
|
|
|
|
return (
|
|
<div className="relative">
|
|
<button
|
|
onClick={() => setIsOpen(!isOpen)}
|
|
className="flex items-center space-x-3 group focus:outline-none"
|
|
>
|
|
<div className="text-right hidden md:block">
|
|
<p className="text-sm font-medium text-white">{user.name}</p>
|
|
<p className="text-xs text-gray-400 capitalize">{role.toLowerCase().replace('_', ' ')}</p>
|
|
</div>
|
|
<div className="w-10 h-10 bg-gold-400 rounded-full flex items-center justify-center overflow-hidden border-2 border-transparent group-hover:border-white/20 transition-all">
|
|
{user.image ? (
|
|
// eslint-disable-next-line @next/next/no-img-element
|
|
<img src={user.image} alt={user.name} className="w-full h-full object-cover" />
|
|
) : (
|
|
<span className="text-navy-900 font-bold">{initials}</span>
|
|
)}
|
|
</div>
|
|
</button>
|
|
|
|
{/* Dropdown Menu */}
|
|
{isOpen && (
|
|
<>
|
|
<div
|
|
className="fixed inset-0 z-40"
|
|
onClick={() => setIsOpen(false)}
|
|
></div>
|
|
<div className="absolute right-0 top-full mt-2 w-48 bg-popover text-popover-foreground backdrop-blur-md rounded-lg shadow-xl z-50 py-1">
|
|
<div className="px-4 py-2 border-b border-white/5 md:hidden">
|
|
<p className="text-sm font-medium text-white">{user.name}</p>
|
|
<p className="text-xs text-gray-400">{user.email}</p>
|
|
</div>
|
|
<Link
|
|
href="/dashboard/profile"
|
|
className="block px-4 py-2 text-sm text-popover-foreground hover:bg-white/10 hover:text-white transition-colors"
|
|
onClick={() => setIsOpen(false)}
|
|
>
|
|
{t('profileSettings')}
|
|
</Link>
|
|
<button
|
|
onClick={handleSignOut}
|
|
className="w-full text-left px-4 py-2 text-sm text-red-400 hover:bg-white/10 hover:text-red-300 transition-colors"
|
|
>
|
|
{t('signOut')}
|
|
</button>
|
|
</div>
|
|
</>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|