router.push("/profile")} className="flex items-center gap-3 hover:opacity-80 transition">
@@ -105,7 +105,7 @@ export default function Navbar({ onMenuClick }: NavbarProps) {
) : (
- {(session?.user?.name || "").split(" ").map((n: string) => n[0]).slice(0,2).join("")}
+ {(session?.user?.name || "").split(" ").map((n: string) => n[0]).slice(0, 2).join("")}
)}
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 (
+
+ );
+
+ 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 */}
+
+
+ {/* 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) */}
+
+
+
+
+
+
+
+
+
+ {/* 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"}
+
+
+
+ {simStatus === "on" ? "Matikan Perangkat" : "Aktifkan Perangkat"}
+
+
+
+
+ {/* 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 */}
+
+
+ );
}
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 */}
-
signIn("google", { callbackUrl: "/" })} className="w-full flex items-center justify-center gap-2 border border-slate-200 hover:bg-slate-50 py-3 rounded-xl transition">
+ signIn("google", { callbackUrl: "/dashboard" })} className="w-full flex items-center justify-center gap-2 border border-slate-200 hover:bg-slate-50 py-3 rounded-xl transition">
Masuk dengan Google
diff --git a/src/views/auth/register/index.tsx b/src/views/auth/register/index.tsx
index e756d7d..d638ad3 100644
--- a/src/views/auth/register/index.tsx
+++ b/src/views/auth/register/index.tsx
@@ -131,7 +131,7 @@ export default function RegisterPage() {