update 18 mei

This commit is contained in:
[Valentino Heman Budiarto] 2026-05-18 09:57:01 +07:00
parent 8d35ec81d8
commit 0aed7a7c01
3 changed files with 26 additions and 28 deletions

View File

@ -53,6 +53,7 @@ func main() {
protected.POST("/bookings", controllers.CreateBooking)
protected.GET("/bookings", controllers.GetAllBookings)
protected.PUT("/bookings/:id/status", controllers.UpdateBookingStatus)
protected.GET("/my-bookings", controllers.GetMyBookings)
// Admin (Manage Rooms)
protected.PUT("/admin/rooms/:id/status", controllers.UpdateRoomStatus)

View File

@ -26,7 +26,7 @@ func CreateBooking(c *gin.Context) {
return
}
//Handle UUID
// Handle UUID User
userIDInterface, exists := c.Get("user_id")
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{"error": "User ID tidak ditemukan"})
@ -45,15 +45,18 @@ func CreateBooking(c *gin.Context) {
return
}
// 🌟 PERBAIKAN 1: Ambil Role User dari Token
userRoleInterface, _ := c.Get("role")
userRole, _ := userRoleInterface.(string)
// Validasi Waktu
if input.EndTime.Before(input.StartTime) {
c.JSON(http.StatusBadRequest, gin.H{"error": "Waktu selesai tidak boleh lebih awal dari waktu mulai!"})
return
}
// (Overlap Check)
// Overlap Check (Mencegah bentrok jadwal)
var count int64
// KITA UBAH STATUSNYA MENJADI: status IN ('Pending', 'Approved')
config.DB.Model(&models.Booking{}).Where(
"room_id = ? AND status IN ('Pending', 'Approved') AND ((start_time < ? AND end_time > ?) OR (start_time < ? AND end_time > ?) OR (start_time >= ? AND end_time <= ?))",
input.RoomID, input.EndTime, input.StartTime, input.EndTime, input.StartTime, input.StartTime, input.EndTime,
@ -64,6 +67,12 @@ func CreateBooking(c *gin.Context) {
return
}
// 🌟 PERBAIKAN 1 Lanjutan: Penentuan Status Otomatis
statusPeminjaman := "Pending" // Default untuk student
if userRole == "lecturer" {
statusPeminjaman = "Approved" // Dosen otomatis disetujui!
}
// Simpan Booking
booking := models.Booking{
UserID: userID,
@ -71,7 +80,7 @@ func CreateBooking(c *gin.Context) {
StartTime: input.StartTime,
EndTime: input.EndTime,
Purpose: input.Purpose,
Status: "Pending",
Status: statusPeminjaman, // <-- Gunakan variabel statusPeminjaman
}
if err := config.DB.Create(&booking).Error; err != nil {
@ -86,18 +95,21 @@ func CreateBooking(c *gin.Context) {
})
}
func GetUserBookings(c *gin.Context) {
// 🌟 PERBAIKAN 3: Fungsi khusus untuk mengambil riwayat pribadi
func GetMyBookings(c *gin.Context) {
var bookings []models.Booking
userID, _ := c.Get("user_id")
role, _ := c.Get("role")
if role == "admin" {
// Admin bisa melihat semua riwayat
if err := config.DB.Preload("Room").Preload("User").Order("created_at desc").Find(&bookings).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
} else {
// Mahasiswa/Dosen HANYA BISA melihat riwayat miliknya sendiri
if err := config.DB.Preload("Room").Where("user_id = ?", userID).Order("created_at desc").Find(&bookings).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
@ -122,13 +134,11 @@ func UpdateBookingStatus(c *gin.Context) {
}
var booking models.Booking
// KUNCI PERBAIKAN: Gunakan Where("booking_id = ?") agar tepat sasaran
if err := config.DB.Where("booking_id = ?", bookingID).First(&booking).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Data booking tidak ditemukan di database"})
return
}
// Gunakan Switch Case (Clean Code) yang sudah kita bahas sebelumnya
switch input.Status {
case "Approved":
if booking.RedeemCode == "" {
@ -140,22 +150,10 @@ func UpdateBookingStatus(c *gin.Context) {
booking.Status = input.Status
// 🌟 PERBAIKAN 2: Menghapus blok Save dan JSON ganda yang bikin error
if err := config.DB.Save(&booking).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Gagal menyimpan ke database"})
return
}
c.JSON(http.StatusOK, gin.H{
"message": "Status booking berhasil diperbarui!",
"data": booking,
})
booking.Status = input.Status
// KITA BUKA KEDOK ERROR DARI POSTGRESQL:
if err := config.DB.Save(&booking).Error; err != nil {
fmt.Println("🔥 ERROR DARI DATABASE:", err.Error()) // Cetak teks merah di terminal
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) // Tembak ke pop-up web
fmt.Println("🔥 ERROR DARI DATABASE:", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
@ -165,7 +163,7 @@ func UpdateBookingStatus(c *gin.Context) {
})
}
// INPUT UNTUK ESP3
// INPUT UNTUK ESP32
type RedeemInput struct {
RedeemCode string `json:"redeem_code" binding:"required"`
}
@ -201,15 +199,13 @@ func VerifyRedeemCode(c *gin.Context) {
func GetAllBookings(c *gin.Context) {
var bookings []models.Booking
// Preload digunakan untuk mengambil data Relasi (Nama Ruangan & Nama Peminjam)
if err := config.DB.Preload("Room").Preload("User").Order("created_at desc").Find(&bookings).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// Perhatikan: responsenya menggunakan "data: bookings" agar cocok dengan Frontend React-mu
c.JSON(http.StatusOK, gin.H{
"status": "success",
"data": bookings,
})
}
}

View File

@ -33,9 +33,10 @@ export default function HistoryPage() {
fetchHistory(token);
}, []);
const fetchHistory = async (token: string) => {
const fetchHistory = async (token: string) => {
try {
const response = await axios.get("http://localhost:8080/api/bookings", {
// PERBAIKAN: Ubah /api/bookings menjadi /api/my-bookings
const response = await axios.get("http://localhost:8080/api/my-bookings", {
headers: { Authorization: `Bearer ${token}` },
});
setBookings(response.data.data || []);