diff --git a/backend/controllers/hardwarecontroller.go b/backend/controllers/hardwarecontroller.go index 7cce450..6ff6f63 100644 --- a/backend/controllers/hardwarecontroller.go +++ b/backend/controllers/hardwarecontroller.go @@ -153,17 +153,19 @@ func ControlHardware(c *gin.Context) { haToken := os.Getenv("HA_TOKEN") var entityID string - switch req.Device { +switch req.Device { case "ac": - if req.Action == "on" { + switch req.Action { + case "on": entityID = "scene.ac_d101_on" - } else { + default: entityID = "scene.ac_d101_off" } case "projector": - if req.Action == "on" { + switch req.Action { + case "on": entityID = "scene.projector_d101_on" - } else { + case "off": entityID = "scene.projector_d101_off" } } diff --git a/frontend/app/admin/monitoring/page.tsx b/frontend/app/admin/monitoring/page.tsx index d01d499..3f01b09 100644 --- a/frontend/app/admin/monitoring/page.tsx +++ b/frontend/app/admin/monitoring/page.tsx @@ -38,7 +38,6 @@ export default function PowerMonitoringPage() { const backendData = result.data; // Kita terjemahkan data Golang ("on"/"off") menjadi boolean (true/false) - // dan masukkan khusus untuk Kelas D101 (id: 1) setRoomDeviceStatus(prev => ({ ...prev, "room_1": { @@ -59,7 +58,7 @@ export default function PowerMonitoringPage() { // 3. INISIALISASI & POLLING (AUTO-REFRESH) // ========================================================================= useEffect(() => { - // A. Simulasi Data Ruangan dari DB/IoT + // Simulasi Data Ruangan const dummyRooms = [ { id: 1, name: "Kelas D101", power: 0, isRelayOn: true, lastUpdate: "Real-time" }, { id: 2, name: "Kelas D102", power: 0, isRelayOn: false, lastUpdate: "2 mnt lalu" }, @@ -68,7 +67,7 @@ export default function PowerMonitoringPage() { ]; setRooms(dummyRooms); - // B. Inisialisasi status default semua device OFF + // Inisialisasi status default semua device OFF const initialStatus: { [roomId: string]: { [deviceName: string]: boolean } } = {}; dummyRooms.forEach(room => { initialStatus[`room_${room.id}`] = { @@ -80,17 +79,15 @@ export default function PowerMonitoringPage() { }); setRoomDeviceStatus(initialStatus); - // C. Tarik data pertama kali saat halaman dibuka + // Tarik data pertama kali & set Interval 2 detik fetchPowerStatus(); fetchDeviceStatus(); - // D. Jalankan Polling setiap 2 detik (2000 ms) const interval = setInterval(() => { fetchPowerStatus(); fetchDeviceStatus(); }, 2000); - // E. Bersihkan interval jika admin pindah halaman return () => clearInterval(interval); }, []); @@ -100,18 +97,24 @@ export default function PowerMonitoringPage() { const handleDeviceToggle = async (roomId: number, roomName: string, deviceName: string) => { const roomIdKey = `room_${roomId}`; const currentStatus = roomDeviceStatus[roomIdKey]?.[deviceName] || false; + + // Logika Pintar: Jika sedang ON, maka klik selanjutnya adalah OFF. Sebaliknya. const actionType = currentStatus ? "off" : "on"; - const confirmMsg = `Apakah Anda yakin ingin mematikan ${deviceName} di ${roomName}?`; - if (currentStatus && !confirm(confirmMsg)) return; + // Konfirmasi mematikan (Biar admin gak salah pencet) + if (currentStatus) { + const confirmMsg = `Apakah Anda yakin ingin mematikan ${deviceName} di ${roomName}?`; + if (!window.confirm(confirmMsg)) return; // Jika di-cancel, berhenti di sini + } + // Mapping nama device untuk backend let backendDevice = ""; if (deviceName === 'AC 1') backendDevice = "ac"; else if (deviceName === 'Proyektor') backendDevice = "projector"; else if (deviceName === 'Lampu 1') backendDevice = "lampu1"; else if (deviceName === 'Lampu 2') backendDevice = "lampu2"; - // Update UI seketika agar terasa responsif bagi admin yang menekan tombol + // 1. UBAH UI SEKETIKA (Optimistic UI) agar layar merespons tanpa delay setRoomDeviceStatus(prev => ({ ...prev, [roomIdKey]: { @@ -120,6 +123,7 @@ export default function PowerMonitoringPage() { }, })); + // 2. KIRIM KE GOLANG try { const response = await fetch("http://172.17.172.17:8080/api/hardware/control", { method: "POST", @@ -127,8 +131,8 @@ export default function PowerMonitoringPage() { body: JSON.stringify({ device: backendDevice, action: actionType }), }); + // 3. JIKA GAGAL, KEMBALIKAN UI KE POSISI SEMULA if (!response.ok) { - // Jika gagal, kembalikan posisi tombol ke keadaan semula setRoomDeviceStatus(prev => ({ ...prev, [roomIdKey]: { @@ -137,11 +141,11 @@ export default function PowerMonitoringPage() { }, })); const errorData = await response.json(); - alert(`GAGAL: ${errorData.error || response.statusText}`); + alert(`GAGAL: ${errorData.error || "Server menolak perintah"}`); } } catch (error) { console.error("Error API:", error); - // Jika server mati, kembalikan posisi tombol + // Rollback UI jika koneksi mati setRoomDeviceStatus(prev => ({ ...prev, [roomIdKey]: { @@ -154,7 +158,7 @@ export default function PowerMonitoringPage() { }; const handleCutOff = (roomName: string) => { - if (confirm(`PERINGATAN: Anda yakin ingin mematikan daya secara paksa di ${roomName}?`)) { + if (window.confirm(`PERINGATAN: Anda yakin ingin mematikan daya secara paksa di ${roomName}?`)) { alert(`Sinyal pemutusan daya dikirim ke Relay Master ${roomName}.`); } }; @@ -164,7 +168,6 @@ export default function PowerMonitoringPage() { // ========================================================================= return (
- {/* Header section */}
@@ -184,7 +187,6 @@ export default function PowerMonitoringPage() { return (
- {/* Status Badge */}
{room.isRelayOn ? 'Sirkuit Aktif' : 'Sirkuit Terputus'} @@ -192,7 +194,6 @@ export default function PowerMonitoringPage() {

{room.name}

- {/* Power display */}
1000 ? 'text-orange-500' : 'text-gray-800'}`}> {room.power} @@ -206,7 +207,6 @@ export default function PowerMonitoringPage() {
)} - {/* PANEL KONTROL IoT */}

IoT Device Control

@@ -262,7 +262,6 @@ export default function PowerMonitoringPage() {
- {/* Footer */}
Update: {room.lastUpdate}