Rounds overhaul: full CRUD submission windows, scheduling UI, analytics, design refresh
All checks were successful
Build and Push Docker Image / build (push) Successful in 7m40s

- Fix special award FK crash: replace 4x raw auditLog.create with logAudit() helper
- Add updateSubmissionWindow + deleteSubmissionWindow mutations to round router
- Add per-round analytics (_count, juryGroup) to competition.getById
- Remove redundant acceptedCategories from intake config
- Rewrite submission window manager with full CRUD, all fields, date pickers
- Add round scheduling card (open/close dates) to round detail page
- Add project count, assignment count, jury group to round list cards
- Visual redesign: pipeline view, brand colors, progress bars, enhanced cards

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-16 07:07:09 +01:00
parent 2fb26d4734
commit f572336781
8 changed files with 1208 additions and 414 deletions

View File

@@ -125,14 +125,15 @@ export const specialAwardRouter = router({
},
})
await tx.auditLog.create({
data: {
userId: ctx.user.id,
action: 'CREATE',
entityType: 'SpecialAward',
entityId: created.id,
detailsJson: { name: input.name, scoringMode: input.scoringMode } as Prisma.InputJsonValue,
},
await logAudit({
prisma: tx,
userId: ctx.user.id,
action: 'CREATE',
entityType: 'SpecialAward',
entityId: created.id,
detailsJson: { name: input.name, scoringMode: input.scoringMode },
ipAddress: ctx.ip,
userAgent: ctx.userAgent,
})
return created
@@ -190,13 +191,14 @@ export const specialAwardRouter = router({
.input(z.object({ id: z.string() }))
.mutation(async ({ ctx, input }) => {
await ctx.prisma.$transaction(async (tx) => {
await tx.auditLog.create({
data: {
userId: ctx.user.id,
action: 'DELETE',
entityType: 'SpecialAward',
entityId: input.id,
},
await logAudit({
prisma: tx,
userId: ctx.user.id,
action: 'DELETE',
entityType: 'SpecialAward',
entityId: input.id,
ipAddress: ctx.ip,
userAgent: ctx.userAgent,
})
await tx.specialAward.delete({ where: { id: input.id } })
@@ -249,22 +251,23 @@ export const specialAwardRouter = router({
data: updateData,
})
await tx.auditLog.create({
data: {
userId: ctx.user.id,
action: 'UPDATE_STATUS',
entityType: 'SpecialAward',
entityId: input.id,
detailsJson: {
previousStatus: current.status,
newStatus: input.status,
...(votingStartAtUpdated && {
votingStartAtUpdated: true,
previousVotingStartAt: current.votingStartAt,
newVotingStartAt: now,
}),
} as Prisma.InputJsonValue,
await logAudit({
prisma: tx,
userId: ctx.user.id,
action: 'UPDATE_STATUS',
entityType: 'SpecialAward',
entityId: input.id,
detailsJson: {
previousStatus: current.status,
newStatus: input.status,
...(votingStartAtUpdated && {
votingStartAtUpdated: true,
previousVotingStartAt: current.votingStartAt,
newVotingStartAt: now,
}),
},
ipAddress: ctx.ip,
userAgent: ctx.userAgent,
})
return updated
@@ -750,19 +753,20 @@ export const specialAwardRouter = router({
},
})
await tx.auditLog.create({
data: {
userId: ctx.user.id,
action: 'UPDATE',
entityType: 'SpecialAward',
entityId: input.awardId,
detailsJson: {
action: 'SET_AWARD_WINNER',
previousWinner: previous.winnerProjectId,
newWinner: input.projectId,
overridden: input.overridden,
} as Prisma.InputJsonValue,
await logAudit({
prisma: tx,
userId: ctx.user.id,
action: 'UPDATE',
entityType: 'SpecialAward',
entityId: input.awardId,
detailsJson: {
action: 'SET_AWARD_WINNER',
previousWinner: previous.winnerProjectId,
newWinner: input.projectId,
overridden: input.overridden,
},
ipAddress: ctx.ip,
userAgent: ctx.userAgent,
})
return updated