with authentication
This commit is contained in:
commit
1d2b51e5c5
26 files changed
+4566
No files matched your search
@@ -0,0 +1,487 @@
|
||||
<!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>
|
||||
Reference in new issue
Block a user