feat: tambah sidebar navigasi ke semua halaman, ganti auto-refresh dengan polling AJAX di monitoring

This commit is contained in:
Adamalfantino 2026-05-22 23:32:00 +07:00
parent 6ba992dab1
commit 797e55e8c9
6 changed files with 523 additions and 159 deletions

View File

@ -7,6 +7,7 @@
#include <WiFi.h>
#include <HTTPClient.h>
#include <WiFiClientSecure.h>
#include <ArduinoJson.h>
#include <SPI.h>
#include <LoRa.h>
@ -18,7 +19,7 @@ const char* ssid = "gege";
const char* password = "biasaaja";
// GANTI DENGAN IP LARAVEL KAMU
const char* API_BASE = "http://10.185.214.166:8000/api";
const char* API_BASE = "https://keamanan-rak-barang-production.up.railway.app/api";
// ============================================
// DEVICE

17
nixpacks.toml Normal file
View File

@ -0,0 +1,17 @@
[phases.setup]
nixPkgs = ["php82", "php82Extensions.pdo", "php82Extensions.pdo_mysql", "php82Extensions.mbstring", "php82Extensions.xml", "php82Extensions.curl", "php82Extensions.zip", "php82Extensions.gd", "php82Extensions.tokenizer", "php82Extensions.bcmath", "php82Packages.composer"]
[phases.install]
cmds = ["composer install --no-dev --optimize-autoloader --no-scripts"]
[phases.build]
cmds = [
"mkdir -p storage/framework/{sessions,views,cache,testing} storage/logs bootstrap/cache",
"chmod -R 777 storage bootstrap/cache",
"php artisan config:cache",
"php artisan route:cache",
"php artisan view:cache"
]
[start]
cmd = "bash start.sh"

View File

@ -15,37 +15,122 @@
</style>
</head>
<body class="bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-100 min-h-screen p-4 md:p-6 font-sans overflow-x-hidden">
<body class="bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-100 font-sans overflow-x-hidden">
<!-- HEADER -->
<div class="flex flex-col sm:flex-row justify-between items-start sm:items-center mb-8 gap-4">
<div class="flex h-screen overflow-hidden">
<div class="flex items-center gap-3">
<div class="w-12 h-12 bg-gradient-to-br from-indigo-500 to-purple-600 rounded-2xl flex items-center justify-center shadow-lg">
<i data-feather="cpu" class="w-6 h-6 text-white"></i>
<!-- OVERLAY untuk mobile -->
<div id="sidebar-overlay" class="fixed inset-0 bg-black/50 z-30 hidden md:hidden" onclick="toggleSidebar()"></div>
<!-- SIDEBAR -->
<aside id="sidebar" class="fixed md:static z-40 top-0 left-0 h-full w-72 bg-gradient-to-b from-slate-900 via-gray-900 to-slate-800 text-gray-200 shadow-2xl p-6 transform -translate-x-full md:translate-x-0 transition-all duration-300 border-r border-gray-700/50 overflow-y-auto">
<!-- LOGO -->
<div class="flex items-center gap-4 mb-12 p-3 bg-gradient-to-r from-indigo-600/20 to-purple-600/20 rounded-2xl border border-indigo-500/20">
<div class="w-12 h-12 bg-gradient-to-br from-indigo-500 to-purple-600 rounded-xl flex items-center justify-center shadow-lg">
<i data-feather="shield" class="w-6 h-6 text-white"></i>
</div>
<div>
<h1 class="text-2xl md:text-4xl font-display font-bold text-gray-800">Status Device IoT</h1>
<p class="text-gray-600 mt-0.5 text-sm">Kondisi perangkat dan konektivitas sistem</p>
<h2 class="text-xl font-display font-bold text-white leading-none">Smart Rack</h2>
<p class="text-sm text-indigo-300">Security System</p>
</div>
</div>
<div class="flex items-center gap-3 w-full sm:w-auto">
<div class="flex items-center gap-2 bg-gradient-to-r from-green-500/10 to-emerald-500/10 px-3 py-2 rounded-xl border border-green-200">
<div class="w-2 h-2 bg-green-500 rounded-full animate-pulse-slow"></div>
<span class="text-green-700 font-semibold text-xs">System Online</span>
<!-- MENU -->
<nav class="space-y-3">
<a href="/" class="group flex items-center gap-4 px-4 py-3 rounded-xl hover:bg-gradient-to-r hover:from-slate-700/50 hover:to-slate-600/50 hover:text-white transition-all duration-300 text-gray-300">
<div class="w-10 h-10 bg-gray-700/50 group-hover:bg-indigo-500/20 rounded-lg flex items-center justify-center transition-all duration-300">
<i data-feather="arrow-left" class="w-5 h-5"></i>
</div>
<span class="font-medium">Home</span>
</a>
<a href="/dashboard" class="ml-auto sm:ml-0 group bg-gradient-to-r from-indigo-600 to-purple-600 text-white px-4 py-2 md:px-6 md:py-3 rounded-xl font-semibold hover:shadow-lg hover:scale-105 transition-all duration-300 flex items-center gap-2">
<i data-feather="arrow-left" class="w-4 h-4 group-hover:-translate-x-1 transition-transform"></i>
<span class="text-sm md:text-base">Dashboard</span>
<a href="/dashboard" class="group flex items-center gap-4 px-4 py-3 rounded-xl hover:bg-gradient-to-r hover:from-slate-700/50 hover:to-slate-600/50 hover:text-white transition-all duration-300 text-gray-300">
<div class="w-10 h-10 bg-gray-700/50 group-hover:bg-indigo-500/20 rounded-lg flex items-center justify-center transition-all duration-300">
<i data-feather="home" class="w-5 h-5"></i>
</div>
<span class="font-medium">Dashboard</span>
</a>
<a href="/monitoring" class="group flex items-center gap-4 px-4 py-3 rounded-xl hover:bg-gradient-to-r hover:from-slate-700/50 hover:to-slate-600/50 hover:text-white transition-all duration-300 text-gray-300">
<div class="w-10 h-10 bg-gray-700/50 group-hover:bg-blue-500/20 rounded-lg flex items-center justify-center transition-all duration-300">
<i data-feather="activity" class="w-5 h-5"></i>
</div>
<span class="font-medium">Monitoring Sensor</span>
</a>
<a href="/log" class="group flex items-center gap-4 px-4 py-3 rounded-xl hover:bg-gradient-to-r hover:from-slate-700/50 hover:to-slate-600/50 hover:text-white transition-all duration-300 text-gray-300">
<div class="w-10 h-10 bg-gray-700/50 group-hover:bg-green-500/20 rounded-lg flex items-center justify-center transition-all duration-300">
<i data-feather="file-text" class="w-5 h-5"></i>
</div>
<span class="font-medium">Log Aktivitas</span>
</a>
<a href="/device" class="group flex items-center gap-4 px-4 py-3 rounded-xl bg-gradient-to-r from-indigo-600 to-purple-600 text-white shadow-lg">
<div class="w-10 h-10 bg-white/20 rounded-lg flex items-center justify-center">
<i data-feather="cpu" class="w-5 h-5"></i>
</div>
<span class="font-medium">Status Device</span>
</a>
</nav>
<!-- DIVIDER -->
<div class="border-t border-gray-700/50 my-8"></div>
<!-- USER -->
<div class="flex items-center gap-4 p-4 bg-gradient-to-r from-gray-800/50 to-slate-700/50 rounded-2xl border border-gray-700/30">
<div class="relative">
<img src="https://i.pravatar.cc/48" class="w-12 h-12 rounded-xl shadow-lg">
<div class="absolute -bottom-1 -right-1 w-4 h-4 bg-green-500 rounded-full border-2 border-slate-800"></div>
</div>
<div class="flex-1">
<p class="font-semibold text-white">Admin</p>
<p class="text-sm text-gray-400">System Operator</p>
</div>
<a href="{{ route('logout') }}" class="w-10 h-10 bg-red-500/20 hover:bg-red-500/30 rounded-lg flex items-center justify-center text-red-400 hover:text-red-300 transition-all duration-300" title="Logout">
<i data-feather="log-out" class="w-5 h-5"></i>
</a>
</div>
</aside>
<!-- MAIN -->
<div class="flex-1 flex flex-col">
<!-- TOPBAR -->
<header class="glass border-b border-white/20 flex justify-between items-center px-4 md:px-8 py-4 md:py-6">
<div class="flex items-center gap-3">
<button onclick="toggleSidebar()" class="md:hidden w-10 h-10 bg-gray-100 rounded-xl flex items-center justify-center text-gray-600 hover:bg-gray-200 transition-all">
<i data-feather="menu" class="w-5 h-5"></i>
</button>
<div>
<h1 class="text-lg md:text-2xl font-display font-bold text-gray-800">Status Device IoT</h1>
<p class="text-gray-600 mt-0.5 text-xs md:text-sm hidden sm:block">Kondisi perangkat dan konektivitas sistem</p>
</div>
</div>
<div class="flex items-center gap-2 md:gap-4">
<div class="flex items-center gap-2 bg-gradient-to-r from-green-500/10 to-emerald-500/10 px-3 py-2 rounded-xl border border-green-200">
<div class="w-2 h-2 md:w-3 md:h-3 bg-green-500 rounded-full animate-pulse-slow"></div>
<span class="text-green-700 font-semibold text-xs md:text-sm hidden sm:inline">System Online</span>
</div>
<div class="flex items-center gap-2">
<div class="relative">
<img src="https://i.pravatar.cc/44" class="w-9 h-9 md:w-11 md:h-11 rounded-xl shadow-lg">
<div class="absolute -bottom-1 -right-1 w-3 h-3 md:w-4 md:h-4 bg-green-500 rounded-full border-2 border-white"></div>
</div>
<div class="hidden sm:block">
<span class="text-gray-800 font-semibold text-sm">Admin</span>
<p class="text-gray-500 text-xs">Online</p>
</div>
</div>
</div>
</header>
<!-- CONTENT -->
<main class="p-4 md:p-8 space-y-6 overflow-y-auto">
<!-- DEVICE GRID -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4 md:gap-6 lg:gap-8">
<!-- DEVICE A -->
<div class="group bg-white/80 backdrop-blur-sm rounded-3xl shadow-lg hover:shadow-2xl hover:scale-105 transition-all duration-500 p-8 border border-gray-100 relative overflow-hidden">
@ -166,7 +251,7 @@
</div>
<!-- SYSTEM INFO -->
<div class="mt-12 bg-white/80 backdrop-blur-sm rounded-3xl shadow-lg p-8 border border-gray-100">
<div class="bg-white/80 backdrop-blur-sm rounded-3xl shadow-lg p-8 border border-gray-100">
<div class="flex items-center gap-3 mb-8">
<div class="w-12 h-12 bg-gradient-to-br from-green-500 to-emerald-600 rounded-xl flex items-center justify-center">
@ -220,8 +305,25 @@
</div>
</main>
</div>
</div>
<script>
feather.replace()
function toggleSidebar() {
const sidebar = document.getElementById('sidebar');
const overlay = document.getElementById('sidebar-overlay');
const isOpen = !sidebar.classList.contains('-translate-x-full');
if (isOpen) {
sidebar.classList.add('-translate-x-full');
overlay.classList.add('hidden');
} else {
sidebar.classList.remove('-translate-x-full');
overlay.classList.remove('hidden');
}
}
</script>
</body>

View File

@ -56,14 +56,14 @@
</div>
</div>
<h1 class="text-6xl md:text-7xl lg:text-8xl font-display font-bold text-white leading-tight mb-6">
<h1 class="text-4xl sm:text-5xl md:text-6xl lg:text-7xl xl:text-8xl font-display font-bold text-white leading-tight mb-6">
Sistem Monitoring
<span class="block gradient-text bg-gradient-to-r from-blue-200 to-purple-200 bg-clip-text text-transparent">
Keamanan IoT
</span>
</h1>
<p class="text-xl md:text-2xl text-blue-100 max-w-3xl mx-auto mb-12 leading-relaxed">
<p class="text-base sm:text-lg md:text-xl lg:text-2xl text-blue-100 max-w-3xl mx-auto mb-8 md:mb-12 leading-relaxed px-4">
Platform monitoring keamanan rak berbasis Internet of Things dengan sensor PIR, getaran SW-420, reed switch, dan komunikasi LoRa untuk pengawasan realtime.
</p>
@ -96,7 +96,7 @@
<p class="text-xl text-gray-600">Teknologi monitoring keamanan yang dapat diandalkan</p>
</div>
<div class="grid grid-cols-2 md:grid-cols-4 gap-8">
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 md:gap-8">
<div class="group text-center p-8 bg-white rounded-2xl shadow-lg hover:shadow-2xl hover:scale-105 transition-all duration-300 border border-gray-100">
<div class="w-16 h-16 bg-gradient-to-br from-indigo-500 to-purple-600 rounded-2xl flex items-center justify-center mx-auto mb-4 group-hover:scale-110 transition-transform">
<i data-feather="layers" class="w-8 h-8 text-white"></i>
@ -142,7 +142,7 @@
<p class="text-xl text-gray-600 max-w-2xl mx-auto">Teknologi sensor terdepan untuk monitoring keamanan yang komprehensif</p>
</div>
<div class="grid md:grid-cols-2 lg:grid-cols-4 gap-8">
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6 md:gap-8">
<!-- PIR -->
<div class="group bg-white p-8 rounded-3xl shadow-lg hover:shadow-2xl hover:-translate-y-4 transition-all duration-500 text-center border border-gray-100 relative overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-indigo-50 to-purple-50 opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>

View File

@ -15,36 +15,119 @@
</style>
</head>
<body class="bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-100 min-h-screen p-4 md:p-6 font-sans overflow-x-hidden">
<body class="bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-100 font-sans overflow-x-hidden">
<!-- HEADER -->
<div class="flex flex-col sm:flex-row justify-between items-start sm:items-center mb-8 gap-4">
<div class="flex h-screen overflow-hidden">
<div>
<div class="flex items-center gap-3 mb-2">
<div class="w-12 h-12 bg-gradient-to-br from-indigo-500 to-purple-600 rounded-2xl flex items-center justify-center shadow-lg">
<i data-feather="file-text" class="w-6 h-6 text-white"></i>
<!-- OVERLAY untuk mobile -->
<div id="sidebar-overlay" class="fixed inset-0 bg-black/50 z-30 hidden md:hidden" onclick="toggleSidebar()"></div>
<!-- SIDEBAR -->
<aside id="sidebar" class="fixed md:static z-40 top-0 left-0 h-full w-72 bg-gradient-to-b from-slate-900 via-gray-900 to-slate-800 text-gray-200 shadow-2xl p-6 transform -translate-x-full md:translate-x-0 transition-all duration-300 border-r border-gray-700/50 overflow-y-auto">
<!-- LOGO -->
<div class="flex items-center gap-4 mb-12 p-3 bg-gradient-to-r from-indigo-600/20 to-purple-600/20 rounded-2xl border border-indigo-500/20">
<div class="w-12 h-12 bg-gradient-to-br from-indigo-500 to-purple-600 rounded-xl flex items-center justify-center shadow-lg">
<i data-feather="shield" class="w-6 h-6 text-white"></i>
</div>
<div>
<h1 class="text-2xl md:text-4xl font-display font-bold text-gray-800">Log Aktivitas</h1>
<p class="text-gray-600 mt-0.5 text-sm">Riwayat kejadian dan aktivitas sensor</p>
</div>
<h2 class="text-xl font-display font-bold text-white leading-none">Smart Rack</h2>
<p class="text-sm text-indigo-300">Security System</p>
</div>
</div>
<div class="flex items-center gap-3 w-full sm:w-auto">
<div class="flex items-center gap-2 bg-gradient-to-r from-blue-500/10 to-indigo-500/10 px-3 py-2 rounded-xl border border-blue-200">
<div class="w-2 h-2 bg-blue-500 rounded-full animate-pulse-slow"></div>
<span class="text-blue-700 font-semibold text-xs">Live Updates</span>
<!-- MENU -->
<nav class="space-y-3">
<a href="/" class="group flex items-center gap-4 px-4 py-3 rounded-xl hover:bg-gradient-to-r hover:from-slate-700/50 hover:to-slate-600/50 hover:text-white transition-all duration-300 text-gray-300">
<div class="w-10 h-10 bg-gray-700/50 group-hover:bg-indigo-500/20 rounded-lg flex items-center justify-center transition-all duration-300">
<i data-feather="arrow-left" class="w-5 h-5"></i>
</div>
<span class="font-medium">Home</span>
</a>
<a href="/dashboard" class="ml-auto sm:ml-0 group bg-gradient-to-r from-indigo-600 to-purple-600 text-white px-4 py-2 md:px-6 md:py-3 rounded-xl font-semibold hover:shadow-lg hover:scale-105 transition-all duration-300 flex items-center gap-2">
<i data-feather="arrow-left" class="w-4 h-4 group-hover:-translate-x-1 transition-transform"></i>
<span class="text-sm md:text-base">Dashboard</span>
<a href="/dashboard" class="group flex items-center gap-4 px-4 py-3 rounded-xl hover:bg-gradient-to-r hover:from-slate-700/50 hover:to-slate-600/50 hover:text-white transition-all duration-300 text-gray-300">
<div class="w-10 h-10 bg-gray-700/50 group-hover:bg-indigo-500/20 rounded-lg flex items-center justify-center transition-all duration-300">
<i data-feather="home" class="w-5 h-5"></i>
</div>
<span class="font-medium">Dashboard</span>
</a>
<a href="/monitoring" class="group flex items-center gap-4 px-4 py-3 rounded-xl hover:bg-gradient-to-r hover:from-slate-700/50 hover:to-slate-600/50 hover:text-white transition-all duration-300 text-gray-300">
<div class="w-10 h-10 bg-gray-700/50 group-hover:bg-blue-500/20 rounded-lg flex items-center justify-center transition-all duration-300">
<i data-feather="activity" class="w-5 h-5"></i>
</div>
<span class="font-medium">Monitoring Sensor</span>
</a>
<a href="/log" class="group flex items-center gap-4 px-4 py-3 rounded-xl bg-gradient-to-r from-indigo-600 to-purple-600 text-white shadow-lg">
<div class="w-10 h-10 bg-white/20 rounded-lg flex items-center justify-center">
<i data-feather="file-text" class="w-5 h-5"></i>
</div>
<span class="font-medium">Log Aktivitas</span>
</a>
<a href="/device" class="group flex items-center gap-4 px-4 py-3 rounded-xl hover:bg-gradient-to-r hover:from-slate-700/50 hover:to-slate-600/50 hover:text-white transition-all duration-300 text-gray-300">
<div class="w-10 h-10 bg-gray-700/50 group-hover:bg-purple-500/20 rounded-lg flex items-center justify-center transition-all duration-300">
<i data-feather="cpu" class="w-5 h-5"></i>
</div>
<span class="font-medium">Status Device</span>
</a>
</nav>
<!-- DIVIDER -->
<div class="border-t border-gray-700/50 my-8"></div>
<!-- USER -->
<div class="flex items-center gap-4 p-4 bg-gradient-to-r from-gray-800/50 to-slate-700/50 rounded-2xl border border-gray-700/30">
<div class="relative">
<img src="https://i.pravatar.cc/48" class="w-12 h-12 rounded-xl shadow-lg">
<div class="absolute -bottom-1 -right-1 w-4 h-4 bg-green-500 rounded-full border-2 border-slate-800"></div>
</div>
<div class="flex-1">
<p class="font-semibold text-white">Admin</p>
<p class="text-sm text-gray-400">System Operator</p>
</div>
<a href="{{ route('logout') }}" class="w-10 h-10 bg-red-500/20 hover:bg-red-500/30 rounded-lg flex items-center justify-center text-red-400 hover:text-red-300 transition-all duration-300" title="Logout">
<i data-feather="log-out" class="w-5 h-5"></i>
</a>
</div>
</aside>
<!-- MAIN -->
<div class="flex-1 flex flex-col">
<!-- TOPBAR -->
<header class="glass border-b border-white/20 flex justify-between items-center px-4 md:px-8 py-4 md:py-6">
<div class="flex items-center gap-3">
<button onclick="toggleSidebar()" class="md:hidden w-10 h-10 bg-gray-100 rounded-xl flex items-center justify-center text-gray-600 hover:bg-gray-200 transition-all">
<i data-feather="menu" class="w-5 h-5"></i>
</button>
<div>
<h1 class="text-lg md:text-2xl font-display font-bold text-gray-800">Log Aktivitas</h1>
<p class="text-gray-600 mt-0.5 text-xs md:text-sm hidden sm:block">Riwayat kejadian dan aktivitas sensor</p>
</div>
</div>
<div class="flex items-center gap-2 md:gap-4">
<div class="flex items-center gap-2 bg-gradient-to-r from-blue-500/10 to-indigo-500/10 px-3 py-2 rounded-xl border border-blue-200">
<div class="w-2 h-2 md:w-3 md:h-3 bg-blue-500 rounded-full animate-pulse-slow"></div>
<span class="text-blue-700 font-semibold text-xs md:text-sm hidden sm:inline">Live Updates</span>
</div>
<div class="flex items-center gap-2">
<div class="relative">
<img src="https://i.pravatar.cc/44" class="w-9 h-9 md:w-11 md:h-11 rounded-xl shadow-lg">
<div class="absolute -bottom-1 -right-1 w-3 h-3 md:w-4 md:h-4 bg-green-500 rounded-full border-2 border-white"></div>
</div>
<div class="hidden sm:block">
<span class="text-gray-800 font-semibold text-sm">Admin</span>
<p class="text-gray-500 text-xs">Online</p>
</div>
</div>
</div>
</header>
<!-- CONTENT -->
<main class="p-4 md:p-8 space-y-6 overflow-y-auto">
<!-- LOG TABLE -->
@ -197,7 +280,7 @@
<!-- STATUS INFO -->
<div class="mt-12 bg-white/80 backdrop-blur-sm rounded-3xl shadow-lg p-8 border border-gray-100">
<div class="bg-white/80 backdrop-blur-sm rounded-3xl shadow-lg p-8 border border-gray-100">
<div class="flex items-center gap-3 mb-8">
<div class="w-12 h-12 bg-gradient-to-br from-green-500 to-emerald-600 rounded-xl flex items-center justify-center">
@ -252,8 +335,25 @@
</div>
</main>
</div>
</div>
<script>
feather.replace()
function toggleSidebar() {
const sidebar = document.getElementById('sidebar');
const overlay = document.getElementById('sidebar-overlay');
const isOpen = !sidebar.classList.contains('-translate-x-full');
if (isOpen) {
sidebar.classList.add('-translate-x-full');
overlay.classList.add('hidden');
} else {
sidebar.classList.remove('-translate-x-full');
overlay.classList.remove('hidden');
}
}
</script>
</body>

View File

@ -15,207 +15,273 @@
</style>
</head>
<body class="bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-100 min-h-screen p-4 md:p-6 font-sans overflow-x-hidden">
<body class="bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-100 font-sans overflow-x-hidden">
<!-- HEADER -->
<div class="flex flex-col sm:flex-row justify-between items-start sm:items-center mb-8 gap-4">
<div class="flex items-center gap-3">
<div class="w-12 h-12 bg-gradient-to-br from-indigo-500 to-purple-600 rounded-2xl flex items-center justify-center shadow-lg">
<i data-feather="activity" class="w-6 h-6 text-white"></i>
<div class="flex h-screen overflow-hidden">
<!-- OVERLAY untuk mobile -->
<div id="sidebar-overlay" class="fixed inset-0 bg-black/50 z-30 hidden md:hidden" onclick="toggleSidebar()"></div>
<!-- SIDEBAR -->
<aside id="sidebar" class="fixed md:static z-40 top-0 left-0 h-full w-72 bg-gradient-to-b from-slate-900 via-gray-900 to-slate-800 text-gray-200 shadow-2xl p-6 transform -translate-x-full md:translate-x-0 transition-all duration-300 border-r border-gray-700/50 overflow-y-auto">
<!-- LOGO -->
<div class="flex items-center gap-4 mb-12 p-3 bg-gradient-to-r from-indigo-600/20 to-purple-600/20 rounded-2xl border border-indigo-500/20">
<div class="w-12 h-12 bg-gradient-to-br from-indigo-500 to-purple-600 rounded-xl flex items-center justify-center shadow-lg">
<i data-feather="shield" class="w-6 h-6 text-white"></i>
</div>
<div>
<h1 class="text-2xl md:text-4xl font-display font-bold text-gray-800">Monitoring Sensor</h1>
<p class="text-gray-600 mt-0.5 text-sm">Data realtime dari sensor keamanan rak</p>
<h2 class="text-xl font-display font-bold text-white leading-none">Smart Rack</h2>
<p class="text-sm text-indigo-300">Security System</p>
</div>
</div>
<div class="flex items-center gap-3 w-full sm:w-auto">
<div class="flex items-center gap-2 bg-gradient-to-r from-green-500/10 to-emerald-500/10 px-3 py-2 rounded-xl border border-green-200">
<div class="w-2 h-2 bg-green-500 rounded-full animate-pulse-slow"></div>
<span class="text-green-700 font-semibold text-xs">Live Monitoring</span>
<!-- MENU -->
<nav class="space-y-3">
<a href="/" class="group flex items-center gap-4 px-4 py-3 rounded-xl hover:bg-gradient-to-r hover:from-slate-700/50 hover:to-slate-600/50 hover:text-white transition-all duration-300 text-gray-300">
<div class="w-10 h-10 bg-gray-700/50 group-hover:bg-indigo-500/20 rounded-lg flex items-center justify-center transition-all duration-300">
<i data-feather="arrow-left" class="w-5 h-5"></i>
</div>
<a href="/dashboard" class="ml-auto sm:ml-0 group bg-gradient-to-r from-indigo-600 to-purple-600 text-white px-4 py-2 md:px-6 md:py-3 rounded-xl font-semibold hover:shadow-lg hover:scale-105 transition-all duration-300 flex items-center gap-2">
<i data-feather="arrow-left" class="w-4 h-4 group-hover:-translate-x-1 transition-transform"></i>
<span class="text-sm md:text-base">Dashboard</span>
<span class="font-medium">Home</span>
</a>
<a href="/dashboard" class="group flex items-center gap-4 px-4 py-3 rounded-xl hover:bg-gradient-to-r hover:from-slate-700/50 hover:to-slate-600/50 hover:text-white transition-all duration-300 text-gray-300">
<div class="w-10 h-10 bg-gray-700/50 group-hover:bg-indigo-500/20 rounded-lg flex items-center justify-center transition-all duration-300">
<i data-feather="home" class="w-5 h-5"></i>
</div>
<span class="font-medium">Dashboard</span>
</a>
<a href="/monitoring" class="group flex items-center gap-4 px-4 py-3 rounded-xl bg-gradient-to-r from-indigo-600 to-purple-600 text-white shadow-lg">
<div class="w-10 h-10 bg-white/20 rounded-lg flex items-center justify-center">
<i data-feather="activity" class="w-5 h-5"></i>
</div>
<span class="font-medium">Monitoring Sensor</span>
</a>
<a href="/log" class="group flex items-center gap-4 px-4 py-3 rounded-xl hover:bg-gradient-to-r hover:from-slate-700/50 hover:to-slate-600/50 hover:text-white transition-all duration-300 text-gray-300">
<div class="w-10 h-10 bg-gray-700/50 group-hover:bg-green-500/20 rounded-lg flex items-center justify-center transition-all duration-300">
<i data-feather="file-text" class="w-5 h-5"></i>
</div>
<span class="font-medium">Log Aktivitas</span>
</a>
<a href="/device" class="group flex items-center gap-4 px-4 py-3 rounded-xl hover:bg-gradient-to-r hover:from-slate-700/50 hover:to-slate-600/50 hover:text-white transition-all duration-300 text-gray-300">
<div class="w-10 h-10 bg-gray-700/50 group-hover:bg-purple-500/20 rounded-lg flex items-center justify-center transition-all duration-300">
<i data-feather="cpu" class="w-5 h-5"></i>
</div>
<span class="font-medium">Status Device</span>
</a>
</nav>
<!-- DIVIDER -->
<div class="border-t border-gray-700/50 my-8"></div>
<!-- USER -->
<div class="flex items-center gap-4 p-4 bg-gradient-to-r from-gray-800/50 to-slate-700/50 rounded-2xl border border-gray-700/30">
<div class="relative">
<img src="https://i.pravatar.cc/48" class="w-12 h-12 rounded-xl shadow-lg">
<div class="absolute -bottom-1 -right-1 w-4 h-4 bg-green-500 rounded-full border-2 border-slate-800"></div>
</div>
<div class="flex-1">
<p class="font-semibold text-white">Admin</p>
<p class="text-sm text-gray-400">System Operator</p>
</div>
<a href="{{ route('logout') }}" class="w-10 h-10 bg-red-500/20 hover:bg-red-500/30 rounded-lg flex items-center justify-center text-red-400 hover:text-red-300 transition-all duration-300" title="Logout">
<i data-feather="log-out" class="w-5 h-5"></i>
</a>
</div>
</aside>
<!-- MAIN -->
<div class="flex-1 flex flex-col">
<!-- TOPBAR -->
<header class="glass border-b border-white/20 flex justify-between items-center px-4 md:px-8 py-4 md:py-6">
<div class="flex items-center gap-3">
<button onclick="toggleSidebar()" class="md:hidden w-10 h-10 bg-gray-100 rounded-xl flex items-center justify-center text-gray-600 hover:bg-gray-200 transition-all">
<i data-feather="menu" class="w-5 h-5"></i>
</button>
<div>
<h1 class="text-lg md:text-2xl font-display font-bold text-gray-800">Monitoring Sensor</h1>
<p class="text-gray-600 mt-0.5 text-xs md:text-sm hidden sm:block">Data realtime dari sensor keamanan rak</p>
</div>
</div>
<div class="flex items-center gap-2 md:gap-4">
<div class="flex items-center gap-2 bg-gradient-to-r from-green-500/10 to-emerald-500/10 px-3 py-2 rounded-xl border border-green-200">
<div id="polling-dot" class="w-2 h-2 md:w-3 md:h-3 bg-green-500 rounded-full animate-pulse-slow"></div>
<span class="text-green-700 font-semibold text-xs md:text-sm hidden sm:inline">Live Monitoring</span>
</div>
<div class="flex items-center gap-2">
<div class="relative">
<img src="https://i.pravatar.cc/44" class="w-9 h-9 md:w-11 md:h-11 rounded-xl shadow-lg">
<div class="absolute -bottom-1 -right-1 w-3 h-3 md:w-4 md:h-4 bg-green-500 rounded-full border-2 border-white"></div>
</div>
<div class="hidden sm:block">
<span class="text-gray-800 font-semibold text-sm">Admin</span>
<p class="text-gray-500 text-xs">Online</p>
</div>
</div>
</div>
</header>
<!-- CONTENT -->
<main class="p-4 md:p-8 space-y-6 md:space-y-8 overflow-y-auto">
<!-- STATISTIK 24 JAM -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-10">
<div class="bg-white rounded-2xl shadow p-6 border border-gray-100 flex items-center gap-4">
<div class="w-14 h-14 bg-indigo-100 rounded-xl flex items-center justify-center">
<i data-feather="eye" class="w-7 h-7 text-indigo-600"></i>
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4 md:gap-6">
<div class="bg-white rounded-2xl shadow p-4 md:p-6 border border-gray-100 flex items-center gap-3 md:gap-4">
<div class="w-12 h-12 md:w-14 md:h-14 bg-indigo-100 rounded-xl flex items-center justify-center flex-shrink-0">
<i data-feather="eye" class="w-6 h-6 md:w-7 md:h-7 text-indigo-600"></i>
</div>
<div>
<p class="text-gray-500 text-sm">Gerakan Terdeteksi (24 jam)</p>
<p class="text-3xl font-display font-bold text-indigo-600">{{ $pirCount24h }}</p>
<p class="text-gray-500 text-xs md:text-sm">Gerakan (24 jam)</p>
<p class="text-2xl md:text-3xl font-display font-bold text-indigo-600">{{ $pirCount24h }}</p>
</div>
</div>
<div class="bg-white rounded-2xl shadow p-6 border border-gray-100 flex items-center gap-4">
<div class="w-14 h-14 bg-yellow-100 rounded-xl flex items-center justify-center">
<i data-feather="zap" class="w-7 h-7 text-yellow-600"></i>
<div class="bg-white rounded-2xl shadow p-4 md:p-6 border border-gray-100 flex items-center gap-3 md:gap-4">
<div class="w-12 h-12 md:w-14 md:h-14 bg-yellow-100 rounded-xl flex items-center justify-center flex-shrink-0">
<i data-feather="zap" class="w-6 h-6 md:w-7 md:h-7 text-yellow-600"></i>
</div>
<div>
<p class="text-gray-500 text-sm">Getaran Abnormal (24 jam)</p>
<p class="text-3xl font-display font-bold text-yellow-600">{{ $vibrationCount24h }}</p>
<p class="text-gray-500 text-xs md:text-sm">Getaran (24 jam)</p>
<p class="text-2xl md:text-3xl font-display font-bold text-yellow-600">{{ $vibrationCount24h }}</p>
</div>
</div>
<div class="bg-white rounded-2xl shadow p-6 border border-gray-100 flex items-center gap-4">
<div class="w-14 h-14 bg-purple-100 rounded-xl flex items-center justify-center">
<i data-feather="unlock" class="w-7 h-7 text-purple-600"></i>
<div class="bg-white rounded-2xl shadow p-4 md:p-6 border border-gray-100 flex items-center gap-3 md:gap-4">
<div class="w-12 h-12 md:w-14 md:h-14 bg-purple-100 rounded-xl flex items-center justify-center flex-shrink-0">
<i data-feather="unlock" class="w-6 h-6 md:w-7 md:h-7 text-purple-600"></i>
</div>
<div>
<p class="text-gray-500 text-sm">Rak Dibuka (24 jam)</p>
<p class="text-3xl font-display font-bold text-purple-600">{{ $reedCount24h }}</p>
<p class="text-gray-500 text-xs md:text-sm">Rak Dibuka (24 jam)</p>
<p class="text-2xl md:text-3xl font-display font-bold text-purple-600">{{ $reedCount24h }}</p>
</div>
</div>
</div>
<!-- SENSOR GRID -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 mb-10">
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 md:gap-6 lg:gap-8">
<!-- PIR -->
<div class="group bg-white/80 backdrop-blur-sm rounded-3xl shadow-lg hover:shadow-2xl transition-all duration-500 p-8 border border-gray-100 relative overflow-hidden">
<div class="group bg-white/80 backdrop-blur-sm rounded-2xl md:rounded-3xl shadow-lg hover:shadow-2xl transition-all duration-500 p-5 md:p-8 border border-gray-100 relative overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-indigo-50 to-blue-50 opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div class="relative z-10">
<div class="flex items-center justify-between mb-6">
<div class="flex items-center gap-4">
<div class="w-16 h-16 bg-gradient-to-br from-indigo-500 to-blue-600 rounded-2xl flex items-center justify-center shadow-lg">
<i data-feather="eye" class="w-8 h-8 text-white"></i>
<div class="flex items-center justify-between mb-4 md:mb-6">
<div class="flex items-center gap-3 md:gap-4">
<div class="w-12 h-12 md:w-16 md:h-16 bg-gradient-to-br from-indigo-500 to-blue-600 rounded-xl md:rounded-2xl flex items-center justify-center shadow-lg">
<i data-feather="eye" class="w-6 h-6 md:w-8 md:h-8 text-white"></i>
</div>
<div>
<h3 class="text-xl font-display font-bold text-gray-800">Sensor PIR</h3>
<p class="text-gray-500 text-sm">Motion Detection</p>
<h3 class="text-lg md:text-xl font-display font-bold text-gray-800">Sensor PIR</h3>
<p class="text-gray-500 text-xs md:text-sm">Motion Detection</p>
</div>
</div>
@if($pirSensor && $pirSensor->status === 'active')
<span class="bg-green-100 text-green-700 px-3 py-1 rounded-xl text-xs font-semibold border border-green-200">Aktif</span>
<span class="bg-green-100 text-green-700 px-2 py-1 md:px-3 rounded-xl text-xs font-semibold border border-green-200">Aktif</span>
@else
<span class="bg-red-100 text-red-700 px-3 py-1 rounded-xl text-xs font-semibold border border-red-200">Tidak Aktif</span>
<span class="bg-red-100 text-red-700 px-2 py-1 md:px-3 rounded-xl text-xs font-semibold border border-red-200">Tidak Aktif</span>
@endif
</div>
@if($pirLatest)
<div class="mb-4">
<p class="text-3xl font-display font-bold {{ $pirLatest->motion_detected ? 'text-red-600' : 'text-green-600' }} mb-1">
{{ $pirLatest->motion_detected ? '⚠ Gerakan Terdeteksi' : '✓ Tidak Ada Gerakan' }}
<div class="mb-3 md:mb-4">
<p id="pir-status-text" class="text-xl md:text-3xl font-display font-bold {{ $pirLatest->motion_detected ? 'text-red-600' : 'text-green-600' }} mb-1">
{{ $pirLatest->motion_detected ? '⚠ Gerakan' : '✓ Aman' }}
</p>
<p class="text-gray-500 text-sm">
Tipe: <span class="font-semibold text-gray-700">{{ ucfirst($pirLatest->motion_type ?? '-') }}</span>
&nbsp;|&nbsp; Intensitas: <span class="font-semibold text-gray-700">{{ $pirLatest->motion_intensity ?? 0 }}%</span>
</p>
<p class="text-gray-500 text-sm mt-1">
Zona: <span class="font-semibold text-gray-700">{{ ucfirst($pirLatest->detection_zone ?? '-') }}</span>
&nbsp;|&nbsp; Durasi: <span class="font-semibold text-gray-700">{{ $pirLatest->duration_seconds ?? 0 }}s</span>
<p id="pir-detail" class="text-gray-500 text-xs md:text-sm">
Intensitas: <span class="font-semibold text-gray-700">{{ $pirLatest->motion_intensity ?? 0 }}%</span>
· Durasi: <span class="font-semibold text-gray-700">{{ $pirLatest->duration_seconds ?? 0 }}s</span>
</p>
</div>
<div class="pt-4 border-t border-gray-100 flex justify-between text-sm">
<span class="text-gray-500">Update terakhir:</span>
<span class="{{ $pirLatest->motion_detected ? 'text-red-600' : 'text-green-600' }} font-semibold">
{{ $pirLatest->recorded_at->diffForHumans() }}
</span>
<div class="pt-3 border-t border-gray-100 flex justify-between text-xs md:text-sm">
<span class="text-gray-500">Update:</span>
<span id="pir-update" class="{{ $pirLatest->motion_detected ? 'text-red-600' : 'text-green-600' }} font-semibold">{{ $pirLatest->recorded_at->diffForHumans() }}</span>
</div>
@else
<p class="text-2xl font-display font-bold text-gray-400 mb-2">Belum Ada Data</p>
<p class="text-gray-500 text-sm">Menunggu data dari sensor...</p>
<p class="text-lg md:text-2xl font-display font-bold text-gray-400 mb-2">Belum Ada Data</p>
<p class="text-gray-500 text-xs md:text-sm">Menunggu data dari sensor...</p>
@endif
</div>
</div>
<!-- VIBRATION -->
<div class="group bg-white/80 backdrop-blur-sm rounded-3xl shadow-lg hover:shadow-2xl transition-all duration-500 p-8 border border-gray-100 relative overflow-hidden">
<div class="group bg-white/80 backdrop-blur-sm rounded-2xl md:rounded-3xl shadow-lg hover:shadow-2xl transition-all duration-500 p-5 md:p-8 border border-gray-100 relative overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-yellow-50 to-orange-50 opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div class="relative z-10">
<div class="flex items-center justify-between mb-6">
<div class="flex items-center gap-4">
<div class="w-16 h-16 bg-gradient-to-br from-yellow-500 to-orange-600 rounded-2xl flex items-center justify-center shadow-lg">
<i data-feather="zap" class="w-8 h-8 text-white"></i>
<div class="flex items-center justify-between mb-4 md:mb-6">
<div class="flex items-center gap-3 md:gap-4">
<div class="w-12 h-12 md:w-16 md:h-16 bg-gradient-to-br from-yellow-500 to-orange-600 rounded-xl md:rounded-2xl flex items-center justify-center shadow-lg">
<i data-feather="zap" class="w-6 h-6 md:w-8 md:h-8 text-white"></i>
</div>
<div>
<h3 class="text-xl font-display font-bold text-gray-800">Sensor Getar</h3>
<p class="text-gray-500 text-sm">SW-420 Vibration</p>
<h3 class="text-lg md:text-xl font-display font-bold text-gray-800">Sensor Getar</h3>
<p class="text-gray-500 text-xs md:text-sm">SW-420 Vibration</p>
</div>
</div>
@if($vibrationSensor && $vibrationSensor->status === 'active')
<span class="bg-green-100 text-green-700 px-3 py-1 rounded-xl text-xs font-semibold border border-green-200">Aktif</span>
<span class="bg-green-100 text-green-700 px-2 py-1 md:px-3 rounded-xl text-xs font-semibold border border-green-200">Aktif</span>
@else
<span class="bg-red-100 text-red-700 px-3 py-1 rounded-xl text-xs font-semibold border border-red-200">Tidak Aktif</span>
<span class="bg-red-100 text-red-700 px-2 py-1 md:px-3 rounded-xl text-xs font-semibold border border-red-200">Tidak Aktif</span>
@endif
</div>
@if($vibrationLatest)
<div class="mb-4">
<p class="text-3xl font-display font-bold {{ $vibrationLatest->is_abnormal ? 'text-red-600' : 'text-green-600' }} mb-1">
{{ $vibrationLatest->is_abnormal ? '⚠ Getaran Abnormal' : '✓ Stabil' }}
<div class="mb-3 md:mb-4">
<p id="vib-status-text" class="text-xl md:text-3xl font-display font-bold {{ $vibrationLatest->is_abnormal ? 'text-red-600' : 'text-green-600' }} mb-1">
{{ $vibrationLatest->is_abnormal ? '⚠ Abnormal' : '✓ Stabil' }}
</p>
<p class="text-gray-500 text-sm">
Status: <span class="font-semibold text-gray-700">{{ ucfirst($vibrationLatest->status ?? '-') }}</span>
&nbsp;|&nbsp; Magnitude: <span class="font-semibold text-gray-700">{{ number_format($vibrationLatest->magnitude ?? 0, 2) }}</span>
</p>
<p class="text-gray-500 text-sm mt-1">
X: <span class="font-semibold">{{ number_format($vibrationLatest->x_axis, 2) }}</span>
&nbsp; Y: <span class="font-semibold">{{ number_format($vibrationLatest->y_axis, 2) }}</span>
&nbsp; Z: <span class="font-semibold">{{ number_format($vibrationLatest->z_axis, 2) }}</span>
<p class="text-gray-500 text-xs md:text-sm">
Magnitude: <span class="font-semibold text-gray-700">{{ number_format($vibrationLatest->magnitude ?? 0, 2) }}</span>
· Status: <span class="font-semibold text-gray-700">{{ ucfirst($vibrationLatest->status ?? '-') }}</span>
</p>
</div>
<div class="pt-4 border-t border-gray-100 flex justify-between text-sm">
<span class="text-gray-500">Update terakhir:</span>
<span class="{{ $vibrationLatest->is_abnormal ? 'text-red-600' : 'text-green-600' }} font-semibold">
{{ $vibrationLatest->recorded_at->diffForHumans() }}
</span>
<div class="pt-3 border-t border-gray-100 flex justify-between text-xs md:text-sm">
<span class="text-gray-500">Update:</span>
<span id="vib-update" class="{{ $vibrationLatest->is_abnormal ? 'text-red-600' : 'text-green-600' }} font-semibold">{{ $vibrationLatest->recorded_at->diffForHumans() }}</span>
</div>
@else
<p class="text-2xl font-display font-bold text-gray-400 mb-2">Belum Ada Data</p>
<p class="text-gray-500 text-sm">Menunggu data dari sensor...</p>
<p class="text-lg md:text-2xl font-display font-bold text-gray-400 mb-2">Belum Ada Data</p>
<p class="text-gray-500 text-xs md:text-sm">Menunggu data dari sensor...</p>
@endif
</div>
</div>
<!-- REED SWITCH -->
<div class="group bg-white/80 backdrop-blur-sm rounded-3xl shadow-lg hover:shadow-2xl transition-all duration-500 p-8 border border-gray-100 relative overflow-hidden">
<div class="group bg-white/80 backdrop-blur-sm rounded-2xl md:rounded-3xl shadow-lg hover:shadow-2xl transition-all duration-500 p-5 md:p-8 border border-gray-100 relative overflow-hidden sm:col-span-2 lg:col-span-1">
<div class="absolute inset-0 bg-gradient-to-br from-purple-50 to-pink-50 opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div class="relative z-10">
<div class="flex items-center justify-between mb-6">
<div class="flex items-center gap-4">
<div class="w-16 h-16 bg-gradient-to-br from-purple-500 to-pink-600 rounded-2xl flex items-center justify-center shadow-lg">
<i data-feather="unlock" class="w-8 h-8 text-white"></i>
<div class="flex items-center justify-between mb-4 md:mb-6">
<div class="flex items-center gap-3 md:gap-4">
<div class="w-12 h-12 md:w-16 md:h-16 bg-gradient-to-br from-purple-500 to-pink-600 rounded-xl md:rounded-2xl flex items-center justify-center shadow-lg">
<i data-feather="unlock" class="w-6 h-6 md:w-8 md:h-8 text-white"></i>
</div>
<div>
<h3 class="text-xl font-display font-bold text-gray-800">Reed Switch</h3>
<p class="text-gray-500 text-sm">Door/Lock Status</p>
<h3 class="text-lg md:text-xl font-display font-bold text-gray-800">Reed Switch</h3>
<p class="text-gray-500 text-xs md:text-sm">Door/Lock Status</p>
</div>
</div>
@if($reedSensor && $reedSensor->status === 'active')
<span class="bg-green-100 text-green-700 px-3 py-1 rounded-xl text-xs font-semibold border border-green-200">Aktif</span>
<span class="bg-green-100 text-green-700 px-2 py-1 md:px-3 rounded-xl text-xs font-semibold border border-green-200">Aktif</span>
@else
<span class="bg-red-100 text-red-700 px-3 py-1 rounded-xl text-xs font-semibold border border-red-200">Tidak Aktif</span>
<span class="bg-red-100 text-red-700 px-2 py-1 md:px-3 rounded-xl text-xs font-semibold border border-red-200">Tidak Aktif</span>
@endif
</div>
@if($reedLatest)
<div class="mb-4">
<p class="text-3xl font-display font-bold {{ $reedLatest->door_open ? 'text-red-600' : 'text-green-600' }} mb-1">
{{ $reedLatest->door_open ? '⚠ Rak Terbuka' : '✓ Rak Tertutup' }}
<div class="mb-3 md:mb-4">
<p id="reed-status-text" class="text-xl md:text-3xl font-display font-bold {{ $reedLatest->door_open ? 'text-red-600' : 'text-green-600' }} mb-1">
{{ $reedLatest->door_open ? '⚠ Terbuka' : '✓ Tertutup' }}
</p>
<p class="text-gray-500 text-sm">
Status: <span class="font-semibold text-gray-700">{{ ucfirst($reedLatest->door_status ?? '-') }}</span>
&nbsp;|&nbsp; Level: <span class="font-semibold text-gray-700">{{ ucfirst($reedLatest->access_level ?? '-') }}</span>
</p>
<p class="text-gray-500 text-sm mt-1">
Metode: <span class="font-semibold text-gray-700">{{ ucfirst($reedLatest->access_method ?? '-') }}</span>
&nbsp;|&nbsp; Durasi: <span class="font-semibold text-gray-700">{{ $reedLatest->open_duration_seconds ?? 0 }}s</span>
<p class="text-gray-500 text-xs md:text-sm">
Level: <span class="font-semibold text-gray-700">{{ ucfirst($reedLatest->access_level ?? '-') }}</span>
· Durasi: <span class="font-semibold text-gray-700">{{ $reedLatest->open_duration_seconds ?? 0 }}s</span>
</p>
</div>
<div class="pt-4 border-t border-gray-100 flex justify-between text-sm">
<span class="text-gray-500">Update terakhir:</span>
<span class="{{ $reedLatest->door_open ? 'text-red-600' : 'text-green-600' }} font-semibold">
{{ $reedLatest->recorded_at->diffForHumans() }}
</span>
<div class="pt-3 border-t border-gray-100 flex justify-between text-xs md:text-sm">
<span class="text-gray-500">Update:</span>
<span id="reed-update" class="{{ $reedLatest->door_open ? 'text-red-600' : 'text-green-600' }} font-semibold">{{ $reedLatest->recorded_at->diffForHumans() }}</span>
</div>
@else
<p class="text-2xl font-display font-bold text-gray-400 mb-2">Belum Ada Data</p>
<p class="text-gray-500 text-sm">Menunggu data dari sensor...</p>
<p class="text-lg md:text-2xl font-display font-bold text-gray-400 mb-2">Belum Ada Data</p>
<p class="text-gray-500 text-xs md:text-sm">Menunggu data dari sensor...</p>
@endif
</div>
</div>
@ -223,7 +289,7 @@
</div>
<!-- RIWAYAT DATA TERBARU -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8 mb-10">
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 md:gap-6 lg:gap-8">
<!-- Riwayat PIR -->
<div class="bg-white/80 backdrop-blur-sm rounded-3xl shadow-lg p-6 border border-gray-100">
@ -354,13 +420,91 @@
</div>
</div>
</main>
</div>
</div>
<script>
feather.replace();
// Auto refresh setiap 10 detik
setTimeout(function() {
window.location.reload();
}, 10000);
// Toggle sidebar mobile
function toggleSidebar() {
const sidebar = document.getElementById('sidebar');
const overlay = document.getElementById('sidebar-overlay');
const isOpen = !sidebar.classList.contains('-translate-x-full');
if (isOpen) {
sidebar.classList.add('-translate-x-full');
overlay.classList.add('hidden');
} else {
sidebar.classList.remove('-translate-x-full');
overlay.classList.remove('hidden');
}
}
// =============================================
// POLLING REALTIME — update kartu sensor tanpa reload halaman
// =============================================
const DETECTION_WINDOW = 30; // detik
async function pollSensorData() {
try {
const [pirRes, vibRes, reedRes] = await Promise.all([
fetch('/api/pir/readings?limit=1').then(r => r.json()).catch(() => null),
fetch('/api/vibration/readings?limit=1').then(r => r.json()).catch(() => null),
fetch('/api/door-access/readings?limit=1').then(r => r.json()).catch(() => null),
]);
const now = Date.now();
// PIR
if (pirRes?.success && pirRes.data?.length > 0) {
const d = pirRes.data[0];
const age = (now - new Date(d.recorded_at).getTime()) / 1000;
const active = d.motion_detected && age <= DETECTION_WINDOW;
document.getElementById('pir-status-text').textContent = active ? '⚠ Gerakan' : '✓ Aman';
document.getElementById('pir-status-text').className = 'text-xl md:text-3xl font-display font-bold mb-1 ' + (active ? 'text-red-600' : 'text-green-600');
document.getElementById('pir-detail').textContent = 'Intensitas: ' + (d.motion_intensity ?? 0) + '% · Durasi: ' + (d.duration_seconds ?? 0) + 's';
document.getElementById('pir-update').textContent = 'Baru saja';
document.getElementById('pir-update').className = active ? 'text-red-600 font-semibold' : 'text-green-600 font-semibold';
}
// Vibration
if (vibRes?.success && vibRes.data?.length > 0) {
const d = vibRes.data[0];
const age = (now - new Date(d.recorded_at).getTime()) / 1000;
const active = d.is_abnormal && age <= DETECTION_WINDOW;
document.getElementById('vib-status-text').textContent = active ? '⚠ Abnormal' : '✓ Stabil';
document.getElementById('vib-status-text').className = 'text-xl md:text-3xl font-display font-bold mb-1 ' + (active ? 'text-red-600' : 'text-green-600');
document.getElementById('vib-update').textContent = 'Baru saja';
document.getElementById('vib-update').className = active ? 'text-red-600 font-semibold' : 'text-green-600 font-semibold';
}
// Reed Switch
if (reedRes?.success && reedRes.data?.length > 0) {
const d = reedRes.data[0];
const age = (now - new Date(d.recorded_at).getTime()) / 1000;
const active = d.door_open && age <= DETECTION_WINDOW;
document.getElementById('reed-status-text').textContent = active ? '⚠ Terbuka' : '✓ Tertutup';
document.getElementById('reed-status-text').className = 'text-xl md:text-3xl font-display font-bold mb-1 ' + (active ? 'text-red-600' : 'text-green-600');
document.getElementById('reed-update').textContent = 'Baru saja';
document.getElementById('reed-update').className = active ? 'text-red-600 font-semibold' : 'text-green-600 font-semibold';
}
// Update dot indicator
const dot = document.getElementById('polling-dot');
dot.classList.remove('bg-red-500');
dot.classList.add('bg-green-500');
} catch (err) {
console.error('Polling error:', err);
const dot = document.getElementById('polling-dot');
dot.classList.remove('bg-green-500');
dot.classList.add('bg-red-500');
}
}
// Poll setiap 10 detik
setInterval(pollSensorData, 10000);
</script>
</body>