(() => {
const { Card, Badge, Button, Icon, Avatar, Input, Select, Field, StatusPill, Checkbox, Modal, Textarea } = window.TaskFlowDesignSystem_dd53c2;
/* Document — arsip dokumen yang sudah diterima (accepted) atau sudah ditandatangani.
Admin melihat seluruh dokumen; user hanya dokumen dari task miliknya sendiri.
Server WAJIB memfilter ulang per user_id (cegah IDOR pada endpoint download). */
const CATS = ["Semua Kategori", "Dokumen", "Operasional", "Kepegawaian", "Kegiatan", "Sarana & Prasarana", "Keuangan"];
const KINDS = ["Semua Dokumen", "Sudah di-TTD", "Tanpa TTD"];
const PAGE = 20;
function docsFrom(tasks, userId) {
const out = [];
tasks.forEach((t) => {
if (t.status !== "done") return; // hanya task yang sudah diterima
if (userId != null && userId !== 0 && t.user !== userId) return;
const files = t.evidences && t.evidences.length ? t.evidences : t.evidence ? [t.evidence] : [];
files.forEach((f, i) => out.push({
key: t.id + "-" + i, task: t, file: f, signed: !!(t.needSign && t.signature),
round: t.versions && t.versions.length ? t.versions.length + 1 : 1,
}));
});
return out;
}
function DocumentScreen({ tasks, userId, onView, onViewSignature, onTimeline, onSign, onDelete }) {
const [q, setQ] = React.useState("");
const [cat, setCat] = React.useState(CATS[0]);
const [kind, setKind] = React.useState(KINDS[0]);
const [shown, setShown] = React.useState(PAGE);
const [sel, setSel] = React.useState([]);
const [zipping, setZipping] = React.useState(false);
const [note, setNote] = React.useState("");
/* Hapus dokumen final — hanya Direktur, wajib beralasan, task dikembalikan ke Need Revision
agar user mengunggah dokumen pengganti (jejaknya tetap di Log Activity). */
const [del, setDel] = React.useState(null);
const [delReason, setDelReason] = React.useState("");
const [delErr, setDelErr] = React.useState("");
const isAdmin = userId == null || userId === 0;
const all = React.useMemo(() => docsFrom(tasks, userId), [tasks, userId]);
const rows = React.useMemo(() => all.filter((d) => {
const s = q.trim().toLowerCase();
if (s && !(d.file.name.toLowerCase().includes(s) || d.task.type.toLowerCase().includes(s) || nameOf(d.task.user).toLowerCase().includes(s))) return false;
if (cat !== CATS[0] && d.task.category !== cat) return false;
if (kind === KINDS[1] && !d.signed) return false;
if (kind === KINDS[2] && d.signed) return false;
return true;
}), [all, q, cat, kind]);
const page = rows.slice(0, shown);
const fmtKb = (n) => `${Math.max(1, Math.round(n / 1024))} KB`;
const toggle = (k) => setSel((s) => (s.includes(k) ? s.filter((x) => x !== k) : [...s, k]));
/* Bulk ZIP: byte asli dipakai bila ada; dokumen contoh tanpa byte diberi berkas
keterangan agar arsip tetap konsisten. Diproses berurutan supaya memori stabil. */
const downloadZip = async () => {
const picked = rows.filter((r) => sel.includes(r.key));
if (!picked.length || !window.makeZip) return;
setZipping(true);
try {
const files = [];
for (const p of picked) {
const bytes = await window.fileBytes(p.file);
const base = (p.signed ? p.file.name.replace(/\.pdf$/i, "") + "-ttd.pdf" : p.file.name);
files.push(bytes
? { name: base, data: bytes }
: { name: base.replace(/\.[a-z0-9]+$/i, "") + ".txt", data: `${p.file.name}\nTask: ${p.task.type}\nUser: ${nameOf(p.task.user)}\nKategori: ${p.task.category}\nDiterima: ${p.task.done}\nTTD: ${p.signed ? "ya" : "tidak"}\n` });
}
window.saveBlob(window.makeZip(files), `arsip-dokumen-${files.length}-berkas.zip`);
setNote(`${files.length} dokumen diunduh sebagai ZIP.`);
setSel([]);
} finally { setZipping(false); }
};
// Dokumen ber-TTD diunduh dengan tanda tangan menyatu di halamannya.
const dl = (d) => {
if (d.signed && d.file.url && window.downloadSigned) {
return window.downloadSigned(d.file, DB.signature, d.task.signature, d.file.name.replace(/(\.[a-z0-9]+)?$/i, "-ttd$1"));
}
if (d.file.url && window.downloadSigned) return window.downloadSigned(d.file, null, null, d.file.name);
return window.downloadEvidence && window.downloadEvidence(
d.signed
? { name: d.file.name.replace(/\.pdf$/i, "") + "-ttd.pdf", size: d.file.size || 480000, compressed: d.file.compressed || 420000 }
: d.file,
d.task.type + (d.signed ? " · sudah ditandatangani Direktur" : " · dokumen final"));
};
const stat = (label, value, tone) => (