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>
This commit is contained in:
2026-03-01 14:42:37 +01:00
parent dd004baf79
commit 9b3a9f6cbf
4 changed files with 68 additions and 8 deletions

View File

@@ -58,6 +58,7 @@ import {
Plus,
Search,
ExternalLink,
Sparkles,
} from 'lucide-react'
import Link from 'next/link'
import type { Route } from 'next'
@@ -136,6 +137,14 @@ export function ProjectStatesTable({ competitionId, roundId }: ProjectStatesTabl
onError: (err) => toast.error(err.message),
})
const tagProject = trpc.tag.tagProject.useMutation({
onSuccess: () => {
toast.success('AI tags generated')
utils.roundEngine.getProjectStates.invalidate({ roundId })
},
onError: (err: any) => toast.error(`Tag generation failed: ${err.message}`),
})
const handleTransition = (projectId: string, newState: ProjectState) => {
transitionMutation.mutate({ projectId, roundId, newState })
}
@@ -165,10 +174,17 @@ export function ProjectStatesTable({ competitionId, roundId }: ProjectStatesTabl
}
if (searchQuery.trim()) {
const q = searchQuery.toLowerCase()
result = result.filter((ps: any) =>
(ps.project?.title || '').toLowerCase().includes(q) ||
(ps.project?.teamName || '').toLowerCase().includes(q)
)
result = result.filter((ps: any) => {
const p = ps.project
return (
(p?.title || '').toLowerCase().includes(q) ||
(p?.teamName || '').toLowerCase().includes(q) ||
(p?.country || '').toLowerCase().includes(q) ||
(p?.institution || '').toLowerCase().includes(q) ||
(p?.competitionCategory || '').toLowerCase().includes(q) ||
(p?.geographicZone || '').toLowerCase().includes(q)
)
})
}
return result
}, [projectStates, stateFilter, searchQuery])
@@ -411,6 +427,16 @@ export function ProjectStatesTable({ competitionId, roundId }: ProjectStatesTabl
View Project
</a>
</DropdownMenuItem>
<DropdownMenuItem
onClick={(e) => {
e.stopPropagation()
tagProject.mutate({ projectId: ps.projectId })
}}
disabled={tagProject.isPending}
>
<Sparkles className="mr-2 h-4 w-4" />
Generate AI Tags
</DropdownMenuItem>
<DropdownMenuSeparator />
{PROJECT_STATES.filter((s) => s !== ps.state).map((state) => {
const sCfg = stateConfig[state]