Files
MOPC-Portal/src/components/dashboard/smart-actions.tsx
Matt 51e18870b6
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m51s
Admin UI audit round 2: fix 28 display bugs across 23 files
HIGH fixes (broken features / wrong data):
- H1: Fix roundAssignments → projectRoundStates in project router (7 occurrences)
- H2: Fix deliberation results panel blank table (wrong field names)
- H3: Fix deliberation participant names blank (wrong data path)
- H4: Fix awards "Evaluated" stat duplicating "Eligible" count
- H5: Fix cross-round comparison enabled at 1 round (backend requires 2)
- H6: Fix setState during render anti-pattern (6 occurrences)
- H7: Fix round detail jury member count always showing 0
- H8: Remove 4 invalid status values from observer dashboard filter
- H9: Fix filtering progress bar always showing 100%

MEDIUM fixes (misleading display):
- M1: Filter special-award rounds from competition timeline
- M2: Exclude special-award rounds from distinct project count
- M3: Fix MENTORING pipeline node hardcoded "0 mentored"
- M4: Fix DELIB_LOCKED badge using red for success state
- M5: Add status label maps to deliberation session detail
- M6: Humanize deliberation category + tie-break method displays
- M8: Rename setStageId → setRoundId, "Select Stage" → "Select Round"
- M9: Add missing INVITED/ACTIVE/SUSPENDED to members status labels
- M10: Add ROUND_DRAFT/ACTIVE/CLOSED/ARCHIVED to StatusBadge
- M11: Fix unsent messages showing "Scheduled" instead of "Draft"
- M12: Rename misleading totalEvaluations → totalAssignments
- M13: Rename "Stage" column to "Program" in projects page

LOW fixes (cosmetic / edge-case):
- L1: Use unfiltered rounds array for active round detection
- L2: Use all rounds length for new round sort order
- L3: Filter special-award rounds from header count
- L4: Fix single-underscore replace in award status badges
- L5: Fix score bucket boundary gaps (4.99 dropped between buckets)
- L6: Title-case LIVE_FINAL pipeline metric status
- L7: Fix roundType.replace only replacing first underscore
- L8: Remove duplicate severity sort in smart-actions component

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 11:11:00 +01:00

110 lines
3.3 KiB
TypeScript

'use client'
import Link from 'next/link'
import type { Route } from 'next'
import {
Zap,
AlertTriangle,
AlertCircle,
Info,
ChevronRight,
CheckCircle2,
} from 'lucide-react'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Badge } from '@/components/ui/badge'
import { cn } from '@/lib/utils'
export type DashboardAction = {
id: string
severity: 'critical' | 'warning' | 'info'
title: string
description: string
href: string
roundId?: string
roundType?: string
count?: number
}
type SmartActionsProps = {
actions: DashboardAction[]
}
const severityConfig = {
critical: {
icon: AlertTriangle,
iconClass: 'text-red-600',
bgClass: 'bg-red-50 dark:bg-red-950/30',
borderClass: 'border-l-red-500',
},
warning: {
icon: AlertCircle,
iconClass: 'text-amber-600',
bgClass: 'bg-amber-50 dark:bg-amber-950/30',
borderClass: 'border-l-amber-500',
},
info: {
icon: Info,
iconClass: 'text-blue-600',
bgClass: 'bg-blue-50 dark:bg-blue-950/30',
borderClass: 'border-l-blue-500',
},
}
export function SmartActions({ actions }: SmartActionsProps) {
return (
<Card>
<CardHeader className="flex flex-row items-center gap-3 space-y-0 pb-4">
<div className="flex h-9 w-9 items-center justify-center rounded-lg bg-amber-100 dark:bg-amber-900/40">
<Zap className="h-5 w-5 text-amber-600 dark:text-amber-400" />
</div>
<CardTitle className="flex-1">Action Required</CardTitle>
{actions.length > 0 && (
<Badge variant="warning">{actions.length}</Badge>
)}
</CardHeader>
<CardContent>
{actions.length === 0 ? (
<div className="flex flex-col items-center justify-center py-8 text-center">
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-emerald-100 dark:bg-emerald-900/40">
<CheckCircle2 className="h-6 w-6 text-emerald-600 dark:text-emerald-400" />
</div>
<p className="mt-3 text-sm font-medium text-muted-foreground">
All caught up!
</p>
</div>
) : (
<div className="space-y-2">
{actions.map((action) => {
const config = severityConfig[action.severity]
const Icon = config.icon
return (
<Link
key={action.id}
href={action.href as Route}
className={cn(
'flex items-center gap-3 rounded-lg border-l-2 px-3 py-2.5 transition-colors hover:opacity-80',
config.bgClass,
config.borderClass
)}
>
<Icon className={cn('h-4 w-4 shrink-0', config.iconClass)} />
<div className="min-w-0 flex-1">
<p className="text-sm font-medium leading-tight">
{action.title}
</p>
<p className="text-xs text-muted-foreground">
{action.description}
</p>
</div>
<ChevronRight className="h-4 w-4 shrink-0 text-muted-foreground" />
</Link>
)
})}
</div>
)}
</CardContent>
</Card>
)
}