// 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 */}
);
}