Decouple projects from rounds with RoundProject join table
Projects now exist at the program level instead of being locked to a single round. A new RoundProject join table enables many-to-many relationships with per-round status tracking. Rounds have sortOrder for configurable progression paths. - Add RoundProject model, programId on Project, sortOrder on Round - Migration preserves existing data (roundId -> RoundProject entries) - Update all routers to query through RoundProject join - Add assign/remove/advance/reorder round endpoints - Add Assign, Advance, Remove Projects dialogs on round detail page - Add round reorder controls (up/down arrows) on rounds list - Show all rounds on project detail page Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -329,7 +329,7 @@ export default function MemberDetailPage() {
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Badge variant="secondary">
|
||||
{assignment.project.status}
|
||||
{assignment.project.roundProjects?.[0]?.status ?? 'SUBMITTED'}
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell className="text-sm text-muted-foreground">
|
||||
|
||||
@@ -112,11 +112,11 @@ async function DashboardStats({ editionId, sessionName }: DashboardStatsProps) {
|
||||
where: { programId: editionId },
|
||||
}),
|
||||
prisma.project.count({
|
||||
where: { round: { programId: editionId } },
|
||||
where: { programId: editionId },
|
||||
}),
|
||||
prisma.project.count({
|
||||
where: {
|
||||
round: { programId: editionId },
|
||||
programId: editionId,
|
||||
createdAt: { gte: sevenDaysAgo },
|
||||
},
|
||||
}),
|
||||
@@ -149,7 +149,7 @@ async function DashboardStats({ editionId, sessionName }: DashboardStatsProps) {
|
||||
include: {
|
||||
_count: {
|
||||
select: {
|
||||
projects: true,
|
||||
roundProjects: true,
|
||||
assignments: true,
|
||||
},
|
||||
},
|
||||
@@ -161,31 +161,33 @@ async function DashboardStats({ editionId, sessionName }: DashboardStatsProps) {
|
||||
},
|
||||
}),
|
||||
prisma.project.findMany({
|
||||
where: { round: { programId: editionId } },
|
||||
where: { programId: editionId },
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: 8,
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
teamName: true,
|
||||
status: true,
|
||||
country: true,
|
||||
competitionCategory: true,
|
||||
oceanIssue: true,
|
||||
logoKey: true,
|
||||
createdAt: true,
|
||||
submittedAt: true,
|
||||
round: { select: { name: true } },
|
||||
roundProjects: {
|
||||
select: { status: true, round: { select: { name: true } } },
|
||||
take: 1,
|
||||
},
|
||||
},
|
||||
}),
|
||||
prisma.project.groupBy({
|
||||
by: ['competitionCategory'],
|
||||
where: { round: { programId: editionId } },
|
||||
where: { programId: editionId },
|
||||
_count: true,
|
||||
}),
|
||||
prisma.project.groupBy({
|
||||
by: ['oceanIssue'],
|
||||
where: { round: { programId: editionId } },
|
||||
where: { programId: editionId },
|
||||
_count: true,
|
||||
}),
|
||||
])
|
||||
@@ -392,7 +394,7 @@ async function DashboardStats({ editionId, sessionName }: DashboardStatsProps) {
|
||||
</Badge>
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{round._count.projects} projects · {round._count.assignments} assignments
|
||||
{round._count.roundProjects} projects · {round._count.assignments} assignments
|
||||
{round.totalEvals > 0 && (
|
||||
<> · {round.evalPercent}% evaluated</>
|
||||
)}
|
||||
@@ -459,10 +461,10 @@ async function DashboardStats({ editionId, sessionName }: DashboardStatsProps) {
|
||||
{truncate(project.title, 45)}
|
||||
</p>
|
||||
<Badge
|
||||
variant={statusColors[project.status] || 'secondary'}
|
||||
variant={statusColors[project.roundProjects[0]?.status ?? 'SUBMITTED'] || 'secondary'}
|
||||
className="shrink-0 text-[10px] px-1.5 py-0"
|
||||
>
|
||||
{project.status.replace('_', ' ')}
|
||||
{(project.roundProjects[0]?.status ?? 'SUBMITTED').replace('_', ' ')}
|
||||
</Badge>
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground mt-0.5">
|
||||
|
||||
@@ -138,7 +138,7 @@ export default async function ProgramDetailPage({ params }: ProgramDetailPagePro
|
||||
{round.status}
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell>{round._count.projects}</TableCell>
|
||||
<TableCell>{round._count.roundProjects}</TableCell>
|
||||
<TableCell>{round._count.assignments}</TableCell>
|
||||
<TableCell>{formatDateOnly(round.createdAt)}</TableCell>
|
||||
</TableRow>
|
||||
|
||||
@@ -96,7 +96,7 @@ export default function ProjectAssignmentsPage() {
|
||||
</div>
|
||||
</div>
|
||||
<Button asChild>
|
||||
<Link href={`/admin/rounds/${project?.roundId}/assignments`}>
|
||||
<Link href={`/admin/rounds/${project?.roundProjects?.[0]?.round?.id}/assignments`}>
|
||||
<Plus className="mr-2 h-4 w-4" />
|
||||
Manage in Round
|
||||
</Link>
|
||||
|
||||
@@ -121,7 +121,7 @@ function EditProjectContent({ projectId }: { projectId: string }) {
|
||||
|
||||
// Fetch existing tags for suggestions
|
||||
const { data: existingTags } = trpc.project.getTags.useQuery({
|
||||
roundId: project?.roundId,
|
||||
roundId: project?.roundProjects?.[0]?.round?.id,
|
||||
})
|
||||
|
||||
// Mutations
|
||||
@@ -162,7 +162,7 @@ function EditProjectContent({ projectId }: { projectId: string }) {
|
||||
title: project.title,
|
||||
teamName: project.teamName || '',
|
||||
description: project.description || '',
|
||||
status: project.status as UpdateProjectForm['status'],
|
||||
status: (project.roundProjects?.[0]?.status ?? 'SUBMITTED') as UpdateProjectForm['status'],
|
||||
tags: project.tags || [],
|
||||
})
|
||||
}
|
||||
@@ -197,6 +197,7 @@ function EditProjectContent({ projectId }: { projectId: string }) {
|
||||
teamName: data.teamName || null,
|
||||
description: data.description || null,
|
||||
status: data.status,
|
||||
roundId: project?.roundProjects?.[0]?.round?.id,
|
||||
tags: data.tags,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -139,20 +139,29 @@ function ProjectDetailContent({ projectId }: { projectId: string }) {
|
||||
fallback="initials"
|
||||
/>
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
||||
<Link
|
||||
href={`/admin/rounds/${project.round.id}`}
|
||||
className="hover:underline"
|
||||
>
|
||||
{project.round.name}
|
||||
</Link>
|
||||
<div className="flex flex-wrap items-center gap-1 text-sm text-muted-foreground">
|
||||
{project.roundProjects?.length > 0 ? (
|
||||
project.roundProjects.map((rp, i) => (
|
||||
<span key={rp.round.id} className="flex items-center gap-1">
|
||||
{i > 0 && <span className="text-muted-foreground/50">/</span>}
|
||||
<Link
|
||||
href={`/admin/rounds/${rp.round.id}`}
|
||||
className="hover:underline"
|
||||
>
|
||||
{rp.round.name}
|
||||
</Link>
|
||||
</span>
|
||||
))
|
||||
) : (
|
||||
<span>No round</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<h1 className="text-2xl font-semibold tracking-tight">
|
||||
{project.title}
|
||||
</h1>
|
||||
<Badge variant={statusColors[project.status] || 'secondary'}>
|
||||
{project.status.replace('_', ' ')}
|
||||
<Badge variant={statusColors[project.roundProjects?.[0]?.status ?? 'SUBMITTED'] || 'secondary'}>
|
||||
{(project.roundProjects?.[0]?.status ?? 'SUBMITTED').replace('_', ' ')}
|
||||
</Badge>
|
||||
</div>
|
||||
{project.teamName && (
|
||||
@@ -504,7 +513,7 @@ function ProjectDetailContent({ projectId }: { projectId: string }) {
|
||||
</CardDescription>
|
||||
</div>
|
||||
<Button variant="outline" size="sm" asChild>
|
||||
<Link href={`/admin/rounds/${project.roundId}/assignments`}>
|
||||
<Link href={`/admin/rounds/${project.roundProjects?.[0]?.round?.id}/assignments`}>
|
||||
Manage
|
||||
</Link>
|
||||
</Button>
|
||||
|
||||
@@ -43,6 +43,7 @@ function ImportPageContent() {
|
||||
const rounds = programs?.flatMap((p) =>
|
||||
(p.rounds || []).map((r) => ({
|
||||
...r,
|
||||
programId: p.id,
|
||||
programName: `${p.year} Edition`,
|
||||
}))
|
||||
) || []
|
||||
@@ -170,6 +171,7 @@ function ImportPageContent() {
|
||||
</TabsList>
|
||||
<TabsContent value="csv" className="mt-4">
|
||||
<CSVImportForm
|
||||
programId={selectedRound.programId}
|
||||
roundId={selectedRoundId}
|
||||
roundName={selectedRound.name}
|
||||
onSuccess={() => {
|
||||
|
||||
@@ -73,6 +73,7 @@ function NewProjectPageContent() {
|
||||
const rounds = programs?.flatMap((p) =>
|
||||
(p.rounds || []).map((r) => ({
|
||||
...r,
|
||||
programId: p.id,
|
||||
programName: `${p.year} Edition`,
|
||||
}))
|
||||
) || []
|
||||
@@ -117,6 +118,7 @@ function NewProjectPageContent() {
|
||||
})
|
||||
|
||||
createProject.mutate({
|
||||
programId: selectedRound!.programId,
|
||||
roundId: selectedRoundId,
|
||||
title: title.trim(),
|
||||
teamName: teamName.trim() || undefined,
|
||||
|
||||
@@ -350,9 +350,9 @@ export default function ProjectsPage() {
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<div>
|
||||
<p>{project.round.name}</p>
|
||||
<p>{project.roundProjects?.[0]?.round?.name ?? '-'}</p>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{project.round.program?.name}
|
||||
{project.program?.name}
|
||||
</p>
|
||||
</div>
|
||||
</TableCell>
|
||||
@@ -365,9 +365,9 @@ export default function ProjectsPage() {
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Badge
|
||||
variant={statusColors[project.status] || 'secondary'}
|
||||
variant={statusColors[project.roundProjects?.[0]?.status ?? 'SUBMITTED'] || 'secondary'}
|
||||
>
|
||||
{project.status.replace('_', ' ')}
|
||||
{(project.roundProjects?.[0]?.status ?? 'SUBMITTED').replace('_', ' ')}
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell className="relative z-10 text-right">
|
||||
@@ -431,11 +431,11 @@ export default function ProjectsPage() {
|
||||
</CardTitle>
|
||||
<Badge
|
||||
variant={
|
||||
statusColors[project.status] || 'secondary'
|
||||
statusColors[project.roundProjects?.[0]?.status ?? 'SUBMITTED'] || 'secondary'
|
||||
}
|
||||
className="shrink-0"
|
||||
>
|
||||
{project.status.replace('_', ' ')}
|
||||
{(project.roundProjects?.[0]?.status ?? 'SUBMITTED').replace('_', ' ')}
|
||||
</Badge>
|
||||
</div>
|
||||
<CardDescription>{project.teamName}</CardDescription>
|
||||
@@ -445,7 +445,7 @@ export default function ProjectsPage() {
|
||||
<CardContent className="space-y-3">
|
||||
<div className="flex items-center justify-between text-sm">
|
||||
<span className="text-muted-foreground">Round</span>
|
||||
<span>{project.round.name}</span>
|
||||
<span>{project.roundProjects?.[0]?.round?.name ?? '-'}</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between text-sm">
|
||||
<span className="text-muted-foreground">Assignments</span>
|
||||
|
||||
@@ -72,7 +72,7 @@ export interface ProjectFilters {
|
||||
}
|
||||
|
||||
interface FilterOptions {
|
||||
rounds: Array<{ id: string; name: string; program: { name: string; year: number } }>
|
||||
rounds: Array<{ id: string; name: string; sortOrder: number; program: { name: string; year: number } }>
|
||||
countries: string[]
|
||||
categories: Array<{ value: string; count: number }>
|
||||
issues: Array<{ value: string; count: number }>
|
||||
|
||||
@@ -180,7 +180,7 @@ function LiveVotingContent({ roundId }: { roundId: string }) {
|
||||
if (storedOrder.length > 0) {
|
||||
setProjectOrder(storedOrder)
|
||||
} else {
|
||||
setProjectOrder(sessionData.round.projects.map((p) => p.id))
|
||||
setProjectOrder(sessionData.round.roundProjects.map((rp) => rp.project.id))
|
||||
}
|
||||
}
|
||||
}, [sessionData])
|
||||
@@ -253,7 +253,7 @@ function LiveVotingContent({ roundId }: { roundId: string }) {
|
||||
)
|
||||
}
|
||||
|
||||
const projects = sessionData.round.projects
|
||||
const projects = sessionData.round.roundProjects.map((rp) => rp.project)
|
||||
const sortedProjects = projectOrder
|
||||
.map((id) => projects.find((p) => p.id === id))
|
||||
.filter((p): p is Project => !!p)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { Suspense, use } from 'react'
|
||||
import { Suspense, use, useState } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { trpc } from '@/lib/trpc/client'
|
||||
@@ -44,8 +44,14 @@ import {
|
||||
Filter,
|
||||
Trash2,
|
||||
Loader2,
|
||||
Plus,
|
||||
ArrowRightCircle,
|
||||
Minus,
|
||||
} from 'lucide-react'
|
||||
import { toast } from 'sonner'
|
||||
import { AssignProjectsDialog } from '@/components/admin/assign-projects-dialog'
|
||||
import { AdvanceProjectsDialog } from '@/components/admin/advance-projects-dialog'
|
||||
import { RemoveProjectsDialog } from '@/components/admin/remove-projects-dialog'
|
||||
import { format, formatDistanceToNow, isPast, isFuture } from 'date-fns'
|
||||
|
||||
interface PageProps {
|
||||
@@ -54,6 +60,9 @@ interface PageProps {
|
||||
|
||||
function RoundDetailContent({ roundId }: { roundId: string }) {
|
||||
const router = useRouter()
|
||||
const [assignOpen, setAssignOpen] = useState(false)
|
||||
const [advanceOpen, setAdvanceOpen] = useState(false)
|
||||
const [removeOpen, setRemoveOpen] = useState(false)
|
||||
|
||||
const { data: round, isLoading } = trpc.round.get.useQuery({ id: roundId })
|
||||
const { data: progress } = trpc.round.getProgress.useQuery({ id: roundId })
|
||||
@@ -235,7 +244,7 @@ function RoundDetailContent({ roundId }: { roundId: string }) {
|
||||
<FileText className="h-4 w-4 text-muted-foreground" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold">{round._count.projects}</div>
|
||||
<div className="text-2xl font-bold">{round._count.roundProjects}</div>
|
||||
<Button variant="link" size="sm" className="px-0" asChild>
|
||||
<Link href={`/admin/projects?round=${round.id}`}>View projects</Link>
|
||||
</Button>
|
||||
@@ -423,9 +432,43 @@ function RoundDetailContent({ roundId }: { roundId: string }) {
|
||||
View Projects
|
||||
</Link>
|
||||
</Button>
|
||||
<Button variant="outline" onClick={() => setAssignOpen(true)}>
|
||||
<Plus className="mr-2 h-4 w-4" />
|
||||
Assign Projects
|
||||
</Button>
|
||||
<Button variant="outline" onClick={() => setAdvanceOpen(true)}>
|
||||
<ArrowRightCircle className="mr-2 h-4 w-4" />
|
||||
Advance Projects
|
||||
</Button>
|
||||
<Button variant="outline" onClick={() => setRemoveOpen(true)}>
|
||||
<Minus className="mr-2 h-4 w-4" />
|
||||
Remove Projects
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Dialogs */}
|
||||
<AssignProjectsDialog
|
||||
roundId={roundId}
|
||||
programId={round.program.id}
|
||||
open={assignOpen}
|
||||
onOpenChange={setAssignOpen}
|
||||
onSuccess={() => utils.round.get.invalidate({ id: roundId })}
|
||||
/>
|
||||
<AdvanceProjectsDialog
|
||||
roundId={roundId}
|
||||
programId={round.program.id}
|
||||
open={advanceOpen}
|
||||
onOpenChange={setAdvanceOpen}
|
||||
onSuccess={() => utils.round.get.invalidate({ id: roundId })}
|
||||
/>
|
||||
<RemoveProjectsDialog
|
||||
roundId={roundId}
|
||||
open={removeOpen}
|
||||
onOpenChange={setRemoveOpen}
|
||||
onSuccess={() => utils.round.get.invalidate({ id: roundId })}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ import {
|
||||
} from '@/components/ui/card'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
@@ -34,6 +33,7 @@ import {
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@/components/ui/form'
|
||||
import { RoundTypeSettings } from '@/components/forms/round-type-settings'
|
||||
import { ArrowLeft, Loader2, AlertCircle } from 'lucide-react'
|
||||
|
||||
const createRoundSchema = z.object({
|
||||
@@ -58,6 +58,8 @@ function CreateRoundContent() {
|
||||
const router = useRouter()
|
||||
const searchParams = useSearchParams()
|
||||
const programIdParam = searchParams.get('program')
|
||||
const [roundType, setRoundType] = useState<'FILTERING' | 'EVALUATION' | 'LIVE_EVENT'>('EVALUATION')
|
||||
const [roundSettings, setRoundSettings] = useState<Record<string, unknown>>({})
|
||||
|
||||
const { data: programs, isLoading: loadingPrograms } = trpc.program.list.useQuery()
|
||||
|
||||
@@ -82,7 +84,9 @@ function CreateRoundContent() {
|
||||
await createRound.mutateAsync({
|
||||
programId: data.programId,
|
||||
name: data.name,
|
||||
roundType,
|
||||
requiredReviews: data.requiredReviews,
|
||||
settingsJson: roundSettings,
|
||||
votingStartAt: data.votingStartAt ? new Date(data.votingStartAt) : undefined,
|
||||
votingEndAt: data.votingEndAt ? new Date(data.votingEndAt) : undefined,
|
||||
})
|
||||
@@ -218,6 +222,14 @@ function CreateRoundContent() {
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Round Type & Settings */}
|
||||
<RoundTypeSettings
|
||||
roundType={roundType}
|
||||
onRoundTypeChange={setRoundType}
|
||||
settings={roundSettings}
|
||||
onSettingsChange={setRoundSettings}
|
||||
/>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg">Voting Window</CardTitle>
|
||||
|
||||
@@ -52,6 +52,8 @@ import {
|
||||
Archive,
|
||||
Trash2,
|
||||
Loader2,
|
||||
ChevronUp,
|
||||
ChevronDown,
|
||||
} from 'lucide-react'
|
||||
import { format, isPast, isFuture } from 'date-fns'
|
||||
|
||||
@@ -106,6 +108,7 @@ function RoundsContent() {
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-20">Order</TableHead>
|
||||
<TableHead>Round</TableHead>
|
||||
<TableHead>Status</TableHead>
|
||||
<TableHead>Voting Window</TableHead>
|
||||
@@ -115,8 +118,15 @@ function RoundsContent() {
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{program.rounds.map((round) => (
|
||||
<RoundRow key={round.id} round={round} />
|
||||
{program.rounds.map((round, index) => (
|
||||
<RoundRow
|
||||
key={round.id}
|
||||
round={round}
|
||||
index={index}
|
||||
totalRounds={program.rounds.length}
|
||||
allRoundIds={program.rounds.map((r) => r.id)}
|
||||
programId={program.id}
|
||||
/>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
@@ -133,10 +143,40 @@ function RoundsContent() {
|
||||
)
|
||||
}
|
||||
|
||||
function RoundRow({ round }: { round: any }) {
|
||||
function RoundRow({
|
||||
round,
|
||||
index,
|
||||
totalRounds,
|
||||
allRoundIds,
|
||||
programId,
|
||||
}: {
|
||||
round: any
|
||||
index: number
|
||||
totalRounds: number
|
||||
allRoundIds: string[]
|
||||
programId: string
|
||||
}) {
|
||||
const utils = trpc.useUtils()
|
||||
const [showDeleteDialog, setShowDeleteDialog] = useState(false)
|
||||
|
||||
const reorder = trpc.round.reorder.useMutation({
|
||||
onSuccess: () => {
|
||||
utils.program.list.invalidate()
|
||||
},
|
||||
})
|
||||
|
||||
const moveUp = () => {
|
||||
const ids = [...allRoundIds]
|
||||
;[ids[index - 1], ids[index]] = [ids[index], ids[index - 1]]
|
||||
reorder.mutate({ programId, roundIds: ids })
|
||||
}
|
||||
|
||||
const moveDown = () => {
|
||||
const ids = [...allRoundIds]
|
||||
;[ids[index], ids[index + 1]] = [ids[index + 1], ids[index]]
|
||||
reorder.mutate({ programId, roundIds: ids })
|
||||
}
|
||||
|
||||
const updateStatus = trpc.round.updateStatus.useMutation({
|
||||
onSuccess: () => {
|
||||
utils.program.list.invalidate()
|
||||
@@ -229,6 +269,28 @@ function RoundRow({ round }: { round: any }) {
|
||||
|
||||
return (
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<div className="flex items-center gap-1">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-7 w-7"
|
||||
onClick={moveUp}
|
||||
disabled={index === 0 || reorder.isPending}
|
||||
>
|
||||
<ChevronUp className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-7 w-7"
|
||||
onClick={moveDown}
|
||||
disabled={index === totalRounds - 1 || reorder.isPending}
|
||||
>
|
||||
<ChevronDown className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Link
|
||||
href={`/admin/rounds/${round.id}`}
|
||||
@@ -242,7 +304,7 @@ function RoundRow({ round }: { round: any }) {
|
||||
<TableCell>
|
||||
<div className="flex items-center gap-1">
|
||||
<FileText className="h-4 w-4 text-muted-foreground" />
|
||||
{round._count?.projects || 0}
|
||||
{round._count?.roundProjects || 0}
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
@@ -325,9 +387,9 @@ function RoundRow({ round }: { round: any }) {
|
||||
<AlertDialogTitle>Delete Round</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
Are you sure you want to delete "{round.name}"? This will
|
||||
permanently delete all {round._count?.projects || 0} projects,{' '}
|
||||
{round._count?.assignments || 0} assignments, and all evaluations
|
||||
in this round. This action cannot be undone.
|
||||
remove {round._count?.roundProjects || 0} project assignments,{' '}
|
||||
{round._count?.assignments || 0} reviewer assignments, and all evaluations
|
||||
in this round. The projects themselves will remain in the program. This action cannot be undone.
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
|
||||
Reference in New Issue
Block a user