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,8 +1301,9 @@ export const applicantRouter = router({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const programId = project.programId
|
const programId = project.programId
|
||||||
const openRounds = programId
|
let openRounds: Array<{ id: string; name: string; slug: string | null; roundType: string; windowCloseAt: Date | null }> = []
|
||||||
? await ctx.prisma.round.findMany({
|
if (programId) {
|
||||||
|
const allActiveRounds = await ctx.prisma.round.findMany({
|
||||||
where: {
|
where: {
|
||||||
competition: { programId },
|
competition: { programId },
|
||||||
status: 'ROUND_ACTIVE',
|
status: 'ROUND_ACTIVE',
|
||||||
@@ -1314,9 +1315,38 @@ export const applicantRouter = router({
|
|||||||
slug: true,
|
slug: true,
|
||||||
roundType: true,
|
roundType: true,
|
||||||
windowCloseAt: 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
|
// Determine user's role in the project
|
||||||
const userMembership = project.teamMembers.find((tm) => tm.userId === ctx.user.id)
|
const userMembership = project.teamMembers.find((tm) => tm.userId === ctx.user.id)
|
||||||
@@ -1391,13 +1421,22 @@ export const applicantRouter = router({
|
|||||||
const hasMentor = !!project.mentorAssignment
|
const hasMentor = !!project.mentorAssignment
|
||||||
|
|
||||||
// Check if there are EVALUATION rounds (CLOSED/ARCHIVED) with applicantVisibility.enabled
|
// 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
|
let hasEvaluationRounds = false
|
||||||
if (project.programId) {
|
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({
|
const closedEvalRounds = await ctx.prisma.round.findMany({
|
||||||
where: {
|
where: {
|
||||||
competition: { programId: project.programId },
|
competition: { programId: project.programId },
|
||||||
roundType: 'EVALUATION',
|
roundType: 'EVALUATION',
|
||||||
status: { in: ['ROUND_CLOSED', 'ROUND_ARCHIVED'] },
|
status: { in: ['ROUND_CLOSED', 'ROUND_ARCHIVED'] },
|
||||||
|
...(projectRoundIds.size > 0 ? { id: { in: [...projectRoundIds] } } : {}),
|
||||||
},
|
},
|
||||||
select: { configJson: true },
|
select: { configJson: true },
|
||||||
})
|
})
|
||||||
@@ -1666,12 +1705,20 @@ export const applicantRouter = router({
|
|||||||
|
|
||||||
if (!project?.programId) return []
|
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({
|
const evalRounds = await ctx.prisma.round.findMany({
|
||||||
where: {
|
where: {
|
||||||
competition: { programId: project.programId },
|
competition: { programId: project.programId },
|
||||||
roundType: 'EVALUATION',
|
roundType: 'EVALUATION',
|
||||||
status: { in: ['ROUND_CLOSED', 'ROUND_ARCHIVED'] },
|
status: { in: ['ROUND_CLOSED', 'ROUND_ARCHIVED'] },
|
||||||
|
...(projectRoundIds.size > 0 ? { id: { in: [...projectRoundIds] } } : {}),
|
||||||
},
|
},
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
@@ -1758,7 +1805,7 @@ export const applicantRouter = router({
|
|||||||
{ teamMembers: { some: { userId: ctx.user.id } } },
|
{ teamMembers: { some: { userId: ctx.user.id } } },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
select: { programId: true },
|
select: { id: true, programId: true },
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!project?.programId) return []
|
if (!project?.programId) return []
|
||||||
@@ -1774,12 +1821,31 @@ export const applicantRouter = router({
|
|||||||
id: true,
|
id: true,
|
||||||
name: true,
|
name: true,
|
||||||
windowCloseAt: true,
|
windowCloseAt: true,
|
||||||
|
specialAwardId: true,
|
||||||
|
specialAward: { select: { name: true } },
|
||||||
},
|
},
|
||||||
orderBy: { windowCloseAt: 'asc' },
|
orderBy: { windowCloseAt: 'asc' },
|
||||||
})
|
})
|
||||||
|
|
||||||
return rounds.map((r) => ({
|
// Filter by award track membership
|
||||||
roundName: r.name,
|
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!,
|
windowCloseAt: r.windowCloseAt!,
|
||||||
}))
|
}))
|
||||||
}),
|
}),
|
||||||
@@ -1805,7 +1871,7 @@ export const applicantRouter = router({
|
|||||||
if (!project?.programId) return []
|
if (!project?.programId) return []
|
||||||
|
|
||||||
// Find active rounds with file requirements
|
// Find active rounds with file requirements
|
||||||
const rounds = await ctx.prisma.round.findMany({
|
const allRounds = await ctx.prisma.round.findMany({
|
||||||
where: {
|
where: {
|
||||||
competition: { programId: project.programId },
|
competition: { programId: project.programId },
|
||||||
status: 'ROUND_ACTIVE',
|
status: 'ROUND_ACTIVE',
|
||||||
@@ -1814,6 +1880,8 @@ export const applicantRouter = router({
|
|||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
name: true,
|
name: true,
|
||||||
|
specialAwardId: true,
|
||||||
|
specialAward: { select: { name: true } },
|
||||||
fileRequirements: {
|
fileRequirements: {
|
||||||
select: { id: true },
|
select: { id: true },
|
||||||
},
|
},
|
||||||
@@ -1821,6 +1889,22 @@ export const applicantRouter = router({
|
|||||||
orderBy: { sortOrder: 'asc' },
|
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 }> = []
|
const results: Array<{ roundId: string; roundName: string; required: number; uploaded: number }> = []
|
||||||
|
|
||||||
for (const round of rounds) {
|
for (const round of rounds) {
|
||||||
@@ -1836,7 +1920,7 @@ export const applicantRouter = router({
|
|||||||
|
|
||||||
results.push({
|
results.push({
|
||||||
roundId: round.id,
|
roundId: round.id,
|
||||||
roundName: round.name,
|
roundName: round.specialAward ? `${round.specialAward.name}: ${round.name}` : round.name,
|
||||||
required: requirementIds.length,
|
required: requirementIds.length,
|
||||||
uploaded,
|
uploaded,
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user