feat: update student import and graduation workflows

This commit is contained in:
2026-04-30 00:04:52 +07:00
parent 189b076ab0
commit ac22f8b7c8
51 changed files with 4547 additions and 1287 deletions
+76
View File
@@ -365,6 +365,82 @@ document.addEventListener('DOMContentLoaded', () => {
confirmText: 'Ya, hapus semua',
});
const bulkUploadInput = document.querySelector('[data-bulk-upload-input]');
const bulkUploadDropzone = document.querySelector('[data-bulk-upload-dropzone]');
const bulkUploadDropzoneInner = document.querySelector('[data-bulk-upload-dropzone-inner]');
const bulkUploadSummary = document.querySelector('[data-bulk-upload-summary]');
const bulkUploadFileList = document.querySelector('[data-bulk-upload-file-list]');
if (bulkUploadInput && bulkUploadDropzone && bulkUploadDropzoneInner) {
const renderBulkUploadFiles = () => {
const files = Array.from(bulkUploadInput.files || []);
if (!bulkUploadSummary || !bulkUploadFileList) {
return;
}
if (files.length === 0) {
bulkUploadSummary.classList.add('hidden');
bulkUploadFileList.classList.add('hidden');
bulkUploadFileList.innerHTML = '';
return;
}
const totalBytes = files.reduce((sum, file) => sum + (file.size || 0), 0);
const totalMb = (totalBytes / (1024 * 1024)).toFixed(2);
bulkUploadSummary.classList.remove('hidden');
bulkUploadSummary.innerHTML = `<div class="font-semibold">${files.length} file siap dipreview</div><div class="mt-1 text-xs text-emerald-700/80">Total ukuran sementara ${totalMb} MB. Batas upload bulk saat ini maksimal 4 MB per file.</div>`;
bulkUploadFileList.classList.remove('hidden');
bulkUploadFileList.innerHTML = `
<div class="mb-3 flex items-center justify-between gap-3">
<div class="text-xs font-semibold uppercase tracking-[0.14em] text-slate-500">File terpilih</div>
<div class="text-xs text-slate-500">Menampilkan ${Math.min(files.length, 8)} dari ${files.length} file</div>
</div>
<div class="space-y-2">
${files.slice(0, 8).map((file) => `
<div class="flex items-center justify-between gap-3 rounded-2xl border border-slate-200 bg-white px-3 py-2 text-xs text-slate-600 shadow-sm ring-1 ring-white/70">
<div class="min-w-0">
<div class="truncate font-semibold text-slate-800">${file.name}</div>
<div class="mt-0.5 text-[11px] text-slate-500">${(file.size / 1024 / 1024).toFixed(2)} MB</div>
</div>
<span class="inline-flex shrink-0 rounded-full bg-indigo-100 px-2.5 py-1 text-[11px] font-semibold text-indigo-700">${(file.name.split('.').pop() || 'FILE').toUpperCase()}</span>
</div>
`).join('')}
${files.length > 8 ? `<div class="rounded-2xl border border-dashed border-slate-200 bg-slate-50 px-3 py-2 text-center text-[11px] font-semibold text-slate-500">+${files.length - 8} file lainnya</div>` : ''}
</div>
`;
};
['dragenter', 'dragover'].forEach((eventName) => {
bulkUploadDropzone.addEventListener(eventName, (event) => {
event.preventDefault();
bulkUploadDropzone.classList.add('border-indigo-400', 'bg-indigo-50/40');
bulkUploadDropzoneInner.classList.add('border-indigo-300', 'bg-indigo-50/50');
});
});
['dragleave', 'drop'].forEach((eventName) => {
bulkUploadDropzone.addEventListener(eventName, (event) => {
event.preventDefault();
bulkUploadDropzone.classList.remove('border-indigo-400', 'bg-indigo-50/40');
bulkUploadDropzoneInner.classList.remove('border-indigo-300', 'bg-indigo-50/50');
});
});
bulkUploadDropzone.addEventListener('drop', (event) => {
const files = event.dataTransfer?.files;
if (files && files.length > 0) {
bulkUploadInput.files = files;
renderBulkUploadFiles();
}
});
bulkUploadInput.addEventListener('change', renderBulkUploadFiles);
renderBulkUploadFiles();
}
const promotionForm = document.querySelector('[data-student-promotion-form]');
if (promotionForm) {