Competition/Round architecture: full platform rewrite (Phases 1-9)
Replace Pipeline/Stage system with Competition/Round architecture.
New schema: Competition, Round (7 types), JuryGroup, AssignmentPolicy,
ProjectRoundState, DeliberationSession, ResultLock, SubmissionWindow.
New services: round-engine, round-assignment, deliberation, result-lock,
submission-manager, competition-context, ai-prompt-guard.
Full admin/jury/applicant/mentor UI rewrite. AI prompt hardening with
structured prompts, retry logic, and injection detection. All legacy
pipeline/stage code removed. 4 new migrations + seed aligned.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:04:15 +01:00
|
|
|
'use client'
|
|
|
|
|
|
|
|
|
|
import { trpc } from '@/lib/trpc/client'
|
|
|
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
|
|
|
|
import { Skeleton } from '@/components/ui/skeleton'
|
2026-02-18 14:03:38 +01:00
|
|
|
import { FileText } from 'lucide-react'
|
|
|
|
|
import { FileViewer } from '@/components/shared/file-viewer'
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
Replace Pipeline/Stage system with Competition/Round architecture.
New schema: Competition, Round (7 types), JuryGroup, AssignmentPolicy,
ProjectRoundState, DeliberationSession, ResultLock, SubmissionWindow.
New services: round-engine, round-assignment, deliberation, result-lock,
submission-manager, competition-context, ai-prompt-guard.
Full admin/jury/applicant/mentor UI rewrite. AI prompt hardening with
structured prompts, retry logic, and injection detection. All legacy
pipeline/stage code removed. 4 new migrations + seed aligned.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:04:15 +01:00
|
|
|
|
|
|
|
|
interface MultiWindowDocViewerProps {
|
|
|
|
|
roundId: string
|
|
|
|
|
projectId: string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function MultiWindowDocViewer({ roundId, projectId }: MultiWindowDocViewerProps) {
|
2026-02-18 12:43:28 +01:00
|
|
|
const { data: files, isLoading } = trpc.file.listByProject.useQuery(
|
|
|
|
|
{ projectId },
|
|
|
|
|
{ enabled: !!projectId }
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
Replace Pipeline/Stage system with Competition/Round architecture.
New schema: Competition, Round (7 types), JuryGroup, AssignmentPolicy,
ProjectRoundState, DeliberationSession, ResultLock, SubmissionWindow.
New services: round-engine, round-assignment, deliberation, result-lock,
submission-manager, competition-context, ai-prompt-guard.
Full admin/jury/applicant/mentor UI rewrite. AI prompt hardening with
structured prompts, retry logic, and injection detection. All legacy
pipeline/stage code removed. 4 new migrations + seed aligned.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:04:15 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if (isLoading) {
|
|
|
|
|
return (
|
|
|
|
|
<Card>
|
|
|
|
|
<CardHeader>
|
|
|
|
|
<Skeleton className="h-6 w-48" />
|
|
|
|
|
</CardHeader>
|
|
|
|
|
<CardContent>
|
|
|
|
|
<Skeleton className="h-64" />
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-18 12:43:28 +01:00
|
|
|
if (!files || files.length === 0) {
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
Replace Pipeline/Stage system with Competition/Round architecture.
New schema: Competition, Round (7 types), JuryGroup, AssignmentPolicy,
ProjectRoundState, DeliberationSession, ResultLock, SubmissionWindow.
New services: round-engine, round-assignment, deliberation, result-lock,
submission-manager, competition-context, ai-prompt-guard.
Full admin/jury/applicant/mentor UI rewrite. AI prompt hardening with
structured prompts, retry logic, and injection detection. All legacy
pipeline/stage code removed. 4 new migrations + seed aligned.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:04:15 +01:00
|
|
|
return (
|
|
|
|
|
<Card>
|
|
|
|
|
<CardHeader>
|
|
|
|
|
<CardTitle>Documents</CardTitle>
|
2026-02-18 12:43:28 +01:00
|
|
|
<CardDescription>Project files and submissions</CardDescription>
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
Replace Pipeline/Stage system with Competition/Round architecture.
New schema: Competition, Round (7 types), JuryGroup, AssignmentPolicy,
ProjectRoundState, DeliberationSession, ResultLock, SubmissionWindow.
New services: round-engine, round-assignment, deliberation, result-lock,
submission-manager, competition-context, ai-prompt-guard.
Full admin/jury/applicant/mentor UI rewrite. AI prompt hardening with
structured prompts, retry logic, and injection detection. All legacy
pipeline/stage code removed. 4 new migrations + seed aligned.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:04:15 +01:00
|
|
|
</CardHeader>
|
|
|
|
|
<CardContent className="text-center py-8">
|
|
|
|
|
<FileText className="h-12 w-12 text-muted-foreground/50 mx-auto mb-3" />
|
2026-02-18 12:43:28 +01:00
|
|
|
<p className="text-sm text-muted-foreground">No files uploaded</p>
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
Replace Pipeline/Stage system with Competition/Round architecture.
New schema: Competition, Round (7 types), JuryGroup, AssignmentPolicy,
ProjectRoundState, DeliberationSession, ResultLock, SubmissionWindow.
New services: round-engine, round-assignment, deliberation, result-lock,
submission-manager, competition-context, ai-prompt-guard.
Full admin/jury/applicant/mentor UI rewrite. AI prompt hardening with
structured prompts, retry logic, and injection detection. All legacy
pipeline/stage code removed. 4 new migrations + seed aligned.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:04:15 +01:00
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-18 14:03:38 +01:00
|
|
|
// Group files by round name for the grouped view
|
|
|
|
|
const groupMap: Record<string, {
|
|
|
|
|
roundId: string | null
|
|
|
|
|
roundName: string
|
|
|
|
|
sortOrder: number
|
|
|
|
|
files: typeof files
|
|
|
|
|
}> = {}
|
|
|
|
|
|
2026-02-18 12:43:28 +01:00
|
|
|
for (const file of files) {
|
2026-04-12 23:20:48 -04:00
|
|
|
const rId = file.requirement?.round?.id ?? (file as any).roundId ?? null
|
|
|
|
|
const roundName = file.requirement?.round?.name ?? (rId ? 'Round Files' : 'General')
|
2026-02-18 14:03:38 +01:00
|
|
|
const sortOrder = file.requirement?.round?.sortOrder ?? 999
|
|
|
|
|
if (!groupMap[roundName]) {
|
|
|
|
|
groupMap[roundName] = { roundId: rId, roundName, sortOrder, files: [] }
|
|
|
|
|
}
|
|
|
|
|
groupMap[roundName].files.push(file)
|
2026-02-18 12:43:28 +01:00
|
|
|
}
|
|
|
|
|
|
2026-02-18 14:03:38 +01:00
|
|
|
const groupedFiles = Object.values(groupMap)
|
2026-02-18 12:43:28 +01:00
|
|
|
|
2026-02-18 14:03:38 +01:00
|
|
|
// If only one group, use flat view
|
|
|
|
|
if (groupedFiles.length === 1) {
|
|
|
|
|
const mappedFiles = files.map((f) => ({
|
|
|
|
|
id: f.id,
|
|
|
|
|
fileType: (f.fileType ?? 'OTHER') as 'EXEC_SUMMARY' | 'PRESENTATION' | 'VIDEO' | 'OTHER' | 'BUSINESS_PLAN' | 'VIDEO_PITCH' | 'SUPPORTING_DOC',
|
|
|
|
|
fileName: f.fileName,
|
|
|
|
|
mimeType: f.mimeType,
|
|
|
|
|
size: f.size,
|
|
|
|
|
bucket: f.bucket,
|
|
|
|
|
objectKey: f.objectKey,
|
|
|
|
|
version: f.version ?? undefined,
|
|
|
|
|
requirementId: f.requirementId,
|
|
|
|
|
requirement: f.requirement ? {
|
|
|
|
|
id: f.requirement.id,
|
|
|
|
|
name: f.requirement.name,
|
|
|
|
|
description: f.requirement.description,
|
|
|
|
|
isRequired: f.requirement.isRequired,
|
|
|
|
|
} : undefined,
|
|
|
|
|
pageCount: (f as any).pageCount ?? undefined,
|
|
|
|
|
textPreview: (f as any).textPreview ?? undefined,
|
|
|
|
|
detectedLang: (f as any).detectedLang ?? undefined,
|
|
|
|
|
langConfidence: (f as any).langConfidence ?? undefined,
|
|
|
|
|
analyzedAt: (f as any).analyzedAt ?? undefined,
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
return <FileViewer files={mappedFiles} />
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Multiple groups — use grouped view
|
|
|
|
|
const mappedGroups = groupedFiles.map((g) => ({
|
|
|
|
|
roundId: g.roundId,
|
|
|
|
|
roundName: g.roundName,
|
|
|
|
|
sortOrder: g.sortOrder,
|
|
|
|
|
files: g.files.map((f) => ({
|
|
|
|
|
id: f.id,
|
|
|
|
|
fileType: (f.fileType ?? 'OTHER') as 'EXEC_SUMMARY' | 'PRESENTATION' | 'VIDEO' | 'OTHER' | 'BUSINESS_PLAN' | 'VIDEO_PITCH' | 'SUPPORTING_DOC',
|
|
|
|
|
fileName: f.fileName,
|
|
|
|
|
mimeType: f.mimeType,
|
|
|
|
|
size: f.size,
|
|
|
|
|
bucket: f.bucket,
|
|
|
|
|
objectKey: f.objectKey,
|
|
|
|
|
version: f.version ?? undefined,
|
|
|
|
|
requirementId: f.requirementId,
|
|
|
|
|
requirement: f.requirement ? {
|
|
|
|
|
id: f.requirement.id,
|
|
|
|
|
name: f.requirement.name,
|
|
|
|
|
description: f.requirement.description,
|
|
|
|
|
isRequired: f.requirement.isRequired,
|
|
|
|
|
} : undefined,
|
|
|
|
|
pageCount: (f as any).pageCount ?? undefined,
|
|
|
|
|
textPreview: (f as any).textPreview ?? undefined,
|
|
|
|
|
detectedLang: (f as any).detectedLang ?? undefined,
|
|
|
|
|
langConfidence: (f as any).langConfidence ?? undefined,
|
|
|
|
|
analyzedAt: (f as any).analyzedAt ?? undefined,
|
|
|
|
|
})),
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
return <FileViewer groupedFiles={mappedGroups} />
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
Replace Pipeline/Stage system with Competition/Round architecture.
New schema: Competition, Round (7 types), JuryGroup, AssignmentPolicy,
ProjectRoundState, DeliberationSession, ResultLock, SubmissionWindow.
New services: round-engine, round-assignment, deliberation, result-lock,
submission-manager, competition-context, ai-prompt-guard.
Full admin/jury/applicant/mentor UI rewrite. AI prompt hardening with
structured prompts, retry logic, and injection detection. All legacy
pipeline/stage code removed. 4 new migrations + seed aligned.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:04:15 +01:00
|
|
|
}
|