Overhaul applicant portal: timeline, evaluations, nav, resources
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m6s

- Fix programId/competitionId bug in competition timeline
- Add applicantVisibility config to EvaluationConfigSchema (JSONB)
- Add admin UI card for controlling applicant feedback visibility
- Add 6 new tRPC procedures: getNavFlags, getMyCompetitionTimeline,
  getMyEvaluations, getUpcomingDeadlines, getDocumentCompleteness,
  and extend getMyDashboard with hasPassedIntake
- Rewrite competition timeline to show only EVALUATION + Grand Finale,
  synthesize FILTERING rejections, handle manually-created projects
- Dynamic ApplicantNav with conditional Evaluations/Mentoring/Resources
- Dashboard: conditional timeline, jury feedback card, deadlines,
  document completeness, conditional mentor tile
- New /applicant/evaluations page with anonymous jury feedback
- New /applicant/resources pages (clone of jury learning hub)
- Rename /applicant/competitions → /applicant/competition
- Remove broken /applicant/competitions/[windowId] page
- Add permission info banner to team invite dialog

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-21 19:51:17 +01:00
parent ee2f10e080
commit 5a609457c2
13 changed files with 1291 additions and 314 deletions

View File

@@ -25,6 +25,14 @@ export function EvaluationConfig({ config, onChange }: EvaluationConfigProps) {
update('advancementConfig', { ...advancementConfig, [key]: value })
}
const visConfig = (config.applicantVisibility as {
enabled?: boolean; showGlobalScore?: boolean; showCriterionScores?: boolean; showFeedbackText?: boolean
}) ?? {}
const updateVisibility = (key: string, value: unknown) => {
update('applicantVisibility', { ...visConfig, [key]: value })
}
return (
<div className="space-y-6">
{/* Scoring */}
@@ -202,6 +210,71 @@ export function EvaluationConfig({ config, onChange }: EvaluationConfigProps) {
</CardContent>
</Card>
{/* Applicant Feedback Visibility */}
<Card>
<CardHeader>
<CardTitle className="text-base">Applicant Feedback Visibility</CardTitle>
<CardDescription>Control what evaluation data applicants can see after this round closes</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="flex items-center justify-between">
<div>
<Label htmlFor="applicantVisEnabled">Show Evaluations to Applicants</Label>
<p className="text-xs text-muted-foreground">Master switch when off, nothing is visible to applicants</p>
</div>
<Switch
id="applicantVisEnabled"
checked={visConfig.enabled ?? false}
onCheckedChange={(v) => updateVisibility('enabled', v)}
/>
</div>
{visConfig.enabled && (
<div className="pl-6 border-l-2 border-muted space-y-4">
<div className="flex items-center justify-between">
<div>
<Label htmlFor="showGlobalScore">Show Global Score</Label>
<p className="text-xs text-muted-foreground">Display the overall score for each evaluation</p>
</div>
<Switch
id="showGlobalScore"
checked={visConfig.showGlobalScore ?? false}
onCheckedChange={(v) => updateVisibility('showGlobalScore', v)}
/>
</div>
<div className="flex items-center justify-between">
<div>
<Label htmlFor="showCriterionScores">Show Per-Criterion Scores</Label>
<p className="text-xs text-muted-foreground">Display individual criterion scores and names</p>
</div>
<Switch
id="showCriterionScores"
checked={visConfig.showCriterionScores ?? false}
onCheckedChange={(v) => updateVisibility('showCriterionScores', v)}
/>
</div>
<div className="flex items-center justify-between">
<div>
<Label htmlFor="showFeedbackText">Show Written Feedback</Label>
<p className="text-xs text-muted-foreground">Display jury members&apos; written comments</p>
</div>
<Switch
id="showFeedbackText"
checked={visConfig.showFeedbackText ?? false}
onCheckedChange={(v) => updateVisibility('showFeedbackText', v)}
/>
</div>
<p className="text-xs text-muted-foreground bg-muted/50 p-2 rounded">
Evaluations are only visible to applicants after this round closes.
</p>
</div>
)}
</CardContent>
</Card>
{/* Advancement */}
<Card>
<CardHeader>