import { Suspense } from 'react' import Link from 'next/link' import { prisma } from '@/lib/prisma' export const dynamic = 'force-dynamic' import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from '@/components/ui/card' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Skeleton } from '@/components/ui/skeleton' import { UserAvatar } from '@/components/shared/user-avatar' import { getUserAvatarUrl } from '@/server/utils/avatar-url' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table' import { Plus, Users } from 'lucide-react' import { formatDate } from '@/lib/utils' import { UserActions, UserMobileActions } from '@/components/admin/user-actions' async function UsersContent() { const users = await prisma.user.findMany({ where: { role: { in: ['JURY_MEMBER', 'OBSERVER'] }, }, include: { _count: { select: { assignments: true, }, }, assignments: { select: { evaluation: { select: { status: true }, }, }, }, }, orderBy: [{ role: 'asc' }, { name: 'asc' }], }) // Generate avatar URLs const usersWithAvatars = await Promise.all( users.map(async (user) => ({ ...user, avatarUrl: await getUserAvatarUrl(user.profileImageKey, user.profileImageProvider), })) ) if (usersWithAvatars.length === 0) { return (

No jury members yet

Invite jury members to start assigning projects for evaluation

) } const statusColors: Record = { ACTIVE: 'success', PENDING: 'secondary', INACTIVE: 'secondary', SUSPENDED: 'destructive', } const roleColors: Record = { JURY_MEMBER: 'default', OBSERVER: 'outline', } return ( <> {/* Desktop table view */} Member Role Expertise Assignments Status Last Login Actions {usersWithAvatars.map((user) => (

{user.name || 'Unnamed'}

{user.email}

{user.role.replace('_', ' ')} {user.expertiseTags && user.expertiseTags.length > 0 ? (
{user.expertiseTags.slice(0, 2).map((tag) => ( {tag} ))} {user.expertiseTags.length > 2 && ( +{user.expertiseTags.length - 2} )}
) : ( - )}

{user._count.assignments} assigned

{user.assignments.filter(a => a.evaluation?.status === 'SUBMITTED').length} completed

{user.status} {user.lastLoginAt ? ( formatDate(user.lastLoginAt) ) : ( Never )}
))}
{/* Mobile card view */}
{usersWithAvatars.map((user) => (
{user.name || 'Unnamed'} {user.email}
{user.status}
Role {user.role.replace('_', ' ')}
Assignments {user.assignments.filter(a => a.evaluation?.status === 'SUBMITTED').length}/{user._count.assignments} completed
{user.expertiseTags && user.expertiseTags.length > 0 && (
{user.expertiseTags.map((tag) => ( {tag} ))}
)}
))}
) } function UsersSkeleton() { return (
{[...Array(5)].map((_, i) => (
))}
) } export default function UsersPage() { return (
{/* Header */}

Jury Members

Manage jury members and observers

{/* Content */} }>
) }