"use client" import { useState } from "react" import { useRouter } from "next/navigation" import { MoreHorizontal, Eye, Pencil, Trash, Archive, UploadCloud, Undo2, Copy } from "lucide-react" import { toast } from "sonner" import { Button } from "@/shared/components/ui/button" import { ScrollArea } from "@/shared/components/ui/scroll-area" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/shared/components/ui/dropdown-menu" import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/shared/components/ui/alert-dialog" import { Dialog, DialogContent, DialogTitle, } from "@/shared/components/ui/dialog" import { deleteExamAction, duplicateExamAction, updateExamAction, getExamPreviewAction } from "../actions" import { Exam } from "../types" import { ExamPaperPreview } from "./assembly/exam-paper-preview" import type { ExamNode } from "./assembly/selected-question-list" import type { Question } from "@/modules/questions/types" interface ExamActionsProps { exam: Exam } export function ExamActions({ exam }: ExamActionsProps) { const router = useRouter() const [showViewDialog, setShowViewDialog] = useState(false) const [showDeleteDialog, setShowDeleteDialog] = useState(false) const [isWorking, setIsWorking] = useState(false) const [previewNodes, setPreviewNodes] = useState(null) const [loadingPreview, setLoadingPreview] = useState(false) const handleView = async () => { setLoadingPreview(true) setShowViewDialog(true) try { const result = await getExamPreviewAction(exam.id) if (result.success && result.data) { const { structure, questions } = result.data const questionById = new Map() for (const q of questions) questionById.set(q.id, q as unknown as Question) // eslint-disable-next-line @typescript-eslint/no-explicit-any const hydrate = (nodes: any[]): ExamNode[] => { return nodes.map((node) => { if (node.type === "question") { const q = node.questionId ? questionById.get(node.questionId) : undefined return { ...node, question: q } } if (node.type === "group") { return { ...node, children: hydrate(node.children || []) } } return node }) } const nodes = Array.isArray(structure) ? hydrate(structure) : [] setPreviewNodes(nodes) } else { toast.error("Failed to load exam preview") setShowViewDialog(false) } } catch (e) { toast.error("Failed to load exam preview") setShowViewDialog(false) } finally { setLoadingPreview(false) } } const copyId = () => { navigator.clipboard.writeText(exam.id) toast.success("Exam ID copied to clipboard") } const setStatus = async (status: Exam["status"]) => { setIsWorking(true) try { const formData = new FormData() formData.set("examId", exam.id) formData.set("status", status) const result = await updateExamAction(null, formData) if (result.success) { toast.success(status === "published" ? "Exam published" : status === "archived" ? "Exam archived" : "Exam moved to draft") router.refresh() } else { toast.error(result.message || "Failed to update exam") } } catch { toast.error("Failed to update exam") } finally { setIsWorking(false) } } const duplicateExam = async () => { setIsWorking(true) try { const formData = new FormData() formData.set("examId", exam.id) const result = await duplicateExamAction(null, formData) if (result.success && result.data) { toast.success("Exam duplicated") router.push(`/teacher/exams/${result.data}/build`) router.refresh() } else { toast.error(result.message || "Failed to duplicate exam") } } catch { toast.error("Failed to duplicate exam") } finally { setIsWorking(false) } } const handleDelete = async () => { setIsWorking(true) try { const formData = new FormData() formData.set("examId", exam.id) const result = await deleteExamAction(null, formData) if (result.success) { toast.success("Exam deleted successfully") setShowDeleteDialog(false) router.refresh() } else { toast.error(result.message || "Failed to delete exam") } } catch { toast.error("Failed to delete exam") } finally { setIsWorking(false) } } return ( <>
Actions Copy ID router.push(`/teacher/exams/${exam.id}/build`)}> Edit router.push(`/teacher/exams/${exam.id}/build`)}> Build Duplicate setStatus("published")} disabled={isWorking || exam.status === "published"} > Publish setStatus("draft")} disabled={isWorking || exam.status === "draft"} > Move to Draft setStatus("archived")} disabled={isWorking || exam.status === "archived"} > Archive setShowDeleteDialog(true)} disabled={isWorking} > Delete
Are you absolutely sure? This action cannot be undone. This will permanently delete the exam "{exam.title}" and remove all associated data. Cancel { e.preventDefault() handleDelete() }} disabled={isWorking} > Delete
{exam.title}
{loadingPreview ? (
Loading preview...
) : previewNodes && previewNodes.length > 0 ? (
) : (
No questions in this exam.
)}
) }