Files
root 608aca79b8
Deploy to Shared Hosting / Shared hosting deploy (push) Failing after 47s
Tests / PHPUnit (push) Failing after 1m19s
fix enrollment, invoice, payment and financila aid
2026-08-24 21:20:58 -04:00

237 lines
10 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?= $this->extend('layout/management_layout') ?>
<?= $this->section('content') ?>
<div class="container-fluid px-0 mt-3">
<div class="d-flex justify-content-between align-items-center mb-3 px-3">
<h3 class="mb-0">Books</h3>
<div class="btn-group">
<a class="btn btn-outline-primary" href="<?= site_url('inventory/book-prices') ?>">Book Prices</a>
<a class="btn btn-primary" href="<?= site_url('inventory/create/book') ?>">Add Book</a>
<button class="btn btn-outline-secondary" data-bs-toggle="modal" data-bs-target="#addCategoryModal">Add Category</button>
<button class="btn btn-outline-secondary" data-bs-toggle="modal" data-bs-target="#editCategoryModal">Edit Category</button>
</div>
</div>
<?= view('partials/flash_messages') ?>
<?php
// Helper to render a compact grade label from a category row
$gradeLabel = function (?array $cat): string {
if (!$cat) return '—';
$gmin = $cat['grade_min'] ?? null;
$gmax = $cat['grade_max'] ?? null;
if ($gmin === null && $gmax === null) return '—';
if ($gmin !== null && $gmax !== null) return 'G' . (int)$gmin . 'G' . (int)$gmax;
if ($gmin !== null) return 'G' . (int)$gmin . '+';
return '≤G' . (int)$gmax;
};
?>
<div class="card mb-4">
<div class="card-header d-flex justify-content-between align-items-center">
<span>Books</span>
<select class="form-select form-select-sm" id="categoryFilter" style="min-width:260px">
<option value="">All Categories</option>
<?php foreach ($categories as $c): ?>
<?php
$label = $c['name'] ?? '';
$gl = $gradeLabel($c);
if ($gl !== '—') $label .= ' (' . $gl . ')';
?>
<option value="<?= esc($c['id']) ?>"><?= esc($label) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="card-body table-responsive">
<table class="table table-striped align-middle" id="inventoryTable" data-no-mgmt-sticky="1">
<thead>
<tr>
<th>Name</th><th>ISBN</th><th>Edition</th>
<th>Category</th>
<th>Grade Range</th> <!-- NEW -->
<th>Qty</th><th>Unit</th>
<th>Updated By</th><th>Updated Date</th>
<th>SKU</th><th style="width:150px">Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($items as $i): ?>
<?php
$cat = array_values(array_filter($categories, fn($c)=>($c['id']??null)==($i['category_id']??null)))[0] ?? null;
$catName = $cat['name'] ?? '—';
$catGrades = $gradeLabel($cat);
?>
<tr data-category="<?= esc($i['category_id'] ?? '') ?>">
<td><?= esc($i['name']) ?></td>
<td><?= esc($i['isbn']) ?></td>
<td><?= esc($i['edition']) ?></td>
<td><?= esc($catName) ?></td>
<td>
<?php if (!empty($cat['id'])): ?>
<button type="button"
class="btn btn-link p-0 text-decoration-none js-edit-category-grades"
data-bs-toggle="modal"
data-bs-target="#editCategoryModal"
data-category-id="<?= (int) $cat['id'] ?>">
<?= esc($catGrades) ?>
</button>
<?php else: ?>
<?= esc($catGrades) ?>
<?php endif; ?>
</td>
<td><?= esc($i['quantity']) ?></td>
<td><?= esc($i['unit']) ?></td>
<td><?= esc($userNames[(int)($i['updated_by'] ?? 0)] ?? '—') ?></td>
<td><?= esc($i['updated_at'] ? local_datetime($i['updated_at'], 'm-d-Y H:i') : '—') ?></td>
<td><?= esc($i['sku']) ?></td>
<td>
<a class="btn btn-sm btn-outline-primary" href="<?= site_url('inventory/edit/'.$i['id']) ?>">Edit Book</a>
<form action="<?= site_url('inventory/delete/'.$i['id']) ?>" method="post" class="d-inline">
<?= csrf_field() ?>
<button class="btn btn-sm btn-outline-danger" onclick="return confirm('Delete this item?')">Del</button>
</form>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
<!-- Add Category Modal -->
<div class="modal fade" id="addCategoryModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<form class="modal-content" method="post" action="<?= site_url('inventory/category/save') ?>">
<?= csrf_field() ?>
<input type="hidden" name="type" value="book">
<div class="modal-header">
<h5 class="modal-title">Add Category (Books)</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">Name</label>
<input type="text" name="name" class="form-control" required>
</div>
<div class="row g-2 mb-3">
<div class="col-6">
<label class="form-label">Grade Min</label>
<input type="number" name="grade_min" class="form-control" min="0" max="13" placeholder="e.g., 1">
</div>
<div class="col-6">
<label class="form-label">Grade Max</label>
<input type="number" name="grade_max" class="form-control" min="0" max="13" placeholder="e.g., 3">
</div>
<div class="col-12">
<small class="text-muted">Optional. Only used for Book categories.</small>
</div>
</div>
<div class="mb-0">
<label class="form-label">Description (optional)</label>
<textarea name="description" class="form-control" rows="2"></textarea>
</div>
</div>
<div class="modal-footer"><button class="btn btn-primary">Save Category</button></div>
</form>
</div>
</div>
<!-- Edit Category Modal -->
<div class="modal fade" id="editCategoryModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<form class="modal-content" method="post" action="<?= site_url('inventory/category/save') ?>" id="editCategoryForm">
<?= csrf_field() ?>
<input type="hidden" name="type" value="book">
<div class="modal-header">
<h5 class="modal-title">Edit Category (Books)</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">Category</label>
<select class="form-select" name="id" id="editCategorySelect" required>
<option value="">— Select category —</option>
<?php foreach ($categories as $c): ?>
<option
value="<?= (int)($c['id'] ?? 0) ?>"
data-name="<?= esc($c['name'] ?? '', 'attr') ?>"
data-description="<?= esc($c['description'] ?? '', 'attr') ?>"
data-gmin="<?= esc((string)($c['grade_min'] ?? ''), 'attr') ?>"
data-gmax="<?= esc((string)($c['grade_max'] ?? ''), 'attr') ?>"
><?= esc(($c['name'] ?? '') . ($gradeLabel($c) !== '—' ? ' (' . $gradeLabel($c) . ')' : '')) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="mb-3">
<label class="form-label">Name</label>
<input type="text" name="name" id="editCategoryName" class="form-control" required>
</div>
<div class="row g-2 mb-3">
<div class="col-6">
<label class="form-label">Grade Min</label>
<input type="number" name="grade_min" id="editCategoryGradeMin" class="form-control" min="0" max="13" placeholder="e.g., 1">
</div>
<div class="col-6">
<label class="form-label">Grade Max</label>
<input type="number" name="grade_max" id="editCategoryGradeMax" class="form-control" min="0" max="13" placeholder="e.g., 3">
</div>
<div class="col-12">
<small class="text-muted">Optional. Changing grade range updates every book in this category.</small>
</div>
</div>
<div class="mb-0">
<label class="form-label">Description (optional)</label>
<textarea name="description" id="editCategoryDescription" class="form-control" rows="2"></textarea>
</div>
</div>
<div class="modal-footer"><button type="submit" class="btn btn-primary" id="editCategorySaveBtn">Update Category</button></div>
</form>
</div>
</div>
<?= $this->endSection() ?>
<?= $this->section('scripts') ?>
<script>
document.getElementById('categoryFilter')?.addEventListener('change', function() {
const val = this.value;
document.querySelectorAll('#inventoryTable tbody tr').forEach(tr => {
tr.style.display = (!val || tr.getAttribute('data-category') === val) ? '' : 'none';
});
});
(function() {
const select = document.getElementById('editCategorySelect');
const nameInput = document.getElementById('editCategoryName');
const descInput = document.getElementById('editCategoryDescription');
const gminInput = document.getElementById('editCategoryGradeMin');
const gmaxInput = document.getElementById('editCategoryGradeMax');
function fillEditCategory() {
const opt = select?.options[select.selectedIndex];
const has = !!(select && select.value);
if (nameInput) nameInput.value = has ? (opt.getAttribute('data-name') || '') : '';
if (descInput) descInput.value = has ? (opt.getAttribute('data-description') || '') : '';
if (gminInput) gminInput.value = has ? (opt.getAttribute('data-gmin') || '') : '';
if (gmaxInput) gmaxInput.value = has ? (opt.getAttribute('data-gmax') || '') : '';
}
select?.addEventListener('change', fillEditCategory);
document.getElementById('editCategoryModal')?.addEventListener('show.bs.modal', function (e) {
const trigger = e.relatedTarget;
const preselect = trigger && trigger.getAttribute ? trigger.getAttribute('data-category-id') : null;
if (preselect && select) {
select.value = preselect;
}
fillEditCategory();
});
})();
</script>
<?= $this->endSection() ?>