📂 FileMgr
📍
/
home
/
u865173473
/
domains
/
yelagiri.co.in
/
public_html
/
admin
/
bookings
✏️ s/index.php
⬅ Kembali
<?php require_once '../includes/auth_session.php'; require_once '../../db.php'; require_once '../includes/header.php'; // Handle Filters $search = $_GET['search'] ?? ''; $status_filter = $_GET['status'] ?? ''; // Fetch Stats $stats_sql = " SELECT COUNT(*) as total, SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) as pending, SUM(CASE WHEN status = 'confirmed' THEN 1 ELSE 0 END) as confirmed, SUM(CASE WHEN status IN ('cancelled', 'rejected') THEN 1 ELSE 0 END) as cancelled FROM bookings "; $stats_result = $conn->query($stats_sql); $stats = $stats_result->fetch_assoc(); // Fetch Bookings with Filters $where_clauses = []; if (!empty($search)) { $search_safe = $conn->real_escape_string($search); $where_clauses[] = "(b.customer_name LIKE '%$search_safe%' OR b.customer_email LIKE '%$search_safe%' OR r.title LIKE '%$search_safe%')"; } if (!empty($status_filter)) { $status_safe = $conn->real_escape_string($status_filter); $where_clauses[] = "b.status = '$status_safe'"; } $where_sql = !empty($where_clauses) ? 'WHERE ' . implode(' AND ', $where_clauses) : ''; $sql = " SELECT b.*, r.title as room_name FROM bookings b JOIN rooms r ON b.room_id = r.id $where_sql ORDER BY b.created_at DESC "; $result = $conn->query($sql); $bookings = $result->fetch_all(MYSQLI_ASSOC); $statusColors = [ 'pending' => 'bg-amber-100 text-amber-700 border-amber-200', 'confirmed' => 'bg-emerald-100 text-emerald-700 border-emerald-200', 'rejected' => 'bg-rose-100 text-rose-700 border-rose-200', 'cancelled' => 'bg-slate-100 text-slate-700 border-slate-200' ]; ?> <div class="p-6 max-w-7xl mx-auto space-y-8"> <!-- Header & Search Section --> <div class="flex flex-col md:flex-row md:items-center justify-between gap-4"> <div> <h1 class="text-3xl font-extrabold text-slate-900 tracking-tight">Booking Management</h1> <p class="text-slate-500 mt-1">Manage and track all room reservations from one place.</p> </div> <form method="GET" class="flex flex-wrap items-center gap-3"> <div class="relative min-w-[280px]"> <i class="fas fa-search absolute left-4 top-1/2 -translate-y-1/2 text-slate-400"></i> <input type="text" name="search" value="<?= htmlspecialchars($search) ?>" placeholder="Search by customer or room..." class="w-full pl-11 pr-4 py-2.5 bg-white border border-slate-200 rounded-xl text-sm focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition-all outline-none"> </div> <select name="status" onchange="this.form.submit()" class="pl-4 pr-10 py-2.5 bg-white border border-slate-200 rounded-xl text-sm focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition-all outline-none appearance-none cursor-pointer"> <option value="">All Statuses</option> <option value="pending" <?= $status_filter == 'pending' ? 'selected' : '' ?>>Pending</option> <option value="confirmed" <?= $status_filter == 'confirmed' ? 'selected' : '' ?>>Confirmed</option> <option value="rejected" <?= $status_filter == 'rejected' ? 'selected' : '' ?>>Rejected</option> <option value="cancelled" <?= $status_filter == 'cancelled' ? 'selected' : '' ?>>Cancelled</option> </select> <?php if (!empty($search) || !empty($status_filter)): ?> <a href="index.php" class="text-slate-500 hover:text-indigo-600 text-sm font-medium transition-colors">Clear All</a> <?php endif; ?> </form> </div> <!-- Stats Grid --> <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6"> <div class="bg-white p-6 rounded-2xl border border-slate-100 shadow-sm hover:shadow-md transition-shadow"> <div class="flex items-center justify-between mb-4"> <div class="w-12 h-12 bg-indigo-50 rounded-xl flex items-center justify-center text-indigo-600"> <i class="fas fa-calendar-check text-xl"></i> </div> </div> <p class="text-sm font-medium text-slate-500 uppercase tracking-wider">Total Bookings</p> <h3 class="text-3xl font-bold text-slate-900 mt-1"><?= number_format($stats['total'] ?? 0) ?></h3> </div> <div class="bg-white p-6 rounded-2xl border border-slate-100 shadow-sm hover:shadow-md transition-shadow"> <div class="flex items-center justify-between mb-4"> <div class="w-12 h-12 bg-amber-50 rounded-xl flex items-center justify-center text-amber-600"> <i class="fas fa-clock text-xl"></i> </div> <span class="text-xs font-bold text-amber-600 bg-amber-50 px-2 py-0.5 rounded-full">ACTION REQUIRED</span> </div> <p class="text-sm font-medium text-slate-500 uppercase tracking-wider">Pending</p> <h3 class="text-3xl font-bold text-slate-900 mt-1"><?= number_format($stats['pending'] ?? 0) ?></h3> </div> <div class="bg-white p-6 rounded-2xl border border-slate-100 shadow-sm hover:shadow-md transition-shadow"> <div class="flex items-center justify-between mb-4"> <div class="w-12 h-12 bg-emerald-50 rounded-xl flex items-center justify-center text-emerald-600"> <i class="fas fa-check-circle text-xl"></i> </div> </div> <p class="text-sm font-medium text-slate-500 uppercase tracking-wider">Confirmed</p> <h3 class="text-3xl font-bold text-slate-900 mt-1"><?= number_format($stats['confirmed'] ?? 0) ?></h3> </div> <div class="bg-white p-6 rounded-2xl border border-slate-100 shadow-sm hover:shadow-md transition-shadow"> <div class="flex items-center justify-between mb-4"> <div class="w-12 h-12 bg-slate-50 rounded-xl flex items-center justify-center text-slate-600"> <i class="fas fa-times-circle text-xl"></i> </div> </div> <p class="text-sm font-medium text-slate-500 uppercase tracking-wider">Cancelled</p> <h3 class="text-3xl font-bold text-slate-900 mt-1"><?= number_format($stats['cancelled'] ?? 0) ?></h3> </div> </div> <!-- Card-based Table Layout --> <div class="bg-white rounded-2xl border border-slate-200 overflow-hidden shadow-sm"> <div class="overflow-x-auto overflow-y-auto max-h-[700px]"> <table class="w-full text-left border-collapse"> <thead class="sticky top-0 bg-slate-50 border-b border-slate-200 z-10"> <tr> <th class="px-6 py-4 text-xs font-bold text-slate-500 uppercase tracking-wider">Booking Info</th> <th class="px-6 py-4 text-xs font-bold text-slate-500 uppercase tracking-wider">Customer</th> <th class="px-6 py-4 text-xs font-bold text-slate-500 uppercase tracking-wider">Stay Period</th> <th class="px-6 py-4 text-xs font-bold text-slate-500 uppercase tracking-wider text-right">Amount</th> <th class="px-6 py-4 text-xs font-bold text-slate-500 uppercase tracking-wider text-center">Status</th> <th class="px-6 py-4 text-xs font-bold text-slate-500 uppercase tracking-wider text-right">Actions</th> </tr> </thead> <tbody class="divide-y divide-slate-100 bg-white"> <?php if (empty($bookings)): ?> <tr> <td colspan="6" class="px-6 py-16 text-center"> <div class="flex flex-col items-center"> <div class="w-16 h-16 bg-slate-50 rounded-full flex items-center justify-center text-slate-300 mb-4"> <i class="fas fa-folder-open text-2xl"></i> </div> <h4 class="text-lg font-semibold text-slate-900">No bookings found</h4> <p class="text-slate-500 text-sm mt-1">Try adjusting your search or filters.</p> </div> </td> </tr> <?php else: ?> <?php foreach ($bookings as $booking): $colorClass = $statusColors[$booking['status']] ?? 'bg-slate-100 text-slate-700 border-slate-200'; ?> <tr class="group hover:bg-slate-50/50 transition-colors"> <!-- Booking Info --> <td class="px-6 py-5"> <div class="flex flex-col"> <span class="text-xs font-bold text-indigo-600 bg-indigo-50 px-2 py-0.5 rounded-md self-start mb-2 uppercase tracking-tight">#<?= $booking['id'] ?></span> <div class="flex items-center gap-2"> <i class="fas fa-bed text-slate-400 text-xs"></i> <a href="../../room_details.php?id=<?= $booking['room_id'] ?>" target="_blank" class="font-semibold text-slate-800 hover:text-indigo-600 transition-colors line-clamp-1 underline-offset-2 hover:underline"> <?= htmlspecialchars($booking['room_name'] ?? 'N/A') ?> </a> </div> <div class="flex items-center gap-1.5 mt-1"> <span class="text-xs text-slate-500"><?= $booking['guests'] ?> Guests</span> <span class="text-[10px] text-slate-300">•</span> <span class="text-[10px] text-slate-400 font-medium uppercase tracking-tight">Booked <?= date('M d', strtotime($booking['created_at'])) ?></span> </div> </div> </td> <!-- Customer --> <td class="px-6 py-5"> <div class="flex flex-col"> <span class="font-bold text-slate-900 text-sm"><?= htmlspecialchars($booking['customer_name']) ?></span> <a href="mailto:<?= htmlspecialchars($booking['customer_email']) ?>" class="text-xs text-slate-500 mt-0.5 flex items-center gap-1.5 hover:text-indigo-600 transition"> <i class="far fa-envelope text-[10px]"></i> <?= htmlspecialchars($booking['customer_email']) ?> </a> <a href="tel:<?= htmlspecialchars($booking['customer_phone']) ?>" class="text-xs text-slate-500 mt-0.5 flex items-center gap-1.5 hover:text-emerald-600 transition"> <i class="fas fa-phone-alt text-[10px]"></i> <?= htmlspecialchars($booking['customer_phone']) ?> </a> </div> </td> <!-- Dates --> <td class="px-6 py-5"> <div class="flex flex-col"> <div class="flex items-center gap-2"> <div class="flex flex-col items-center"> <span class="text-[10px] uppercase font-bold text-slate-400 leading-none">In</span> <span class="text-sm font-semibold text-slate-800"><?= date('d M', strtotime($booking['check_in'])) ?></span> </div> <i class="fas fa-long-arrow-alt-right text-slate-300"></i> <div class="flex flex-col items-center"> <span class="text-[10px] uppercase font-bold text-slate-400 leading-none">Out</span> <span class="text-sm font-semibold text-slate-800"><?= date('d M', strtotime($booking['check_out'])) ?></span> </div> </div> <?php $checkin = new DateTime($booking['check_in']); $checkout = new DateTime($booking['check_out']); $nights = $checkin->diff($checkout)->days; ?> <span class="text-[11px] text-slate-500 font-medium mt-1 inline-flex items-center gap-1"> <i class="far fa-moon text-[10px]"></i> <?= $nights ?> Nights </span> </div> </td> <!-- Price --> <td class="px-6 py-5 text-right"> <div class="flex flex-col items-end"> <span class="text-lg font-bold text-slate-900 tracking-tight">₹<?= number_format($booking['total_price']) ?></span> <span class="text-[10px] text-slate-400 uppercase font-bold tracking-widest mt-0.5">Total Amount</span> </div> </td> <!-- Status --> <td class="px-6 py-5 text-center"> <span class="inline-flex items-center px-3 py-1 rounded-full text-[11px] font-bold border <?= $colorClass ?> uppercase tracking-wide"> <span class="w-1.5 h-1.5 rounded-full bg-current mr-2 animate-pulse"></span> <?= $booking['status'] ?> </span> </td> <!-- Actions --> <td class="px-6 py-5 text-right"> <?php if ($booking['status'] == 'pending'): ?> <div class="flex items-center justify-end gap-2.5 opacity-0 group-hover:opacity-100 transition-opacity"> <form action="update_status.php" method="POST" onsubmit="return confirm('Approve this booking?');"> <input type="hidden" name="booking_id" value="<?= $booking['id'] ?>"> <input type="hidden" name="status" value="confirmed"> <button type="submit" class="w-9 h-9 flex items-center justify-center bg-emerald-50 text-emerald-600 rounded-xl hover:bg-emerald-100 hover:scale-110 active:scale-95 transition-all shadow-sm border border-emerald-100" title="Confirm Booking"> <i class="fas fa-check text-sm"></i> </button> </form> <form action="update_status.php" method="POST" onsubmit="return confirm('Reject this booking?');"> <input type="hidden" name="booking_id" value="<?= $booking['id'] ?>"> <input type="hidden" name="status" value="rejected"> <button type="submit" class="w-9 h-9 flex items-center justify-center bg-rose-50 text-rose-600 rounded-xl hover:bg-rose-100 hover:scale-110 active:scale-95 transition-all shadow-sm border border-rose-100" title="Reject Booking"> <i class="fas fa-times text-sm"></i> </button> </form> </div> <?php else: ?> <div class="opacity-30 group-hover:opacity-100 transition-opacity flex justify-end"> <button disabled class="w-9 h-9 flex items-center justify-center bg-slate-50 text-slate-400 rounded-xl border border-slate-100 cursor-not-allowed"> <i class="fas fa-minus text-xs"></i> </button> </div> <?php endif; ?> </td> </tr> <?php endforeach; ?> <?php endif; ?> </tbody> </table> </div> <!-- Pagination Placeholder or Footer --> <div class="bg-slate-50 px-6 py-4 border-t border-slate-200 flex items-center justify-between"> <p class="text-xs font-semibold text-slate-500 uppercase tracking-widest">Showing <?= count($bookings) ?> reservations</p> <div class="flex gap-2"> <!-- Add pagination if needed later --> </div> </div> </div> </div> <style> /* Custom Scrollbar for the table container */ .overflow-y-auto::-webkit-scrollbar { width: 6px; height: 6px; } .overflow-y-auto::-webkit-scrollbar-track { background: transparent; } .overflow-y-auto::-webkit-scrollbar-thumb { background: #e2e8f0; border-radius: 10px; } .overflow-y-auto::-webkit-scrollbar-thumb:hover { background: #cbd5e1; } /* Micro-interactions */ .group:hover .group-hover\:opacity-100 { opacity: 1 !important; } select { background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%2364748b' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e"); background-position: right 0.75rem center; background-repeat: no-repeat; background-size: 1.25em 1.25em; } </style> <?php require_once '../includes/footer.php'; ?>
💾 Simpan
Batal
⬅ admin
2 item
Nama
Tipe
Ukuran
Diubah
Aksi
🐘
index.php
php
18.8 KB
2026-01-25 15:46
✏️
👁️
🔤
🗑
🐘
update_status.php
php
3.7 KB
2026-01-25 15:46
✏️
👁️
🔤
🗑
✏️ Rename
Nama Baru
Simpan
Batal