feat: group observer project files by round
All checks were successful
Build and Push Docker Image / build (push) Successful in 7m15s
All checks were successful
Build and Push Docker Image / build (push) Successful in 7m15s
Files on the observer project detail page are now grouped by round (e.g., "Application Intake", "Semi-Finals Document Submission") instead of shown in a flat list. Uses FileViewer's existing groupedFiles prop. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -929,41 +929,66 @@ export function ObserverProjectDetail({ projectId }: { projectId: string }) {
|
|||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
{project.files && project.files.length > 0 ? (
|
{project.files && project.files.length > 0 ? (() => {
|
||||||
<FileViewer
|
// Group files by round
|
||||||
projectId={projectId}
|
type FileItem = (typeof project.files)[number]
|
||||||
files={project.files.map((f) => ({
|
const roundMap = new Map<string, { roundId: string | null; roundName: string; sortOrder: number; files: FileItem[] }>()
|
||||||
id: f.id,
|
for (const f of project.files) {
|
||||||
fileName: f.fileName,
|
const key = (f as any).roundId ?? '__none__'
|
||||||
fileType: f.fileType as
|
if (!roundMap.has(key)) {
|
||||||
| 'EXEC_SUMMARY'
|
const round = (f as any).round as { id: string; name: string; sortOrder: number } | null
|
||||||
| 'PRESENTATION'
|
roundMap.set(key, {
|
||||||
| 'VIDEO'
|
roundId: round?.id ?? null,
|
||||||
| 'OTHER'
|
roundName: round?.name ?? 'Other Files',
|
||||||
| 'BUSINESS_PLAN'
|
sortOrder: round?.sortOrder ?? 999,
|
||||||
| 'VIDEO_PITCH'
|
files: [],
|
||||||
| 'SUPPORTING_DOC',
|
})
|
||||||
mimeType: f.mimeType,
|
}
|
||||||
size: f.size,
|
roundMap.get(key)!.files.push(f)
|
||||||
bucket: f.bucket,
|
}
|
||||||
objectKey: f.objectKey,
|
const groups = Array.from(roundMap.values()).sort((a, b) => a.sortOrder - b.sortOrder)
|
||||||
pageCount: f.pageCount,
|
|
||||||
textPreview: f.textPreview,
|
return (
|
||||||
detectedLang: f.detectedLang,
|
<FileViewer
|
||||||
langConfidence: f.langConfidence,
|
projectId={projectId}
|
||||||
analyzedAt: f.analyzedAt ? String(f.analyzedAt) : null,
|
groupedFiles={groups.map((g) => ({
|
||||||
requirementId: f.requirementId,
|
roundId: g.roundId,
|
||||||
requirement: f.requirement
|
roundName: g.roundName,
|
||||||
? {
|
sortOrder: g.sortOrder,
|
||||||
id: f.requirement.id,
|
files: g.files.map((f) => ({
|
||||||
name: f.requirement.name,
|
id: f.id,
|
||||||
description: f.requirement.description,
|
fileName: f.fileName,
|
||||||
isRequired: f.requirement.isRequired,
|
fileType: f.fileType as
|
||||||
}
|
| 'EXEC_SUMMARY'
|
||||||
: null,
|
| 'PRESENTATION'
|
||||||
}))}
|
| 'VIDEO'
|
||||||
/>
|
| 'OTHER'
|
||||||
) : (
|
| 'BUSINESS_PLAN'
|
||||||
|
| 'VIDEO_PITCH'
|
||||||
|
| 'SUPPORTING_DOC',
|
||||||
|
mimeType: f.mimeType,
|
||||||
|
size: f.size,
|
||||||
|
bucket: f.bucket,
|
||||||
|
objectKey: f.objectKey,
|
||||||
|
pageCount: f.pageCount,
|
||||||
|
textPreview: f.textPreview,
|
||||||
|
detectedLang: f.detectedLang,
|
||||||
|
langConfidence: f.langConfidence,
|
||||||
|
analyzedAt: f.analyzedAt ? String(f.analyzedAt) : null,
|
||||||
|
requirementId: f.requirementId,
|
||||||
|
requirement: f.requirement
|
||||||
|
? {
|
||||||
|
id: f.requirement.id,
|
||||||
|
name: f.requirement.name,
|
||||||
|
description: f.requirement.description,
|
||||||
|
isRequired: f.requirement.isRequired,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
})),
|
||||||
|
}))}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})() : (
|
||||||
<div className="flex flex-col items-center justify-center py-8 text-center">
|
<div className="flex flex-col items-center justify-center py-8 text-center">
|
||||||
<FileText className="h-12 w-12 text-muted-foreground/50" />
|
<FileText className="h-12 w-12 text-muted-foreground/50" />
|
||||||
<p className="mt-2 text-sm text-muted-foreground">
|
<p className="mt-2 text-sm text-muted-foreground">
|
||||||
|
|||||||
@@ -1378,9 +1378,12 @@ export const analyticsRouter = router({
|
|||||||
id: true, fileName: true, fileType: true, mimeType: true, size: true,
|
id: true, fileName: true, fileType: true, mimeType: true, size: true,
|
||||||
bucket: true, objectKey: true, pageCount: true, textPreview: true,
|
bucket: true, objectKey: true, pageCount: true, textPreview: true,
|
||||||
detectedLang: true, langConfidence: true, analyzedAt: true,
|
detectedLang: true, langConfidence: true, analyzedAt: true,
|
||||||
|
roundId: true,
|
||||||
|
round: { select: { id: true, name: true, roundType: true, sortOrder: true } },
|
||||||
requirementId: true,
|
requirementId: true,
|
||||||
requirement: { select: { id: true, name: true, description: true, isRequired: true } },
|
requirement: { select: { id: true, name: true, description: true, isRequired: true } },
|
||||||
},
|
},
|
||||||
|
orderBy: [{ round: { sortOrder: 'asc' } }, { createdAt: 'asc' }],
|
||||||
},
|
},
|
||||||
teamMembers: {
|
teamMembers: {
|
||||||
include: {
|
include: {
|
||||||
@@ -1526,6 +1529,7 @@ export const analyticsRouter = router({
|
|||||||
return {
|
return {
|
||||||
project: {
|
project: {
|
||||||
...projectRaw,
|
...projectRaw,
|
||||||
|
files: projectRaw.files,
|
||||||
projectTags,
|
projectTags,
|
||||||
teamMembers: teamMembersWithAvatars,
|
teamMembers: teamMembersWithAvatars,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user