'use client' import { useState, useMemo } from 'react' import { cn } from '@/lib/utils' import { Button } from '@/components/ui/button' import { Checkbox } from '@/components/ui/checkbox' import { Label } from '@/components/ui/label' import { Badge } from '@/components/ui/badge' import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select' import { Loader2 } from 'lucide-react' export type AdvanceProjectsDialogProps = { open: boolean onOpenChange: (open: boolean) => void roundId: string roundType?: string projectStates: any[] | undefined config: Record advanceMutation: { mutate: (input: { roundId: string; projectIds?: string[]; targetRoundId?: string; autoPassPending?: boolean }) => void; isPending: boolean } competitionRounds?: Array<{ id: string; name: string; sortOrder: number; roundType: string }> currentSortOrder?: number } export function AdvanceProjectsDialog({ open, onOpenChange, roundId, roundType, projectStates, config, advanceMutation, competitionRounds, currentSortOrder, }: AdvanceProjectsDialogProps) { // For non-jury rounds (INTAKE, SUBMISSION, MENTORING), offer a simpler "advance all" flow const isSimpleAdvance = ['INTAKE', 'SUBMISSION', 'MENTORING'].includes(roundType ?? '') // Target round selector const availableTargets = useMemo(() => (competitionRounds ?? []) .filter((r) => r.sortOrder > (currentSortOrder ?? -1) && r.id !== roundId) .sort((a, b) => a.sortOrder - b.sortOrder), [competitionRounds, currentSortOrder, roundId]) const [targetRoundId, setTargetRoundId] = useState('') // Default to first available target when dialog opens if (open && !targetRoundId && availableTargets.length > 0) { setTargetRoundId(availableTargets[0].id) } const allProjects = projectStates ?? [] const pendingCount = allProjects.filter((ps: any) => ps.state === 'PENDING').length const passedProjects = useMemo(() => allProjects.filter((ps: any) => ps.state === 'PASSED'), [allProjects]) const startups = useMemo(() => passedProjects.filter((ps: any) => ps.project?.competitionCategory === 'STARTUP'), [passedProjects]) const concepts = useMemo(() => passedProjects.filter((ps: any) => ps.project?.competitionCategory === 'BUSINESS_CONCEPT'), [passedProjects]) const other = useMemo(() => passedProjects.filter((ps: any) => ps.project?.competitionCategory !== 'STARTUP' && ps.project?.competitionCategory !== 'BUSINESS_CONCEPT', ), [passedProjects]) const startupCap = (config.startupAdvanceCount as number) || 0 const conceptCap = (config.conceptAdvanceCount as number) || 0 const [selected, setSelected] = useState>(new Set()) // Reset selection when dialog opens if (open && selected.size === 0 && passedProjects.length > 0) { const initial = new Set() // Auto-select all (or up to cap if configured) const startupSlice = startupCap > 0 ? startups.slice(0, startupCap) : startups const conceptSlice = conceptCap > 0 ? concepts.slice(0, conceptCap) : concepts for (const ps of startupSlice) initial.add(ps.project?.id) for (const ps of conceptSlice) initial.add(ps.project?.id) for (const ps of other) initial.add(ps.project?.id) setSelected(initial) } const toggleProject = (projectId: string) => { setSelected((prev) => { const next = new Set(prev) if (next.has(projectId)) next.delete(projectId) else next.add(projectId) return next }) } const toggleAll = (projects: any[], on: boolean) => { setSelected((prev) => { const next = new Set(prev) for (const ps of projects) { if (on) next.add(ps.project?.id) else next.delete(ps.project?.id) } return next }) } const handleAdvance = (autoPass?: boolean) => { if (autoPass) { // Auto-pass all pending then advance all advanceMutation.mutate({ roundId, autoPassPending: true, ...(targetRoundId ? { targetRoundId } : {}), }) } else { const ids = Array.from(selected) if (ids.length === 0) return advanceMutation.mutate({ roundId, projectIds: ids, ...(targetRoundId ? { targetRoundId } : {}), }) } onOpenChange(false) setSelected(new Set()) setTargetRoundId('') } const handleClose = () => { onOpenChange(false) setSelected(new Set()) setTargetRoundId('') } const renderCategorySection = ( label: string, projects: any[], cap: number, badgeColor: string, ) => { const selectedInCategory = projects.filter((ps: any) => selected.has(ps.project?.id)).length const overCap = cap > 0 && selectedInCategory > cap return (
0 && projects.every((ps: any) => selected.has(ps.project?.id))} onCheckedChange={(checked) => toggleAll(projects, !!checked)} /> {label} {selectedInCategory}/{projects.length} {cap > 0 && ( (target: {cap}) )}
{projects.length === 0 ? (

No passed projects in this category

) : (
{projects.map((ps: any) => ( ))}
)}
) } const totalProjectCount = allProjects.length return ( Advance Projects {isSimpleAdvance ? `Move all ${totalProjectCount} projects to the next round.` : `Select which passed projects to advance. ${selected.size} of ${passedProjects.length} selected.` } {/* Target round selector */} {availableTargets.length > 0 && (
)} {availableTargets.length === 0 && (
No subsequent rounds found. Projects will advance to the next round by sort order.
)} {isSimpleAdvance ? ( /* Simple mode for INTAKE/SUBMISSION/MENTORING — no per-project selection needed */

{totalProjectCount}

projects will be advanced

{pendingCount > 0 && (

{pendingCount} pending project{pendingCount !== 1 ? 's' : ''} will be automatically marked as passed and advanced. {passedProjects.length > 0 && ` ${passedProjects.length} already passed.`}

)}
) : ( /* Detailed mode for jury/evaluation rounds — per-project selection */
{renderCategorySection('Startup', startups, startupCap, 'bg-blue-100 text-blue-700')} {renderCategorySection('Business Concept', concepts, conceptCap, 'bg-purple-100 text-purple-700')} {other.length > 0 && renderCategorySection('Other / Uncategorized', other, 0, 'bg-gray-100 text-gray-700')}
)} {isSimpleAdvance ? ( ) : ( )}
) }