// Inventory Management System import ky from "https://cdn.jsdelivr.net/npm/ky@1.8.1/+esm"; class InventoryManager { constructor() { this.baseUrl = "http://localhost:11000/api"; // Replace with your Bruno API endpoint this.client = ky.extend({ prefixUrl: this.baseUrl, headers: { "Content-Type": "application/json", }, timeout: 10000, retry: 2, }); this.items = []; this.init(); } async init() { this.bindEvents(); await this.loadItems(); } bindEvents() { // Add item form document.getElementById("addItemForm").addEventListener("submit", (e) => { e.preventDefault(); this.addItem(); }); // Edit modal events document.getElementById("editItemForm").addEventListener("submit", (e) => { e.preventDefault(); this.updateItem(); }); document.getElementById("cancelEdit").addEventListener("click", () => { this.closeEditModal(); }); // Close modal when clicking outside document.getElementById("editModal").addEventListener("click", (e) => { if (e.target.id === "editModal") { this.closeEditModal(); } }); // Close modal on escape key document.addEventListener("keydown", (e) => { if (e.key === "Escape") { this.closeEditModal(); } }); } async loadItems() { try { this.showLoading(true); this.hideMessages(); const response = await this.client.get("read"); const result = await response.json(); if (result.status === "success") { this.items = result; this.renderItems(); this.showLoading(false); } else { this.showLoading(false); this.showError(result.message || "Failed to load items"); } } catch (error) { this.showLoading(false); this.showError( "Failed to load inventory items. Please check your connection." ); console.error("Error loading items:", error); } } async addItem() { const form = document.getElementById("addItemForm"); const formData = new FormData(form); const newItem = { name: formData.get("name").trim(), price: parseInt(formData.get("price")), qty: parseInt(formData.get("qty")), }; // Validation if (!newItem.name || newItem.price < 0 || newItem.qty < 0) { this.showError("Please fill in all fields with valid values."); return; } try { this.showLoading(true); this.hideMessages(); const response = await this.client.post("create", { json: newItem, }); const result = await response.json(); if (result.status === "success") { // Add the new item with the ID returned from the API this.items.data.push(result.data); this.renderItems(); form.reset(); this.showSuccess(result.message || "Item added successfully!"); this.showLoading(false); } else { this.showLoading(false); this.showError(result.message || "Failed to add item"); } } catch (error) { this.showLoading(false); this.showError("Failed to add item. Please try again."); console.error("Error adding item:", error); } } async updateItem() { const id = document.getElementById("editItemId").value; const form = document.getElementById("editItemForm"); const formData = new FormData(form); const updatedItem = { id: parseInt(id), name: formData.get("name").trim(), price: parseInt(formData.get("price")), qty: parseInt(formData.get("qty")), }; // Validation if (!updatedItem.name || updatedItem.price < 0 || updatedItem.qty < 0) { this.showError("Please fill in all fields with valid values."); return; } try { this.showLoading(true); this.hideMessages(); const response = await this.client.put(`update`, { json: updatedItem, }); const result = await response.json(); if (result.status === "success") { const index = this.items.data.findIndex( (item) => item.id === parseInt(id) ); if (index !== -1) { this.items.data[index] = result.data; } this.renderItems(); this.closeEditModal(); this.showSuccess(result.message || "Item updated successfully!"); this.showLoading(false); } else { this.showLoading(false); this.showError(result.message || "Failed to update item"); } } catch (error) { this.showLoading(false); this.showError("Failed to update item. Please try again."); console.error("Error updating item:", error); } } async deleteItem(id) { if (!confirm("Are you sure you want to delete this item?")) { return; } try { this.showLoading(true); this.hideMessages(); const response = await this.client.delete(`delete`, { json: { id: parseInt(id) }, }); const result = await response.json(); if (result.status === "success") { this.items.data = this.items.data.filter( (item) => item.id !== parseInt(id) ); this.renderItems(); this.showSuccess(result.message || "Item deleted successfully!"); this.showLoading(false); } else { this.showLoading(false); this.showError(result.message || "Failed to delete item"); } } catch (error) { this.showLoading(false); this.showError("Failed to delete item. Please try again."); console.error("Error deleting item:", error); } } openEditModal(item) { document.getElementById("editItemId").value = item.id; document.getElementById("editItemName").value = item.name; document.getElementById("editItemPrice").value = item.price; document.getElementById("editItemQty").value = item.qty; document.getElementById("editModal").classList.remove("hidden"); document.getElementById("editItemName").focus(); } closeEditModal() { document.getElementById("editModal").classList.add("hidden"); document.getElementById("editItemForm").reset(); } renderItems() { const grid = document.getElementById("inventoryGrid"); const emptyState = document.getElementById("emptyState"); if (!this.items.data || this.items.data.length === 0) { grid.innerHTML = ""; emptyState.classList.remove("hidden"); return; } emptyState.classList.add("hidden"); const itemsHTML = this.items.data .map((item) => this.createItemCard(item)) .join(""); grid.innerHTML = itemsHTML; // Add event listeners for buttons this.items.data.forEach((item) => { const editBtn = document.getElementById(`edit-${item.id}`); const deleteBtn = document.getElementById(`delete-${item.id}`); if (editBtn) { editBtn.addEventListener("click", () => this.openEditModal(item)); } if (deleteBtn) { deleteBtn.addEventListener("click", () => this.deleteItem(item.id)); } }); } createItemCard(item) { const stockLevel = this.getStockLevel(item.qty); const stockClass = this.getStockClass(stockLevel); return `

${item.name}

$${item.price} ${stockLevel}
Quantity: ${item.qty} units
Total Value: $${item.price * item.qty}
`; } getStockLevel(qty) { if (qty <= 5) return "Low Stock"; if (qty <= 20) return "Medium Stock"; return "High Stock"; } getStockClass(stockLevel) { switch (stockLevel) { case "Low Stock": return "stock-low"; case "Medium Stock": return "stock-medium"; case "High Stock": return "stock-high"; default: return "stock-medium"; } } showLoading(show) { const loading = document.getElementById("loading"); if (show) { loading.classList.remove("hidden"); } else { loading.classList.add("hidden"); } } showError(message) { const errorDiv = document.getElementById("errorMessage"); const errorText = document.getElementById("errorText"); errorText.textContent = message; errorDiv.classList.remove("hidden"); setTimeout(() => { errorDiv.classList.add("hidden"); }, 5000); } showSuccess(message) { const successDiv = document.getElementById("successMessage"); const successText = document.getElementById("successText"); successText.textContent = message; successDiv.classList.remove("hidden"); setTimeout(() => { successDiv.classList.add("hidden"); }, 3000); } hideMessages() { document.getElementById("errorMessage").classList.add("hidden"); document.getElementById("successMessage").classList.add("hidden"); } } // Initialize the app when DOM is loaded document.addEventListener("DOMContentLoaded", () => { new InventoryManager(); });