fix: filter applicant portal rounds by award track membership
Some checks failed
Build and Push Docker Image / build (push) Has been cancelled
Some checks failed
Build and Push Docker Image / build (push) Has been cancelled
Projects in SEPARATE_POOL awards now only see their award rounds (not main pool rounds) across all applicant queries: openRounds, deadlines, document completeness, nav flags, and evaluations. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1301,22 +1301,52 @@ export const applicantRouter = router({
|
||||
}
|
||||
|
||||
const programId = project.programId
|
||||
const openRounds = programId
|
||||
? await ctx.prisma.round.findMany({
|
||||
where: {
|
||||
competition: { programId },
|
||||
status: 'ROUND_ACTIVE',
|
||||
},
|
||||
orderBy: { sortOrder: 'asc' },
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
roundType: true,
|
||||
windowCloseAt: true,
|
||||
},
|
||||
let openRounds: Array<{ id: string; name: string; slug: string | null; roundType: string; windowCloseAt: Date | null }> = []
|
||||
if (programId) {
|
||||
const allActiveRounds = await ctx.prisma.round.findMany({
|
||||
where: {
|
||||
competition: { programId },
|
||||
status: 'ROUND_ACTIVE',
|
||||
},
|
||||
orderBy: { sortOrder: 'asc' },
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
roundType: true,
|
||||
windowCloseAt: true,
|
||||
specialAwardId: true,
|
||||
specialAward: { select: { name: true } },
|
||||
},
|
||||
})
|
||||
|
||||
// Filter rounds based on award track: only show rounds the project is actually in
|
||||
const projectRoundIds = new Set(
|
||||
(await ctx.prisma.projectRoundState.findMany({
|
||||
where: { projectId: project.id },
|
||||
select: { roundId: true },
|
||||
})).map((prs) => prs.roundId)
|
||||
)
|
||||
const isInAwardTrack = allActiveRounds.some(
|
||||
(r) => r.specialAwardId && projectRoundIds.has(r.id)
|
||||
)
|
||||
|
||||
openRounds = allActiveRounds
|
||||
.filter((r) => {
|
||||
// Award round project isn't in → hide
|
||||
if (r.specialAwardId && !projectRoundIds.has(r.id)) return false
|
||||
// Main round when project is in award track and has no state in this round → hide
|
||||
if (!r.specialAwardId && isInAwardTrack && !projectRoundIds.has(r.id)) return false
|
||||
return true
|
||||
})
|
||||
: []
|
||||
.map((r) => ({
|
||||
id: r.id,
|
||||
name: r.specialAward ? `${r.specialAward.name}: ${r.name}` : r.name,
|
||||
slug: r.slug,
|
||||
roundType: r.roundType,
|
||||
windowCloseAt: r.windowCloseAt,
|
||||
}))
|
||||
}
|
||||
|
||||
// Determine user's role in the project
|
||||
const userMembership = project.teamMembers.find((tm) => tm.userId === ctx.user.id)
|
||||
@@ -1391,13 +1421,22 @@ export const applicantRouter = router({
|
||||
const hasMentor = !!project.mentorAssignment
|
||||
|
||||
// Check if there are EVALUATION rounds (CLOSED/ARCHIVED) with applicantVisibility.enabled
|
||||
// Only consider rounds the project actually participated in (award track filtering)
|
||||
let hasEvaluationRounds = false
|
||||
if (project.programId) {
|
||||
const projectRoundIds = new Set(
|
||||
(await ctx.prisma.projectRoundState.findMany({
|
||||
where: { projectId: project.id },
|
||||
select: { roundId: true },
|
||||
})).map((prs) => prs.roundId)
|
||||
)
|
||||
|
||||
const closedEvalRounds = await ctx.prisma.round.findMany({
|
||||
where: {
|
||||
competition: { programId: project.programId },
|
||||
roundType: 'EVALUATION',
|
||||
status: { in: ['ROUND_CLOSED', 'ROUND_ARCHIVED'] },
|
||||
...(projectRoundIds.size > 0 ? { id: { in: [...projectRoundIds] } } : {}),
|
||||
},
|
||||
select: { configJson: true },
|
||||
})
|
||||
@@ -1666,12 +1705,20 @@ export const applicantRouter = router({
|
||||
|
||||
if (!project?.programId) return []
|
||||
|
||||
// Get closed/archived EVALUATION rounds for this competition
|
||||
// Get closed/archived EVALUATION rounds — only ones this project participated in
|
||||
const projectRoundIds = new Set(
|
||||
(await ctx.prisma.projectRoundState.findMany({
|
||||
where: { projectId: project.id },
|
||||
select: { roundId: true },
|
||||
})).map((prs) => prs.roundId)
|
||||
)
|
||||
|
||||
const evalRounds = await ctx.prisma.round.findMany({
|
||||
where: {
|
||||
competition: { programId: project.programId },
|
||||
roundType: 'EVALUATION',
|
||||
status: { in: ['ROUND_CLOSED', 'ROUND_ARCHIVED'] },
|
||||
...(projectRoundIds.size > 0 ? { id: { in: [...projectRoundIds] } } : {}),
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
@@ -1758,7 +1805,7 @@ export const applicantRouter = router({
|
||||
{ teamMembers: { some: { userId: ctx.user.id } } },
|
||||
],
|
||||
},
|
||||
select: { programId: true },
|
||||
select: { id: true, programId: true },
|
||||
})
|
||||
|
||||
if (!project?.programId) return []
|
||||
@@ -1774,14 +1821,33 @@ export const applicantRouter = router({
|
||||
id: true,
|
||||
name: true,
|
||||
windowCloseAt: true,
|
||||
specialAwardId: true,
|
||||
specialAward: { select: { name: true } },
|
||||
},
|
||||
orderBy: { windowCloseAt: 'asc' },
|
||||
})
|
||||
|
||||
return rounds.map((r) => ({
|
||||
roundName: r.name,
|
||||
windowCloseAt: r.windowCloseAt!,
|
||||
}))
|
||||
// Filter by award track membership
|
||||
const projectRoundIds = new Set(
|
||||
(await ctx.prisma.projectRoundState.findMany({
|
||||
where: { projectId: project.id },
|
||||
select: { roundId: true },
|
||||
})).map((prs) => prs.roundId)
|
||||
)
|
||||
const isInAwardTrack = rounds.some(
|
||||
(r) => r.specialAwardId && projectRoundIds.has(r.id)
|
||||
)
|
||||
|
||||
return rounds
|
||||
.filter((r) => {
|
||||
if (r.specialAwardId && !projectRoundIds.has(r.id)) return false
|
||||
if (!r.specialAwardId && isInAwardTrack && !projectRoundIds.has(r.id)) return false
|
||||
return true
|
||||
})
|
||||
.map((r) => ({
|
||||
roundName: r.specialAward ? `${r.specialAward.name}: ${r.name}` : r.name,
|
||||
windowCloseAt: r.windowCloseAt!,
|
||||
}))
|
||||
}),
|
||||
|
||||
/**
|
||||
@@ -1805,7 +1871,7 @@ export const applicantRouter = router({
|
||||
if (!project?.programId) return []
|
||||
|
||||
// Find active rounds with file requirements
|
||||
const rounds = await ctx.prisma.round.findMany({
|
||||
const allRounds = await ctx.prisma.round.findMany({
|
||||
where: {
|
||||
competition: { programId: project.programId },
|
||||
status: 'ROUND_ACTIVE',
|
||||
@@ -1814,6 +1880,8 @@ export const applicantRouter = router({
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
specialAwardId: true,
|
||||
specialAward: { select: { name: true } },
|
||||
fileRequirements: {
|
||||
select: { id: true },
|
||||
},
|
||||
@@ -1821,6 +1889,22 @@ export const applicantRouter = router({
|
||||
orderBy: { sortOrder: 'asc' },
|
||||
})
|
||||
|
||||
// Filter by award track membership
|
||||
const projectRoundIds = new Set(
|
||||
(await ctx.prisma.projectRoundState.findMany({
|
||||
where: { projectId: project.id },
|
||||
select: { roundId: true },
|
||||
})).map((prs) => prs.roundId)
|
||||
)
|
||||
const isInAwardTrack = allRounds.some(
|
||||
(r) => r.specialAwardId && projectRoundIds.has(r.id)
|
||||
)
|
||||
const rounds = allRounds.filter((r) => {
|
||||
if (r.specialAwardId && !projectRoundIds.has(r.id)) return false
|
||||
if (!r.specialAwardId && isInAwardTrack && !projectRoundIds.has(r.id)) return false
|
||||
return true
|
||||
})
|
||||
|
||||
const results: Array<{ roundId: string; roundName: string; required: number; uploaded: number }> = []
|
||||
|
||||
for (const round of rounds) {
|
||||
@@ -1836,7 +1920,7 @@ export const applicantRouter = router({
|
||||
|
||||
results.push({
|
||||
roundId: round.id,
|
||||
roundName: round.name,
|
||||
roundName: round.specialAward ? `${round.specialAward.name}: ${round.name}` : round.name,
|
||||
required: requirementIds.length,
|
||||
uploaded,
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user