149 lines
5.9 KiB
TypeScript
149 lines
5.9 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import axios from "axios";
|
|
import { useRouter } from "next/navigation";
|
|
import { CalendarPlus, Clock, FileText, MapPin, CheckCircle2 } from "lucide-react";
|
|
|
|
export default function AddBookingPage() {
|
|
const router = useRouter();
|
|
const [rooms, setRooms] = useState<any[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
const [submitLoading, setSubmitLoading] = useState(false);
|
|
|
|
// State Form
|
|
const [selectedRoomId, setSelectedRoomId] = useState("");
|
|
const [startTime, setStartTime] = useState("");
|
|
const [endTime, setEndTime] = useState("");
|
|
const [purpose, setPurpose] = useState("");
|
|
|
|
// Ambil daftar ruangan untuk Dropdown
|
|
useEffect(() => {
|
|
const fetchRooms = async () => {
|
|
try {
|
|
const token = localStorage.getItem("token");
|
|
const res = await axios.get("http://172.17.110.6:8080/api/rooms", {
|
|
headers: { Authorization: `Bearer ${token}` },
|
|
});
|
|
setRooms(res.data.data);
|
|
} catch (error) {
|
|
console.error("Gagal memuat ruangan", error);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
fetchRooms();
|
|
}, []);
|
|
|
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
if (!selectedRoomId) return alert("Pilih ruangan terlebih dahulu!");
|
|
|
|
setSubmitLoading(true);
|
|
const token = localStorage.getItem("token");
|
|
|
|
try {
|
|
const startISO = new Date(startTime).toISOString();
|
|
const endISO = new Date(endTime).toISOString();
|
|
|
|
await axios.post("http://172.17.110.6:8080/api/bookings", {
|
|
room_id: parseInt(selectedRoomId),
|
|
start_time: startISO,
|
|
end_time: endISO,
|
|
purpose: purpose,
|
|
}, {
|
|
headers: { Authorization: `Bearer ${token}` },
|
|
});
|
|
|
|
alert("Booking Berhasil Diajukan!");
|
|
router.push("/dashboard/bookings/calendar"); // Arahkan ke jadwal setelah sukses
|
|
|
|
} catch (error: any) {
|
|
alert("GAGAL: " + (error.response?.data?.error || "Terjadi kesalahan"));
|
|
} finally {
|
|
setSubmitLoading(false);
|
|
}
|
|
};
|
|
|
|
if (loading) return <div className="p-8 text-gray-500 font-medium">Memuat formulir...</div>;
|
|
|
|
return (
|
|
<div className="max-w-3xl mx-auto bg-white rounded-xl shadow-sm border border-gray-100 p-8">
|
|
<div className="flex items-center gap-3 mb-8 border-b pb-4">
|
|
<div className="bg-blue-100 p-3 rounded-lg text-blue-600">
|
|
<CalendarPlus size={28} />
|
|
</div>
|
|
<div>
|
|
<h2 className="text-2xl font-bold text-gray-800">Buat Booking Baru</h2>
|
|
<p className="text-gray-500 text-sm mt-1">Isi detail di bawah ini untuk memesan ruangan kelas S-CLASS.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<form onSubmit={handleSubmit} className="space-y-6">
|
|
{/* Pilih Ruangan */}
|
|
<div>
|
|
<label className="block text-sm font-semibold text-gray-700 mb-2">Pilih Ruangan</label>
|
|
<div className="relative">
|
|
<MapPin className="absolute left-3 top-3 text-gray-400 h-5 w-5" />
|
|
<select
|
|
required
|
|
className="pl-10 w-full border border-gray-300 rounded-lg p-3 text-sm font-medium focus:ring-2 focus:ring-blue-500 outline-none bg-white appearance-none"
|
|
value={selectedRoomId}
|
|
onChange={(e) => setSelectedRoomId(e.target.value)}
|
|
>
|
|
<option value="" disabled>-- Pilih Ruangan yang Tersedia --</option>
|
|
{rooms.map(room => (
|
|
<option key={room.room_id} value={room.room_id}>
|
|
{room.name} (Kapasitas: {room.capacity} | {room.floor})
|
|
</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Waktu Mulai & Selesai (Grid 2 Kolom) */}
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div>
|
|
<label className="block text-sm font-semibold text-gray-700 mb-2">Waktu Mulai</label>
|
|
<div className="relative">
|
|
<Clock className="absolute left-3 top-3 text-gray-400 h-5 w-5" />
|
|
<input type="datetime-local" required
|
|
className="pl-10 w-full border border-gray-300 rounded-lg p-3 text-sm focus:ring-2 focus:ring-blue-500 outline-none"
|
|
value={startTime} onChange={(e) => setStartTime(e.target.value)}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-semibold text-gray-700 mb-2">Waktu Selesai</label>
|
|
<div className="relative">
|
|
<Clock className="absolute left-3 top-3 text-gray-400 h-5 w-5" />
|
|
<input type="datetime-local" required
|
|
className="pl-10 w-full border border-gray-300 rounded-lg p-3 text-sm focus:ring-2 focus:ring-blue-500 outline-none"
|
|
value={endTime} onChange={(e) => setEndTime(e.target.value)}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Keperluan */}
|
|
<div>
|
|
<label className="block text-sm font-semibold text-gray-700 mb-2">Keperluan Kegiatan</label>
|
|
<div className="relative">
|
|
<FileText className="absolute left-3 top-3 text-gray-400 h-5 w-5" />
|
|
<textarea required rows={4} placeholder="Jelaskan keperluan peminjaman ruangan ini..."
|
|
className="pl-10 w-full border border-gray-300 rounded-lg p-3 text-sm focus:ring-2 focus:ring-blue-500 outline-none"
|
|
value={purpose} onChange={(e) => setPurpose(e.target.value)}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<button type="submit" disabled={submitLoading}
|
|
className={`w-full flex items-center justify-center gap-2 py-3.5 rounded-lg text-white font-bold transition-all shadow-sm
|
|
${submitLoading ? 'bg-blue-400 cursor-not-allowed' : 'bg-blue-600 hover:bg-blue-700'}`}
|
|
>
|
|
{submitLoading ? 'Memproses...' : <><CheckCircle2 size={20} /> Ajukan Booking Sekarang</>}
|
|
</button>
|
|
</form>
|
|
</div>
|
|
);
|
|
} |