Round system redesign: criteria voting, audience voting, pipeline view, and admin UX improvements
- Schema: Extend LiveVotingSession with votingMode, criteriaJson, audience fields; add AudienceVoter model; make LiveVote.userId nullable for audience voters - Backend: Criteria-based voting with weighted scores, audience registration/voting with token-based dedup, configurable jury/audience weight in results - Jury UI: Criteria scoring with per-criterion sliders alongside simple 1-10 mode - Public audience voting page at /vote/[sessionId] with mobile-first design - Admin live voting: Tabbed layout (Session/Config/Results), criteria config, audience settings, weight-adjustable results with tie detection - Round type settings: Visual card selector replacing dropdown, feature tags - Round detail page: Live event status section, type-specific stats and actions - Round pipeline view: Horizontal visualization with bottleneck detection, List/Pipeline toggle on rounds page - SSE: Separate jury/audience vote events, audience vote tracking - Field visibility: Hide irrelevant fields per round type in create/edit forms Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -38,6 +38,13 @@ export interface LiveEventRoundSettings {
|
||||
votingWindowSeconds: number
|
||||
showLiveScores: boolean
|
||||
allowVoteChange: boolean
|
||||
votingMode: 'simple' | 'criteria'
|
||||
|
||||
// Audience voting
|
||||
audienceVotingMode: 'disabled' | 'per_project' | 'per_category' | 'favorites'
|
||||
audienceMaxFavorites: number
|
||||
audienceRequireId: boolean
|
||||
audienceVotingDuration: number | null
|
||||
|
||||
// Display
|
||||
displayMode: 'SCORES' | 'RANKING' | 'NONE'
|
||||
@@ -74,6 +81,11 @@ export const defaultLiveEventSettings: LiveEventRoundSettings = {
|
||||
votingWindowSeconds: 30,
|
||||
showLiveScores: true,
|
||||
allowVoteChange: false,
|
||||
votingMode: 'simple',
|
||||
audienceVotingMode: 'disabled',
|
||||
audienceMaxFavorites: 3,
|
||||
audienceRequireId: false,
|
||||
audienceVotingDuration: null,
|
||||
displayMode: 'RANKING',
|
||||
}
|
||||
|
||||
@@ -90,3 +102,43 @@ export const roundTypeDescriptions: Record<string, string> = {
|
||||
EVALUATION: 'In-depth evaluation with detailed criteria and feedback',
|
||||
LIVE_EVENT: 'Real-time voting during presentations',
|
||||
}
|
||||
|
||||
// Field visibility per round type
|
||||
export const ROUND_FIELD_VISIBILITY: Record<string, {
|
||||
showRequiredReviews: boolean
|
||||
showAssignmentLimits: boolean
|
||||
showVotingWindow: boolean
|
||||
showSubmissionDates: boolean
|
||||
showEvaluationForm: boolean
|
||||
}> = {
|
||||
FILTERING: {
|
||||
showRequiredReviews: false,
|
||||
showAssignmentLimits: false,
|
||||
showVotingWindow: false,
|
||||
showSubmissionDates: true,
|
||||
showEvaluationForm: false,
|
||||
},
|
||||
EVALUATION: {
|
||||
showRequiredReviews: true,
|
||||
showAssignmentLimits: true,
|
||||
showVotingWindow: true,
|
||||
showSubmissionDates: true,
|
||||
showEvaluationForm: true,
|
||||
},
|
||||
LIVE_EVENT: {
|
||||
showRequiredReviews: false,
|
||||
showAssignmentLimits: false,
|
||||
showVotingWindow: false,
|
||||
showSubmissionDates: false,
|
||||
showEvaluationForm: false,
|
||||
},
|
||||
}
|
||||
|
||||
// Live voting criterion type
|
||||
export interface LiveVotingCriterion {
|
||||
id: string
|
||||
label: string
|
||||
description?: string
|
||||
scale: number // max score (e.g. 10)
|
||||
weight: number // 0-1, weights must sum to 1
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user