380 lines
24 KiB
PHP
380 lines
24 KiB
PHP
<div class="space-y-6">
|
||
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
|
||
<div>
|
||
<h1 class="text-xl font-semibold">Siswa</h1>
|
||
<p class="text-gray-600 dark:text-gray-400 mt-1">Kelola data siswa.</p>
|
||
</div>
|
||
<button type="button" id="btn-add-student" class="inline-flex items-center gap-2 px-4 py-2.5 rounded-lg bg-primary text-white font-medium hover:bg-primary-hover transition-colors">
|
||
<i class="bx bx-plus text-xl"></i>
|
||
<span>Tambah Siswa</span>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="flex flex-col sm:flex-row gap-4">
|
||
<div class="flex-1">
|
||
<label for="filter-search" class="sr-only">Cari</label>
|
||
<input type="text" id="filter-search" placeholder="Cari nama atau NISN..." class="w-full px-4 py-2.5 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-primary focus:border-transparent">
|
||
</div>
|
||
<div class="w-full sm:w-48">
|
||
<label for="filter-class" class="sr-only">Kelas</label>
|
||
<select id="filter-class" class="w-full px-4 py-2.5 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-primary focus:border-transparent">
|
||
<option value="">Semua kelas</option>
|
||
</select>
|
||
</div>
|
||
<label class="flex items-center gap-2 cursor-pointer self-center whitespace-nowrap">
|
||
<input type="checkbox" id="filter-unmapped" class="rounded border-gray-300 text-primary focus:ring-primary">
|
||
<span class="text-sm text-gray-700 dark:text-gray-300">Hanya unmapped</span>
|
||
</label>
|
||
<div class="flex items-center gap-2 self-center">
|
||
<label for="filter-per-page" class="text-sm text-gray-600 dark:text-gray-400">Per halaman</label>
|
||
<select id="filter-per-page" class="px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 text-sm">
|
||
<option value="20" selected>20</option>
|
||
<option value="50">50</option>
|
||
<option value="100">100</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="students-loading" class="rounded-2xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 p-12 text-center text-gray-500 dark:text-gray-400">Memuat…</div>
|
||
<div id="students-error" class="hidden rounded-2xl border border-red-200 dark:border-red-800 bg-red-50 dark:bg-red-900/20 p-6 text-red-700 dark:text-red-300"></div>
|
||
<div id="students-content" class="hidden rounded-2xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 shadow-sm overflow-hidden">
|
||
<div class="overflow-x-auto">
|
||
<table class="w-full text-left">
|
||
<thead class="bg-gray-50 dark:bg-gray-700/50 text-sm text-gray-600 dark:text-gray-400">
|
||
<tr>
|
||
<th class="px-6 py-3 font-medium">NISN</th>
|
||
<th class="px-6 py-3 font-medium">Nama</th>
|
||
<th class="px-6 py-3 font-medium">JK</th>
|
||
<th class="px-6 py-3 font-medium">Kelas</th>
|
||
<th class="px-6 py-3 font-medium">Status</th>
|
||
<th class="px-6 py-3 font-medium text-right">Aksi</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="students-tbody" class="divide-y divide-gray-200 dark:divide-gray-700"></tbody>
|
||
</table>
|
||
</div>
|
||
<div id="students-pagination" class="flex flex-wrap items-center justify-between gap-4 px-6 py-4 border-t border-gray-200 dark:border-gray-700">
|
||
<p id="pagination-info" class="text-sm text-gray-600 dark:text-gray-400"></p>
|
||
<div id="pagination-buttons" class="flex items-center gap-2"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Add/Edit Modal -->
|
||
<div id="modal-student" class="fixed inset-0 z-50 hidden" aria-hidden="true">
|
||
<div class="fixed inset-0 bg-black/50" id="modal-student-backdrop"></div>
|
||
<div class="fixed inset-0 flex items-center justify-center p-4">
|
||
<div class="relative w-full max-w-md rounded-2xl bg-white dark:bg-gray-800 shadow-xl border border-gray-200 dark:border-gray-700">
|
||
<div class="p-6">
|
||
<h2 id="modal-student-title" class="text-lg font-semibold mb-4">Tambah Siswa</h2>
|
||
<form id="form-student">
|
||
<input type="hidden" id="form-student-id" value="">
|
||
<div class="space-y-4">
|
||
<div>
|
||
<label for="form-student-nisn" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">NISN <span class="text-red-500">*</span></label>
|
||
<input type="text" id="form-student-nisn" name="nisn" required maxlength="50" class="w-full px-4 py-2.5 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-primary focus:border-transparent">
|
||
</div>
|
||
<div>
|
||
<label for="form-student-name" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Nama <span class="text-red-500">*</span></label>
|
||
<input type="text" id="form-student-name" name="name" required maxlength="255" class="w-full px-4 py-2.5 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-primary focus:border-transparent">
|
||
</div>
|
||
<div>
|
||
<label for="form-student-gender" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Jenis Kelamin</label>
|
||
<select id="form-student-gender" name="gender" class="w-full px-4 py-2.5 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-primary focus:border-transparent">
|
||
<option value="">— Pilih —</option>
|
||
<option value="L">Laki-laki</option>
|
||
<option value="P">Perempuan</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label for="form-student-class" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Kelas</label>
|
||
<select id="form-student-class" name="class_id" class="w-full px-4 py-2.5 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-primary focus:border-transparent">
|
||
<option value="">— Tidak ada —</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label class="flex items-center gap-2 cursor-pointer">
|
||
<input type="checkbox" id="form-student-active" name="is_active" value="1" checked class="rounded border-gray-300 text-primary focus:ring-primary">
|
||
<span class="text-sm text-gray-700 dark:text-gray-300">Aktif</span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
<div class="flex gap-3 mt-6">
|
||
<button type="submit" id="form-student-submit" class="flex-1 px-4 py-2.5 rounded-lg bg-primary text-white font-medium hover:bg-primary-hover">Simpan</button>
|
||
<button type="button" id="form-student-cancel" class="px-4 py-2.5 rounded-lg border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700">Batal</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Delete confirmation -->
|
||
<div id="modal-student-delete" class="fixed inset-0 z-50 hidden" aria-hidden="true">
|
||
<div class="fixed inset-0 bg-black/50" id="modal-student-delete-backdrop"></div>
|
||
<div class="fixed inset-0 flex items-center justify-center p-4">
|
||
<div class="relative w-full max-w-sm rounded-2xl bg-white dark:bg-gray-800 shadow-xl border border-gray-200 dark:border-gray-700 p-6">
|
||
<h2 class="text-lg font-semibold mb-2">Hapus Siswa</h2>
|
||
<p id="modal-student-delete-message" class="text-gray-600 dark:text-gray-400 mb-6">Yakin ingin menghapus?</p>
|
||
<div class="flex gap-3">
|
||
<button type="button" id="modal-student-delete-confirm" class="flex-1 px-4 py-2.5 rounded-lg bg-red-600 text-white font-medium hover:bg-red-700">Hapus</button>
|
||
<button type="button" id="modal-student-delete-cancel" class="px-4 py-2.5 rounded-lg border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700">Batal</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="toast-container" class="fixed bottom-6 right-6 z-[60] flex flex-col gap-2 pointer-events-none"></div>
|
||
|
||
<script>
|
||
(function() {
|
||
var baseUrl = '<?= base_url() ?>'.replace(/\/$/, '');
|
||
var apiStudents = baseUrl + '/api/academic/students';
|
||
var apiClasses = baseUrl + '/api/academic/classes';
|
||
|
||
var loading = document.getElementById('students-loading');
|
||
var errorEl = document.getElementById('students-error');
|
||
var content = document.getElementById('students-content');
|
||
var tbody = document.getElementById('students-tbody');
|
||
var filterSearch = document.getElementById('filter-search');
|
||
var filterClass = document.getElementById('filter-class');
|
||
var filterUnmapped = document.getElementById('filter-unmapped');
|
||
var filterPerPage = document.getElementById('filter-per-page');
|
||
var btnAdd = document.getElementById('btn-add-student');
|
||
var paginationInfo = document.getElementById('pagination-info');
|
||
var paginationButtons = document.getElementById('pagination-buttons');
|
||
var currentPage = 1;
|
||
var modal = document.getElementById('modal-student');
|
||
var modalTitle = document.getElementById('modal-student-title');
|
||
var form = document.getElementById('form-student');
|
||
var formId = document.getElementById('form-student-id');
|
||
var formNisn = document.getElementById('form-student-nisn');
|
||
var formName = document.getElementById('form-student-name');
|
||
var formGender = document.getElementById('form-student-gender');
|
||
var formClass = document.getElementById('form-student-class');
|
||
var formActive = document.getElementById('form-student-active');
|
||
var formSubmit = document.getElementById('form-student-submit');
|
||
var formCancel = document.getElementById('form-student-cancel');
|
||
var modalBackdrop = document.getElementById('modal-student-backdrop');
|
||
var modalDelete = document.getElementById('modal-student-delete');
|
||
var modalDeleteMsg = document.getElementById('modal-student-delete-message');
|
||
var modalDeleteConfirm = document.getElementById('modal-student-delete-confirm');
|
||
var modalDeleteCancel = document.getElementById('modal-student-delete-cancel');
|
||
var modalDeleteBackdrop = document.getElementById('modal-student-delete-backdrop');
|
||
var toastContainer = document.getElementById('toast-container');
|
||
var deleteTargetId = null;
|
||
var classesList = [];
|
||
var searchTimeout = null;
|
||
|
||
function showLoading() { loading.classList.remove('hidden'); errorEl.classList.add('hidden'); content.classList.add('hidden'); }
|
||
function showError(msg) { loading.classList.add('hidden'); content.classList.add('hidden'); errorEl.classList.remove('hidden'); errorEl.textContent = msg; }
|
||
function showContent() { loading.classList.add('hidden'); errorEl.classList.add('hidden'); content.classList.remove('hidden'); }
|
||
|
||
function escapeHtml(str) { if (str == null) return ''; var d = document.createElement('div'); d.textContent = str; return d.innerHTML; }
|
||
|
||
function showToast(message, type) {
|
||
type = type || 'success';
|
||
var el = document.createElement('div');
|
||
el.className = 'pointer-events-auto px-4 py-3 rounded-lg shadow-lg text-sm font-medium ' + (type === 'success' ? 'bg-green-600 text-white' : 'bg-red-600 text-white');
|
||
el.textContent = message;
|
||
toastContainer.appendChild(el);
|
||
setTimeout(function() { if (el.parentNode) el.parentNode.removeChild(el); }, 3000);
|
||
}
|
||
|
||
var fetchOpts = { method: 'GET', credentials: 'same-origin', headers: { 'X-Requested-With': 'XMLHttpRequest', 'Accept': 'application/json' } };
|
||
function postOpts(body) { return { method: 'POST', credentials: 'same-origin', headers: { 'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify(body) }; }
|
||
function putOpts(body) { return { method: 'PUT', credentials: 'same-origin', headers: { 'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify(body) }; }
|
||
function deleteOpts() { return { method: 'DELETE', credentials: 'same-origin', headers: { 'X-Requested-With': 'XMLHttpRequest', 'Accept': 'application/json' } }; }
|
||
|
||
function loadClasses(callback) {
|
||
fetch(apiClasses, fetchOpts)
|
||
.then(function(res) { return res.json(); })
|
||
.then(function(r) {
|
||
var list = (r && r.data && r.data.data) ? r.data.data : (Array.isArray(r && r.data) ? r.data : []);
|
||
classesList = list;
|
||
filterClass.innerHTML = '<option value="">Semua kelas</option>';
|
||
formClass.innerHTML = '<option value="">— Tidak ada —</option>';
|
||
list.forEach(function(c) {
|
||
var label = c.full_label || (c.grade + ' ' + (c.major || '') + ' ' + c.name).trim();
|
||
var opt1 = document.createElement('option');
|
||
opt1.value = c.id;
|
||
opt1.textContent = label;
|
||
filterClass.appendChild(opt1);
|
||
var opt2 = document.createElement('option');
|
||
opt2.value = c.id;
|
||
opt2.textContent = label;
|
||
formClass.appendChild(opt2);
|
||
});
|
||
if (callback) callback();
|
||
})
|
||
.catch(function() { if (callback) callback(); });
|
||
}
|
||
|
||
function buildStudentsUrl(page) {
|
||
var p = page != null ? page : currentPage;
|
||
var url = apiStudents;
|
||
var params = [];
|
||
if (filterUnmapped && filterUnmapped.checked) params.push('unmapped_only=1');
|
||
else if (filterClass.value) params.push('class_id=' + encodeURIComponent(filterClass.value));
|
||
if (filterSearch.value.trim()) params.push('search=' + encodeURIComponent(filterSearch.value.trim()));
|
||
params.push('page=' + p);
|
||
params.push('per_page=' + (filterPerPage ? filterPerPage.value : 20));
|
||
url += '?' + params.join('&');
|
||
return url;
|
||
}
|
||
|
||
function renderPagination(meta) {
|
||
if (!paginationInfo || !paginationButtons || !meta) return;
|
||
var total = meta.total || 0;
|
||
var page = meta.page || 1;
|
||
var perPage = meta.per_page || 20;
|
||
var totalPages = meta.total_pages || 0;
|
||
var from = total === 0 ? 0 : (page - 1) * perPage + 1;
|
||
var to = Math.min(page * perPage, total);
|
||
paginationInfo.textContent = 'Menampilkan ' + from + '–' + to + ' dari ' + total + ' siswa';
|
||
paginationButtons.innerHTML = '';
|
||
if (totalPages <= 1) return;
|
||
var prevBtn = document.createElement('button');
|
||
prevBtn.type = 'button';
|
||
prevBtn.className = 'px-3 py-1.5 rounded-lg border border-gray-300 dark:border-gray-600 text-sm font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 disabled:opacity-50 disabled:cursor-not-allowed';
|
||
prevBtn.textContent = 'Sebelumnya';
|
||
prevBtn.disabled = page <= 1;
|
||
prevBtn.addEventListener('click', function() { if (page > 1) { currentPage = page - 1; loadStudents(); } });
|
||
paginationButtons.appendChild(prevBtn);
|
||
var nextBtn = document.createElement('button');
|
||
nextBtn.type = 'button';
|
||
nextBtn.className = 'px-3 py-1.5 rounded-lg border border-gray-300 dark:border-gray-600 text-sm font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 disabled:opacity-50 disabled:cursor-not-allowed';
|
||
nextBtn.textContent = 'Berikutnya';
|
||
nextBtn.disabled = page >= totalPages;
|
||
nextBtn.addEventListener('click', function() { if (page < totalPages) { currentPage = page + 1; loadStudents(); } });
|
||
paginationButtons.appendChild(nextBtn);
|
||
var pageInfo = document.createElement('span');
|
||
pageInfo.className = 'text-sm text-gray-600 dark:text-gray-400 ml-2';
|
||
pageInfo.textContent = 'Halaman ' + page + ' dari ' + totalPages;
|
||
paginationButtons.appendChild(pageInfo);
|
||
}
|
||
|
||
function loadStudents(page) {
|
||
if (page != null) currentPage = page;
|
||
showLoading();
|
||
fetch(buildStudentsUrl(), fetchOpts)
|
||
.then(function(res) { return res.json().then(function(j) { return { ok: res.ok, data: j }; }); })
|
||
.then(function(r) {
|
||
if (!r.ok) { showError(r.data && r.data.message ? r.data.message : 'Gagal memuat'); return; }
|
||
var response = r.data;
|
||
var list = (response && response.data) ? response.data : (Array.isArray(response) ? response : []);
|
||
var meta = (response && response.meta) ? response.meta : null;
|
||
tbody.innerHTML = '';
|
||
list.forEach(function(row) {
|
||
var tr = document.createElement('tr');
|
||
tr.className = 'hover:bg-gray-50 dark:hover:bg-gray-700/30';
|
||
var genderText = row.gender === 'L' ? 'L' : row.gender === 'P' ? 'P' : '–';
|
||
var classCell = row.class_id == null
|
||
? '<span class="inline-flex px-2 py-0.5 rounded text-xs font-medium bg-amber-100 text-amber-800 dark:bg-amber-900/40 dark:text-amber-300">UNMAPPED</span>'
|
||
: (row.class_label ? escapeHtml(row.class_label) : '–');
|
||
var status = row.is_active ? 'Aktif' : 'Nonaktif';
|
||
var statusClass = row.is_active ? 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400' : 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-400';
|
||
tr.innerHTML =
|
||
'<td class="px-6 py-3 font-medium">' + escapeHtml(row.nisn) + '</td>' +
|
||
'<td class="px-6 py-3">' + escapeHtml(row.name) + '</td>' +
|
||
'<td class="px-6 py-3 text-gray-600 dark:text-gray-400">' + genderText + '</td>' +
|
||
'<td class="px-6 py-3 text-gray-600 dark:text-gray-400">' + classCell + '</td>' +
|
||
'<td class="px-6 py-3"><span class="inline-flex px-2.5 py-0.5 rounded-full text-xs font-medium ' + statusClass + '">' + status + '</span></td>' +
|
||
'<td class="px-6 py-3 text-right">' +
|
||
'<button type="button" class="btn-edit px-3 py-1.5 rounded-lg text-primary hover:bg-primary/10" data-id="' + row.id + '" data-nisn="' + escapeHtml(row.nisn) + '" data-name="' + escapeHtml(row.name) + '" data-gender="' + (row.gender || '') + '" data-class-id="' + (row.class_id || '') + '" data-active="' + (row.is_active ? '1' : '0') + '">Edit</button> ' +
|
||
'<button type="button" class="btn-delete px-3 py-1.5 rounded-lg text-red-600 hover:bg-red-50 dark:hover:bg-red-900/20" data-id="' + row.id + '" data-name="' + escapeHtml(row.name) + '">Hapus</button>' +
|
||
'</td>';
|
||
tbody.appendChild(tr);
|
||
});
|
||
tbody.querySelectorAll('.btn-edit').forEach(function(btn) {
|
||
btn.addEventListener('click', function() {
|
||
formId.value = btn.getAttribute('data-id');
|
||
formNisn.value = btn.getAttribute('data-nisn') || '';
|
||
formName.value = btn.getAttribute('data-name') || '';
|
||
formGender.value = btn.getAttribute('data-gender') || '';
|
||
formClass.value = btn.getAttribute('data-class-id') || '';
|
||
formActive.checked = btn.getAttribute('data-active') === '1';
|
||
modalTitle.textContent = 'Edit Siswa';
|
||
modal.classList.remove('hidden');
|
||
});
|
||
});
|
||
tbody.querySelectorAll('.btn-delete').forEach(function(btn) {
|
||
btn.addEventListener('click', function() {
|
||
deleteTargetId = parseInt(btn.getAttribute('data-id'), 10);
|
||
modalDeleteMsg.textContent = 'Yakin ingin menghapus "' + (btn.getAttribute('data-name') || '') + '"?';
|
||
modalDelete.classList.remove('hidden');
|
||
});
|
||
});
|
||
renderPagination(meta);
|
||
showContent();
|
||
})
|
||
.catch(function() { showError('Gagal memuat data'); });
|
||
}
|
||
|
||
filterClass.addEventListener('change', function() { currentPage = 1; loadStudents(); });
|
||
if (filterUnmapped) filterUnmapped.addEventListener('change', function() { currentPage = 1; loadStudents(); });
|
||
if (filterPerPage) filterPerPage.addEventListener('change', function() { currentPage = 1; loadStudents(); });
|
||
filterSearch.addEventListener('input', function() {
|
||
if (searchTimeout) clearTimeout(searchTimeout);
|
||
searchTimeout = setTimeout(function() { currentPage = 1; loadStudents(); }, 300);
|
||
});
|
||
|
||
btnAdd.addEventListener('click', function() {
|
||
formId.value = ''; formNisn.value = ''; formName.value = ''; formGender.value = ''; formClass.value = '';
|
||
formActive.checked = true;
|
||
modalTitle.textContent = 'Tambah Siswa';
|
||
modal.classList.remove('hidden');
|
||
});
|
||
|
||
form.addEventListener('submit', function(e) {
|
||
e.preventDefault();
|
||
var id = formId.value ? parseInt(formId.value, 10) : null;
|
||
var payload = {
|
||
nisn: formNisn.value.trim(),
|
||
name: formName.value.trim(),
|
||
gender: formGender.value || null,
|
||
class_id: formClass.value ? parseInt(formClass.value, 10) : null,
|
||
is_active: formActive.checked ? 1 : 0
|
||
};
|
||
formSubmit.disabled = true;
|
||
var url = apiStudents;
|
||
var opts = postOpts(payload);
|
||
if (id) { url = apiStudents + '/' + id; opts = putOpts(payload); }
|
||
fetch(url, opts)
|
||
.then(function(res) { return res.json().then(function(j) { return { ok: res.ok, data: j }; }); })
|
||
.then(function(r) {
|
||
formSubmit.disabled = false;
|
||
if (!r.ok) { showToast(r.data && r.data.message ? r.data.message : 'Gagal menyimpan', 'error'); return; }
|
||
showToast(id ? 'Berhasil diubah' : 'Berhasil ditambahkan');
|
||
modal.classList.add('hidden');
|
||
loadStudents();
|
||
})
|
||
.catch(function() { formSubmit.disabled = false; showToast('Gagal menyimpan', 'error'); });
|
||
});
|
||
|
||
formCancel.addEventListener('click', function() { modal.classList.add('hidden'); });
|
||
modalBackdrop.addEventListener('click', function() { modal.classList.add('hidden'); });
|
||
|
||
modalDeleteConfirm.addEventListener('click', function() {
|
||
if (!deleteTargetId) return;
|
||
var id = deleteTargetId;
|
||
modalDeleteConfirm.disabled = true;
|
||
fetch(apiStudents + '/' + id, deleteOpts())
|
||
.then(function(res) { return res.json().then(function(j) { return { ok: res.ok, data: j }; }); })
|
||
.then(function(r) {
|
||
modalDeleteConfirm.disabled = false;
|
||
if (!r.ok) { showToast(r.data && r.data.message ? r.data.message : 'Gagal menghapus', 'error'); return; }
|
||
showToast('Berhasil dihapus');
|
||
modalDelete.classList.add('hidden');
|
||
deleteTargetId = null;
|
||
loadStudents();
|
||
})
|
||
.catch(function() { modalDeleteConfirm.disabled = false; showToast('Gagal menghapus', 'error'); });
|
||
});
|
||
modalDeleteCancel.addEventListener('click', function() { modalDelete.classList.add('hidden'); deleteTargetId = null; });
|
||
modalDeleteBackdrop.addEventListener('click', function() { modalDelete.classList.add('hidden'); deleteTargetId = null; });
|
||
|
||
loadClasses(function() { loadStudents(); });
|
||
})();
|
||
</script>
|