Comprehensive platform audit: security, UX, performance, and visual polish

Phase 1: Security - status transition validation, Zod tightening, DB indexes, transactions

Phase 2: Admin UX - search/filter for awards, learning, partners pages

Phase 3: Dashboard - Recent Activity feed, Pending Actions card, quick actions

Phase 4: Jury - assignments progress/urgency, autosave indicator, divergence highlighting

Phase 5: Portals - observer charts, mentor search, login/onboarding polish

Phase 6: Messages preview dialog, CsvExportDialog with column selection

Phase 7: Performance - query optimizations, loading skeletons, useDebounce hook

Phase 8: Visual - AnimatedCard, hover effects, StatusBadge, empty state CTAs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-08 22:05:01 +01:00
parent e0e4cb2a32
commit e73a676412
33 changed files with 3193 additions and 977 deletions

View File

@@ -32,7 +32,6 @@ import {
History,
Trophy,
User,
LayoutTemplate,
MessageSquare,
Wand2,
} from 'lucide-react'
@@ -51,80 +50,85 @@ interface AdminSidebarProps {
}
}
type NavItem = {
name: string
href: string
icon: typeof LayoutDashboard
activeMatch?: string // pathname must include this to be active
activeExclude?: string // pathname must NOT include this to be active
}
// Main navigation - scoped to selected edition
const navigation = [
const navigation: NavItem[] = [
{
name: 'Dashboard',
href: '/admin' as const,
href: '/admin',
icon: LayoutDashboard,
},
{
name: 'Rounds',
href: '/admin/rounds' as const,
href: '/admin/rounds',
icon: CircleDot,
},
{
name: 'Templates',
href: '/admin/round-templates' as const,
icon: LayoutTemplate,
},
{
name: 'Awards',
href: '/admin/awards' as const,
href: '/admin/awards',
icon: Trophy,
},
{
name: 'Projects',
href: '/admin/projects' as const,
href: '/admin/projects',
icon: ClipboardList,
},
{
name: 'Members',
href: '/admin/members' as const,
href: '/admin/members',
icon: Users,
},
{
name: 'Reports',
href: '/admin/reports' as const,
href: '/admin/reports',
icon: FileSpreadsheet,
},
{
name: 'Learning Hub',
href: '/admin/learning' as const,
href: '/admin/learning',
icon: BookOpen,
},
{
name: 'Messages',
href: '/admin/messages' as const,
href: '/admin/messages',
icon: MessageSquare,
},
{
name: 'Partners',
href: '/admin/partners' as const,
href: '/admin/partners',
icon: Handshake,
},
]
// Admin-only navigation
const adminNavigation = [
const adminNavigation: NavItem[] = [
{
name: 'Manage Editions',
href: '/admin/programs' as const,
href: '/admin/programs',
icon: FolderKanban,
activeExclude: 'apply-settings',
},
{
name: 'Apply Settings',
href: '/admin/programs' as const,
name: 'Apply Page',
href: '/admin/programs',
icon: Wand2,
activeMatch: 'apply-settings',
},
{
name: 'Audit Log',
href: '/admin/audit' as const,
href: '/admin/audit',
icon: History,
},
{
name: 'Settings',
href: '/admin/settings' as const,
href: '/admin/settings',
icon: Settings,
},
]
@@ -232,11 +236,16 @@ export function AdminSidebar({ user }: AdminSidebarProps) {
Administration
</p>
{adminNavigation.map((item) => {
const isActive = pathname.startsWith(item.href)
let isActive = pathname.startsWith(item.href)
if (item.activeMatch) {
isActive = pathname.includes(item.activeMatch)
} else if (item.activeExclude && pathname.includes(item.activeExclude)) {
isActive = false
}
return (
<Link
key={item.name}
href={item.href}
href={item.href as Route}
onClick={() => setIsMobileMenuOpen(false)}
className={cn(
'group flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-all duration-150',