fix: project status counts now show latest round state per project
Previously counted distinct projects per state across ALL rounds, inflating counts (e.g., 215 Passed when many were later rejected). Now picks each project's latest round state (highest sortOrder) to determine its current status. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -165,28 +165,40 @@ export const projectRouter = router({
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
ctx.prisma.project.count({ where }),
|
ctx.prisma.project.count({ where }),
|
||||||
// Count distinct projects per state (avoids double-counting projects that passed multiple rounds)
|
// Count projects by their LATEST round state (highest sortOrder round).
|
||||||
|
// This avoids inflated counts where a project that passed round 1
|
||||||
|
// but was rejected in round 2 shows up in both PASSED and REJECTED.
|
||||||
(async () => {
|
(async () => {
|
||||||
const stateFilter = where.programId ? { project: { programId: where.programId as string } } : {}
|
const stateFilter: Record<string, unknown> = {}
|
||||||
const states = ['PENDING', 'IN_PROGRESS', 'PASSED', 'REJECTED', 'COMPLETED', 'WITHDRAWN'] as const
|
if (where.programId) stateFilter.project = { programId: where.programId as string }
|
||||||
const counts = await Promise.all(
|
|
||||||
states.map(async (state) => ({
|
const allStates = await ctx.prisma.projectRoundState.findMany({
|
||||||
state,
|
where: stateFilter,
|
||||||
count: await ctx.prisma.projectRoundState.findMany({
|
select: { projectId: true, state: true, round: { select: { sortOrder: true } } },
|
||||||
where: { ...stateFilter, state },
|
orderBy: { round: { sortOrder: 'desc' } },
|
||||||
select: { projectId: true },
|
})
|
||||||
distinct: ['projectId'],
|
|
||||||
}).then((rows) => rows.length),
|
// Pick the latest round state per project
|
||||||
}))
|
const latestByProject = new Map<string, string>()
|
||||||
)
|
for (const s of allStates) {
|
||||||
return counts
|
if (!latestByProject.has(s.projectId)) {
|
||||||
|
latestByProject.set(s.projectId, s.state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aggregate counts
|
||||||
|
const countMap = new Map<string, number>()
|
||||||
|
for (const state of latestByProject.values()) {
|
||||||
|
countMap.set(state, (countMap.get(state) ?? 0) + 1)
|
||||||
|
}
|
||||||
|
return countMap
|
||||||
})(),
|
})(),
|
||||||
])
|
])
|
||||||
|
|
||||||
// Build round-state counts (distinct projects per state)
|
// Build round-state counts from the latest-state map
|
||||||
const statusCounts: Record<string, number> = {}
|
const statusCounts: Record<string, number> = {}
|
||||||
for (const g of roundStateCounts) {
|
for (const [state, count] of roundStateCounts) {
|
||||||
statusCounts[g.state] = g.count
|
statusCounts[state] = count
|
||||||
}
|
}
|
||||||
|
|
||||||
const projectsWithLogos = await attachProjectLogoUrls(projects)
|
const projectsWithLogos = await attachProjectLogoUrls(projects)
|
||||||
|
|||||||
Reference in New Issue
Block a user