Admin system overhaul: full round config UI, flattened navigation, juries, awards integration, evaluation rewrite
- Phase 1: 7 round config sub-components covering all ~65 Zod schema fields across INTAKE, FILTERING, EVALUATION, SUBMISSION, MENTORING, LIVE_FINAL, DELIBERATION
- Phase 2: Replace Competitions nav with Rounds + add Juries; new /admin/rounds and /admin/rounds/[roundId] pages with tabbed detail (Config, Projects, Windows, Documents, Awards)
- Phase 3: Top-level /admin/juries with list + detail pages (members table, settings panel, self-service review)
- Phase 4: File requirements editor in round config; project detail per-requirement upload slots replacing generic drop zone
- Phase 5: Awards edit page with source round dropdown, eligibility mode, auto-tag rules builder; round detail Awards tab; specialAward router enhanced with evaluationRoundId/eligibilityMode fields
- Phase 6: Evaluation page rewrite supporting all 3 scoring modes (criteria/global/binary) with config-driven behavior; live voting UI polish
- Phase 7: UI design polish across admin pages — consistent headers, cards, hover transitions, empty states, brand colors
- Bulk upload page for admin project imports
- File router enhanced with admin upload and submission window procedures
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 01:16:55 +01:00
|
|
|
'use client'
|
|
|
|
|
|
|
|
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
|
|
|
|
import { Input } from '@/components/ui/input'
|
|
|
|
|
import { Label } from '@/components/ui/label'
|
|
|
|
|
import { Switch } from '@/components/ui/switch'
|
|
|
|
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
|
|
|
|
|
|
|
|
|
|
type EvaluationConfigProps = {
|
|
|
|
|
config: Record<string, unknown>
|
|
|
|
|
onChange: (config: Record<string, unknown>) => void
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function EvaluationConfig({ config, onChange }: EvaluationConfigProps) {
|
|
|
|
|
const update = (key: string, value: unknown) => {
|
|
|
|
|
onChange({ ...config, [key]: value })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const advancementMode = (config.advancementMode as string) ?? 'admin_selection'
|
|
|
|
|
const advancementConfig = (config.advancementConfig as {
|
|
|
|
|
perCategory?: boolean; startupCount?: number; conceptCount?: number; tieBreaker?: string
|
|
|
|
|
}) ?? {}
|
|
|
|
|
|
|
|
|
|
const updateAdvancement = (key: string, value: unknown) => {
|
|
|
|
|
update('advancementConfig', { ...advancementConfig, [key]: value })
|
|
|
|
|
}
|
|
|
|
|
|
Overhaul applicant portal: timeline, evaluations, nav, resources
- 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>
2026-02-21 19:51:17 +01:00
|
|
|
const visConfig = (config.applicantVisibility as {
|
|
|
|
|
enabled?: boolean; showGlobalScore?: boolean; showCriterionScores?: boolean; showFeedbackText?: boolean
|
|
|
|
|
}) ?? {}
|
|
|
|
|
|
|
|
|
|
const updateVisibility = (key: string, value: unknown) => {
|
|
|
|
|
update('applicantVisibility', { ...visConfig, [key]: value })
|
|
|
|
|
}
|
|
|
|
|
|
Admin system overhaul: full round config UI, flattened navigation, juries, awards integration, evaluation rewrite
- Phase 1: 7 round config sub-components covering all ~65 Zod schema fields across INTAKE, FILTERING, EVALUATION, SUBMISSION, MENTORING, LIVE_FINAL, DELIBERATION
- Phase 2: Replace Competitions nav with Rounds + add Juries; new /admin/rounds and /admin/rounds/[roundId] pages with tabbed detail (Config, Projects, Windows, Documents, Awards)
- Phase 3: Top-level /admin/juries with list + detail pages (members table, settings panel, self-service review)
- Phase 4: File requirements editor in round config; project detail per-requirement upload slots replacing generic drop zone
- Phase 5: Awards edit page with source round dropdown, eligibility mode, auto-tag rules builder; round detail Awards tab; specialAward router enhanced with evaluationRoundId/eligibilityMode fields
- Phase 6: Evaluation page rewrite supporting all 3 scoring modes (criteria/global/binary) with config-driven behavior; live voting UI polish
- Phase 7: UI design polish across admin pages — consistent headers, cards, hover transitions, empty states, brand colors
- Bulk upload page for admin project imports
- File router enhanced with admin upload and submission window procedures
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 01:16:55 +01:00
|
|
|
return (
|
|
|
|
|
<div className="space-y-6">
|
|
|
|
|
{/* Scoring */}
|
|
|
|
|
<Card>
|
|
|
|
|
<CardHeader>
|
|
|
|
|
<CardTitle className="text-base">Scoring & Reviews</CardTitle>
|
|
|
|
|
<CardDescription>How jury members evaluate and score projects</CardDescription>
|
|
|
|
|
</CardHeader>
|
|
|
|
|
<CardContent className="space-y-4">
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
<Label htmlFor="requiredReviews">Required Reviews per Project</Label>
|
|
|
|
|
<p className="text-xs text-muted-foreground">Minimum number of jury evaluations needed</p>
|
|
|
|
|
<Input
|
|
|
|
|
id="requiredReviews"
|
|
|
|
|
type="number"
|
|
|
|
|
min={1}
|
|
|
|
|
className="w-32"
|
|
|
|
|
value={(config.requiredReviewsPerProject as number) ?? 3}
|
|
|
|
|
onChange={(e) => update('requiredReviewsPerProject', parseInt(e.target.value, 10) || 3)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
<Label htmlFor="scoringMode">Scoring Mode</Label>
|
|
|
|
|
<p className="text-xs text-muted-foreground">How jurors assign scores to projects</p>
|
|
|
|
|
<Select
|
|
|
|
|
value={(config.scoringMode as string) ?? 'criteria'}
|
|
|
|
|
onValueChange={(v) => update('scoringMode', v)}
|
|
|
|
|
>
|
|
|
|
|
<SelectTrigger id="scoringMode" className="w-64">
|
|
|
|
|
<SelectValue />
|
|
|
|
|
</SelectTrigger>
|
|
|
|
|
<SelectContent>
|
|
|
|
|
<SelectItem value="criteria">Criteria-based (multiple criteria with weights)</SelectItem>
|
|
|
|
|
<SelectItem value="global">Global score (single overall score)</SelectItem>
|
|
|
|
|
<SelectItem value="binary">Binary (pass/fail)</SelectItem>
|
|
|
|
|
</SelectContent>
|
|
|
|
|
</Select>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
<Label htmlFor="anonymizationLevel">Anonymization Level</Label>
|
|
|
|
|
<p className="text-xs text-muted-foreground">How much of other jurors' identities are revealed</p>
|
|
|
|
|
<Select
|
|
|
|
|
value={(config.anonymizationLevel as string) ?? 'fully_anonymous'}
|
|
|
|
|
onValueChange={(v) => update('anonymizationLevel', v)}
|
|
|
|
|
>
|
|
|
|
|
<SelectTrigger id="anonymizationLevel" className="w-64">
|
|
|
|
|
<SelectValue />
|
|
|
|
|
</SelectTrigger>
|
|
|
|
|
<SelectContent>
|
|
|
|
|
<SelectItem value="fully_anonymous">Fully Anonymous</SelectItem>
|
|
|
|
|
<SelectItem value="show_initials">Show Initials</SelectItem>
|
|
|
|
|
<SelectItem value="named">Named (full names visible)</SelectItem>
|
|
|
|
|
</SelectContent>
|
|
|
|
|
</Select>
|
|
|
|
|
</div>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
|
|
|
|
|
{/* Feedback */}
|
|
|
|
|
<Card>
|
|
|
|
|
<CardHeader>
|
|
|
|
|
<CardTitle className="text-base">Feedback Requirements</CardTitle>
|
|
|
|
|
<CardDescription>What jurors must provide alongside scores</CardDescription>
|
|
|
|
|
</CardHeader>
|
|
|
|
|
<CardContent className="space-y-4">
|
|
|
|
|
<div className="flex items-center justify-between">
|
|
|
|
|
<div>
|
|
|
|
|
<Label htmlFor="requireFeedback">Require Written Feedback</Label>
|
|
|
|
|
<p className="text-xs text-muted-foreground">Jurors must write feedback text</p>
|
|
|
|
|
</div>
|
|
|
|
|
<Switch
|
|
|
|
|
id="requireFeedback"
|
|
|
|
|
checked={(config.requireFeedback as boolean) ?? true}
|
|
|
|
|
onCheckedChange={(v) => update('requireFeedback', v)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{(config.requireFeedback as boolean) !== false && (
|
|
|
|
|
<div className="pl-6 border-l-2 border-muted space-y-2">
|
|
|
|
|
<Label htmlFor="feedbackMinLength">Minimum Feedback Length</Label>
|
|
|
|
|
<p className="text-xs text-muted-foreground">Minimum characters (0 = no minimum)</p>
|
|
|
|
|
<Input
|
|
|
|
|
id="feedbackMinLength"
|
|
|
|
|
type="number"
|
|
|
|
|
min={0}
|
|
|
|
|
className="w-32"
|
|
|
|
|
value={(config.feedbackMinLength as number) ?? 0}
|
|
|
|
|
onChange={(e) => update('feedbackMinLength', parseInt(e.target.value, 10) || 0)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
<div className="flex items-center justify-between">
|
|
|
|
|
<div>
|
|
|
|
|
<Label htmlFor="requireAllCriteriaScored">Require All Criteria Scored</Label>
|
|
|
|
|
<p className="text-xs text-muted-foreground">Jurors must score every criterion before submitting</p>
|
|
|
|
|
</div>
|
|
|
|
|
<Switch
|
|
|
|
|
id="requireAllCriteriaScored"
|
|
|
|
|
checked={(config.requireAllCriteriaScored as boolean) ?? true}
|
|
|
|
|
onCheckedChange={(v) => update('requireAllCriteriaScored', v)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="flex items-center justify-between">
|
|
|
|
|
<div>
|
|
|
|
|
<Label htmlFor="coiRequired">COI Declaration Required</Label>
|
|
|
|
|
<p className="text-xs text-muted-foreground">Jurors must declare conflicts of interest</p>
|
|
|
|
|
</div>
|
|
|
|
|
<Switch
|
|
|
|
|
id="coiRequired"
|
|
|
|
|
checked={(config.coiRequired as boolean) ?? true}
|
|
|
|
|
onCheckedChange={(v) => update('coiRequired', v)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-02-17 14:13:25 +01:00
|
|
|
<div className="flex items-center justify-between">
|
|
|
|
|
<div>
|
|
|
|
|
<Label htmlFor="requireDocumentUpload">Require Document Upload</Label>
|
|
|
|
|
<p className="text-xs text-muted-foreground">Applicants must upload documents for this evaluation round (disable if documents were uploaded in a previous round)</p>
|
|
|
|
|
</div>
|
|
|
|
|
<Switch
|
|
|
|
|
id="requireDocumentUpload"
|
|
|
|
|
checked={(config.requireDocumentUpload as boolean) ?? false}
|
|
|
|
|
onCheckedChange={(v) => update('requireDocumentUpload', v)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
Admin system overhaul: full round config UI, flattened navigation, juries, awards integration, evaluation rewrite
- Phase 1: 7 round config sub-components covering all ~65 Zod schema fields across INTAKE, FILTERING, EVALUATION, SUBMISSION, MENTORING, LIVE_FINAL, DELIBERATION
- Phase 2: Replace Competitions nav with Rounds + add Juries; new /admin/rounds and /admin/rounds/[roundId] pages with tabbed detail (Config, Projects, Windows, Documents, Awards)
- Phase 3: Top-level /admin/juries with list + detail pages (members table, settings panel, self-service review)
- Phase 4: File requirements editor in round config; project detail per-requirement upload slots replacing generic drop zone
- Phase 5: Awards edit page with source round dropdown, eligibility mode, auto-tag rules builder; round detail Awards tab; specialAward router enhanced with evaluationRoundId/eligibilityMode fields
- Phase 6: Evaluation page rewrite supporting all 3 scoring modes (criteria/global/binary) with config-driven behavior; live voting UI polish
- Phase 7: UI design polish across admin pages — consistent headers, cards, hover transitions, empty states, brand colors
- Bulk upload page for admin project imports
- File router enhanced with admin upload and submission window procedures
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 01:16:55 +01:00
|
|
|
<div className="flex items-center justify-between">
|
|
|
|
|
<div>
|
|
|
|
|
<Label htmlFor="peerReviewEnabled">Peer Review</Label>
|
|
|
|
|
<p className="text-xs text-muted-foreground">Allow jurors to see and comment on other evaluations</p>
|
|
|
|
|
</div>
|
|
|
|
|
<Switch
|
|
|
|
|
id="peerReviewEnabled"
|
|
|
|
|
checked={(config.peerReviewEnabled as boolean) ?? false}
|
|
|
|
|
onCheckedChange={(v) => update('peerReviewEnabled', v)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
|
|
|
|
|
{/* AI Features */}
|
|
|
|
|
<Card>
|
|
|
|
|
<CardHeader>
|
|
|
|
|
<CardTitle className="text-base">AI Features</CardTitle>
|
|
|
|
|
<CardDescription>AI-powered evaluation assistance</CardDescription>
|
|
|
|
|
</CardHeader>
|
|
|
|
|
<CardContent className="space-y-4">
|
|
|
|
|
<div className="flex items-center justify-between">
|
|
|
|
|
<div>
|
|
|
|
|
<Label htmlFor="aiSummaryEnabled">AI Evaluation Summary</Label>
|
|
|
|
|
<p className="text-xs text-muted-foreground">Generate AI synthesis of all jury evaluations</p>
|
|
|
|
|
</div>
|
|
|
|
|
<Switch
|
|
|
|
|
id="aiSummaryEnabled"
|
|
|
|
|
checked={(config.aiSummaryEnabled as boolean) ?? false}
|
|
|
|
|
onCheckedChange={(v) => update('aiSummaryEnabled', v)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="flex items-center justify-between">
|
|
|
|
|
<div>
|
|
|
|
|
<Label htmlFor="generateAiShortlist">AI Shortlist Recommendations</Label>
|
|
|
|
|
<p className="text-xs text-muted-foreground">AI suggests which projects should advance</p>
|
|
|
|
|
</div>
|
|
|
|
|
<Switch
|
|
|
|
|
id="generateAiShortlist"
|
|
|
|
|
checked={(config.generateAiShortlist as boolean) ?? false}
|
|
|
|
|
onCheckedChange={(v) => update('generateAiShortlist', v)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
|
Overhaul applicant portal: timeline, evaluations, nav, resources
- 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>
2026-02-21 19:51:17 +01:00
|
|
|
{/* 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' 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>
|
|
|
|
|
|
Admin system overhaul: full round config UI, flattened navigation, juries, awards integration, evaluation rewrite
- Phase 1: 7 round config sub-components covering all ~65 Zod schema fields across INTAKE, FILTERING, EVALUATION, SUBMISSION, MENTORING, LIVE_FINAL, DELIBERATION
- Phase 2: Replace Competitions nav with Rounds + add Juries; new /admin/rounds and /admin/rounds/[roundId] pages with tabbed detail (Config, Projects, Windows, Documents, Awards)
- Phase 3: Top-level /admin/juries with list + detail pages (members table, settings panel, self-service review)
- Phase 4: File requirements editor in round config; project detail per-requirement upload slots replacing generic drop zone
- Phase 5: Awards edit page with source round dropdown, eligibility mode, auto-tag rules builder; round detail Awards tab; specialAward router enhanced with evaluationRoundId/eligibilityMode fields
- Phase 6: Evaluation page rewrite supporting all 3 scoring modes (criteria/global/binary) with config-driven behavior; live voting UI polish
- Phase 7: UI design polish across admin pages — consistent headers, cards, hover transitions, empty states, brand colors
- Bulk upload page for admin project imports
- File router enhanced with admin upload and submission window procedures
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 01:16:55 +01:00
|
|
|
{/* Advancement */}
|
|
|
|
|
<Card>
|
|
|
|
|
<CardHeader>
|
|
|
|
|
<CardTitle className="text-base">Advancement Rules</CardTitle>
|
|
|
|
|
<CardDescription>How projects move to the next round</CardDescription>
|
|
|
|
|
</CardHeader>
|
|
|
|
|
<CardContent className="space-y-4">
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
<Label htmlFor="advancementMode">Advancement Mode</Label>
|
|
|
|
|
<Select
|
|
|
|
|
value={advancementMode}
|
|
|
|
|
onValueChange={(v) => update('advancementMode', v)}
|
|
|
|
|
>
|
|
|
|
|
<SelectTrigger id="advancementMode" className="w-64">
|
|
|
|
|
<SelectValue />
|
|
|
|
|
</SelectTrigger>
|
|
|
|
|
<SelectContent>
|
|
|
|
|
<SelectItem value="admin_selection">Admin Selection (manual)</SelectItem>
|
|
|
|
|
<SelectItem value="auto_top_n">Auto Top-N (by score)</SelectItem>
|
|
|
|
|
<SelectItem value="ai_recommended">AI Recommended</SelectItem>
|
|
|
|
|
</SelectContent>
|
|
|
|
|
</Select>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{advancementMode === 'auto_top_n' && (
|
|
|
|
|
<div className="pl-6 border-l-2 border-muted space-y-4">
|
|
|
|
|
<Label className="text-sm font-medium">Auto Top-N Settings</Label>
|
|
|
|
|
|
|
|
|
|
<div className="flex items-center justify-between">
|
|
|
|
|
<div>
|
|
|
|
|
<Label htmlFor="perCategory">Per Category</Label>
|
|
|
|
|
<p className="text-xs text-muted-foreground">Apply limits separately for each category</p>
|
|
|
|
|
</div>
|
|
|
|
|
<Switch
|
|
|
|
|
id="perCategory"
|
|
|
|
|
checked={advancementConfig.perCategory ?? true}
|
|
|
|
|
onCheckedChange={(v) => updateAdvancement('perCategory', v)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="grid gap-4 sm:grid-cols-2">
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
<Label htmlFor="startupCount">Startup Advancement Count</Label>
|
|
|
|
|
<p className="text-xs text-muted-foreground">Number of startups to advance</p>
|
|
|
|
|
<Input
|
|
|
|
|
id="startupCount"
|
|
|
|
|
type="number"
|
|
|
|
|
min={0}
|
|
|
|
|
className="w-32"
|
|
|
|
|
value={advancementConfig.startupCount ?? 10}
|
|
|
|
|
onChange={(e) => updateAdvancement('startupCount', parseInt(e.target.value, 10) || 0)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
<Label htmlFor="conceptCount">Business Concept Advancement Count</Label>
|
|
|
|
|
<p className="text-xs text-muted-foreground">Number of business concepts to advance</p>
|
|
|
|
|
<Input
|
|
|
|
|
id="conceptCount"
|
|
|
|
|
type="number"
|
|
|
|
|
min={0}
|
|
|
|
|
className="w-32"
|
|
|
|
|
value={advancementConfig.conceptCount ?? 10}
|
|
|
|
|
onChange={(e) => updateAdvancement('conceptCount', parseInt(e.target.value, 10) || 0)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
<Label htmlFor="tieBreaker">Tie Breaker</Label>
|
|
|
|
|
<p className="text-xs text-muted-foreground">How to handle tied scores</p>
|
|
|
|
|
<Select
|
|
|
|
|
value={advancementConfig.tieBreaker ?? 'admin_decides'}
|
|
|
|
|
onValueChange={(v) => updateAdvancement('tieBreaker', v)}
|
|
|
|
|
>
|
|
|
|
|
<SelectTrigger id="tieBreaker" className="w-64">
|
|
|
|
|
<SelectValue />
|
|
|
|
|
</SelectTrigger>
|
|
|
|
|
<SelectContent>
|
|
|
|
|
<SelectItem value="admin_decides">Admin Decides</SelectItem>
|
|
|
|
|
<SelectItem value="highest_individual">Highest Individual Score</SelectItem>
|
|
|
|
|
<SelectItem value="revote">Re-vote</SelectItem>
|
|
|
|
|
</SelectContent>
|
|
|
|
|
</Select>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|