diff --git a/README.md b/README.md index cdc37fa..a2edce4 100644 --- a/README.md +++ b/README.md @@ -108,15 +108,16 @@ src/ ## Routes -### Public / auth routes +### Public / Auth Routes -- `/auth/login` -- `/auth/register` +- `/` - Public Interactive Landing Page (features, tech stack, live ESP32 simulator, and system telemetry console) +- `/auth/login` - User Sign-in Page (Credentials login + Google Google login) +- `/auth/register` - User Registration Page -### Main app routes +### Protected App Routes (Dashboard) -- `/` - dashboard -- `/monitoring` - live bin monitoring +- `/dashboard` - Summary cards, attention list, and pickup priority leaderboard +- `/monitoring` - Live monitoring sheet of all bins with status/building filters - `/monitoring/[id]` - bin detail / action page - `/manage` - bin management - `/notifications` - derived alerts diff --git a/public/img/dashboard.png b/public/img/dashboard.png new file mode 100644 index 0000000..e784df0 Binary files /dev/null and b/public/img/dashboard.png differ diff --git a/src/components/layout/navbar/index.tsx b/src/components/layout/navbar/index.tsx index 2820882..740592a 100644 --- a/src/components/layout/navbar/index.tsx +++ b/src/components/layout/navbar/index.tsx @@ -39,7 +39,7 @@ export default function Navbar({ onMenuClick }: NavbarProps) { {/* Menu Button - Mobile Only */}
- + {/* User Profile */}
diff --git a/src/components/layout/sidebar/index.tsx b/src/components/layout/sidebar/index.tsx index 689d1de..3ba9d39 100644 --- a/src/components/layout/sidebar/index.tsx +++ b/src/components/layout/sidebar/index.tsx @@ -6,7 +6,7 @@ import { signOut, useSession } from "next-auth/react"; import Image from "next/image"; const menuItems = [ - { name: "Dashboard", icon: , path: "/", role: ["admin", "petugas"] }, + { name: "Dashboard", icon: , path: "/dashboard", role: ["admin", "petugas"] }, { name: "Monitoring", icon: , path: "/monitoring", role: ["admin", "petugas"] }, { name: "Manage Bin", icon: , path: "/manage", role: ["admin"] }, // hanya admin // { name: "Analytics", icon: , path: "/analytics", role: ["admin", "petugas"] }, diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 4c6704e..7ba5758 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -11,7 +11,7 @@ export default function App({ Component, pageProps }: AppProps) { const router = useRouter(); const [isMobileNavOpen, setIsMobileNavOpen] = useState(false); - const disableLayout = ["/auth/login", "/auth/register"]; + const disableLayout = ["/", "/auth/login", "/auth/register"]; const isDisable = disableLayout.includes(router.pathname); return ( diff --git a/src/pages/dashboard/index.tsx b/src/pages/dashboard/index.tsx new file mode 100644 index 0000000..5669808 --- /dev/null +++ b/src/pages/dashboard/index.tsx @@ -0,0 +1,23 @@ +import DashboardView from "@/views/dashboard"; +import { useSession } from "next-auth/react"; +import { useRouter } from "next/router"; +import { useEffect } from "react"; + +export default function DashboardPage() { + const { status } = useSession(); + const router = useRouter(); + + useEffect(() => { + if (status === "unauthenticated") { + router.push("/auth/login"); + } + }, [status, router]); + + if (status === "loading") return ( +
+
Loading Session...
+
+ ); + + return ; +} diff --git a/src/pages/index.tsx b/src/pages/index.tsx index c6baf95..ca18c33 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,19 +1,748 @@ -import DashboardView from "@/views/dashboard"; import { useSession } from "next-auth/react"; -import { useRouter } from "next/router"; -import { useEffect } from "react"; +import Link from "next/link"; +import Image from "next/image"; +import { useState } from "react"; +import { + FiArrowRight, + FiCpu, + FiActivity, + FiBell, + FiTrendingUp, + FiGithub, + FiGrid, + FiSun, + FiMoon, + FiServer, + FiDatabase, + FiLayers, + FiGlobe, + FiZap, + FiShield, + FiLayout +} from "react-icons/fi"; -export default function DashboardPage() { - const { status } = useSession(); - const router = useRouter(); +export default function LandingPage() { + const { data: session, status } = useSession(); - useEffect(() => { - if (status === "unauthenticated") { - router.push("/auth/login"); + // Theme Toggle State - Default to Light Mode (false) + const [isDarkMode, setIsDarkMode] = useState(false); + + // Interactive Simulator State + const [simLevel, setSimLevel] = useState(65); + const [simStatus, setSimStatus] = useState("on"); + + // Dynamic status check based on simulated level and status + const getSimColor = (level: number, status: string) => { + if (status !== "on") { + return isDarkMode + ? "bg-slate-900 border-slate-800 text-slate-500" + : "bg-slate-100 border-slate-200 text-slate-500"; + } + if (level >= 90) { + return isDarkMode + ? "bg-red-500/10 border-red-500/30 text-red-400" + : "bg-red-50 border-red-200 text-red-650"; + } + if (level >= 70) { + return isDarkMode + ? "bg-orange-500/10 border-orange-500/30 text-orange-400" + : "bg-orange-50 border-orange-200 text-orange-650"; } - }, [status, router]); + if (level > 0) { + return isDarkMode + ? "bg-emerald-500/10 border-emerald-500/30 text-emerald-400" + : "bg-emerald-50 border-emerald-250 text-emerald-700"; + } + return isDarkMode + ? "bg-slate-900 border-slate-800 text-slate-550" + : "bg-slate-100 border-slate-200 text-slate-500"; + }; + + const getSimLabel = (level: number, status: string) => { + if (status !== "on") return "Offline"; + if (level >= 90) return "Penuh"; + if (level >= 70) return "Hampir Penuh"; + if (level > 0) return "Terisi"; + return "Kosong"; + }; + + const handleSimIncrement = () => { + setSimLevel((prev) => Math.min(prev + 15, 100)); + }; + + const handleSimDecrement = () => { + setSimLevel((prev) => Math.max(prev - 15, 0)); + }; + + const toggleSimStatus = () => { + setSimStatus((prev) => (prev === "on" ? "off" : "on")); + }; + + return ( +
+ {/* Decorative Background Glowing Orbs */} + {isDarkMode ? ( + <> +
+
+
+ + ) : ( + <> +
+
+
+ + )} + + {/* Sticky Glassmorphic Header */} +
+
+ + {/* Logo & Branding */} +
+
+ Trashware Logo +
+
+ TrashWare +

IoT Operations

+
+
+ + {/* Desktop Navigation */} + + + {/* User & Theme controls */} +
+ + + {status === "loading" ? ( +
+ ) : session ? ( + +
+ + Dashboard + +
+ + ) : ( + <> + {/* Desktop Buttons */} +
+ + + Masuk + + + + + Daftar + + +
+ + {/* Mobile Button - Combined into 1 button */} + +
+ Masuk +
+ + + )} +
+
+
+ + {/* Hero Section */} +
+
+ + {/* Hero Left Content */} +
+
+ + Sistem Pemantauan Tempat Sampah Pintar IoT +
+ +

+ Kelola Sampah dengan
+ + Data IoT Real-Time + +

+ +

+ Pantau volume sampah di setiap gedung secara real-time. Minimalkan sampah meluap, optimalkan rute armada kebersihan, dan jaga lingkungan kampus tetap bersih dan asri. +

+ +
+ {session ? ( + +
+ Masuk ke Dashboard +
+ + ) : ( + <> + +
+ Mulai Sekarang +
+ + + Coba Simulator + + + )} +
+
+ + {/* Hero Right Content - Dashboard Mockup Image with Premium Browser Frame (Hidden on Mobile) */} +
+ {/* Glowing Backdrop Aura */} +
+ + {/* Browser Mockup Container */} +
+ {/* Browser Header Bar */} +
+ {/* Mac Dots */} +
+
+
+
+
+ {/* Simulated URL bar */} +
+ trashware.id/dashboard +
+ {/* Spacer */} +
+
+ + {/* Dashboard Screenshot Image Container (Self-adapting without crop) */} +
+ Trashware Live Dashboard +
+
+
+ +
+
+ + {/* Features Section */} +
+
+
+ Didesain untuk Efisiensi +

+ Unggul dalam Operasional & Manajemen +

+

+ Serangkaian fitur terintegrasi yang dirancang untuk mempercepat koordinasi pengambilan sampah dan menjaga kebersihan lingkungan tanpa beban administrasi. +

+
+ +
+ {/* Card 1 */} +
+
+ +
+

Syncing Telemetri

+

+ Menghubungkan sensor ultrasonik IoT langsung ke Firestore dengan langganan database real-time untuk pembaruan data instan. +

+
+ + {/* Card 2 */} +
+
+ +
+

Urutan Prioritas

+

+ Menghitung prioritas pengambilan berdasarkan durasi tingkat pengisian sampah agar lokasi yang paling kritis dibersihkan terlebih dahulu. +

+
+ + {/* Card 3 */} +
+
+ +
+

Notifikasi Otomatis

+

+ Mendeteksi kondisi penuh secara langsung untuk menghasilkan notifikasi on-the-fly dengan penanda unread yang efisien di Firestore. +

+
+ + {/* Card 4 */} +
+
+ +
+

Histori

+

+ Merekam histori telemetri secara berkala untuk analisis performa jangka panjang dan pelaporan. +

+
+
+
+
+ + {/* Interactive Simulator Section */} +
+
+
+ +
+
+ Coba Platform Kami +

+ Coba Simulator Sensor Secara Langsung +

+

+ Perangkat IoT mengirimkan telemetri secara berkelanjutan. Pada panel simulator di sebelah kanan, Anda dapat menyimulasikan tempat sampah pintar fisik. Coba naikkan level isi hingga 90% atau lebih dan lihat perubahan status operasional. +

+ +
    +
  • + + Kontrol penyesuaian level isi secara interaktif +
  • +
  • + + Perubahan status real-time (Online / Offline) +
  • +
  • + + Notifikasi otomatis saat kapasitas penuh +
  • +
+ +
+ {session ? ( + + + Buka Dashboard + + + + ) : ( + + + Masuk untuk Akses Dashboard + + + + )} +
+
+ +
+ {/* Simulator Card duplicating the interactive preview for full attention */} +
+
+

+ + Panel Simulator TR-ENG-04 +

+
+ + Aktif +
+
+ +
+ {/* Slider control */} +
+
+ Level Isi Sampah: + = 90 ? "text-red-500" : "text-emerald-500"}`}> + {simLevel}% + +
+ setSimLevel(Number(e.target.value))} + disabled={simStatus === "off"} + className="w-full accent-emerald-500 h-2 bg-slate-800 rounded-lg cursor-pointer disabled:opacity-40" + /> +
+ + {/* Live Display Visualizer */} +
+
+
= 90 + ? "bg-red-500" + : simLevel >= 70 + ? "bg-orange-500" + : "bg-emerald-500" + }`} + style={{ height: `${simStatus === "on" ? simLevel : 0}%` }} + /> +
+ +
+

+ Kategori Status: {getSimLabel(simLevel, simStatus)} +

+

+ Status Operasional: {simStatus === "on" ? "Online" : "Offline"} +

+ + +
+
+ + {/* Trigger alert output */} + {simLevel >= 90 && simStatus === "on" ? ( +
+
+ +
+
+

Notifikasi Simulasi Terkirim

+

Telemetri perangkat memicu permintaan pengambilan otomatis pada dashboard utama.

+
+
+ ) : ( +
+
+ +
+

+ Level sampah normal. Status operasional dalam batas aman. Pengambilan belum diperlukan. +

+
+ )} +
+
+
+ +
+
+
+ + {/* Tech Stack Section */} +
+
+ Infrastruktur Modern +

+ Teknologi & Ekosistem Terintegrasi +

+ +
+ {/* Next.js Card */} +
+
+ +

+ Next.js +

+
+

Server-Side Rendering & Pages Routing framework.

+
+ + {/* Firebase Card */} +
+
+ +

+ Firebase +

+
+

Firestore Real-time Subscriptions database telemetry.

+
+ + {/* NextAuth.js Card */} +
+
+ +

+ NextAuth.js +

+
+

Otentikasi & otorisasi berbasis token JWT dan Role.

+
+ + {/* Tailwind CSS Card */} +
+
+ +

+ Tailwind CSS +

+
+

Pengembangan styling responsif berbasis utility-first.

+
+ + {/* ESP32 Card */} +
+
+ +

+ ESP32 Node MCU +

+
+

Mikrokontroler klien pengirim data telemetri sensor ultrasonik.

+
+ + {/* GCP Card */} +
+
+ +

+ Google Cloud (GCP) +

+
+

Penyimpanan Firestore DB, Hosting, dan Cloud Functions backend.

+
+ + {/* Hadoop Card */} +
+
+ +

+ Apache Hadoop +

+
+

Pemrosesan batch data besar historis tempat sampah offline.

+
+ + {/* React Card */} +
+
+ +

+ React.js +

+
+

Pustaka UI deklaratif responsif berbasis komponen web reusable.

+
+
+
+
+ + {/* Footer */} +
+
+
+ {/* Brand Column */} +
+
+
+ Trashware Logo +
+ + TrashWare + +
+

+ Sistem pemantauan tempat sampah pintar berbasis IoT untuk mendukung kebersihan, keberlanjutan, dan efisiensi operasional kampus secara real-time. +

+
+ + + +
+
+ + {/* Quick Links Column */} + + + {/* Platform Column */} +
+

Akses

+
    +
  • + + + Masuk Aplikasi + + +
  • +
  • + + + Daftar Akun Baru + + +
  • +
+
- if (status === "loading") return

Loading...

; + {/* Status Sistem Column */} +
+

Status Sistem

+
    +
  • + Database Firestore: + + + Online + +
  • +
  • + IoT Gateway (ESP32): + + + Aktif + +
  • +
  • + API Service: + + + Normal + +
  • +
+
+
- return ; + {/* Copyright Bottom Bar */} +
+

© {new Date().getFullYear()} TrashWare IoT Operations. All rights reserved.

+
+
+
+
+ ); } diff --git a/src/views/auth/login/index.tsx b/src/views/auth/login/index.tsx index 157ddf8..e83a19c 100644 --- a/src/views/auth/login/index.tsx +++ b/src/views/auth/login/index.tsx @@ -23,7 +23,7 @@ export default function LoginPage() { }); if (res?.ok) { - router.push("/"); // redirect ke dashboard/home + router.push("/dashboard"); // redirect ke dashboard/home } else { alert("Login gagal!"); } @@ -121,7 +121,7 @@ export default function LoginPage() {
{/* Google */} -
{/* Google Login */} -