mirror of
https://github.com/myronblair/parkerslingshotrentals
synced 2026-06-30 17:50:31 -05:00
Fix admin navigation — eliminate page reloads and browser cache
- Add PHP no-cache headers (Cache-Control: no-store) at top of file so OLS cannot cache the login page and serve it to authenticated users — this was the root cause (OLS ignores .htaccess Header directives) - Replace status filter anchor links (/admin/?status=X) with client-side JS filterBookings() — no page navigation means no cookie re-verification on each filter click, eliminating the persistent login redirect - Add data-status attribute to booking rows for JS filtering - Load all bookings at once; filter is instant and stays on same page Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+26
-12
@@ -1,4 +1,9 @@
|
||||
<?php
|
||||
// Force no-cache BEFORE any output (OLS .htaccess Header directives are unreliable)
|
||||
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
|
||||
header('Pragma: no-cache');
|
||||
header('Expires: Thu, 01 Jan 1970 00:00:00 GMT');
|
||||
|
||||
require_once dirname(__DIR__) . '/db.php';
|
||||
|
||||
// ── Cookie-based auth (no PHP sessions — avoids server caching/permission issues) ──
|
||||
@@ -289,9 +294,7 @@ button:hover{background:#ea580c}
|
||||
<?php exit; }
|
||||
|
||||
// ── Dashboard data ─────────────────────────────────────────────────────────────
|
||||
$statusFilter = $_GET['status'] ?? '';
|
||||
$where = $statusFilter ? "WHERE status = " . db()->quote($statusFilter) : '';
|
||||
$bookings = db()->query("SELECT * FROM bookings {$where} ORDER BY rental_date ASC, created_at DESC")->fetchAll();
|
||||
$bookings = db()->query("SELECT * FROM bookings ORDER BY rental_date ASC, created_at DESC")->fetchAll();
|
||||
$blocked = db()->query("SELECT * FROM blocked_dates ORDER BY block_date ASC")->fetchAll();
|
||||
|
||||
$stats = db()->query("
|
||||
@@ -332,8 +335,8 @@ header a:hover{color:#fff}
|
||||
.card{background:#fff;border-radius:10px;border:1px solid #e5e7eb;margin-bottom:2rem;overflow:hidden}
|
||||
.card-header{padding:1rem 1.5rem;border-bottom:1px solid #f3f4f6;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:.75rem}
|
||||
.card-header h2{font-size:1rem;font-weight:700}
|
||||
.filters a{padding:.35rem .75rem;border-radius:6px;font-size:.8rem;text-decoration:none;color:#6b7280;border:1px solid #e5e7eb;margin-left:.35rem}
|
||||
.filters a.active,.filters a:hover{background:#f97316;color:#fff;border-color:#f97316}
|
||||
.filters .filter-btn{padding:.35rem .75rem;border-radius:6px;font-size:.8rem;color:#6b7280;border:1px solid #e5e7eb;margin-left:.35rem;background:#fff;cursor:pointer;font-family:inherit}
|
||||
.filters .filter-btn.active,.filters .filter-btn:hover{background:#f97316;color:#fff;border-color:#f97316}
|
||||
|
||||
/* Table */
|
||||
table{width:100%;border-collapse:collapse;font-size:.875rem}
|
||||
@@ -445,11 +448,11 @@ textarea.notes-ta:focus{border-color:#f97316}
|
||||
<div class="card-header">
|
||||
<h2>Bookings</h2>
|
||||
<div class="filters">
|
||||
<a href="/admin/" class="<?= !$statusFilter?'active':'' ?>">All</a>
|
||||
<a href="/admin/?status=pending" class="<?= $statusFilter==='pending' ?'active':'' ?>">Pending</a>
|
||||
<a href="/admin/?status=confirmed" class="<?= $statusFilter==='confirmed' ?'active':'' ?>">Confirmed</a>
|
||||
<a href="/admin/?status=completed" class="<?= $statusFilter==='completed' ?'active':'' ?>">Completed</a>
|
||||
<a href="/admin/?status=cancelled" class="<?= $statusFilter==='cancelled' ?'active':'' ?>">Cancelled</a>
|
||||
<button class="filter-btn active" onclick="filterBookings('all',this)">All</button>
|
||||
<button class="filter-btn" onclick="filterBookings('pending',this)">Pending</button>
|
||||
<button class="filter-btn" onclick="filterBookings('confirmed',this)">Confirmed</button>
|
||||
<button class="filter-btn" onclick="filterBookings('completed',this)">Completed</button>
|
||||
<button class="filter-btn" onclick="filterBookings('cancelled',this)">Cancelled</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -494,7 +497,7 @@ textarea.notes-ta:focus{border-color:#f97316}
|
||||
(!$stepConfirmed?1:0)+(!$stepWaiver?1:0)+(!$stepInsurance?1:0)+(!$stepDeposit?1:0)+(!$stepLicense?1:0)
|
||||
));
|
||||
?>
|
||||
<tr class="booking-row" onclick="toggleDetail(<?= $bid ?>)">
|
||||
<tr class="booking-row" data-status="<?= htmlspecialchars($b['status']) ?>" onclick="toggleDetail(<?= $bid ?>)">
|
||||
<td onclick="event.stopPropagation()">
|
||||
<button class="expand-btn" id="expand-<?= $bid ?>" onclick="toggleDetail(<?= $bid ?>)">►</button>
|
||||
</td>
|
||||
@@ -535,7 +538,7 @@ textarea.notes-ta:focus{border-color:#f97316}
|
||||
</tr>
|
||||
|
||||
<!-- ── Detail Panel ───────────────────────────────────────────── -->
|
||||
<tr class="detail-row" id="detail-<?= $bid ?>">
|
||||
<tr class="detail-row" id="detail-<?= $bid ?>" data-status="<?= htmlspecialchars($b['status']) ?>">
|
||||
<td colspan="8">
|
||||
<div class="detail-panel">
|
||||
|
||||
@@ -793,6 +796,17 @@ textarea.notes-ta:focus{border-color:#f97316}
|
||||
</div><!-- /.main -->
|
||||
|
||||
<script>
|
||||
// ── Status filter (client-side — no page navigation) ─────────────────────────
|
||||
function filterBookings(status, btn) {
|
||||
document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
|
||||
if (btn) btn.classList.add('active');
|
||||
const rows = document.querySelectorAll('tr.booking-row, tr.detail-row');
|
||||
rows.forEach(row => {
|
||||
const show = status === 'all' || row.dataset.status === status;
|
||||
row.style.display = show ? '' : 'none';
|
||||
});
|
||||
}
|
||||
|
||||
// ── Expand/collapse detail panel ──────────────────────────────────────────────
|
||||
function toggleDetail(id) {
|
||||
const row = document.getElementById('detail-' + id);
|
||||
|
||||
Reference in New Issue
Block a user