'use client'
import { Badge } from '@/components/ui/badge'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { CheckCircle2, AlertCircle, AlertTriangle, Layers, GitBranch, ArrowRight, ShieldCheck } from 'lucide-react'
import { InfoTooltip } from '@/components/ui/info-tooltip'
import { cn } from '@/lib/utils'
import { validateAll } from '@/lib/pipeline-validation'
import { normalizeStageConfig } from '@/lib/stage-config-schema'
import type { WizardState, ValidationResult, WizardStageConfig } from '@/types/pipeline-wizard'
type ReviewSectionProps = {
state: WizardState
}
function ValidationStatusIcon({ result }: { result: ValidationResult }) {
if (result.valid && result.warnings.length === 0) {
return
}
if (result.valid && result.warnings.length > 0) {
return
}
return
}
function ValidationSection({
label,
result,
}: {
label: string
result: ValidationResult
}) {
return (
{label}
{result.errors.map((err, i) => (
{err}
))}
{result.warnings.map((warn, i) => (
{warn}
))}
{result.valid && result.errors.length === 0 && result.warnings.length === 0 && (
Looks good
)}
)
}
function stagePolicySummary(stage: WizardStageConfig): string {
const config = normalizeStageConfig(
stage.stageType,
stage.configJson as Record
)
switch (stage.stageType) {
case 'INTAKE':
return `${String(config.lateSubmissionPolicy)} late policy, ${Array.isArray(config.fileRequirements) ? config.fileRequirements.length : 0} file reqs`
case 'FILTER':
return `${Array.isArray(config.rules) ? config.rules.length : 0} rules, AI ${config.aiRubricEnabled ? 'on' : 'off'}`
case 'EVALUATION':
return `${String(config.requiredReviews)} reviews, load ${String(config.minLoadPerJuror)}-${String(config.maxLoadPerJuror)}`
case 'SELECTION':
return `ranking ${String(config.rankingMethod)}, tie ${String(config.tieBreaker)}`
case 'LIVE_FINAL':
return `jury ${config.juryVotingEnabled ? 'on' : 'off'}, audience ${config.audienceVotingEnabled ? 'on' : 'off'}`
case 'RESULTS':
return `publication ${String(config.publicationMode)}, rankings ${config.showRankings ? 'shown' : 'hidden'}`
default:
return 'Configured'
}
}
export function ReviewSection({ state }: ReviewSectionProps) {
const validation = validateAll(state)
const totalTracks = state.tracks.length
const totalStages = state.tracks.reduce((sum, t) => sum + t.stages.length, 0)
const totalTransitions = state.tracks.reduce(
(sum, t) => sum + Math.max(0, t.stages.length - 1),
0
)
const enabledNotifications = Object.values(state.notificationConfig).filter(Boolean).length
const blockers = [
...validation.sections.basics.errors,
...validation.sections.tracks.errors,
...validation.sections.notifications.errors,
]
const warnings = [
...validation.sections.basics.warnings,
...validation.sections.tracks.warnings,
...validation.sections.notifications.warnings,
]
const hasMainTrack = state.tracks.some((track) => track.kind === 'MAIN')
const hasStages = totalStages > 0
const hasNotificationDefaults = enabledNotifications > 0
const publishReady = validation.valid && hasMainTrack && hasStages
return (
{publishReady ? (
) : (
)}
{publishReady
? 'Pipeline is ready for publish'
: 'Pipeline has publish blockers'}
Draft save can proceed with warnings. Publish should only proceed with zero blockers.
Readiness Checks
{blockers.length}
Blockers
{warnings.length}
Warnings
{blockers.length > 0 && (
Publish Blockers
{blockers.map((blocker, i) => (
{blocker}
))}
)}
{warnings.length > 0 && (
Warnings
{warnings.map((warn, i) => (
{warn}
))}
)}
Validation Detail
Structure and Policy Matrix
{totalTransitions}
Transitions
{enabledNotifications}
Notifications
{state.tracks.map((track, i) => (
{track.kind}
{track.name || '(unnamed track)'}
{track.stages.length} stages
{track.stages.map((stage, stageIndex) => (
{stageIndex + 1}. {stage.name || '(unnamed stage)'} ({stage.stageType})
{stagePolicySummary(stage)}
))}
))}
Publish Guardrails
Main track present
{hasMainTrack ? 'Pass' : 'Fail'}
At least one stage configured
{hasStages ? 'Pass' : 'Fail'}
Validation blockers cleared
{blockers.length === 0 ? 'Pass' : 'Fail'}
Notification policy configured
{hasNotificationDefaults ? 'Configured' : 'Optional'}
)
}