All checks were successful
Build and Push Docker Image / build (push) Successful in 8m18s
Complete rewrite of the admin dashboard replacing the 1056-line monolith with modular components. Key improvements: - Competition pipeline: horizontal visualization of all rounds in pipeline order (by sortOrder, not creation date) with type-specific icons and metrics - Round-specific stats: stat cards dynamically change based on active round type (INTAKE shows submissions/docs, FILTERING shows pass/fail/flagged, EVALUATION shows assignments/completion, fallback shows generic project/jury stats) - Smart actions: context-aware "Action Required" panel that only flags the next draft round (not all), only flags unassigned projects for EVALUATION rounds, includes deadline warnings with severity levels (critical/warning/info) - Active round panel: detailed view with project state bar, type-specific content, and deadline countdown - Extracted components: project list, activity feed, category breakdown, skeleton Backend enriched with 17 parallel queries building rich PipelineRound data including per-round project states, eval stats, filtering stats, live session status, and deliberation counts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
79 lines
2.5 KiB
TypeScript
79 lines
2.5 KiB
TypeScript
'use client'
|
|
|
|
import { Card, CardContent, CardHeader } from '@/components/ui/card'
|
|
import { Skeleton } from '@/components/ui/skeleton'
|
|
|
|
export function DashboardSkeleton() {
|
|
return (
|
|
<>
|
|
{/* Header skeleton */}
|
|
<Skeleton className="h-32 w-full rounded-2xl" />
|
|
|
|
{/* Stats row skeleton */}
|
|
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-5">
|
|
{[...Array(5)].map((_, i) => (
|
|
<Card key={i} className="border-l-4 border-l-muted">
|
|
<CardContent className="p-4">
|
|
<Skeleton className="h-4 w-16" />
|
|
<Skeleton className="mt-2 h-8 w-12" />
|
|
<Skeleton className="mt-1 h-3 w-20" />
|
|
</CardContent>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
|
|
{/* Two-column content skeleton */}
|
|
<div className="grid gap-6 lg:grid-cols-12">
|
|
<div className="space-y-6 lg:col-span-8">
|
|
<Card>
|
|
<CardHeader>
|
|
<Skeleton className="h-5 w-32" />
|
|
<Skeleton className="h-3 w-48" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-3">
|
|
{[...Array(3)].map((_, i) => (
|
|
<Skeleton key={i} className="h-24 w-full rounded-xl" />
|
|
))}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
<Card>
|
|
<CardHeader>
|
|
<Skeleton className="h-5 w-40" />
|
|
<Skeleton className="h-3 w-32" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-2">
|
|
{[...Array(5)].map((_, i) => (
|
|
<Skeleton key={i} className="h-14 w-full" />
|
|
))}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
<div className="space-y-6 lg:col-span-4">
|
|
{[...Array(4)].map((_, i) => (
|
|
<Card key={i}>
|
|
<CardHeader><Skeleton className="h-5 w-32" /></CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-3">
|
|
{[...Array(3)].map((_, j) => (
|
|
<Skeleton key={j} className="h-10 w-full" />
|
|
))}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Bottom skeleton */}
|
|
<div className="grid gap-6 lg:grid-cols-12">
|
|
<Skeleton className="h-[400px] w-full rounded-lg lg:col-span-8" />
|
|
<Skeleton className="h-[400px] w-full rounded-lg lg:col-span-4" />
|
|
</div>
|
|
</>
|
|
)
|
|
}
|