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:
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user