'use client'
import { useState } from 'react'
import Link from 'next/link'
import { trpc } from '@/lib/trpc/client'
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from '@/components/ui/card'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import { Progress } from '@/components/ui/progress'
import { Skeleton } from '@/components/ui/skeleton'
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table'
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
import {
FileSpreadsheet,
Download,
BarChart3,
Users,
ClipboardList,
CheckCircle2,
PieChart,
TrendingUp,
} from 'lucide-react'
import { formatDateOnly } from '@/lib/utils'
import {
ScoreDistributionChart,
EvaluationTimelineChart,
StatusBreakdownChart,
JurorWorkloadChart,
ProjectRankingsChart,
CriteriaScoresChart,
GeographicDistribution,
} from '@/components/charts'
function ReportsOverview() {
const { data: programs, isLoading } = trpc.program.list.useQuery({ includeRounds: true })
// Flatten rounds from all programs
const rounds = programs?.flatMap(p => p.rounds.map(r => ({ ...r, programId: p.id, programName: `${p.year} Edition` }))) || []
if (isLoading) {
return (
{[...Array(4)].map((_, i) => (
))}
)
}
if (!rounds || rounds.length === 0) {
return (
No data to report
Create rounds and assign jury members to generate reports
)
}
// Calculate totals
const totalProjects = programs?.reduce((acc, p) => acc + (p._count?.rounds || 0), 0) || 0
const totalPrograms = programs?.length || 0
const activeRounds = rounds.filter((r) => r.status === 'ACTIVE').length
return (
{/* Quick Stats */}
Total Rounds
{rounds.length}
{activeRounds} active
Total Projects
{totalProjects}
Across all rounds
Active Rounds
{activeRounds}
Currently active
Programs
{totalPrograms}
Total programs
{/* Rounds Table */}
Round Reports
View progress and export data for each round
Round
Program
Projects
Status
Export
{rounds.map((round) => (
{round.name}
{round.votingEndAt && (
Ends: {formatDateOnly(round.votingEndAt)}
)}
{round.programName}
-
{round.status}
))}
)
}
function RoundAnalytics() {
const [selectedRoundId, setSelectedRoundId] = useState(null)
const { data: programs, isLoading: roundsLoading } = trpc.program.list.useQuery({ includeRounds: true })
// Flatten rounds from all programs with program name
const rounds = programs?.flatMap(p => p.rounds.map(r => ({ ...r, programName: `${p.year} Edition` }))) || []
// Set default selected round
if (rounds.length && !selectedRoundId) {
setSelectedRoundId(rounds[0].id)
}
const { data: scoreDistribution, isLoading: scoreLoading } =
trpc.analytics.getScoreDistribution.useQuery(
{ roundId: selectedRoundId! },
{ enabled: !!selectedRoundId }
)
const { data: timeline, isLoading: timelineLoading } =
trpc.analytics.getEvaluationTimeline.useQuery(
{ roundId: selectedRoundId! },
{ enabled: !!selectedRoundId }
)
const { data: statusBreakdown, isLoading: statusLoading } =
trpc.analytics.getStatusBreakdown.useQuery(
{ roundId: selectedRoundId! },
{ enabled: !!selectedRoundId }
)
const { data: jurorWorkload, isLoading: workloadLoading } =
trpc.analytics.getJurorWorkload.useQuery(
{ roundId: selectedRoundId! },
{ enabled: !!selectedRoundId }
)
const { data: projectRankings, isLoading: rankingsLoading } =
trpc.analytics.getProjectRankings.useQuery(
{ roundId: selectedRoundId!, limit: 15 },
{ enabled: !!selectedRoundId }
)
const { data: criteriaScores, isLoading: criteriaLoading } =
trpc.analytics.getCriteriaScores.useQuery(
{ roundId: selectedRoundId! },
{ enabled: !!selectedRoundId }
)
const selectedRound = rounds.find((r) => r.id === selectedRoundId)
const { data: geoData, isLoading: geoLoading } =
trpc.analytics.getGeographicDistribution.useQuery(
{ programId: selectedRound?.programId || '', roundId: selectedRoundId! },
{ enabled: !!selectedRoundId && !!selectedRound?.programId }
)
if (roundsLoading) {
return (
)
}
if (!rounds?.length) {
return (
No rounds available
Create a round to view analytics
)
}
return (
{/* Round Selector */}
{selectedRoundId && (
{/* Row 1: Score Distribution & Status Breakdown */}
{scoreLoading ? (
) : scoreDistribution ? (
) : null}
{statusLoading ? (
) : statusBreakdown ? (
) : null}
{/* Row 2: Evaluation Timeline */}
{timelineLoading ? (
) : timeline?.length ? (
) : (
No evaluation data available yet
)}
{/* Row 3: Criteria Scores */}
{criteriaLoading ? (
) : criteriaScores?.length ? (
) : null}
{/* Row 4: Juror Workload */}
{workloadLoading ? (
) : jurorWorkload?.length ? (
) : (
No juror assignments yet
)}
{/* Row 5: Project Rankings */}
{rankingsLoading ? (
) : projectRankings?.length ? (
) : (
No project scores available yet
)}
{/* Row 6: Geographic Distribution */}
{geoLoading ? (
) : geoData?.length ? (
) : null}
)}
)
}
export default function ReportsPage() {
return (
{/* Header */}
Reports
View progress, analytics, and export evaluation data
{/* Tabs */}
Overview
Analytics
)
}