feat: semi-finalist tracker dashboard, account reminders, search + UX fixes

- Add getSemiFinalistStats query with per-category/per-award breakdown
- Add sendAccountReminders mutation with invite token generation and dedup
- Add SemiFinalistTracker dashboard widget with progress bars and remind buttons
- Add ACCOUNT_REMINDER email template
- Extend project search to match team member name/email (7 locations)
- Fix Passed count deduplication: count distinct projects, not round-state rows
- Fix role switcher: visible pills above user section, auto-refresh session on mount

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-04 15:41:03 +01:00
parent af03c12ae5
commit 43e21c6c6e
10 changed files with 622 additions and 14 deletions

View File

@@ -57,7 +57,7 @@ export const projectPoolRouter = router({
where.competitionCategory = competitionCategory
}
// Search in title, teamName, description, institution, country, geographicZone, team member names
// Search in title, teamName, description, institution, country, geographicZone, team member names/emails
if (search) {
where.OR = [
{ title: { contains: search, mode: 'insensitive' } },
@@ -67,6 +67,7 @@ export const projectPoolRouter = router({
{ country: { contains: search, mode: 'insensitive' } },
{ geographicZone: { contains: search, mode: 'insensitive' } },
{ teamMembers: { some: { user: { name: { contains: search, mode: 'insensitive' } } } } },
{ teamMembers: { some: { user: { email: { contains: search, mode: 'insensitive' } } } } },
]
}
@@ -344,6 +345,8 @@ export const projectPoolRouter = router({
OR: [
{ title: { contains: search, mode: 'insensitive' } },
{ teamName: { contains: search, mode: 'insensitive' } },
{ teamMembers: { some: { user: { name: { contains: search, mode: 'insensitive' } } } } },
{ teamMembers: { some: { user: { email: { contains: search, mode: 'insensitive' } } } } },
],
}
}