Fix project detail crash: replace dynamic hooks with single query

The project detail page called useQuery inside .map() to fetch file
requirements per round, violating React's rules of hooks. When
competitionRounds changed from [] to [round1, round2], the hook count
changed, causing React to crash with "Cannot read properties of
undefined (reading 'length')".

Fix: Add listRequirementsByRounds endpoint that accepts multiple
roundIds in one query, replacing the dynamic hook pattern with a
single stable useQuery call.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Matt
2026-02-16 15:30:44 +01:00
parent 65a22e6f19
commit f12c29103c
2 changed files with 20 additions and 7 deletions

View File

@@ -105,14 +105,13 @@ function ProjectDetailContent({ projectId }: { projectId: string }) {
// Extract all rounds from the competition
const competitionRounds = competition?.rounds || []
// Fetch requirements for each round
const requirementQueries = competitionRounds.map((round: { id: string; name: string }) =>
trpc.file.listRequirements.useQuery({ roundId: round.id })
// Fetch requirements for all rounds in a single query (avoids dynamic hook violation)
const roundIds = competitionRounds.map((r: { id: string }) => r.id)
const { data: allRequirements = [] } = trpc.file.listRequirementsByRounds.useQuery(
{ roundIds },
{ enabled: roundIds.length > 0 }
)
// Combine requirements from all rounds
const allRequirements = requirementQueries.flatMap((q: { data?: unknown[] }) => q.data || [])
const utils = trpc.useUtils()
if (isLoading) {
@@ -592,7 +591,7 @@ function ProjectDetailContent({ projectId }: { projectId: string }) {
</p>
)}
<div className="flex items-center gap-2 text-xs text-muted-foreground mt-0.5">
{req.acceptedMimeTypes.length > 0 && (
{req.acceptedMimeTypes?.length > 0 && (
<span>
{req.acceptedMimeTypes.map((mime: string) => {
if (mime === 'application/pdf') return 'PDF'