// src/pages/mentor/EligibleInternTable.tsx import { useState } from "react"; import { useNavigate } from "react-router-dom"; import { CheckCircle2, AlertCircle, Eye, ChevronLeft, ChevronRight, Sparkles, Check, Loader2 } from "lucide-react"; import type { InternSubmissionProgress } from "../../../../hooks/useInternProgress"; import JSZip from "jszip"; import { generateCertificate, resolveImageUrl } from "../../../utils/SertificateGenerator"; import { useGenerateCertificates } from "../../../../hooks/useCertificates"; import Avatar from "../../Avatar"; import ProgressBar from "../../ProgressBar"; import { customToast } from "../../../utils/showToast"; import type { Project } from "../../../../types/project.types"; interface EligibleInternTableProps { interns: InternSubmissionProgress[]; loading: boolean; eligibleCount: number; project: Project } const PER_PAGE = 5; function StatusBadge({ status }: { status: boolean }) { return (
{status ? : } {status ? "Eligible" : "Incomplete"}
); } // Main Component export default function EligibleInternTable({ interns, loading, eligibleCount, project // Durasi tanggal Proyek }: EligibleInternTableProps) { const navigate = useNavigate(); // const { project } = useProjectDetail(String(projectId)); const { generate: SubmitCertificates } = useGenerateCertificates(); const initialSelected = new Set( interns.filter(i => i.is_eligible).map(i => i.id_user) ); const [selected, setSelected] = useState>(initialSelected); const [generating, setGenerating] = useState(false); const [generateError, setGenerateError] = useState(null); const [page, setPage] = useState(1); const totalPages = Math.ceil(interns.length / PER_PAGE); const paginated = interns.slice((page - 1) * PER_PAGE, page * PER_PAGE); const eligibleIds = interns.filter(i => i.is_eligible).map(i => i.id_user); const allEligibleSelected = eligibleIds.every(id => selected.has(id)); const toggleSelectAll = () => { setSelected(allEligibleSelected ? new Set() : new Set(eligibleIds)); }; const toggleOne = (id: number, isEligible: boolean) => { if (!isEligible) return; setSelected((prev) => { const next = new Set(prev); next.has(id) ? next.delete(id) : next.add(id); return next; }); }; const handleGenerate = async () => { if (!project?.certificate_template) { customToast.error("Template belum ada", "Template sertifikat belum diupload."); return; } if (selected.size === 0) { customToast.error("Tidak ada intern dipilih", "Pilih minimal satu intern untuk generate sertifikat."); return; } setGenerating(true); setGenerateError(null); const ok = await customToast.promise( (async () => { const result = await SubmitCertificates(project.id, Array.from(selected)); if (!result) throw new Error("Tidak ada data sertifikat yang dikembalikan."); const zip = new JSZip(); const templateUrl = resolveImageUrl(project.certificate_template!); await Promise.all( result.map(async (cert) => { const verifyUrl = `${window.location.origin}/verify-certificate/${cert.uuid}`; const blob = await generateCertificate( templateUrl, cert.user.full_name, cert.project.project_name, cert.certificate_no, verifyUrl, "20 Juni 2024 - 20 September 2024" ); zip.file(`Sertifikat - ${cert.user.full_name}.png`, blob); }) ); })(), { loading: "Generating sertifikat...", success: () => ({ title: "Sertifikat berhasil dibuat", description: `${selected.size} sertifikat berhasil digenerate.`, }), error: (err) => ({ title: "Gagal generate sertifikat", description: err instanceof Error ? err.message : "Terjadi kesalahan, coba lagi.", }), } ).then(() => true).catch(() => false); setGenerating(false); if (ok) navigate(`/mentor/certificates/${project.id}/result`); }; if (loading) { return (
Memuat data intern...
); } return (
{/* Roster Card */}

Intern Roster

Confirm completion status before final certificate generation.

{/* Column Headers */}
Intern Name Task Progress Status Action
{/* Rows */}
{paginated.map((intern) => { const isChecked = selected.has(intern.id_user); const isIncomplete = !intern.is_eligible; const initials = intern.full_name .split(" ") .slice(0, 2) .map(n => n[0]) .join("") .toUpperCase(); return (
{/* Checkbox */} {/* Name + role */}
{intern.avatar ? ( ) : ( )}

{intern.full_name}

{intern.email}

{/* Task Progress */}
{/* Status */}
{/* Action */}
{isIncomplete ? ( ) : ( )}
); })}
{/* Pagination Footer */}

Showing {(page - 1) * PER_PAGE + 1} to {Math.min(page * PER_PAGE, interns.length)} of {interns.length} entries

{Array.from({ length: totalPages }, (_, i) => i + 1).map((n) => ( ))}
{generateError && (

{generateError}

)} {/* Bottom Action Bar */}
); }