Files
2026-04-24 11:00:14 +08:00

488 lines
18 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ICIS Inventory System</title>
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap"
rel="stylesheet"
/>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css"
/>
<style>
body {
font-family: "Inter", sans-serif;
background-color: #f8f9fa;
}
.card-custom {
border: none;
border-radius: 12px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.04);
}
.table-custom th {
font-weight: 600;
text-transform: uppercase;
font-size: 0.8rem;
letter-spacing: 0.5px;
color: #6c757d;
}
.table-custom td {
vertical-align: middle;
}
/* Navbar */
.navbar-custom {
background-color: #ffffff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.02);
}
</style>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
<div id="dashboardSection">
<nav class="navbar navbar-expand-lg navbar-custom py-3 mb-4">
<div class="container">
<a
class="navbar-brand fw-bold d-flex align-items-center gap-2"
href="#"
>
<i class="bi bi-box-seam text-primary"></i> Inventory Pro
</a>
</div>
</nav>
<div class="container">
<div id="alertBox"></div>
<ul class="nav nav-pills mb-4" id="dashboardTabs">
<li class="nav-item">
<a
class="nav-link active"
href="#"
id="tab-inventory"
onclick="switchTab('inventory')"
>Inventory View</a
>
</li>
<li class="nav-item">
<a class="nav-link" href="#" id="tab-po" onclick="switchTab('po')"
>Purchase Orders</a
>
</li>
<li class="nav-item">
<a
class="nav-link"
href="#"
id="tab-analytics"
onclick="switchTab('analytics')"
><i class="bi bi-graph-up"></i> Reports & Analytics</a
>
</li>
</ul>
<div id="inventoryContainer">
<div class="d-flex justify-content-between align-items-center mb-4">
<h4 class="fw-bold mb-0">Overview</h4>
<button
class="btn btn-primary shadow-sm rounded-pill px-4"
data-bs-toggle="modal"
data-bs-target="#addItemModal"
>
<i class="bi bi-plus-lg"></i> Add Item
</button>
</div>
<div class="card card-custom">
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover table-custom mb-0">
<thead class="bg-light">
<tr>
<th class="ps-4">Item Details</th>
<th>Supplier</th>
<th>Unit Price</th>
<th>Stock Level</th>
<th class="pe-4 text-end">Status</th>
<th class="pe-4 text-end">Action</th>
</tr>
</thead>
<tbody id="inventoryTableBody"></tbody>
</table>
</div>
</div>
</div>
</div>
<div class="card card-custom" id="poContainer" style="display: none">
<div
class="card-header bg-white d-flex justify-content-between align-items-center py-3"
>
<h5 class="mb-0 fw-bold">Recent Purchase Orders</h5>
<button
class="btn btn-primary shadow-sm rounded-pill px-4"
data-bs-toggle="modal"
data-bs-target="#createPOModal"
>
<i class="bi bi-cart-plus"></i> Create PO
</button>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover table-custom mb-0">
<thead class="bg-light">
<tr>
<th class="ps-4">PO #</th>
<th>Date</th>
<th>Supplier</th>
<th>Total Amount</th>
<th>Status</th>
<th class="pe-4 text-end">Action</th>
</tr>
</thead>
<tbody id="poTableBody"></tbody>
</table>
</div>
</div>
</div>
<div id="analyticsContainer" style="display: none">
<div class="card card-custom">
<div
class="card-header bg-white border-bottom d-flex justify-content-between align-items-center py-3 px-4"
>
<h5 class="mb-0 fw-bold">Dashboard Overview</h5>
<button
class="btn btn-sm btn-outline-primary shadow-sm rounded-pill px-3"
onclick="loadAnalytics(this)"
>
<i class="bi bi-arrow-clockwise"></i> Refresh Data
</button>
</div>
<div class="card-body p-4">
<div class="row g-4 mb-4">
<div class="col-12 col-md-4">
<div
class="card bg-light border-0 shadow-none p-4 text-center h-100 rounded-3"
>
<div class="text-muted small fw-bold mb-2">
STOCK VALUATION
</div>
<h3 id="statTotalValue" class="fw-bold text-primary mb-0">
₱0.00
</h3>
</div>
</div>
<div class="col-12 col-md-4">
<div
class="card bg-light border-0 shadow-none p-4 text-center h-100 rounded-3"
>
<div class="text-muted small fw-bold mb-2">
TOTAL PO SPEND
</div>
<h3 id="statTotalSpend" class="fw-bold text-success mb-0">
₱0.00
</h3>
</div>
</div>
<div class="col-12 col-md-4">
<div
class="card bg-light border-0 shadow-none p-4 text-center h-100 rounded-3"
>
<div class="text-muted small fw-bold mb-2">
INVENTORY TURNOVER
</div>
<h3 id="statTurnover" class="fw-bold text-dark mb-0">
0.00
</h3>
</div>
</div>
</div>
<div class="row g-4 mb-5">
<div class="col-12 col-md-4">
<div
class="card bg-light border-0 shadow-none p-4 text-center h-100 rounded-3"
>
<div class="text-muted small fw-bold mb-2">TOTAL ITEMS</div>
<h3 id="statTotalItems" class="fw-bold text-dark mb-0">
0
</h3>
</div>
</div>
<div class="col-12 col-md-4">
<div
class="card bg-danger bg-opacity-10 border-0 shadow-none p-4 text-center h-100 rounded-3"
>
<div class="text-danger small fw-bold mb-2">
SHORTAGES (LOW STOCK)
</div>
<h3 id="statLowStock" class="fw-bold text-danger mb-0">
0
</h3>
</div>
</div>
<div class="col-12 col-md-4">
<div
class="card bg-warning bg-opacity-10 border-0 shadow-none p-4 text-center h-100 rounded-3"
>
<div class="text-warning small fw-bold mb-2">
OVERSTOCK ALERTS
</div>
<h3 id="statOverstock" class="fw-bold text-warning mb-0">
0
</h3>
</div>
</div>
</div>
<div class="row g-4">
<div class="col-12 col-lg-6">
<h6
class="fw-bold mb-4 text-secondary text-uppercase"
style="letter-spacing: 0.5px"
>
Stock Valuation by Supplier
</h6>
<div style="position: relative; height: 35vh; width: 100%">
<canvas id="valuationChart"></canvas>
</div>
</div>
<div class="col-12 col-lg-6">
<h6
class="fw-bold mb-4 text-secondary text-uppercase"
style="letter-spacing: 0.5px"
>
Spend by Category (Supplier)
</h6>
<div style="position: relative; height: 35vh; width: 100%">
<canvas id="spendChart"></canvas>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal fade" id="addItemModal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content border-0 shadow">
<form id="addItemForm">
<div class="modal-header border-bottom-0 pb-0">
<h5 class="modal-title fw-bold">Add New Item</h5>
<button
type="button"
class="btn-close"
data-bs-dismiss="modal"
></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label class="form-label text-muted small">Item Name</label>
<input
type="text"
name="name"
class="form-control bg-light border-0"
required
/>
</div>
<div class="mb-3">
<label class="form-label text-muted small"
>Description (Include Location / Serial No. for
Equipment)</label
>
<textarea
name="description"
class="form-control bg-light border-0"
rows="2"
placeholder="e.g., Stored in Science Lab 302. Serial: #XYZ123"
></textarea>
</div>
<div class="row">
<div class="col-md-4 mb-3">
<label class="form-label text-muted small">Initial Qty</label>
<input
type="number"
name="quantity"
class="form-control bg-light border-0"
value="0"
/>
</div>
<div class="col-md-4 mb-3">
<label class="form-label text-muted small">Price (₱)</label>
<input
type="number"
name="unit_price"
step="0.01"
class="form-control bg-light border-0"
required
/>
</div>
<div class="col-md-4 mb-3">
<label class="form-label text-muted small">Reorder At</label>
<input
type="number"
name="reorder_level"
class="form-control bg-light border-0"
value="10"
/>
</div>
</div>
<div class="mb-3">
<label class="form-label text-muted small">Supplier</label>
<select
name="supplier_id"
id="supplierSelect"
class="form-select bg-light border-0"
required
>
<option value="">Select...</option>
</select>
</div>
</div>
<div class="modal-footer border-top-0 pt-0">
<button
type="button"
class="btn btn-light"
data-bs-dismiss="modal"
>
Cancel
</button>
<button type="submit" class="btn btn-primary px-4">
Save Item
</button>
</div>
</form>
</div>
</div>
</div>
<script>
$(document).ready(function () {
// Initialize App directly
loadInventory();
loadSuppliers();
// Data Loading functions
function loadInventory() {
$.ajax({
url: "api.php?action=get_inventory",
type: "GET",
cache: false,
dataType: "json",
success: function (res) {
if (res.status === "success") {
let rows = "";
res.data.forEach(function (item) {
let isLowStock =
parseInt(item.quantity) <= parseInt(item.reorder_level);
let statusBadge = isLowStock
? '<span class="badge bg-danger bg-opacity-10 text-danger border border-danger border-opacity-25 rounded-pill px-3 py-2"><i class="bi bi-exclamation-triangle-fill me-1"></i> Low Stock</span>'
: '<span class="badge bg-success bg-opacity-10 text-success border border-success border-opacity-25 rounded-pill px-3 py-2"><i class="bi bi-check-circle-fill me-1"></i> Healthy</span>';
rows += `<tr>
<td class="ps-4">
<div class="fw-bold text-dark">${item.name}</div>
<div class="text-muted small">${item.description || "No description"}</div>
<div class="text-muted small">ID: #${item.inventory_id}</div>
</td>
<td><span class="badge bg-light text-dark border">${item.supplier_name || "N/A"}</span></td>
<td class="fw-medium">₱${parseFloat(item.unit_price).toFixed(2)}</td>
<td>
<div class="fw-bold ${isLowStock ? "text-danger" : ""}">${item.quantity} units</div>
<div class="text-muted small">Reorder at ${item.reorder_level}</div>
</td>
<td class="text-end">${statusBadge}</td>
<td class="pe-4 text-end">
<button class="btn btn-sm btn-light text-warning me-1 issue-btn" data-id="${item.inventory_id}" data-name="${item.name}"><i class="bi bi-box-arrow-up"></i></button>
<button class="btn btn-sm btn-light text-primary me-1 edit-btn" data-id="${item.inventory_id}" data-name="${item.name}" data-desc="${item.description}" data-qty="${item.quantity}" data-price="${item.unit_price}" data-reorder="${item.reorder_level}" data-supplier="${item.supplier_id}"><i class="bi bi-pencil"></i></button>
<button class="btn btn-sm btn-light text-danger delete-btn" data-id="${item.inventory_id}"><i class="bi bi-trash"></i></button>
</td>
</tr>`;
});
$("#inventoryTableBody").html(rows);
}
},
});
}
function loadSuppliers() {
$.ajax({
url: "api.php?action=get_suppliers",
type: "GET",
dataType: "json",
success: function (res) {
if (res.status === "success") {
let options = '<option value="">Select...</option>';
res.data.forEach(function (sup) {
options += `<option value="${sup.supplier_id}">${sup.name}</option>`;
});
$("#supplierSelect").html(options);
}
},
});
}
// Add Item Handling
$("#addItemForm").submit(function (e) {
e.preventDefault();
$.ajax({
url: "api.php?action=add_item",
type: "POST",
data: $(this).serialize(),
dataType: "json",
success: function (res) {
if (res.status === "success") {
$("#addItemModal").modal("hide");
$("#addItemForm")[0].reset();
showAlert(res.message, "success");
loadInventory();
} else {
showAlert(res.message, "danger");
}
},
});
});
// Tab Switching Logic
window.switchTab = function (tab) {
$(".nav-link").removeClass("active");
$("#tab-" + tab).addClass("active");
$("#inventoryContainer, #poContainer, #analyticsContainer").hide();
if (tab === "inventory") {
$("#inventoryContainer").fadeIn();
loadInventory();
} else if (tab === "po") {
$("#poContainer").fadeIn();
// loadPOs logic here
} else if (tab === "analytics") {
$("#analyticsContainer").fadeIn();
loadAnalytics();
}
};
// Helper function for alerts
function showAlert(msg, type) {
$("#alertBox").html(
`<div class="alert alert-${type} alert-dismissible fade show border-0 shadow-sm">${msg}<button type="button" class="btn-close" data-bs-dismiss="alert"></button></div>`,
);
}
});
</script>
</body>
</html>