Fix reports: status breakdown uses round states, filter boolean criteria, replace insight tiles with country chart
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m47s

- getStatusBreakdown now uses ProjectRoundState when a specific round is selected
  (fixes donut showing all "Eligible")
- Filter out boolean/section_header criteria from getCriteriaScores
  (removes "Move to the Next Stage?" from bar chart)
- Replace 6 insight tiles with Top Countries horizontal bar chart
- Add round-level state labels/colors to chart-theme

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-21 00:00:55 +01:00
parent 26e8830df2
commit 4f73ba5a0e
3 changed files with 77 additions and 177 deletions

View File

@@ -249,12 +249,24 @@ export const analyticsRouter = router({
getStatusBreakdown: observerProcedure
.input(editionOrRoundInput)
.query(async ({ ctx, input }) => {
if (input.roundId) {
// Round-level: use ProjectRoundState for accurate per-round breakdown
const states = await ctx.prisma.projectRoundState.groupBy({
by: ['state'],
where: { roundId: input.roundId },
_count: true,
})
return states.map((s) => ({
status: s.state,
count: s._count,
}))
}
// Edition-level: use global project status
const projects = await ctx.prisma.project.groupBy({
by: ['status'],
where: projectWhere(input),
_count: true,
})
return projects.map((p) => ({
status: p.status,
count: p._count,
@@ -327,12 +339,14 @@ export const analyticsRouter = router({
}
// Build label → Set<id> map so program-level queries match all IDs for the same criterion label
// Skip boolean and section_header criteria — they don't have numeric scores
const labelToIds = new Map<string, Set<string>>()
const labelToFirst = new Map<string, { id: string; label: string }>()
evaluationForms.forEach((form) => {
const criteria = form.criteriaJson as Array<{ id: string; label: string }> | null
const criteria = form.criteriaJson as Array<{ id: string; label: string; type?: string }> | null
if (criteria) {
criteria.forEach((c) => {
if (c.type === 'boolean' || c.type === 'section_header') return
if (!labelToIds.has(c.label)) {
labelToIds.set(c.label, new Set())
labelToFirst.set(c.label, c)