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.POST("/bookings", controllers.CreateBooking)
protected.GET("/bookings", controllers.GetAllBookings) protected.GET("/bookings", controllers.GetAllBookings)
protected.PUT("/bookings/:id/status", controllers.UpdateBookingStatus) protected.PUT("/bookings/:id/status", controllers.UpdateBookingStatus)
protected.GET("/my-bookings", controllers.GetMyBookings)
// Admin (Manage Rooms) // Admin (Manage Rooms)
protected.PUT("/admin/rooms/:id/status", controllers.UpdateRoomStatus) protected.PUT("/admin/rooms/:id/status", controllers.UpdateRoomStatus)

View File

@ -26,7 +26,7 @@ func CreateBooking(c *gin.Context) {
return return
} }
//Handle UUID // Handle UUID User
userIDInterface, exists := c.Get("user_id") userIDInterface, exists := c.Get("user_id")
if !exists { if !exists {
c.JSON(http.StatusUnauthorized, gin.H{"error": "User ID tidak ditemukan"}) c.JSON(http.StatusUnauthorized, gin.H{"error": "User ID tidak ditemukan"})
@ -45,15 +45,18 @@ func CreateBooking(c *gin.Context) {
return return
} }
// 🌟 PERBAIKAN 1: Ambil Role User dari Token
userRoleInterface, _ := c.Get("role")
userRole, _ := userRoleInterface.(string)
// Validasi Waktu // Validasi Waktu
if input.EndTime.Before(input.StartTime) { if input.EndTime.Before(input.StartTime) {
c.JSON(http.StatusBadRequest, gin.H{"error": "Waktu selesai tidak boleh lebih awal dari waktu mulai!"}) c.JSON(http.StatusBadRequest, gin.H{"error": "Waktu selesai tidak boleh lebih awal dari waktu mulai!"})
return return
} }
// (Overlap Check) // Overlap Check (Mencegah bentrok jadwal)
var count int64 var count int64
// KITA UBAH STATUSNYA MENJADI: status IN ('Pending', 'Approved')
config.DB.Model(&models.Booking{}).Where( 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 <= ?))", "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, input.RoomID, input.EndTime, input.StartTime, input.EndTime, input.StartTime, input.StartTime, input.EndTime,
@ -64,6 +67,12 @@ func CreateBooking(c *gin.Context) {
return return
} }
// 🌟 PERBAIKAN 1 Lanjutan: Penentuan Status Otomatis
statusPeminjaman := "Pending" // Default untuk student
if userRole == "lecturer" {
statusPeminjaman = "Approved" // Dosen otomatis disetujui!
}
// Simpan Booking // Simpan Booking
booking := models.Booking{ booking := models.Booking{
UserID: userID, UserID: userID,
@ -71,7 +80,7 @@ func CreateBooking(c *gin.Context) {
StartTime: input.StartTime, StartTime: input.StartTime,
EndTime: input.EndTime, EndTime: input.EndTime,
Purpose: input.Purpose, Purpose: input.Purpose,
Status: "Pending", Status: statusPeminjaman, // <-- Gunakan variabel statusPeminjaman
} }
if err := config.DB.Create(&booking).Error; err != nil { 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 var bookings []models.Booking
userID, _ := c.Get("user_id") userID, _ := c.Get("user_id")
role, _ := c.Get("role") role, _ := c.Get("role")
if role == "admin" { 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 { 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()}) c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return return
} }
} else { } 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 { 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()}) c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return return
@ -122,13 +134,11 @@ func UpdateBookingStatus(c *gin.Context) {
} }
var booking models.Booking 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 { 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"}) c.JSON(http.StatusNotFound, gin.H{"error": "Data booking tidak ditemukan di database"})
return return
} }
// Gunakan Switch Case (Clean Code) yang sudah kita bahas sebelumnya
switch input.Status { switch input.Status {
case "Approved": case "Approved":
if booking.RedeemCode == "" { if booking.RedeemCode == "" {
@ -140,22 +150,10 @@ func UpdateBookingStatus(c *gin.Context) {
booking.Status = input.Status booking.Status = input.Status
// 🌟 PERBAIKAN 2: Menghapus blok Save dan JSON ganda yang bikin error
if err := config.DB.Save(&booking).Error; err != nil { if err := config.DB.Save(&booking).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Gagal menyimpan ke database"}) fmt.Println("🔥 ERROR DARI DATABASE:", err.Error())
return c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
}
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
return return
} }
@ -165,7 +163,7 @@ func UpdateBookingStatus(c *gin.Context) {
}) })
} }
// INPUT UNTUK ESP3 // INPUT UNTUK ESP32
type RedeemInput struct { type RedeemInput struct {
RedeemCode string `json:"redeem_code" binding:"required"` RedeemCode string `json:"redeem_code" binding:"required"`
} }
@ -201,15 +199,13 @@ func VerifyRedeemCode(c *gin.Context) {
func GetAllBookings(c *gin.Context) { func GetAllBookings(c *gin.Context) {
var bookings []models.Booking 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 { 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()}) c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return return
} }
// Perhatikan: responsenya menggunakan "data: bookings" agar cocok dengan Frontend React-mu
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"status": "success", "status": "success",
"data": bookings, "data": bookings,
}) })
} }

View File

@ -33,9 +33,10 @@ export default function HistoryPage() {
fetchHistory(token); fetchHistory(token);
}, []); }, []);
const fetchHistory = async (token: string) => { const fetchHistory = async (token: string) => {
try { 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}` }, headers: { Authorization: `Bearer ${token}` },
}); });
setBookings(response.data.data || []); setBookings(response.data.data || []);