feat: show submission round file requirements on project edit page
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m40s
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m40s
Adds a new tRPC procedure `round.getSubmissionRoundForProgram` that fetches the most recent SUBMISSION round for a given program, then displays any `requiredDocuments` from its configJson as labeled info cards above the general file upload section on the project edit page. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { Suspense, use, useState, useEffect, useCallback } from 'react'
|
||||
import { Suspense, use, useState, useEffect, useCallback, useMemo } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { useForm } from 'react-hook-form'
|
||||
@@ -57,6 +57,7 @@ import {
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from '@/components/ui/table'
|
||||
import { Separator } from '@/components/ui/separator'
|
||||
import { FileUpload } from '@/components/shared/file-upload'
|
||||
import { ProjectLogo } from '@/components/shared/project-logo'
|
||||
import { LogoUpload } from '@/components/shared/logo-upload'
|
||||
@@ -133,6 +134,27 @@ function EditProjectContent({ projectId }: { projectId: string }) {
|
||||
// Fetch existing tags for suggestions
|
||||
const { data: existingTags } = trpc.project.getTags.useQuery({})
|
||||
|
||||
// Fetch submission round config to show required documents
|
||||
const programId = project?.programId
|
||||
const { data: submissionRound } = trpc.round.getSubmissionRoundForProgram.useQuery(
|
||||
{ programId: programId! },
|
||||
{ enabled: !!programId }
|
||||
)
|
||||
|
||||
const submissionRoundConfig = useMemo(() => {
|
||||
if (!submissionRound?.configJson) return null
|
||||
const config = submissionRound.configJson as Record<string, unknown>
|
||||
const docs = config.requiredDocuments as
|
||||
| Array<{ name: string; required?: boolean; description?: string }>
|
||||
| null
|
||||
| undefined
|
||||
if (!docs || docs.length === 0) return null
|
||||
return {
|
||||
roundName: submissionRound.name,
|
||||
requiredDocuments: docs,
|
||||
}
|
||||
}, [submissionRound])
|
||||
|
||||
// Mutations
|
||||
const utils = trpc.useUtils()
|
||||
const updateProject = trpc.project.update.useMutation({
|
||||
@@ -702,7 +724,34 @@ function EditProjectContent({ projectId }: { projectId: string }) {
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
{files && files.length > 0 ? (
|
||||
{submissionRoundConfig && (
|
||||
<div className="mb-4 space-y-3">
|
||||
<div>
|
||||
<p className="text-sm font-medium">Required Documents</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
From {submissionRoundConfig.roundName}
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
{submissionRoundConfig.requiredDocuments.map((doc, i) => (
|
||||
<div key={i} className="flex items-center justify-between rounded-md border border-dashed p-3">
|
||||
<div>
|
||||
<p className="text-sm font-medium">{doc.name}</p>
|
||||
{doc.description && (
|
||||
<p className="text-xs text-muted-foreground">{doc.description}</p>
|
||||
)}
|
||||
{doc.required && (
|
||||
<Badge variant="outline" className="mt-1 text-xs">Required</Badge>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<Separator />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{files && files.length > 0 ? (
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
|
||||
@@ -861,4 +861,26 @@ export const roundRouter = router({
|
||||
orderBy: { sortOrder: 'asc' },
|
||||
})
|
||||
}),
|
||||
|
||||
/**
|
||||
* Get the most recent SUBMISSION round config for a program.
|
||||
* Used on the project edit page to show required document slots.
|
||||
*/
|
||||
getSubmissionRoundForProgram: adminProcedure
|
||||
.input(z.object({ programId: z.string() }))
|
||||
.query(async ({ ctx, input }) => {
|
||||
const round = await ctx.prisma.round.findFirst({
|
||||
where: {
|
||||
roundType: 'SUBMISSION',
|
||||
competition: { programId: input.programId },
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
configJson: true,
|
||||
},
|
||||
orderBy: { sortOrder: 'desc' },
|
||||
})
|
||||
return round ?? null
|
||||
}),
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user