Platform-wide visual overhaul, team invites, analytics improvements, and deployment hardening
UI overhaul applying jury dashboard design patterns across all pages: - Stat cards with border-l-4 accent + icon pills on admin, observer, mentor, applicant dashboards and reports - Card section headers with color-coded icon pills throughout - Hover lift effects (translate-y + shadow) on cards and list items - Gradient progress bars (brand-teal to brand-blue) platform-wide - AnimatedCard stagger animations on all dashboard sections - Auth pages with gradient accent strip and polished icon containers - EmptyState component upgraded with rounded icon pill containers - Replaced AI-looking icons (Brain/Sparkles/Bot/Wand2/Cpu) with descriptive alternatives across 12 files - Removed gradient overlay from jury dashboard header - Quick actions restyled as card links with group hover effects Backend improvements: - Team member invite emails with account setup flow and notification logging - Analytics routers accept edition-wide queries (programId) in addition to roundId - Round detail endpoint returns inline progress data (eliminates extra getProgress call) - Award voting endpoints parallelized with Promise.all - Bulk invite supports optional sendInvitation flag - AwardVote composite index migration for query performance Infrastructure: - Docker entrypoint with migration retry loop (configurable retries/delay) - docker-compose pull_policy: always for automatic image refresh - Simplified deploy/update scripts using docker compose up -d --pull always - Updated deployment documentation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -525,32 +525,31 @@ export const specialAwardRouter = router({
|
||||
})
|
||||
}
|
||||
|
||||
const award = await ctx.prisma.specialAward.findUniqueOrThrow({
|
||||
where: { id: input.awardId },
|
||||
})
|
||||
|
||||
// Get eligible projects
|
||||
const eligibleProjects = await ctx.prisma.awardEligibility.findMany({
|
||||
where: { awardId: input.awardId, eligible: true },
|
||||
include: {
|
||||
project: {
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
teamName: true,
|
||||
description: true,
|
||||
competitionCategory: true,
|
||||
country: true,
|
||||
tags: true,
|
||||
// Fetch award, eligible projects, and votes in parallel
|
||||
const [award, eligibleProjects, myVotes] = await Promise.all([
|
||||
ctx.prisma.specialAward.findUniqueOrThrow({
|
||||
where: { id: input.awardId },
|
||||
}),
|
||||
ctx.prisma.awardEligibility.findMany({
|
||||
where: { awardId: input.awardId, eligible: true },
|
||||
include: {
|
||||
project: {
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
teamName: true,
|
||||
description: true,
|
||||
competitionCategory: true,
|
||||
country: true,
|
||||
tags: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// Get user's existing votes
|
||||
const myVotes = await ctx.prisma.awardVote.findMany({
|
||||
where: { awardId: input.awardId, userId: ctx.user.id },
|
||||
})
|
||||
}),
|
||||
ctx.prisma.awardVote.findMany({
|
||||
where: { awardId: input.awardId, userId: ctx.user.id },
|
||||
}),
|
||||
])
|
||||
|
||||
return {
|
||||
award,
|
||||
@@ -646,25 +645,25 @@ export const specialAwardRouter = router({
|
||||
getVoteResults: adminProcedure
|
||||
.input(z.object({ awardId: z.string() }))
|
||||
.query(async ({ ctx, input }) => {
|
||||
const award = await ctx.prisma.specialAward.findUniqueOrThrow({
|
||||
where: { id: input.awardId },
|
||||
})
|
||||
|
||||
const votes = await ctx.prisma.awardVote.findMany({
|
||||
where: { awardId: input.awardId },
|
||||
include: {
|
||||
project: {
|
||||
select: { id: true, title: true, teamName: true },
|
||||
const [award, votes, jurorCount] = await Promise.all([
|
||||
ctx.prisma.specialAward.findUniqueOrThrow({
|
||||
where: { id: input.awardId },
|
||||
}),
|
||||
ctx.prisma.awardVote.findMany({
|
||||
where: { awardId: input.awardId },
|
||||
include: {
|
||||
project: {
|
||||
select: { id: true, title: true, teamName: true },
|
||||
},
|
||||
user: {
|
||||
select: { id: true, name: true, email: true },
|
||||
},
|
||||
},
|
||||
user: {
|
||||
select: { id: true, name: true, email: true },
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const jurorCount = await ctx.prisma.awardJuror.count({
|
||||
where: { awardId: input.awardId },
|
||||
})
|
||||
}),
|
||||
ctx.prisma.awardJuror.count({
|
||||
where: { awardId: input.awardId },
|
||||
}),
|
||||
])
|
||||
|
||||
const votedJurorCount = new Set(votes.map((v) => v.userId)).size
|
||||
|
||||
|
||||
Reference in New Issue
Block a user