--- import { Icon } from 'astro-icon/components' import { z } from 'astro:content' import { orderBy as lodashOrderBy } from 'lodash-es' import SortArrowIcon from '../../../components/SortArrowIcon.astro' import TimeFormatted from '../../../components/TimeFormatted.astro' import Tooltip from '../../../components/Tooltip.astro' import UserBadge from '../../../components/UserBadge.astro' import BaseLayout from '../../../layouts/BaseLayout.astro' import { zodParseQueryParamsStoringErrors } from '../../../lib/parseUrlFilters' import { pluralize } from '../../../lib/pluralize' import { prisma } from '../../../lib/prisma' import { formatDateShort } from '../../../lib/timeAgo' import type { Prisma } from '@prisma/client' const { data: filters } = zodParseQueryParamsStoringErrors( { 'sort-by': z.enum(['name', 'role', 'createdAt', 'karma']).default('createdAt'), 'sort-order': z.enum(['asc', 'desc']).default('desc'), search: z.string().optional(), role: z.enum(['user', 'admin', 'verifier', 'verified', 'spammer']).optional(), }, Astro ) // Set up Prisma orderBy with correct typing const prismaOrderBy = filters['sort-by'] === 'name' || filters['sort-by'] === 'createdAt' || filters['sort-by'] === 'karma' ? { [filters['sort-by'] === 'karma' ? 'totalKarma' : filters['sort-by']]: filters['sort-order'] === 'asc' ? 'asc' : 'desc', } : { createdAt: 'desc' as const } // Build where clause based on role filter const whereClause: Prisma.UserWhereInput = {} if (filters.search) { whereClause.OR = [{ name: { contains: filters.search, mode: 'insensitive' } }] } if (filters.role) { switch (filters.role) { case 'user': { whereClause.admin = false whereClause.verifier = false whereClause.verified = false whereClause.spammer = false break } case 'admin': { whereClause.admin = true break } case 'verifier': { whereClause.verifier = true break } case 'verified': { whereClause.verified = true break } case 'spammer': { whereClause.spammer = true break } } } // Retrieve users from the database const dbUsers = await prisma.user.findMany({ where: whereClause, select: { id: true, name: true, displayName: true, picture: true, verified: true, admin: true, verifier: true, spammer: true, totalKarma: true, createdAt: true, updatedAt: true, internalNotes: { select: { id: true, content: true, createdAt: true, }, }, _count: { select: { suggestions: true, comments: true, }, }, }, orderBy: prismaOrderBy, }) const users = filters['sort-by'] === 'role' ? lodashOrderBy(dbUsers, [(u) => (u.admin ? 'admin' : 'user')], [filters['sort-order']]) : dbUsers const makeSortUrl = (slug: NonNullable<(typeof filters)['sort-by']>) => { const currentSortBy = filters['sort-by'] const currentSortOrder = filters['sort-order'] const newSortOrder = currentSortBy === slug && currentSortOrder === 'asc' ? 'desc' : 'asc' const searchParams = new URLSearchParams(Astro.url.search) searchParams.set('sort-by', slug) searchParams.set('sort-order', newSortOrder) return `/admin/users?${searchParams.toString()}` } ---

User Management

{users.length} users

Users List

Scroll horizontally to see more →
{ users.map((user) => ( )) }
Name Status Role Karma Joined Activity Actions
{user.internalNotes.length > 0 && ( `${formatDateShort(note.createdAt, { prefix: false, hourPrecision: true, caseType: 'sentence', })}: ${note.content}` ) .join('\n\n')} > {user.internalNotes.length} internal {pluralize('note', user.internalNotes.length)} )}
{user.spammer && ( Spammer )} {user.verified && ( Verified )} {user.verifier && ( Verifier )}
{user.admin ? 'Admin' : 'User'} = 100 ? 'text-green-400' : user.totalKarma >= 0 ? 'text-zinc-300' : 'text-red-400'}`} > {user.totalKarma}
Suggestions {user._count.suggestions}
Comments {user._count.comments}