Fix AI filtering bugs, add special award shortlist integration
Part 1 - Bug Fixes:
- Fix toProjectWithRelations() stripping file fields needed by AI (detectedLang, textContent, etc.)
- Fix parseAIData() reading flat when aiScreeningJson is nested under rule ID
- Fix getAIConfidenceScore() with same nesting issue (always returned 0)
Part 2 - Special Award Track Integration:
- Add shortlistSize to SpecialAward, qualityScore/shortlisted/confirmed fields to AwardEligibility
- Add specialAwardId to Round for award-owned rounds
- Update AI eligibility service to return qualityScore (0-100) for ranking
- Update eligibility job with filteringRoundId scoping and auto-shortlist top N
- Add 8 new specialAward router procedures (listForRound, runEligibilityForRound,
listShortlist, toggleShortlisted, confirmShortlist, listRounds, createRound, deleteRound)
- Create award-shortlist.tsx component with ranked table, shortlist checkboxes, confirm dialog
- Add "Special Award Tracks" section to filtering dashboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 15:38:31 +01:00
'use client'
feat: enhance project search to include all criteria, add AI tag generation button
- ProjectStatesTable local search now covers country, institution, competitionCategory, geographicZone
- project-pool.ts DB search extended to institution, country, geographicZone, team member names
- AwardShortlist eligibility table gains a search input filtering by title, team, country, institution, category
- IndividualAssignmentsTable project filter extended to include country and institution
- Add "Generate AI Tags" dropdown item per row in ProjectStatesTable using tag.tagProject mutation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 14:42:37 +01:00
import { useState , useMemo } from 'react'
Fix AI filtering bugs, add special award shortlist integration
Part 1 - Bug Fixes:
- Fix toProjectWithRelations() stripping file fields needed by AI (detectedLang, textContent, etc.)
- Fix parseAIData() reading flat when aiScreeningJson is nested under rule ID
- Fix getAIConfidenceScore() with same nesting issue (always returned 0)
Part 2 - Special Award Track Integration:
- Add shortlistSize to SpecialAward, qualityScore/shortlisted/confirmed fields to AwardEligibility
- Add specialAwardId to Round for award-owned rounds
- Update AI eligibility service to return qualityScore (0-100) for ranking
- Update eligibility job with filteringRoundId scoping and auto-shortlist top N
- Add 8 new specialAward router procedures (listForRound, runEligibilityForRound,
listShortlist, toggleShortlisted, confirmShortlist, listRounds, createRound, deleteRound)
- Create award-shortlist.tsx component with ranked table, shortlist checkboxes, confirm dialog
- Add "Special Award Tracks" section to filtering dashboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 15:38:31 +01:00
import { trpc } from '@/lib/trpc/client'
import { toast } from 'sonner'
import { Button } from '@/components/ui/button'
feat: enhance project search to include all criteria, add AI tag generation button
- ProjectStatesTable local search now covers country, institution, competitionCategory, geographicZone
- project-pool.ts DB search extended to institution, country, geographicZone, team member names
- AwardShortlist eligibility table gains a search input filtering by title, team, country, institution, category
- IndividualAssignmentsTable project filter extended to include country and institution
- Add "Generate AI Tags" dropdown item per row in ProjectStatesTable using tag.tagProject mutation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 14:42:37 +01:00
import { Input } from '@/components/ui/input'
Fix AI filtering bugs, add special award shortlist integration
Part 1 - Bug Fixes:
- Fix toProjectWithRelations() stripping file fields needed by AI (detectedLang, textContent, etc.)
- Fix parseAIData() reading flat when aiScreeningJson is nested under rule ID
- Fix getAIConfidenceScore() with same nesting issue (always returned 0)
Part 2 - Special Award Track Integration:
- Add shortlistSize to SpecialAward, qualityScore/shortlisted/confirmed fields to AwardEligibility
- Add specialAwardId to Round for award-owned rounds
- Update AI eligibility service to return qualityScore (0-100) for ranking
- Update eligibility job with filteringRoundId scoping and auto-shortlist top N
- Add 8 new specialAward router procedures (listForRound, runEligibilityForRound,
listShortlist, toggleShortlisted, confirmShortlist, listRounds, createRound, deleteRound)
- Create award-shortlist.tsx component with ranked table, shortlist checkboxes, confirm dialog
- Add "Special Award Tracks" section to filtering dashboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 15:38:31 +01:00
import { Badge } from '@/components/ui/badge'
import { Checkbox } from '@/components/ui/checkbox'
import { Progress } from '@/components/ui/progress'
import { Skeleton } from '@/components/ui/skeleton'
import {
AlertDialog ,
AlertDialogAction ,
AlertDialogCancel ,
AlertDialogContent ,
AlertDialogDescription ,
AlertDialogFooter ,
AlertDialogHeader ,
AlertDialogTitle ,
AlertDialogTrigger ,
} from '@/components/ui/alert-dialog'
import {
Collapsible ,
CollapsibleContent ,
CollapsibleTrigger ,
} from '@/components/ui/collapsible'
import {
ChevronDown ,
ChevronUp ,
Loader2 ,
CheckCircle2 ,
Play ,
Trophy ,
2026-02-17 19:53:20 +01:00
AlertTriangle ,
feat: enhance project search to include all criteria, add AI tag generation button
- ProjectStatesTable local search now covers country, institution, competitionCategory, geographicZone
- project-pool.ts DB search extended to institution, country, geographicZone, team member names
- AwardShortlist eligibility table gains a search input filtering by title, team, country, institution, category
- IndividualAssignmentsTable project filter extended to include country and institution
- Add "Generate AI Tags" dropdown item per row in ProjectStatesTable using tag.tagProject mutation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 14:42:37 +01:00
Search ,
Fix AI filtering bugs, add special award shortlist integration
Part 1 - Bug Fixes:
- Fix toProjectWithRelations() stripping file fields needed by AI (detectedLang, textContent, etc.)
- Fix parseAIData() reading flat when aiScreeningJson is nested under rule ID
- Fix getAIConfidenceScore() with same nesting issue (always returned 0)
Part 2 - Special Award Track Integration:
- Add shortlistSize to SpecialAward, qualityScore/shortlisted/confirmed fields to AwardEligibility
- Add specialAwardId to Round for award-owned rounds
- Update AI eligibility service to return qualityScore (0-100) for ranking
- Update eligibility job with filteringRoundId scoping and auto-shortlist top N
- Add 8 new specialAward router procedures (listForRound, runEligibilityForRound,
listShortlist, toggleShortlisted, confirmShortlist, listRounds, createRound, deleteRound)
- Create award-shortlist.tsx component with ranked table, shortlist checkboxes, confirm dialog
- Add "Special Award Tracks" section to filtering dashboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 15:38:31 +01:00
} from 'lucide-react'
feat: multi-role jury fix, country flags, applicant deadline banner, timeline
- Fix project list returning empty for users with both SUPER_ADMIN and
JURY_MEMBER roles (jury filter now skips admins) in project, assignment,
and evaluation routers
- Add CountryDisplay component showing flag emoji + name everywhere
country is displayed (admin, observer, jury, mentor views — 17 files)
- Add countdown deadline banner on applicant dashboard for INTAKE,
SUBMISSION, and MENTORING rounds with live timer
- Remove quick action buttons from applicant dashboard
- Fix competition timeline sidebar: green dots/connectors only up to
current round, yellow dot for current round, red connector into
rejected round, grey after
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:00:29 +01:00
import { CountryDisplay } from '@/components/shared/country-display'
Fix AI filtering bugs, add special award shortlist integration
Part 1 - Bug Fixes:
- Fix toProjectWithRelations() stripping file fields needed by AI (detectedLang, textContent, etc.)
- Fix parseAIData() reading flat when aiScreeningJson is nested under rule ID
- Fix getAIConfidenceScore() with same nesting issue (always returned 0)
Part 2 - Special Award Track Integration:
- Add shortlistSize to SpecialAward, qualityScore/shortlisted/confirmed fields to AwardEligibility
- Add specialAwardId to Round for award-owned rounds
- Update AI eligibility service to return qualityScore (0-100) for ranking
- Update eligibility job with filteringRoundId scoping and auto-shortlist top N
- Add 8 new specialAward router procedures (listForRound, runEligibilityForRound,
listShortlist, toggleShortlisted, confirmShortlist, listRounds, createRound, deleteRound)
- Create award-shortlist.tsx component with ranked table, shortlist checkboxes, confirm dialog
- Add "Special Award Tracks" section to filtering dashboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 15:38:31 +01:00
type AwardShortlistProps = {
awardId : string
roundId : string
awardName : string
criteriaText? : string | null
eligibilityMode : string
shortlistSize : number
jobStatus? : string | null
jobTotal? : number | null
jobDone? : number | null
}
export function AwardShortlist ( {
awardId ,
roundId ,
awardName ,
criteriaText ,
eligibilityMode ,
shortlistSize ,
jobStatus ,
jobTotal ,
jobDone ,
} : AwardShortlistProps ) {
const [ expanded , setExpanded ] = useState ( false )
feat: enhance project search to include all criteria, add AI tag generation button
- ProjectStatesTable local search now covers country, institution, competitionCategory, geographicZone
- project-pool.ts DB search extended to institution, country, geographicZone, team member names
- AwardShortlist eligibility table gains a search input filtering by title, team, country, institution, category
- IndividualAssignmentsTable project filter extended to include country and institution
- Add "Generate AI Tags" dropdown item per row in ProjectStatesTable using tag.tagProject mutation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 14:42:37 +01:00
const [ eligibilitySearch , setEligibilitySearch ] = useState ( '' )
Fix AI filtering bugs, add special award shortlist integration
Part 1 - Bug Fixes:
- Fix toProjectWithRelations() stripping file fields needed by AI (detectedLang, textContent, etc.)
- Fix parseAIData() reading flat when aiScreeningJson is nested under rule ID
- Fix getAIConfidenceScore() with same nesting issue (always returned 0)
Part 2 - Special Award Track Integration:
- Add shortlistSize to SpecialAward, qualityScore/shortlisted/confirmed fields to AwardEligibility
- Add specialAwardId to Round for award-owned rounds
- Update AI eligibility service to return qualityScore (0-100) for ranking
- Update eligibility job with filteringRoundId scoping and auto-shortlist top N
- Add 8 new specialAward router procedures (listForRound, runEligibilityForRound,
listShortlist, toggleShortlisted, confirmShortlist, listRounds, createRound, deleteRound)
- Create award-shortlist.tsx component with ranked table, shortlist checkboxes, confirm dialog
- Add "Special Award Tracks" section to filtering dashboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 15:38:31 +01:00
const utils = trpc . useUtils ( )
const isRunning = jobStatus === 'PENDING' || jobStatus === 'PROCESSING'
const { data : shortlist , isLoading : isLoadingShortlist } = trpc . specialAward . listShortlist . useQuery (
{ awardId , perPage : 100 } ,
{ enabled : expanded && ! isRunning }
)
const { data : jobPoll } = trpc . specialAward . getEligibilityJobStatus . useQuery (
{ awardId } ,
{ enabled : isRunning , refetchInterval : 3000 }
)
const runMutation = trpc . specialAward . runEligibilityForRound . useMutation ( {
onSuccess : ( ) = > {
toast . success ( 'Eligibility evaluation started' )
utils . specialAward . getEligibilityJobStatus . invalidate ( { awardId } )
utils . specialAward . listForRound . invalidate ( { roundId } )
} ,
onError : ( err ) = > toast . error ( ` Failed: ${ err . message } ` ) ,
} )
const toggleMutation = trpc . specialAward . toggleShortlisted . useMutation ( {
onSuccess : ( data ) = > {
utils . specialAward . listShortlist . invalidate ( { awardId } )
utils . specialAward . listForRound . invalidate ( { roundId } )
toast . success ( data . shortlisted ? 'Added to shortlist' : 'Removed from shortlist' )
} ,
onError : ( err ) = > toast . error ( ` Failed: ${ err . message } ` ) ,
} )
2026-02-17 22:05:58 +01:00
const bulkToggleMutation = trpc . specialAward . bulkToggleShortlisted . useMutation ( {
onSuccess : ( data ) = > {
utils . specialAward . listShortlist . invalidate ( { awardId } )
utils . specialAward . listForRound . invalidate ( { roundId } )
toast . success ( ` ${ data . updated } projects ${ data . shortlisted ? 'added to' : 'removed from' } shortlist ` )
} ,
onError : ( err ) = > toast . error ( ` Failed: ${ err . message } ` ) ,
} )
2026-02-17 19:53:20 +01:00
const { data : awardRounds } = trpc . specialAward . listRounds . useQuery (
{ awardId } ,
{ enabled : expanded && eligibilityMode === 'SEPARATE_POOL' }
)
const hasAwardRounds = ( awardRounds ? . length ? ? 0 ) > 0
Fix AI filtering bugs, add special award shortlist integration
Part 1 - Bug Fixes:
- Fix toProjectWithRelations() stripping file fields needed by AI (detectedLang, textContent, etc.)
- Fix parseAIData() reading flat when aiScreeningJson is nested under rule ID
- Fix getAIConfidenceScore() with same nesting issue (always returned 0)
Part 2 - Special Award Track Integration:
- Add shortlistSize to SpecialAward, qualityScore/shortlisted/confirmed fields to AwardEligibility
- Add specialAwardId to Round for award-owned rounds
- Update AI eligibility service to return qualityScore (0-100) for ranking
- Update eligibility job with filteringRoundId scoping and auto-shortlist top N
- Add 8 new specialAward router procedures (listForRound, runEligibilityForRound,
listShortlist, toggleShortlisted, confirmShortlist, listRounds, createRound, deleteRound)
- Create award-shortlist.tsx component with ranked table, shortlist checkboxes, confirm dialog
- Add "Special Award Tracks" section to filtering dashboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 15:38:31 +01:00
const confirmMutation = trpc . specialAward . confirmShortlist . useMutation ( {
onSuccess : ( data ) = > {
utils . specialAward . listShortlist . invalidate ( { awardId } )
utils . specialAward . listForRound . invalidate ( { roundId } )
toast . success (
` Confirmed ${ data . confirmedCount } projects ` +
( data . routedCount > 0 ? ` — ${ data . routedCount } routed to award track ` : '' )
)
} ,
onError : ( err ) = > toast . error ( ` Failed: ${ err . message } ` ) ,
} )
const currentJobStatus = jobPoll ? . eligibilityJobStatus ? ? jobStatus
const currentJobDone = jobPoll ? . eligibilityJobDone ? ? jobDone
const currentJobTotal = jobPoll ? . eligibilityJobTotal ? ? jobTotal
const jobProgress = currentJobTotal && currentJobTotal > 0
? Math . round ( ( ( currentJobDone ? ? 0 ) / currentJobTotal ) * 100 )
: 0
feat: enhance project search to include all criteria, add AI tag generation button
- ProjectStatesTable local search now covers country, institution, competitionCategory, geographicZone
- project-pool.ts DB search extended to institution, country, geographicZone, team member names
- AwardShortlist eligibility table gains a search input filtering by title, team, country, institution, category
- IndividualAssignmentsTable project filter extended to include country and institution
- Add "Generate AI Tags" dropdown item per row in ProjectStatesTable using tag.tagProject mutation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 14:42:37 +01:00
const filteredEligibilities = useMemo ( ( ) = > {
if ( ! shortlist ) return [ ]
if ( ! eligibilitySearch . trim ( ) ) return shortlist . eligibilities
const q = eligibilitySearch . toLowerCase ( )
return shortlist . eligibilities . filter ( ( e : any ) = >
( e . project ? . title || '' ) . toLowerCase ( ) . includes ( q ) ||
( e . project ? . teamName || '' ) . toLowerCase ( ) . includes ( q ) ||
( e . project ? . country || '' ) . toLowerCase ( ) . includes ( q ) ||
( e . project ? . institution || '' ) . toLowerCase ( ) . includes ( q ) ||
( e . project ? . competitionCategory || '' ) . toLowerCase ( ) . includes ( q )
)
} , [ shortlist , eligibilitySearch ] )
Fix AI filtering bugs, add special award shortlist integration
Part 1 - Bug Fixes:
- Fix toProjectWithRelations() stripping file fields needed by AI (detectedLang, textContent, etc.)
- Fix parseAIData() reading flat when aiScreeningJson is nested under rule ID
- Fix getAIConfidenceScore() with same nesting issue (always returned 0)
Part 2 - Special Award Track Integration:
- Add shortlistSize to SpecialAward, qualityScore/shortlisted/confirmed fields to AwardEligibility
- Add specialAwardId to Round for award-owned rounds
- Update AI eligibility service to return qualityScore (0-100) for ranking
- Update eligibility job with filteringRoundId scoping and auto-shortlist top N
- Add 8 new specialAward router procedures (listForRound, runEligibilityForRound,
listShortlist, toggleShortlisted, confirmShortlist, listRounds, createRound, deleteRound)
- Create award-shortlist.tsx component with ranked table, shortlist checkboxes, confirm dialog
- Add "Special Award Tracks" section to filtering dashboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 15:38:31 +01:00
const shortlistedCount = shortlist ? . eligibilities ? . filter ( ( e ) = > e . shortlisted ) . length ? ? 0
2026-02-17 22:05:58 +01:00
const allShortlisted = shortlist && shortlist . eligibilities . length > 0 && shortlist . eligibilities . every ( ( e ) = > e . shortlisted )
const someShortlisted = shortlistedCount > 0 && ! allShortlisted
const handleBulkToggle = ( ) = > {
if ( ! shortlist ) return
const projectIds = shortlist . eligibilities . map ( ( e ) = > e . project . id )
const newValue = ! allShortlisted
bulkToggleMutation . mutate ( { awardId , projectIds , shortlisted : newValue } )
}
Fix AI filtering bugs, add special award shortlist integration
Part 1 - Bug Fixes:
- Fix toProjectWithRelations() stripping file fields needed by AI (detectedLang, textContent, etc.)
- Fix parseAIData() reading flat when aiScreeningJson is nested under rule ID
- Fix getAIConfidenceScore() with same nesting issue (always returned 0)
Part 2 - Special Award Track Integration:
- Add shortlistSize to SpecialAward, qualityScore/shortlisted/confirmed fields to AwardEligibility
- Add specialAwardId to Round for award-owned rounds
- Update AI eligibility service to return qualityScore (0-100) for ranking
- Update eligibility job with filteringRoundId scoping and auto-shortlist top N
- Add 8 new specialAward router procedures (listForRound, runEligibilityForRound,
listShortlist, toggleShortlisted, confirmShortlist, listRounds, createRound, deleteRound)
- Create award-shortlist.tsx component with ranked table, shortlist checkboxes, confirm dialog
- Add "Special Award Tracks" section to filtering dashboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 15:38:31 +01:00
return (
< Collapsible open = { expanded } onOpenChange = { setExpanded } >
< div className = "border rounded-lg" >
< CollapsibleTrigger asChild >
< button className = "w-full flex items-center justify-between p-4 hover:bg-muted/50 transition-colors text-left" >
< div className = "flex items-center gap-3" >
< Trophy className = "h-5 w-5 text-amber-600" / >
< div >
< h4 className = "font-semibold text-sm" > { awardName } < / h4 >
{ criteriaText && (
< p className = "text-xs text-muted-foreground line-clamp-1 max-w-md" >
{ criteriaText }
< / p >
) }
< / div >
< / div >
< div className = "flex items-center gap-3" >
< Badge variant = "outline" className = { eligibilityMode === 'SEPARATE_POOL'
? 'bg-purple-50 text-purple-700 border-purple-200'
: 'bg-blue-50 text-blue-700 border-blue-200'
} >
{ eligibilityMode === 'SEPARATE_POOL' ? 'Separate Pool' : 'Main Pool' }
< / Badge >
{ currentJobStatus === 'COMPLETED' && (
< Badge variant = "outline" className = "bg-green-50 text-green-700 border-green-200" >
< CheckCircle2 className = "h-3 w-3 mr-1" / >
Evaluated
< / Badge >
) }
{ expanded ? < ChevronUp className = "h-4 w-4" / > : < ChevronDown className = "h-4 w-4" / > }
< / div >
< / button >
< / CollapsibleTrigger >
< CollapsibleContent >
< div className = "border-t p-4 space-y-4" >
{ /* Job controls */ }
< div className = "flex items-center justify-between" >
< div className = "text-sm text-muted-foreground" >
Evaluate PASSED projects against this award & apos ; s criteria
< / div >
< Button
size = "sm"
onClick = { ( ) = > runMutation . mutate ( { awardId , roundId } ) }
disabled = { runMutation . isPending || isRunning }
>
{ isRunning ? (
< > < Loader2 className = "h-4 w-4 mr-2 animate-spin" / > Processing . . . < / >
) : runMutation . isPending ? (
< > < Loader2 className = "h-4 w-4 mr-2 animate-spin" / > Starting . . . < / >
) : currentJobStatus === 'COMPLETED' ? (
< > < Play className = "h-4 w-4 mr-2" / > Re - evaluate < / >
) : (
< > < Play className = "h-4 w-4 mr-2" / > Run Eligibility < / >
) }
< / Button >
< / div >
{ /* Progress bar */ }
{ isRunning && currentJobTotal && currentJobTotal > 0 && (
< div className = "space-y-1" >
< Progress value = { jobProgress } className = "h-2" / >
< p className = "text-xs text-muted-foreground text-right" >
{ currentJobDone ? ? 0 } / { currentJobTotal } projects
< / p >
< / div >
) }
{ /* Shortlist table */ }
{ expanded && currentJobStatus === 'COMPLETED' && (
< >
{ isLoadingShortlist ? (
< div className = "space-y-2" >
{ [ 1 , 2 , 3 ] . map ( ( i ) = > < Skeleton key = { i } className = "h-12 w-full" / > ) }
< / div >
) : shortlist && shortlist . eligibilities . length > 0 ? (
< div className = "space-y-3" >
< div className = "flex items-center justify-between" >
< p className = "text-sm font-medium" >
{ shortlist . total } eligible projects
{ shortlistedCount > 0 && (
< span className = "text-muted-foreground ml-1" >
( { shortlistedCount } shortlisted )
< / span >
) }
< / p >
{ shortlistedCount > 0 && (
< AlertDialog >
< AlertDialogTrigger asChild >
< Button size = "sm" variant = "default" >
< CheckCircle2 className = "h-4 w-4 mr-2" / >
Confirm Shortlist ( { shortlistedCount } )
< / Button >
< / AlertDialogTrigger >
< AlertDialogContent >
< AlertDialogHeader >
< AlertDialogTitle > Confirm Shortlist < / AlertDialogTitle >
2026-02-17 19:53:20 +01:00
< AlertDialogDescription asChild >
< div className = "space-y-2" >
< p >
{ eligibilityMode === 'SEPARATE_POOL'
? ` This will confirm ${ shortlistedCount } projects for the " ${ awardName } " award track. Projects will be routed to the award's rounds for separate evaluation. `
: ` This will confirm ${ shortlistedCount } projects as eligible for the " ${ awardName } " award. Projects remain in the main competition pool. `
}
< / p >
{ eligibilityMode === 'SEPARATE_POOL' && ! hasAwardRounds && (
< div className = "flex items-start gap-2 rounded-md border border-amber-200 bg-amber-50 p-3 text-amber-800 dark:border-amber-800 dark:bg-amber-950/30 dark:text-amber-300" >
< AlertTriangle className = "h-4 w-4 mt-0.5 shrink-0" / >
< p className = "text-sm" >
No award rounds have been created yet . Projects will be confirmed but < strong > not routed < / strong > to an evaluation track . Create rounds on the award page first .
< / p >
< / div >
) }
< / div >
Fix AI filtering bugs, add special award shortlist integration
Part 1 - Bug Fixes:
- Fix toProjectWithRelations() stripping file fields needed by AI (detectedLang, textContent, etc.)
- Fix parseAIData() reading flat when aiScreeningJson is nested under rule ID
- Fix getAIConfidenceScore() with same nesting issue (always returned 0)
Part 2 - Special Award Track Integration:
- Add shortlistSize to SpecialAward, qualityScore/shortlisted/confirmed fields to AwardEligibility
- Add specialAwardId to Round for award-owned rounds
- Update AI eligibility service to return qualityScore (0-100) for ranking
- Update eligibility job with filteringRoundId scoping and auto-shortlist top N
- Add 8 new specialAward router procedures (listForRound, runEligibilityForRound,
listShortlist, toggleShortlisted, confirmShortlist, listRounds, createRound, deleteRound)
- Create award-shortlist.tsx component with ranked table, shortlist checkboxes, confirm dialog
- Add "Special Award Tracks" section to filtering dashboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 15:38:31 +01:00
< / AlertDialogDescription >
< / AlertDialogHeader >
< AlertDialogFooter >
< AlertDialogCancel > Cancel < / AlertDialogCancel >
< AlertDialogAction
onClick = { ( ) = > confirmMutation . mutate ( { awardId } ) }
disabled = { confirmMutation . isPending }
>
{ confirmMutation . isPending ? 'Confirming...' : 'Confirm' }
< / AlertDialogAction >
< / AlertDialogFooter >
< / AlertDialogContent >
< / AlertDialog >
) }
< / div >
feat: enhance project search to include all criteria, add AI tag generation button
- ProjectStatesTable local search now covers country, institution, competitionCategory, geographicZone
- project-pool.ts DB search extended to institution, country, geographicZone, team member names
- AwardShortlist eligibility table gains a search input filtering by title, team, country, institution, category
- IndividualAssignmentsTable project filter extended to include country and institution
- Add "Generate AI Tags" dropdown item per row in ProjectStatesTable using tag.tagProject mutation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 14:42:37 +01:00
< div className = "mb-3" >
< div className = "relative" >
< Search className = "absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" / >
< Input
placeholder = "Search projects..."
value = { eligibilitySearch }
onChange = { ( e ) = > setEligibilitySearch ( e . target . value ) }
className = "pl-9 h-9 max-w-sm"
/ >
< / div >
< / div >
Fix AI filtering bugs, add special award shortlist integration
Part 1 - Bug Fixes:
- Fix toProjectWithRelations() stripping file fields needed by AI (detectedLang, textContent, etc.)
- Fix parseAIData() reading flat when aiScreeningJson is nested under rule ID
- Fix getAIConfidenceScore() with same nesting issue (always returned 0)
Part 2 - Special Award Track Integration:
- Add shortlistSize to SpecialAward, qualityScore/shortlisted/confirmed fields to AwardEligibility
- Add specialAwardId to Round for award-owned rounds
- Update AI eligibility service to return qualityScore (0-100) for ranking
- Update eligibility job with filteringRoundId scoping and auto-shortlist top N
- Add 8 new specialAward router procedures (listForRound, runEligibilityForRound,
listShortlist, toggleShortlisted, confirmShortlist, listRounds, createRound, deleteRound)
- Create award-shortlist.tsx component with ranked table, shortlist checkboxes, confirm dialog
- Add "Special Award Tracks" section to filtering dashboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 15:38:31 +01:00
< div className = "border rounded-md overflow-hidden" >
< table className = "w-full text-sm" >
< thead className = "bg-muted/50" >
< tr >
< th className = "px-3 py-2 text-left w-8" > # < / th >
< th className = "px-3 py-2 text-left" > Project < / th >
< th className = "px-3 py-2 text-left w-24" > Score < / th >
2026-02-18 10:01:31 +01:00
< th className = "px-3 py-2 text-left min-w-[300px]" > Reasoning < / th >
2026-02-17 22:05:58 +01:00
< th className = "px-3 py-2 text-center w-20" >
< div className = "flex items-center justify-center gap-1" >
< Checkbox
checked = { allShortlisted ? true : someShortlisted ? 'indeterminate' : false }
onCheckedChange = { handleBulkToggle }
disabled = { bulkToggleMutation . isPending }
aria - label = "Select all"
/ >
< span className = "text-xs" > All < / span >
< / div >
< / th >
Fix AI filtering bugs, add special award shortlist integration
Part 1 - Bug Fixes:
- Fix toProjectWithRelations() stripping file fields needed by AI (detectedLang, textContent, etc.)
- Fix parseAIData() reading flat when aiScreeningJson is nested under rule ID
- Fix getAIConfidenceScore() with same nesting issue (always returned 0)
Part 2 - Special Award Track Integration:
- Add shortlistSize to SpecialAward, qualityScore/shortlisted/confirmed fields to AwardEligibility
- Add specialAwardId to Round for award-owned rounds
- Update AI eligibility service to return qualityScore (0-100) for ranking
- Update eligibility job with filteringRoundId scoping and auto-shortlist top N
- Add 8 new specialAward router procedures (listForRound, runEligibilityForRound,
listShortlist, toggleShortlisted, confirmShortlist, listRounds, createRound, deleteRound)
- Create award-shortlist.tsx component with ranked table, shortlist checkboxes, confirm dialog
- Add "Special Award Tracks" section to filtering dashboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 15:38:31 +01:00
< / tr >
< / thead >
< tbody >
feat: enhance project search to include all criteria, add AI tag generation button
- ProjectStatesTable local search now covers country, institution, competitionCategory, geographicZone
- project-pool.ts DB search extended to institution, country, geographicZone, team member names
- AwardShortlist eligibility table gains a search input filtering by title, team, country, institution, category
- IndividualAssignmentsTable project filter extended to include country and institution
- Add "Generate AI Tags" dropdown item per row in ProjectStatesTable using tag.tagProject mutation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 14:42:37 +01:00
{ filteredEligibilities . map ( ( e , i ) = > {
Fix AI filtering bugs, add special award shortlist integration
Part 1 - Bug Fixes:
- Fix toProjectWithRelations() stripping file fields needed by AI (detectedLang, textContent, etc.)
- Fix parseAIData() reading flat when aiScreeningJson is nested under rule ID
- Fix getAIConfidenceScore() with same nesting issue (always returned 0)
Part 2 - Special Award Track Integration:
- Add shortlistSize to SpecialAward, qualityScore/shortlisted/confirmed fields to AwardEligibility
- Add specialAwardId to Round for award-owned rounds
- Update AI eligibility service to return qualityScore (0-100) for ranking
- Update eligibility job with filteringRoundId scoping and auto-shortlist top N
- Add 8 new specialAward router procedures (listForRound, runEligibilityForRound,
listShortlist, toggleShortlisted, confirmShortlist, listRounds, createRound, deleteRound)
- Create award-shortlist.tsx component with ranked table, shortlist checkboxes, confirm dialog
- Add "Special Award Tracks" section to filtering dashboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 15:38:31 +01:00
const reasoning = ( e . aiReasoningJson as Record < string , unknown > ) ? . reasoning as string | undefined
2026-02-17 22:05:58 +01:00
const isTop5 = i < shortlistSize
Fix AI filtering bugs, add special award shortlist integration
Part 1 - Bug Fixes:
- Fix toProjectWithRelations() stripping file fields needed by AI (detectedLang, textContent, etc.)
- Fix parseAIData() reading flat when aiScreeningJson is nested under rule ID
- Fix getAIConfidenceScore() with same nesting issue (always returned 0)
Part 2 - Special Award Track Integration:
- Add shortlistSize to SpecialAward, qualityScore/shortlisted/confirmed fields to AwardEligibility
- Add specialAwardId to Round for award-owned rounds
- Update AI eligibility service to return qualityScore (0-100) for ranking
- Update eligibility job with filteringRoundId scoping and auto-shortlist top N
- Add 8 new specialAward router procedures (listForRound, runEligibilityForRound,
listShortlist, toggleShortlisted, confirmShortlist, listRounds, createRound, deleteRound)
- Create award-shortlist.tsx component with ranked table, shortlist checkboxes, confirm dialog
- Add "Special Award Tracks" section to filtering dashboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 15:38:31 +01:00
return (
2026-02-17 22:05:58 +01:00
< tr key = { e . id } className = { ` border-t ${ isTop5 ? 'bg-amber-50/50' : '' } ` } >
Fix AI filtering bugs, add special award shortlist integration
Part 1 - Bug Fixes:
- Fix toProjectWithRelations() stripping file fields needed by AI (detectedLang, textContent, etc.)
- Fix parseAIData() reading flat when aiScreeningJson is nested under rule ID
- Fix getAIConfidenceScore() with same nesting issue (always returned 0)
Part 2 - Special Award Track Integration:
- Add shortlistSize to SpecialAward, qualityScore/shortlisted/confirmed fields to AwardEligibility
- Add specialAwardId to Round for award-owned rounds
- Update AI eligibility service to return qualityScore (0-100) for ranking
- Update eligibility job with filteringRoundId scoping and auto-shortlist top N
- Add 8 new specialAward router procedures (listForRound, runEligibilityForRound,
listShortlist, toggleShortlisted, confirmShortlist, listRounds, createRound, deleteRound)
- Create award-shortlist.tsx component with ranked table, shortlist checkboxes, confirm dialog
- Add "Special Award Tracks" section to filtering dashboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 15:38:31 +01:00
< td className = "px-3 py-2 text-muted-foreground font-mono" >
2026-02-17 22:05:58 +01:00
{ isTop5 ? (
< span className = "text-amber-600 font-semibold" > { i + 1 } < / span >
) : (
i + 1
) }
Fix AI filtering bugs, add special award shortlist integration
Part 1 - Bug Fixes:
- Fix toProjectWithRelations() stripping file fields needed by AI (detectedLang, textContent, etc.)
- Fix parseAIData() reading flat when aiScreeningJson is nested under rule ID
- Fix getAIConfidenceScore() with same nesting issue (always returned 0)
Part 2 - Special Award Track Integration:
- Add shortlistSize to SpecialAward, qualityScore/shortlisted/confirmed fields to AwardEligibility
- Add specialAwardId to Round for award-owned rounds
- Update AI eligibility service to return qualityScore (0-100) for ranking
- Update eligibility job with filteringRoundId scoping and auto-shortlist top N
- Add 8 new specialAward router procedures (listForRound, runEligibilityForRound,
listShortlist, toggleShortlisted, confirmShortlist, listRounds, createRound, deleteRound)
- Create award-shortlist.tsx component with ranked table, shortlist checkboxes, confirm dialog
- Add "Special Award Tracks" section to filtering dashboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 15:38:31 +01:00
< / td >
< td className = "px-3 py-2" >
< div >
2026-02-17 22:05:58 +01:00
< p className = { ` font-medium ${ isTop5 ? 'text-amber-900' : '' } ` } >
2026-03-01 14:37:45 +01:00
< a
href = { ` /admin/projects/ ${ e . project . id } ` }
target = "_blank"
rel = "noopener noreferrer"
className = "text-primary hover:underline font-medium"
onClick = { ( ev ) = > ev . stopPropagation ( ) }
>
{ e . project . title }
< / a >
2026-02-17 22:05:58 +01:00
< / p >
Fix AI filtering bugs, add special award shortlist integration
Part 1 - Bug Fixes:
- Fix toProjectWithRelations() stripping file fields needed by AI (detectedLang, textContent, etc.)
- Fix parseAIData() reading flat when aiScreeningJson is nested under rule ID
- Fix getAIConfidenceScore() with same nesting issue (always returned 0)
Part 2 - Special Award Track Integration:
- Add shortlistSize to SpecialAward, qualityScore/shortlisted/confirmed fields to AwardEligibility
- Add specialAwardId to Round for award-owned rounds
- Update AI eligibility service to return qualityScore (0-100) for ranking
- Update eligibility job with filteringRoundId scoping and auto-shortlist top N
- Add 8 new specialAward router procedures (listForRound, runEligibilityForRound,
listShortlist, toggleShortlisted, confirmShortlist, listRounds, createRound, deleteRound)
- Create award-shortlist.tsx component with ranked table, shortlist checkboxes, confirm dialog
- Add "Special Award Tracks" section to filtering dashboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 15:38:31 +01:00
< p className = "text-xs text-muted-foreground" >
feat: multi-role jury fix, country flags, applicant deadline banner, timeline
- Fix project list returning empty for users with both SUPER_ADMIN and
JURY_MEMBER roles (jury filter now skips admins) in project, assignment,
and evaluation routers
- Add CountryDisplay component showing flag emoji + name everywhere
country is displayed (admin, observer, jury, mentor views — 17 files)
- Add countdown deadline banner on applicant dashboard for INTAKE,
SUBMISSION, and MENTORING rounds with live timer
- Remove quick action buttons from applicant dashboard
- Fix competition timeline sidebar: green dots/connectors only up to
current round, yellow dot for current round, red connector into
rejected round, grey after
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:00:29 +01:00
{ [ e . project . teamName , e . project . competitionCategory ] . filter ( Boolean ) . length > 0 || e . project . country ? (
< >
{ [ e . project . teamName , e . project . competitionCategory ] . filter ( Boolean ) . join ( ', ' ) }
{ ( e . project . teamName || e . project . competitionCategory ) && e . project . country ? ', ' : '' }
{ e . project . country && < CountryDisplay country = { e . project . country } / > }
< / >
) : '—' }
Fix AI filtering bugs, add special award shortlist integration
Part 1 - Bug Fixes:
- Fix toProjectWithRelations() stripping file fields needed by AI (detectedLang, textContent, etc.)
- Fix parseAIData() reading flat when aiScreeningJson is nested under rule ID
- Fix getAIConfidenceScore() with same nesting issue (always returned 0)
Part 2 - Special Award Track Integration:
- Add shortlistSize to SpecialAward, qualityScore/shortlisted/confirmed fields to AwardEligibility
- Add specialAwardId to Round for award-owned rounds
- Update AI eligibility service to return qualityScore (0-100) for ranking
- Update eligibility job with filteringRoundId scoping and auto-shortlist top N
- Add 8 new specialAward router procedures (listForRound, runEligibilityForRound,
listShortlist, toggleShortlisted, confirmShortlist, listRounds, createRound, deleteRound)
- Create award-shortlist.tsx component with ranked table, shortlist checkboxes, confirm dialog
- Add "Special Award Tracks" section to filtering dashboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 15:38:31 +01:00
< / p >
< / div >
< / td >
< td className = "px-3 py-2" >
< div className = "flex items-center gap-2" >
< Progress
value = { e . qualityScore ? ? 0 }
className = "h-2 w-16"
/ >
< span className = "text-xs font-mono font-medium" >
{ e . qualityScore ? ? 0 }
< / span >
< / div >
< / td >
< td className = "px-3 py-2" >
{ reasoning ? (
2026-02-18 10:01:31 +01:00
< p className = "text-xs text-muted-foreground whitespace-pre-wrap leading-relaxed" >
{ reasoning }
< / p >
Fix AI filtering bugs, add special award shortlist integration
Part 1 - Bug Fixes:
- Fix toProjectWithRelations() stripping file fields needed by AI (detectedLang, textContent, etc.)
- Fix parseAIData() reading flat when aiScreeningJson is nested under rule ID
- Fix getAIConfidenceScore() with same nesting issue (always returned 0)
Part 2 - Special Award Track Integration:
- Add shortlistSize to SpecialAward, qualityScore/shortlisted/confirmed fields to AwardEligibility
- Add specialAwardId to Round for award-owned rounds
- Update AI eligibility service to return qualityScore (0-100) for ranking
- Update eligibility job with filteringRoundId scoping and auto-shortlist top N
- Add 8 new specialAward router procedures (listForRound, runEligibilityForRound,
listShortlist, toggleShortlisted, confirmShortlist, listRounds, createRound, deleteRound)
- Create award-shortlist.tsx component with ranked table, shortlist checkboxes, confirm dialog
- Add "Special Award Tracks" section to filtering dashboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 15:38:31 +01:00
) : (
< span className = "text-xs text-muted-foreground" > — < / span >
) }
< / td >
< td className = "px-3 py-2 text-center" >
< Checkbox
checked = { e . shortlisted }
onCheckedChange = { ( ) = >
toggleMutation . mutate ( { awardId , projectId : e.project.id } )
}
disabled = { toggleMutation . isPending }
/ >
< / td >
< / tr >
)
} ) }
< / tbody >
< / table >
< / div >
< / div >
) : (
< p className = "text-sm text-muted-foreground text-center py-4" >
No eligible projects found
< / p >
) }
< / >
) }
{ /* Not yet evaluated */ }
{ expanded && ! currentJobStatus && (
< p className = "text-sm text-muted-foreground text-center py-4" >
Click & quot ; Run Eligibility & quot ; to evaluate projects against this award & apos ; s criteria
< / p >
) }
{ /* Failed */ }
{ currentJobStatus === 'FAILED' && (
< p className = "text-sm text-red-600 text-center py-2" >
Eligibility evaluation failed . Try again .
< / p >
) }
< / div >
< / CollapsibleContent >
< / div >
< / Collapsible >
)
}