Add ability to define completely different evaluation criteria for each competition category. Admins toggle "Separate Criteria per Category" in round config, then configure criteria independently via tabbed editor. - Schema: add nullable `category` to EvaluationForm with updated constraints - Config: add `perCategoryCriteria` boolean to EvaluationConfigSchema - Helper: new `findActiveForm()` with category-aware resolution + fallback - Backend: getForm, upsertForm, getStageForm, startStage all category-aware - AI services: use project category for form lookup in summaries + ranking - Export/ranking: merge criteria from all active forms for cross-category reports - Admin UI: toggle switch + tabbed criteria editor with per-category builders - Jury UI: auto-selects correct form based on project category (invisible to juror) - Fully backwards compatible: toggle defaults OFF, existing forms unchanged Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
27 lines
924 B
TypeScript
27 lines
924 B
TypeScript
import type { PrismaClient, CompetitionCategory, EvaluationForm } from '@prisma/client'
|
|
|
|
/**
|
|
* Find the active EvaluationForm for a round, with category-aware resolution.
|
|
*
|
|
* Resolution order:
|
|
* 1. If `category` is provided, try the category-specific active form first.
|
|
* 2. Fall back to the shared form (category = null).
|
|
* 3. If no `category` provided, return the shared form directly.
|
|
*/
|
|
export async function findActiveForm(
|
|
prisma: PrismaClient | Pick<PrismaClient, 'evaluationForm'>,
|
|
roundId: string,
|
|
category?: CompetitionCategory | null,
|
|
): Promise<EvaluationForm | null> {
|
|
if (category) {
|
|
const specific = await prisma.evaluationForm.findFirst({
|
|
where: { roundId, isActive: true, category },
|
|
})
|
|
if (specific) return specific
|
|
}
|
|
// Fallback to shared form (category = null)
|
|
return prisma.evaluationForm.findFirst({
|
|
where: { roundId, isActive: true, category: null },
|
|
})
|
|
}
|