import { useState } from "react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Plus, FileSpreadsheet, CheckCircle2, Loader2 } from "lucide-react"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { institutionalExamService } from "@/services/institutional-exam.service"; import { useToast } from "@/hooks/use-toast"; import type { ResultTemplate, Marksheet, MarksheetLine, GradeConfig } from "@/types/institutional-exam"; const marksheetStateBadge: Record = { draft: "outline", validated: "default", cancelled: "destructive", }; export default function MarksheetManager() { const { toast } = useToast(); const qc = useQueryClient(); const [activeTab, setActiveTab] = useState<"templates" | "marksheets">("templates"); const [showCreateTemplate, setShowCreateTemplate] = useState(false); const [selectedMarksheetId, setSelectedMarksheetId] = useState(null); const { data: templatesData, isLoading: loadingTemplates } = useQuery({ queryKey: ["result-templates", "list"], queryFn: () => institutionalExamService.listResultTemplates(), }); const templates = templatesData?.items ?? []; const { data: marksheetsData, isLoading: loadingMarksheets } = useQuery({ queryKey: ["marksheets", "list"], queryFn: () => institutionalExamService.listMarksheets(), enabled: activeTab === "marksheets", }); const marksheets = marksheetsData?.items ?? []; const { data: selectedMarksheet } = useQuery({ queryKey: ["marksheets", selectedMarksheetId], queryFn: () => institutionalExamService.getMarksheet(selectedMarksheetId!), enabled: !!selectedMarksheetId, }); const { data: sessionsData } = useQuery({ queryKey: ["inst-exam-sessions", "list"], queryFn: () => institutionalExamService.listSessions(), }); const sessions = sessionsData?.items ?? []; const { data: gradeConfigsData } = useQuery({ queryKey: ["grade-configs", "list"], queryFn: () => institutionalExamService.listGradeConfigs(), }); const gradeConfigs = gradeConfigsData?.items ?? []; const [templateForm, setTemplateForm] = useState({ name: "", exam_session_id: 0, grade_ids: [] as number[], }); const createTemplateMutation = useMutation({ mutationFn: () => institutionalExamService.createResultTemplate(templateForm as Parameters[0]), onSuccess: () => { qc.invalidateQueries({ queryKey: ["result-templates"] }); toast({ title: "Template created" }); setShowCreateTemplate(false); setTemplateForm({ name: "", exam_session_id: 0, grade_ids: [] }); }, onError: () => toast({ title: "Error", description: "Failed to create template", variant: "destructive" }), }); const generateMutation = useMutation({ mutationFn: (templateId: number) => institutionalExamService.generateMarksheets(templateId), onSuccess: () => { qc.invalidateQueries({ queryKey: ["marksheets"] }); qc.invalidateQueries({ queryKey: ["result-templates"] }); toast({ title: "Marksheets generated" }); }, onError: () => toast({ title: "Error", description: "Generation failed", variant: "destructive" }), }); const validateMutation = useMutation({ mutationFn: (id: number) => institutionalExamService.validateMarksheet(id), onSuccess: () => { qc.invalidateQueries({ queryKey: ["marksheets"] }); toast({ title: "Marksheet validated" }); }, onError: () => toast({ title: "Error", description: "Validation failed", variant: "destructive" }), }); const isLoading = activeTab === "templates" ? loadingTemplates : loadingMarksheets; if (isLoading) return
; return (

Marksheet Manager

Manage result templates and marksheets.

{activeTab === "templates" && ( Result Templates Create Result Template
setTemplateForm({ ...templateForm, name: e.target.value })} />
{gradeConfigs.map((gc: GradeConfig) => ( ))} {gradeConfigs.length === 0 &&

No grade configs available.

}
Name Exam Session Evaluation Result Date State Actions {templates.map((tpl: ResultTemplate) => ( {tpl.name} {tpl.exam_session_name} {tpl.evaluation_type} {tpl.result_date} {tpl.state.replace("_", " ")} {tpl.state === "draft" && ( )} ))} {templates.length === 0 && ( No result templates found. )}
)} {activeTab === "marksheets" && (
Name Exam Session Generated Pass Fail State Actions {marksheets.map((ms: Marksheet) => ( setSelectedMarksheetId(selectedMarksheetId === ms.id ? null : ms.id)} > {ms.name} {ms.exam_session_name} {ms.generated_date} by {ms.generated_by_name} {ms.total_pass} {ms.total_failed} {ms.state} e.stopPropagation()}> {ms.state === "draft" && ( )} ))} {marksheets.length === 0 && ( No marksheets found. )}
{selectedMarksheet && ( Results — {selectedMarksheet.name} Student Total Marks Percentage Grade Status {(selectedMarksheet.lines ?? []).map((line: MarksheetLine) => ( {line.student_name} {line.total_marks} {line.percentage.toFixed(1)}% {line.grade ?? "—"} {line.status} ))} {(selectedMarksheet.lines ?? []).length === 0 && ( No results in this marksheet. )}
)}
)}
); }