291 lines
8.5 KiB
JavaScript
291 lines
8.5 KiB
JavaScript
// Global variables
|
|
let inventory = [];
|
|
let currentEditId = null;
|
|
let apiBaseUrl = 'http://localhost:11000/api'; // Replace with your actual API URL
|
|
|
|
// DOM elements
|
|
const inventoryTableBody = document.getElementById('inventoryTableBody');
|
|
const addBtn = document.getElementById('addBtn');
|
|
const refreshBtn = document.getElementById('refreshBtn');
|
|
const searchInput = document.getElementById('searchInput');
|
|
const modal = document.getElementById('modal');
|
|
const modalTitle = document.getElementById('modalTitle');
|
|
const itemForm = document.getElementById('itemForm');
|
|
const cancelBtn = document.getElementById('cancelBtn');
|
|
const closeBtn = document.querySelector('.close');
|
|
const loading = document.getElementById('loading');
|
|
const error = document.getElementById('error');
|
|
const errorMessage = document.getElementById('errorMessage');
|
|
|
|
// Stats elements
|
|
const totalItems = document.getElementById('totalItems');
|
|
const totalValue = document.getElementById('totalValue');
|
|
const lowStock = document.getElementById('lowStock');
|
|
|
|
// API functions
|
|
async function fetchInventory() {
|
|
try {
|
|
showLoading(true);
|
|
hideError();
|
|
|
|
const response = await fetch(`${apiBaseUrl}/read`);
|
|
const result = await response.json();
|
|
|
|
if (result.status === 'Berhasil') {
|
|
inventory = result.data || [];
|
|
renderInventoryTable();
|
|
updateStats();
|
|
} else {
|
|
throw new Error(result.message || 'Failed to fetch inventory');
|
|
}
|
|
} catch (err) {
|
|
console.error('Error fetching inventory:', err);
|
|
showError(`Failed to load inventory: ${err.message}`);
|
|
inventory = [];
|
|
renderInventoryTable();
|
|
} finally {
|
|
showLoading(false);
|
|
}
|
|
}
|
|
|
|
async function createItem(item) {
|
|
try {
|
|
const response = await fetch(`${apiBaseUrl}/create`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(item)
|
|
});
|
|
|
|
const result = await response.json();
|
|
|
|
if (result.status === 'Berhasil') {
|
|
await fetchInventory(); // Refresh the list
|
|
return true;
|
|
} else {
|
|
throw new Error(result.message || 'Failed to create item');
|
|
}
|
|
} catch (err) {
|
|
console.error('Error creating item:', err);
|
|
showError(`Failed to create item: ${err.message}`);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async function updateItem(id, item) {
|
|
item.key = id; // Ensure the item has the ID for update
|
|
try {
|
|
const response = await fetch(`${apiBaseUrl}/update`, {
|
|
method: 'PUT',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(item)
|
|
});
|
|
|
|
const result = await response.json();
|
|
|
|
if (result.status === 'Berhasil') {
|
|
await fetchInventory(); // Refresh the list
|
|
return true;
|
|
} else {
|
|
throw new Error(result.message || 'Failed to update item');
|
|
}
|
|
} catch (err) {
|
|
console.error('Error updating item:', err);
|
|
showError(`Failed to update item: ${err.message}`);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async function deleteItem(id) {
|
|
try {
|
|
const response = await fetch(`${apiBaseUrl}/delete`, {
|
|
method: 'DELETE',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({ key: id })
|
|
});
|
|
|
|
const result = await response.json();
|
|
|
|
if (result.status === 'Berhasil') {
|
|
await fetchInventory(); // Refresh the list
|
|
return true;
|
|
} else {
|
|
throw new Error(result.message || 'Failed to delete item');
|
|
}
|
|
} catch (err) {
|
|
console.error('Error deleting item:', err);
|
|
showError(`Failed to delete item: ${err.message}`);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// UI functions
|
|
function renderInventoryTable(items = inventory) {
|
|
inventoryTableBody.innerHTML = '';
|
|
|
|
if (items.length === 0) {
|
|
const row = document.createElement('tr');
|
|
row.innerHTML = `
|
|
<td colspan="6" style="text-align: center; padding: 40px; color: #7f8c8d;">
|
|
No items found
|
|
</td>
|
|
`;
|
|
inventoryTableBody.appendChild(row);
|
|
return;
|
|
}
|
|
|
|
items.forEach(item => {
|
|
const row = document.createElement('tr');
|
|
const totalItemValue = (item.price * item.qty).toFixed(2);
|
|
const quantityClass = item.qty <= 10 ? 'low-stock' : '';
|
|
|
|
row.innerHTML = `
|
|
<td>${item.id}</td>
|
|
<td>${item.name}</td>
|
|
<td class="price">$${item.price.toFixed(2)}</td>
|
|
<td class="quantity ${quantityClass}">${item.qty}</td>
|
|
<td class="price">$${totalItemValue}</td>
|
|
<td class="actions">
|
|
<button class="btn btn-warning" onclick="editItem(${item.id})">Edit</button>
|
|
<button class="btn btn-danger" onclick="deleteItemConfirm(${item.id})">Delete</button>
|
|
</td>
|
|
`;
|
|
|
|
inventoryTableBody.appendChild(row);
|
|
});
|
|
}
|
|
|
|
function updateStats() {
|
|
const total = inventory.length;
|
|
const value = inventory.reduce((sum, item) => sum + (item.price * item.qty), 0);
|
|
const lowStockCount = inventory.filter(item => item.qty <= 10).length;
|
|
|
|
totalItems.textContent = total;
|
|
totalValue.textContent = `$${value.toFixed(2)}`;
|
|
lowStock.textContent = lowStockCount;
|
|
}
|
|
|
|
function showLoading(show) {
|
|
loading.style.display = show ? 'block' : 'none';
|
|
}
|
|
|
|
function showError(message) {
|
|
errorMessage.textContent = message;
|
|
error.style.display = 'block';
|
|
}
|
|
|
|
function hideError() {
|
|
error.style.display = 'none';
|
|
}
|
|
|
|
function showModal(title = 'Add New Item') {
|
|
modalTitle.textContent = title;
|
|
modal.style.display = 'block';
|
|
}
|
|
|
|
function hideModal() {
|
|
modal.style.display = 'none';
|
|
itemForm.reset();
|
|
currentEditId = null;
|
|
}
|
|
|
|
function filterItems(searchTerm) {
|
|
const filtered = inventory.filter(item =>
|
|
item.name.toLowerCase().includes(searchTerm.toLowerCase())
|
|
);
|
|
renderInventoryTable(filtered);
|
|
}
|
|
|
|
// Event handlers
|
|
function editItem(id) {
|
|
const item = inventory.find(item => item.id === id);
|
|
if (item) {
|
|
currentEditId = id;
|
|
document.getElementById('itemName').value = item.name;
|
|
document.getElementById('itemPrice').value = item.price;
|
|
document.getElementById('itemQty').value = item.qty;
|
|
showModal('Edit Item');
|
|
}
|
|
}
|
|
|
|
function deleteItemConfirm(id) {
|
|
const item = inventory.find(item => item.id === id);
|
|
if (item && confirm(`Are you sure you want to delete "${item.name}"?`)) {
|
|
deleteItem(id);
|
|
}
|
|
}
|
|
|
|
// Event listeners
|
|
addBtn.addEventListener('click', () => {
|
|
showModal('Add New Item');
|
|
});
|
|
|
|
refreshBtn.addEventListener('click', fetchInventory);
|
|
|
|
searchInput.addEventListener('input', (e) => {
|
|
filterItems(e.target.value);
|
|
});
|
|
|
|
closeBtn.addEventListener('click', hideModal);
|
|
cancelBtn.addEventListener('click', hideModal);
|
|
|
|
// Close modal when clicking outside
|
|
window.addEventListener('click', (e) => {
|
|
if (e.target === modal) {
|
|
hideModal();
|
|
}
|
|
});
|
|
|
|
// Form submission
|
|
itemForm.addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
|
|
const name = document.getElementById('itemName').value.trim();
|
|
const price = parseFloat(document.getElementById('itemPrice').value);
|
|
const qty = parseInt(document.getElementById('itemQty').value);
|
|
|
|
if (!name || isNaN(price) || isNaN(qty)) {
|
|
alert('Please fill in all fields correctly');
|
|
return;
|
|
}
|
|
|
|
const item = { name, price, qty };
|
|
|
|
let success = false;
|
|
|
|
if (currentEditId) {
|
|
success = await updateItem(currentEditId, item);
|
|
} else {
|
|
success = await createItem(item);
|
|
}
|
|
|
|
if (success) {
|
|
hideModal();
|
|
}
|
|
});
|
|
|
|
// Initialize the application
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
fetchInventory();
|
|
});
|
|
|
|
// For demo purposes - if API is not available, use mock data
|
|
function loadMockData() {
|
|
inventory = [
|
|
{ id: 1, name: 'Laptop', price: 999.99, qty: 15 },
|
|
{ id: 2, name: 'Mouse', price: 29.99, qty: 50 },
|
|
{ id: 3, name: 'Keyboard', price: 79.99, qty: 8 },
|
|
{ id: 4, name: 'Monitor', price: 299.99, qty: 12 },
|
|
{ id: 5, name: 'Headphones', price: 149.99, qty: 3 }
|
|
];
|
|
renderInventoryTable();
|
|
updateStats();
|
|
}
|
|
|
|
// Uncomment the line below to use mock data for testing
|
|
// loadMockData();
|