feat: fix project status counts, add top pagination and sortable columns
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m39s
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m39s
- Status counts now show each project's latest round state only (no more inflated counts from projects passing multiple rounds) - Add pagination controls at top of projects, members, and observer lists - Add sortable column headers to admin projects table (title, category, program, assignments, status) and members table (name, role, status, last login) - Backend: add sortBy/sortDir params to project.list and user.list Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -76,6 +76,8 @@ export const projectRouter = router({
|
||||
hasAssignments: z.boolean().optional(),
|
||||
page: z.number().int().min(1).default(1),
|
||||
perPage: z.number().int().min(1).max(200).default(20),
|
||||
sortBy: z.enum(['title', 'category', 'program', 'assignments', 'status', 'createdAt']).optional(),
|
||||
sortDir: z.enum(['asc', 'desc']).optional(),
|
||||
})
|
||||
)
|
||||
.query(async ({ ctx, input }) => {
|
||||
@@ -83,10 +85,23 @@ export const projectRouter = router({
|
||||
programId, roundId, excludeInRoundId, status, statuses, unassignedOnly, search, tags,
|
||||
competitionCategory, oceanIssue, country,
|
||||
wantsMentorship, hasFiles, hasAssignments,
|
||||
page, perPage,
|
||||
page, perPage, sortBy, sortDir,
|
||||
} = input
|
||||
const skip = (page - 1) * perPage
|
||||
|
||||
const dir = sortDir ?? 'desc'
|
||||
const orderBy: Prisma.ProjectOrderByWithRelationInput = (() => {
|
||||
switch (sortBy) {
|
||||
case 'title': return { title: dir }
|
||||
case 'category': return { competitionCategory: dir }
|
||||
case 'program': return { program: { name: dir } }
|
||||
case 'assignments': return { assignments: { _count: dir } }
|
||||
case 'status': return { status: dir }
|
||||
case 'createdAt':
|
||||
default: return { createdAt: dir }
|
||||
}
|
||||
})()
|
||||
|
||||
// Build where clause
|
||||
const where: Record<string, unknown> = {}
|
||||
|
||||
@@ -151,7 +166,7 @@ export const projectRouter = router({
|
||||
where,
|
||||
skip,
|
||||
take: perPage,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
orderBy,
|
||||
include: {
|
||||
program: { select: { id: true, name: true, year: true } },
|
||||
_count: { select: { assignments: true, files: true } },
|
||||
|
||||
@@ -238,10 +238,12 @@ export const userRouter = router({
|
||||
search: z.string().optional(),
|
||||
page: z.number().int().min(1).default(1),
|
||||
perPage: z.number().int().min(1).max(100).default(20),
|
||||
sortBy: z.enum(['name', 'email', 'role', 'status', 'lastLoginAt', 'createdAt']).optional(),
|
||||
sortDir: z.enum(['asc', 'desc']).optional(),
|
||||
})
|
||||
)
|
||||
.query(async ({ ctx, input }) => {
|
||||
const { role, roles, status, search, page, perPage } = input
|
||||
const { role, roles, status, search, page, perPage, sortBy, sortDir } = input
|
||||
const skip = (page - 1) * perPage
|
||||
|
||||
const where: Record<string, unknown> = {}
|
||||
@@ -259,12 +261,17 @@ export const userRouter = router({
|
||||
]
|
||||
}
|
||||
|
||||
const dir = sortDir ?? 'asc'
|
||||
const orderBy: Record<string, string> = sortBy
|
||||
? { [sortBy]: dir }
|
||||
: { createdAt: 'desc' }
|
||||
|
||||
const [users, total] = await Promise.all([
|
||||
ctx.prisma.user.findMany({
|
||||
where,
|
||||
skip,
|
||||
take: perPage,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
orderBy,
|
||||
select: {
|
||||
id: true,
|
||||
email: true,
|
||||
|
||||
Reference in New Issue
Block a user