34627-vm/assets/js/main.js
Flatlogic Bot 2be5f009ee dua
2025-10-03 14:19:02 +00:00

264 lines
10 KiB
JavaScript

document.addEventListener('DOMContentLoaded', function () {
// --- Constants ---
const API_BASE = 'api/';
const addAssetForm = document.getElementById('addAssetForm');
const editAssetForm = document.getElementById('editAssetForm');
const assetsTableBody = document.getElementById('assets-table-body');
const loadingIndicator = document.getElementById('loading-indicator');
const notificationToastEl = document.getElementById('notificationToast');
const notificationToast = new bootstrap.Toast(notificationToastEl);
const editAssetModalEl = document.getElementById('editAssetModal');
const editAssetModal = new bootstrap.Modal(editAssetModalEl);
// --- Functions ---
/**
* Shows a toast notification.
* @param {string} title - The title of the toast.
* @param {string} body - The body message of the toast.
* @param {string} type - 'success' or 'error'.
*/
function showToast(title, body, type = 'success') {
const toastHeader = notificationToastEl.querySelector('.toast-header');
toastHeader.classList.remove('bg-success', 'text-white', 'bg-danger', 'text-white');
if (type === 'success') {
toastHeader.classList.add('bg-success', 'text-white');
} else if (type === 'error') {
toastHeader.classList.add('bg-danger', 'text-white');
}
document.getElementById('toast-title').textContent = title;
document.getElementById('toast-body').textContent = body;
notificationToast.show();
}
/**
* Fetches data from the API.
* @param {string} endpoint - The API endpoint to fetch from.
* @param {object} options - Optional fetch options.
* @returns {Promise<any>} - The JSON response.
*/
async function fetchApi(endpoint, options = {}) {
try {
const response = await fetch(API_BASE + endpoint, options);
if (!response.ok) {
const errorData = await response.json().catch(() => ({ message: 'Gagal memuat detail error.' }));
throw new Error(errorData.message || `HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error(`Error fetching ${endpoint}:`, error);
showToast('Error', `Terjadi kesalahan: ${error.message}`, 'error');
return null;
}
}
/**
* Populates select dropdowns for both add and edit modals.
*/
async function populateSelectOptions() {
const data = await fetchApi('get_options.php');
if (!data) return;
const selects = [
{ el: document.getElementById('id_kategori'), data: data.kategori, placeholder: 'Pilih Kategori...', name: 'nama_kategori' },
{ el: document.getElementById('id_kantor_lokasi'), data: data.kantor, placeholder: 'Pilih Lokasi...', name: 'nama_kantor' },
{ el: document.getElementById('edit_id_kategori'), data: data.kategori, placeholder: 'Pilih Kategori...', name: 'nama_kategori' },
{ el: document.getElementById('edit_id_kantor_lokasi'), data: data.kantor, placeholder: 'Pilih Lokasi...', name: 'nama_kantor' }
];
selects.forEach(s => {
if (s.el) {
s.el.innerHTML = `<option value="">${s.placeholder}</option>`;
s.data.forEach(item => {
s.el.innerHTML += `<option value="${item.id}">${item[s.name]}</option>`;
});
}
});
}
/**
* Fetches assets and renders them in the table.
*/
async function loadAssets() {
loadingIndicator.style.display = 'block';
assetsTableBody.innerHTML = '';
const assets = await fetchApi('get_assets.php');
loadingIndicator.style.display = 'none';
if (assets && assets.length > 0) {
assets.forEach(asset => {
const row = `
<tr>
<td>${asset.kode_aset}</td>
<td>${asset.nama_aset}</td>
<td>${asset.nama_kategori}</td>
<td>${asset.nama_kantor}</td>
<td><span class="status-badge status-${asset.status.toLowerCase()}">${asset.status}</span></td>
<td>
<button class="btn btn-sm btn-outline-primary btn-edit" data-asset-id="${asset.id}" title="Edit">
<i data-feather="edit-2" class="feather-sm"></i>
</button>
<button class="btn btn-sm btn-outline-danger btn-delete" data-asset-id="${asset.id}" title="Hapus">
<i data-feather="trash-2" class="feather-sm"></i>
</button>
</td>
</tr>
`;
assetsTableBody.innerHTML += row;
});
} else if (assets) {
assetsTableBody.innerHTML = '<tr><td colspan="6" class="text-center">Belum ada data aset.</td></tr>';
} else {
assetsTableBody.innerHTML = '<tr><td colspan="6" class="text-center text-danger">Gagal memuat data aset.</td></tr>';
}
feather.replace();
}
/**
* Handles the submission of the 'Add Asset' form.
*/
async function handleAddAssetSubmit(event) {
event.preventDefault();
event.stopPropagation();
if (!addAssetForm.checkValidity()) {
addAssetForm.classList.add('was-validated');
return;
}
const formData = new FormData(addAssetForm);
const submitButton = addAssetForm.querySelector('button[type="submit"]');
submitButton.disabled = true;
submitButton.innerHTML = '''<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Menyimpan...''';
const result = await fetchApi('add_asset.php', { method: 'POST', body: formData });
if (result && result.success) {
showToast('Sukses', 'Aset baru berhasil ditambahkan.');
addAssetForm.reset();
addAssetForm.classList.remove('was-validated');
bootstrap.Modal.getInstance(document.getElementById('addAssetModal')).hide();
loadAssets();
} else if (result) {
showToast('Error', result.message, 'error');
}
submitButton.disabled = false;
submitButton.innerHTML = 'Simpan Aset';
}
/**
* Opens the edit modal and populates it with asset data.
* @param {number} assetId - The ID of the asset to edit.
*/
async function openEditModal(assetId) {
const asset = await fetchApi(`get_asset.php?id=${assetId}`);
if (!asset) return;
document.getElementById('edit_id').value = asset.id;
document.getElementById('edit_nama_aset').value = asset.nama_aset;
document.getElementById('edit_id_kategori').value = asset.id_kategori;
document.getElementById('edit_id_kantor_lokasi').value = asset.id_kantor_lokasi;
document.getElementById('edit_spesifikasi').value = asset.spesifikasi;
document.getElementById('edit_tanggal_pembelian').value = asset.tanggal_pembelian;
document.getElementById('edit_harga_pembelian').value = asset.harga_pembelian;
document.getElementById('edit_vendor').value = asset.vendor;
document.getElementById('edit_status').value = asset.status;
editAssetModal.show();
}
/**
* Handles the submission of the 'Edit Asset' form.
*/
async function handleEditAssetSubmit(event) {
event.preventDefault();
event.stopPropagation();
if (!editAssetForm.checkValidity()) {
editAssetForm.classList.add('was-validated');
return;
}
const formData = new FormData(editAssetForm);
const submitButton = editAssetForm.querySelector('button[type="submit"]');
submitButton.disabled = true;
submitButton.innerHTML = '''<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Menyimpan...''';
const result = await fetchApi('update_asset.php', { method: 'POST', body: formData });
if (result && result.success) {
showToast('Sukses', 'Aset berhasil diperbarui.');
editAssetModal.hide();
loadAssets();
} else if (result) {
showToast('Error', result.message, 'error');
}
submitButton.disabled = false;
submitButton.innerHTML = 'Simpan Perubahan';
}
/**
* Handles the deletion of an asset.
* @param {number} assetId - The ID of the asset to delete.
*/
async function handleDeleteAsset(assetId) {
if (!confirm('Anda yakin ingin menghapus aset ini? Tindakan ini tidak dapat dibatalkan.')) {
return;
}
const result = await fetchApi('delete_asset.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id: assetId })
});
if (result && result.success) {
showToast('Sukses', 'Aset berhasil dihapus.');
loadAssets();
} else if (result) {
showToast('Error', result.message, 'error');
}
}
// --- Initializations ---
feather.replace();
populateSelectOptions();
loadAssets();
// --- Event Listeners ---
addAssetForm.addEventListener('submit', handleAddAssetSubmit);
editAssetForm.addEventListener('submit', handleEditAssetSubmit);
assetsTableBody.addEventListener('click', function(event) {
const editButton = event.target.closest('.btn-edit');
const deleteButton = event.target.closest('.btn-delete');
if (editButton) {
const assetId = editButton.dataset.assetId;
openEditModal(assetId);
}
if (deleteButton) {
const assetId = deleteButton.dataset.assetId;
handleDeleteAsset(assetId);
}
});
// Add feather icon class for easier styling
document.querySelectorAll('i[data-feather]').forEach(el => {
if(el.classList.contains('feather-sm')) return;
const iconName = el.getAttribute('data-feather');
el.classList.add(`icon-${iconName}`);
});
});