feat: add user profile page and replace nav welcome text with avatar dropdown
- Replace welcome text in navigation with clickable avatar dropdown - Add dropdown menu showing user name, email, profile link, and logout - Create comprehensive user profile page (/profile) with: - Profile overview with avatar, name, email, and verification status - Account information section with detailed user data - Account activity tracking with current session status - Quick actions section with placeholder buttons for future features - Add missing UI components (Card, Badge, Separator) following shadcn/ui patterns - Use proper design tokens and destructive variant for logout action - All components pass lint and type checking 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
222
src/app/profile/page.tsx
Normal file
222
src/app/profile/page.tsx
Normal file
@@ -0,0 +1,222 @@
|
||||
"use client";
|
||||
|
||||
import { useSession } from "@/lib/auth-client";
|
||||
import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { Mail, Calendar, User, Shield, ArrowLeft } from "lucide-react";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
export default function ProfilePage() {
|
||||
const { data: session, isPending } = useSession();
|
||||
const router = useRouter();
|
||||
|
||||
if (isPending) {
|
||||
return (
|
||||
<div className="flex items-center justify-center min-h-screen">
|
||||
<div>Loading...</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!session) {
|
||||
router.push("/");
|
||||
return null;
|
||||
}
|
||||
|
||||
const user = session.user;
|
||||
const createdDate = user.createdAt ? new Date(user.createdAt).toLocaleDateString('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
}) : null;
|
||||
|
||||
return (
|
||||
<div className="container max-w-4xl mx-auto py-8 px-4">
|
||||
<div className="flex items-center gap-4 mb-8">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => router.back()}
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<ArrowLeft className="h-4 w-4" />
|
||||
Back
|
||||
</Button>
|
||||
<h1 className="text-3xl font-bold">Your Profile</h1>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-6">
|
||||
{/* Profile Overview Card */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div className="flex items-center space-x-4">
|
||||
<Avatar className="h-20 w-20">
|
||||
<AvatarImage
|
||||
src={user.image || ""}
|
||||
alt={user.name || "User"}
|
||||
referrerPolicy="no-referrer"
|
||||
/>
|
||||
<AvatarFallback className="text-lg">
|
||||
{(
|
||||
user.name?.[0] ||
|
||||
user.email?.[0] ||
|
||||
"U"
|
||||
).toUpperCase()}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="space-y-2">
|
||||
<h2 className="text-2xl font-semibold">{user.name}</h2>
|
||||
<div className="flex items-center gap-2 text-muted-foreground">
|
||||
<Mail className="h-4 w-4" />
|
||||
<span>{user.email}</span>
|
||||
{user.emailVerified && (
|
||||
<Badge variant="outline" className="text-green-600 border-green-600">
|
||||
<Shield className="h-3 w-3 mr-1" />
|
||||
Verified
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
{createdDate && (
|
||||
<div className="flex items-center gap-2 text-muted-foreground text-sm">
|
||||
<Calendar className="h-4 w-4" />
|
||||
<span>Member since {createdDate}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
|
||||
{/* Account Information */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Account Information</CardTitle>
|
||||
<CardDescription>
|
||||
Your account details and settings
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-muted-foreground">
|
||||
Full Name
|
||||
</label>
|
||||
<div className="p-3 border rounded-md bg-muted/10">
|
||||
{user.name || "Not provided"}
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-muted-foreground">
|
||||
Email Address
|
||||
</label>
|
||||
<div className="p-3 border rounded-md bg-muted/10 flex items-center justify-between">
|
||||
<span>{user.email}</span>
|
||||
{user.emailVerified && (
|
||||
<Badge variant="outline" className="text-green-600 border-green-600">
|
||||
Verified
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-lg font-medium">Account Status</h3>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div className="flex items-center justify-between p-4 border rounded-lg">
|
||||
<div className="space-y-1">
|
||||
<p className="font-medium">Email Verification</p>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Email address verification status
|
||||
</p>
|
||||
</div>
|
||||
<Badge variant={user.emailVerified ? "default" : "secondary"}>
|
||||
{user.emailVerified ? "Verified" : "Unverified"}
|
||||
</Badge>
|
||||
</div>
|
||||
<div className="flex items-center justify-between p-4 border rounded-lg">
|
||||
<div className="space-y-1">
|
||||
<p className="font-medium">Account Type</p>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Your account access level
|
||||
</p>
|
||||
</div>
|
||||
<Badge variant="outline">Standard</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Account Activity */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Recent Activity</CardTitle>
|
||||
<CardDescription>
|
||||
Your recent account activity and sessions
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between p-4 border rounded-lg">
|
||||
<div className="flex items-center space-x-3">
|
||||
<div className="h-2 w-2 bg-green-500 rounded-full"></div>
|
||||
<div>
|
||||
<p className="font-medium">Current Session</p>
|
||||
<p className="text-sm text-muted-foreground">Active now</p>
|
||||
</div>
|
||||
</div>
|
||||
<Badge variant="outline" className="text-green-600 border-green-600">
|
||||
Active
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Quick Actions */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Quick Actions</CardTitle>
|
||||
<CardDescription>
|
||||
Manage your account settings and preferences
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<Button variant="outline" className="justify-start h-auto p-4" disabled>
|
||||
<User className="h-4 w-4 mr-2" />
|
||||
<div className="text-left">
|
||||
<div className="font-medium">Edit Profile</div>
|
||||
<div className="text-xs text-muted-foreground">Update your information</div>
|
||||
</div>
|
||||
</Button>
|
||||
<Button variant="outline" className="justify-start h-auto p-4" disabled>
|
||||
<Shield className="h-4 w-4 mr-2" />
|
||||
<div className="text-left">
|
||||
<div className="font-medium">Security Settings</div>
|
||||
<div className="text-xs text-muted-foreground">Manage security options</div>
|
||||
</div>
|
||||
</Button>
|
||||
<Button variant="outline" className="justify-start h-auto p-4" disabled>
|
||||
<Mail className="h-4 w-4 mr-2" />
|
||||
<div className="text-left">
|
||||
<div className="font-medium">Email Preferences</div>
|
||||
<div className="text-xs text-muted-foreground">Configure notifications</div>
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground mt-4">
|
||||
Additional profile management features coming soon.
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user