[Valentino Heman Budiarto] 9d4cc8bfed Frontend
2026-02-19 18:14:19 +07:00

154 lines
5.8 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
import axios from "axios";
import { useRouter } from "next/navigation";
import { LogOut, CheckCircle, XCircle, Clock } from "lucide-react";
export default function AdminDashboard() {
const router = useRouter();
const [admin, setAdmin] = useState<any>(null);
const [bookings, setBookings] = useState<any[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const token = localStorage.getItem("token");
const userData = localStorage.getItem("user");
if (!token || !userData) {
router.push("/login");
return;
}
const userObj = JSON.parse(userData);
// Tendang kalau bukan admin yang masuk
if (userObj.role !== "admin") {
router.push("/dashboard");
return;
}
setAdmin(userObj);
fetchBookings(token);
}, []);
const fetchBookings = async (token: string) => {
try {
const response = await axios.get("http://localhost:8080/api/bookings", {
headers: { Authorization: `Bearer ${token}` },
});
setBookings(response.data.data || []);
} catch (error) {
console.error("Gagal ambil data booking:", error);
} finally {
setLoading(false);
}
};
const handleUpdateStatus = async (bookingId: string, newStatus: string) => {
const token = localStorage.getItem("token");
try {
await axios.patch(
`http://localhost:8080/api/bookings/${bookingId}`,
{ status: newStatus },
{ headers: { Authorization: `Bearer ${token}` } }
);
alert(`Booking berhasil di-${newStatus}!`);
fetchBookings(token as string); // Refresh data setelah update
} catch (error) {
alert("Gagal mengubah status booking.");
console.error(error);
}
};
const handleLogout = () => {
localStorage.removeItem("token");
localStorage.removeItem("user");
router.push("/login");
};
if (loading) return <div className="p-10 text-center">Memuat panel admin...</div>;
return (
<div className="min-h-screen bg-gray-100">
{/* Navbar Admin */}
<nav className="bg-slate-800 shadow-sm px-6 py-4 flex justify-between items-center text-white sticky top-0 z-10">
<div>
<h1 className="text-xl font-bold text-blue-400">S-CLASS | ADMIN PANEL</h1>
<p className="text-xs text-gray-300">Welcome, {admin?.full_name}</p>
</div>
<button
onClick={handleLogout}
className="flex items-center gap-2 text-sm bg-red-500 hover:bg-red-600 px-4 py-2 rounded-lg transition"
>
<LogOut size={16} /> Keluar
</button>
</nav>
{/* Konten Utama */}
<main className="max-w-6xl mx-auto p-6">
<h2 className="text-2xl font-bold text-gray-800 mb-6">Manajemen Peminjaman Ruangan</h2>
<div className="bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden">
<table className="w-full text-left border-collapse">
<thead>
<tr className="bg-gray-50 text-gray-600 text-sm border-b">
<th className="p-4">Ruangan</th>
<th className="p-4">Peminjam</th>
<th className="p-4">Waktu</th>
<th className="p-4">Keperluan</th>
<th className="p-4">Status</th>
<th className="p-4 text-center">Aksi</th>
</tr>
</thead>
<tbody>
{bookings.length === 0 ? (
<tr>
<td colSpan={6} className="text-center p-8 text-gray-500">Belum ada pengajuan peminjaman.</td>
</tr>
) : (
bookings.map((b) => (
<tr key={b.booking_id} className="border-b hover:bg-gray-50">
<td className="p-4 font-semibold text-gray-800">{b.room?.name}</td>
<td className="p-4 text-sm text-gray-600">ID User: {b.user_id.substring(0,8)}...</td>
<td className="p-4 text-sm text-gray-600">
<div>Mulai: {new Date(b.start_time).toLocaleString('id-ID')}</div>
<div>Selesai: {new Date(b.end_time).toLocaleString('id-ID')}</div>
</td>
<td className="p-4 text-sm text-gray-600">{b.purpose}</td>
<td className="p-4">
<span className={`px-2 py-1 text-xs font-bold rounded-full ${
b.status === 'Approved' ? 'bg-green-100 text-green-700' :
b.status === 'Rejected' ? 'bg-red-100 text-red-700' :
'bg-yellow-100 text-yellow-700'
}`}>
{b.status}
</span>
</td>
<td className="p-4">
{b.status === 'Pending' ? (
<div className="flex justify-center gap-2">
<button
onClick={() => handleUpdateStatus(b.booking_id, 'Approved')}
className="bg-green-500 hover:bg-green-600 text-white p-2 rounded-lg" title="Setujui">
<CheckCircle size={18} />
</button>
<button
onClick={() => handleUpdateStatus(b.booking_id, 'Rejected')}
className="bg-red-500 hover:bg-red-600 text-white p-2 rounded-lg" title="Tolak">
<XCircle size={18} />
</button>
</div>
) : (
<div className="text-center text-gray-400 text-xs">- Selesai -</div>
)}
</td>
</tr>
))
)}
</tbody>
</table>
</div>
</main>
</div>
);
}