diff --git a/src/app/(admin)/admin/rounds/[roundId]/page.tsx b/src/app/(admin)/admin/rounds/[roundId]/page.tsx index 43327ec..23590cd 100644 --- a/src/app/(admin)/admin/rounds/[roundId]/page.tsx +++ b/src/app/(admin)/admin/rounds/[roundId]/page.tsx @@ -233,6 +233,12 @@ export default function RoundDetailPage() { ) const roundAwards = awards?.filter((a) => a.evaluationRoundId === roundId) ?? [] + // Filtering results stats (only for FILTERING rounds) + const { data: filteringStats } = trpc.filtering.getResultStats.useQuery( + { roundId }, + { enabled: round?.roundType === 'FILTERING', refetchInterval: 5_000 }, + ) + // Sync config from server when no pending save if (round && !pendingSaveRef.current) { const roundConfig = (round.configJson as Record) ?? {} @@ -245,8 +251,12 @@ export default function RoundDetailPage() { const updateMutation = trpc.round.update.useMutation({ onSuccess: () => { utils.round.getById.invalidate({ id: roundId }) - pendingSaveRef.current = false setAutosaveStatus('saved') + // Keep pendingSaveRef locked briefly so the sync block doesn't + // overwrite local config with stale cache before refetch completes + setTimeout(() => { + pendingSaveRef.current = false + }, 500) setTimeout(() => setAutosaveStatus('idle'), 2000) }, onError: (err) => { @@ -866,8 +876,81 @@ export default function RoundDetailPage() { + {/* Filtering Results Summary — only for FILTERING rounds with results */} + {isFiltering && filteringStats && filteringStats.total > 0 && ( + + + +
+
+
+ +
+
+ Filtering Results + + {filteringStats.total} projects evaluated + +
+
+ +
+
+ +
+
+

{filteringStats.passed}

+

Passed

+
+
+

{filteringStats.filteredOut}

+

Filtered Out

+
+
+

{filteringStats.flagged}

+

Flagged

+
+
+ {/* Progress bar showing pass rate */} +
+
+ Pass rate + {Math.round((filteringStats.passed / filteringStats.total) * 100)}% +
+
+
+
+
+
+ {filteringStats.overridden > 0 && ( +

+ {filteringStats.overridden} result(s) manually overridden +

+ )} +
+ + + + )} + {/* Quick Actions — Grouped & styled */} - + Quick Actions diff --git a/src/components/admin/round/filtering-dashboard.tsx b/src/components/admin/round/filtering-dashboard.tsx index e3b60aa..11c2446 100644 --- a/src/components/admin/round/filtering-dashboard.tsx +++ b/src/components/admin/round/filtering-dashboard.tsx @@ -774,7 +774,7 @@ export function FilteringDashboard({ competitionId, roundId }: FilteringDashboar
- {result.project?.competitionCategory || '\u2014'} + {formatCategory(result.project?.competitionCategory) || '\u2014'}
@@ -1092,6 +1092,18 @@ export function FilteringDashboard({ competitionId, roundId }: FilteringDashboar ) } +// -- Helpers -- + +const categoryLabels: Record = { + BUSINESS_CONCEPT: 'Concept', + STARTUP: 'Startup', +} + +function formatCategory(cat: string | null | undefined): string { + if (!cat) return '' + return categoryLabels[cat] ?? cat.charAt(0) + cat.slice(1).toLowerCase().replace(/_/g, ' ') +} + // -- Sub-components -- function OutcomeBadge({ outcome, overridden }: { outcome: string; overridden: boolean }) { diff --git a/src/server/routers/filtering.ts b/src/server/routers/filtering.ts index 6b3cc7a..841f1a4 100644 --- a/src/server/routers/filtering.ts +++ b/src/server/routers/filtering.ts @@ -493,6 +493,11 @@ export const filteringRouter = router({ }) } + // Clear previous filtering results so new ones stream in fresh + await ctx.prisma.filteringResult.deleteMany({ + where: { roundId: input.roundId }, + }) + const job = await ctx.prisma.filteringJob.create({ data: { roundId: input.roundId,