import { useQuery } from "@tanstack/react-query";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Skeleton } from "@/components/ui/skeleton";
import { ArrowLeft, Users, Shield, Clock, Mail, User } from "lucide-react";
import { Link } from "wouter";
import { useAuth } from "@/hooks/use-auth";
import { usePageTitle } from "@/hooks/use-page-title";
import type { User as UserType } from "@shared/schema";
function UserCard({ user }: { user: UserType }) {
const initials = `${user.firstName?.charAt(0) || ''}${user.lastName?.charAt(0) || ''}`.toUpperCase() || 'U';
const displayName = user.firstName && user.lastName
? `${user.firstName} ${user.lastName}`
: user.email || 'Unknown User';
return (
<div className="flex items-center justify-between p-4 border rounded-md hover-elevate" data-testid={`user-card-${user.id}`}>
<div className="flex items-center gap-4">
<Avatar className="h-10 w-10">
<AvatarImage src={user.profileImageUrl || undefined} alt={displayName} />
<AvatarFallback>{initials}</AvatarFallback>
</Avatar>
<div>
<p className="font-medium">{displayName}</p>
<p className="text-sm text-muted-foreground">{user.email || 'No email'}</p>
</div>
</div>
<div className="flex items-center gap-3">
<Badge variant="outline" className="gap-1">
<Clock className="h-3 w-3" />
{user.createdAt ? new Date(user.createdAt).toLocaleDateString() : 'N/A'}
</Badge>
</div>
</div>
);
}
function UserCardSkeleton() {
return (
<div className="flex items-center justify-between p-4 border rounded-md">
<div className="flex items-center gap-4">
<Skeleton className="h-10 w-10 rounded-full" />
<div className="space-y-2">
<Skeleton className="h-4 w-32" />
<Skeleton className="h-3 w-48" />
</div>
</div>
<Skeleton className="h-6 w-24" />
</div>
);
}
export default function UsersPage() {
usePageTitle("User Management");
const { user: currentUser, isLoading: authLoading } = useAuth();
const { data: users, isLoading: usersLoading } = useQuery<UserType[]>({
queryKey: ["/api/users"],
enabled: !!currentUser,
});
if (authLoading) {
return (
<div className="min-h-screen bg-background flex items-center justify-center">
<div className="text-center">
<Skeleton className="h-8 w-8 rounded-full mx-auto mb-4" />
<p className="text-muted-foreground">Loading...</p>
</div>
</div>
);
}
if (!currentUser) {
return (
<div className="min-h-screen bg-background">
<div className="border-b">
<div className="container mx-auto px-4 py-4 flex items-center gap-4">
<Link href="/">
<Button variant="ghost" size="icon" data-testid="button-back-home">
<ArrowLeft className="h-4 w-4" />
</Button>
</Link>
<div className="flex items-center gap-2">
<Users className="h-6 w-6 text-primary" />
<h1 className="text-xl font-semibold">User Management</h1>
</div>
</div>
</div>
<div className="container mx-auto px-4 py-16 text-center">
<Shield className="h-16 w-16 text-muted-foreground mx-auto mb-4" />
<h2 className="text-2xl font-semibold mb-2">Access Restricted</h2>
<p className="text-muted-foreground mb-6">You need to sign in to access user management.</p>
<a href="/api/login">
<Button data-testid="button-sign-in">Sign In</Button>
</a>
</div>
</div>
);
}
return (
<div className="min-h-screen bg-background">
<div className="border-b">
<div className="container mx-auto px-4 py-4 flex items-center gap-4">
<Link href="/">
<Button variant="ghost" size="icon" data-testid="button-back-home">
<ArrowLeft className="h-4 w-4" />
</Button>
</Link>
<div className="flex items-center gap-2">
<Users className="h-6 w-6 text-primary" />
<h1 className="text-xl font-semibold">User Management</h1>
</div>
</div>
</div>
<div className="container mx-auto px-4 py-8 max-w-4xl">
<div className="space-y-6">
<Card>
<CardHeader>
<div className="flex items-center justify-between">
<div>
<CardTitle className="flex items-center gap-2">
<User className="h-5 w-5 text-blue-500" />
Your Profile
</CardTitle>
<CardDescription>Currently signed in</CardDescription>
</div>
</div>
</CardHeader>
<CardContent>
<div className="flex items-center gap-4">
<Avatar className="h-16 w-16">
<AvatarImage src={currentUser.profileImageUrl || undefined} />
<AvatarFallback className="text-lg">
{`${currentUser.firstName?.charAt(0) || ''}${currentUser.lastName?.charAt(0) || ''}`.toUpperCase() || 'U'}
</AvatarFallback>
</Avatar>
<div>
<p className="text-lg font-medium">
{currentUser.firstName && currentUser.lastName
? `${currentUser.firstName} ${currentUser.lastName}`
: 'User'}
</p>
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<Mail className="h-4 w-4" />
{currentUser.email || 'No email'}
</div>
<div className="flex items-center gap-2 text-sm text-muted-foreground mt-1">
<Clock className="h-4 w-4" />
Joined: {currentUser.createdAt ? new Date(currentUser.createdAt).toLocaleDateString() : 'N/A'}
</div>
</div>
</div>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Users className="h-5 w-5 text-purple-500" />
All Users
</CardTitle>
<CardDescription>Users registered in the system</CardDescription>
</CardHeader>
<CardContent>
<ScrollArea className="h-[400px]">
<div className="space-y-3">
{usersLoading ? (
<>
<UserCardSkeleton />
<UserCardSkeleton />
<UserCardSkeleton />
</>
) : users && users.length > 0 ? (
users.map((user) => (
<UserCard key={user.id} user={user} />
))
) : (
<div className="text-center py-8 text-muted-foreground">
<Users className="h-12 w-12 mx-auto mb-4 opacity-50" />
<p>No users found</p>
</div>
)}
</div>
</ScrollArea>
</CardContent>
</Card>
</div>
</div>
</div>
);
}