diff --git a/app/dashboard/admin/page.tsx b/app/dashboard/admin/dashboard/page.tsx similarity index 74% rename from app/dashboard/admin/page.tsx rename to app/dashboard/admin/dashboard/page.tsx index 41f7fa2..91a081f 100644 --- a/app/dashboard/admin/page.tsx +++ b/app/dashboard/admin/dashboard/page.tsx @@ -1,12 +1,12 @@ import DashboardNavbar from "@/components/dashboard/dashboard-navbar"; -import AdminTable from "@/components/table/admin-table"; +import AdminDashboard from "@/components/table/admin-table"; export default function AdminPage() { return (
- +
); diff --git a/app/dashboard/admin/user-management/page.tsx b/app/dashboard/admin/user-management/page.tsx new file mode 100644 index 0000000..ac752ac --- /dev/null +++ b/app/dashboard/admin/user-management/page.tsx @@ -0,0 +1,13 @@ +import DashboardNavbar from "@/components/dashboard/dashboard-navbar"; +import UserManagementTable from "@/components/table/user-management-table"; + +export default function UserManagementPage() { + return ( +
+ +
+ +
+
+ ); +} diff --git a/app/page.tsx b/app/page.tsx index 59962cd..1abb1cc 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,5 +1,6 @@ import Footer from "@/components/landing-page/footer"; import Header from "@/components/landing-page/header"; +import MediaOptions from "@/components/landing-page/media-options"; import Navbar from "@/components/landing-page/navbar"; export default function Home() { @@ -8,6 +9,7 @@ export default function Home() {
+
diff --git a/components/dashboard/dashboard-navbar.tsx b/components/dashboard/dashboard-navbar.tsx index 5c45865..94c347a 100644 --- a/components/dashboard/dashboard-navbar.tsx +++ b/components/dashboard/dashboard-navbar.tsx @@ -1,7 +1,13 @@ "use client"; import Image from "next/image"; -import { Bell, LogOut } from "lucide-react"; +import { + Bell, + Images, + LayoutDashboardIcon, + LogOut, + UserCog2Icon, +} from "lucide-react"; import Link from "next/link"; import { usePathname, useRouter } from "next/navigation"; import { useEffect, useState } from "react"; @@ -30,7 +36,7 @@ export default function DashboardNavbar() { const pathname = usePathname(); const [role, setRole] = useState(null); const [activeTab, setActiveTab] = useState("Manajemen User"); - const [approverTab, setApproverTab] = useState("Kurasi Konten"); + // const [approverTab, setApproverTab] = useState("Kurasi Konten"); const segments = pathname.split("/").filter(Boolean); @@ -90,17 +96,26 @@ export default function DashboardNavbar() { {role === "admin" && (
+ +
@@ -109,7 +124,7 @@ export default function DashboardNavbar() { {/* APPROVER */} {role === "approver" && (
- {["Kurasi Konten", "Publish Konten"].map((tab) => ( + {/* {["Kurasi Konten", "Publish Konten"].map((tab) => ( - ))} + ))} */}
)} {/* SUPERVISOR */} {role === "supervisor" && ( -
- Supervisor Dashboard -
+
)} {/* USER */} {role === "user" && ( -
- User Dashboard -
+
)} diff --git a/components/form/login.tsx b/components/form/login.tsx index 40bea48..41a6a11 100644 --- a/components/form/login.tsx +++ b/components/form/login.tsx @@ -47,7 +47,7 @@ export default function Login() { e.preventDefault(); const foundUser = users.find( - (u) => u.nrp === nrp && u.password === password + (u) => u.nrp === nrp && u.password === password, ); if (!foundUser) { @@ -61,7 +61,7 @@ export default function Login() { // ✅ Redirect sesuai role switch (foundUser.role) { case "admin": - router.push("/dashboard/admin"); + router.push("/dashboard/admin/user-management"); break; case "user": router.push("/dashboard/user"); diff --git a/components/landing-page/header.tsx b/components/landing-page/header.tsx index 689530a..70099f7 100644 --- a/components/landing-page/header.tsx +++ b/components/landing-page/header.tsx @@ -4,9 +4,9 @@ export default function Header() { return (
{/* Bagian Atas */} -
-
-

+
+
+

Capai Audiens yang Lebih Luas dengan melakukan
Promote di CampaignPOOL

@@ -27,10 +27,12 @@ export default function Header() { {/* Bagian Langkah-langkah */}
-

+

Cara Promote di CampaignPOOL

-

Langkah mudah untuk memasang iklan

+

+ Langkah mudah untuk memasang iklan +

{/* Langkah-langkah */}
@@ -45,10 +47,10 @@ export default function Header() { className="object-contain" />
-

+

Langkah 1

-

+

Pilih tanggal tayang, tentukan target promote, dan unggah materi iklan

@@ -65,10 +67,10 @@ export default function Header() { className="object-contain" />
-

+

Langkah 2

-

+

Pemrosesan Internal dan Persetujuan

@@ -84,10 +86,10 @@ export default function Header() { className="object-contain" />
-

+

Langkah 3

-

+

Selamat! Promote Anda tayang

@@ -104,10 +106,10 @@ export default function Header() { className="object-contain" />
-

+

Langkah 4

-

+

Pantau perkembangan Promote Anda

diff --git a/components/landing-page/media-options.tsx b/components/landing-page/media-options.tsx new file mode 100644 index 0000000..f8241a0 --- /dev/null +++ b/components/landing-page/media-options.tsx @@ -0,0 +1,76 @@ +import Image from "next/image"; + +export default function MediaOptions() { + const items = [ + { + title: "Videotron", + desc: "Large-format advertising di lokasi strategis dengan traffic tinggi", + img: "/videotron.png", + }, + { + title: "Media Online", + desc: "Branding interior kereta api dengan jangkauan penumpang tinggi", + img: "/gemini.png", + }, + { + title: "Media Sosial", + desc: "Display digital untuk konten dinamis dan engaging di stasiun & mall", + img: "/ai.png", + }, + { + title: "Radio Polri", + desc: "Large-format advertising di lokasi strategis dengan traffic tinggi", + img: "/radio.png", + }, + { + title: "TV Polri", + desc: "Branding interior kereta api dengan jangkauan penumpang tinggi", + img: "/tvpolri.png", + }, + { + title: "Majalah Digital", + desc: "Display digital untuk konten dinamis dan engaging di stasiun & mall", + img: "/majalah.png", + }, + ]; + + return ( +
+
+

+ Pilihan Media Iklan untuk Brand Anda +

+

+ Maksimalkan visibilitas brand dengan media iklan strategis +

+
+ +
+ {items.map((item, index) => ( +
+
+ {item.title} +
+ +
+

{item.title}

+

{item.desc}

+ + +
+
+ ))} +
+
+ ); +} diff --git a/components/table/admin-table.tsx b/components/table/admin-table.tsx index 1e52135..5aaeedf 100644 --- a/components/table/admin-table.tsx +++ b/components/table/admin-table.tsx @@ -1,127 +1,425 @@ "use client"; import { useState } from "react"; +import { Card, CardContent } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table"; -import DialogUserDetail from "../dialog/admin-detail"; + BarChart, + Bar, + XAxis, + YAxis, + Tooltip, + ResponsiveContainer, + PieChart, + Pie, + Cell, + RadarChart, + PolarGrid, + PolarAngleAxis, + PolarRadiusAxis, + Radar, + Legend, + AreaChart, + CartesianGrid, + Area, +} from "recharts"; -export default function AdminTable() { - const [selectedUser, setSelectedUser] = useState(null); - const [isDialogOpen, setIsDialogOpen] = useState(false); +export default function AdminDashboard() { + const [range, setRange] = useState("1 Day"); - const data = [ - { - createdAt: "14 Januari 2025 13:00", - fullName: "Novan Farhandi", - email: "novanfarhandi@example.com", - status: "Approved", - }, - { - createdAt: "14 Januari 2025 13:00", - fullName: "Salma Husna", - email: "salmahusna@example.com", - status: "Tertunda", - }, + const userData = [ + { name: "Salma Husna", value: 80 }, + { name: "Sheva", value: 70 }, + { name: "Haryanto Wijaya", value: 55 }, + { name: "Rina Wati", value: 55 }, + { name: "Novan Farhandi", value: 40 }, ]; - const openDialog = (user: any) => { - setSelectedUser(user); - setIsDialogOpen(true); - }; + const mediaData = [ + { name: "Media Sosial", value: 30 }, + { name: "Media Online", value: 25 }, + { name: "Videotron", value: 20 }, + { name: "Radio Polri", value: 10 }, + { name: "TV Polri", value: 8 }, + { name: "Majalah Digital", value: 12 }, + ]; - const closeDialog = () => { - setIsDialogOpen(false); - setSelectedUser(null); - }; + const colors = [ + "#1D4ED8", + "#10B981", + "#F59E0B", + "#F97316", + "#86EFAC", + "#A78BFA", + ]; + + const FilterButton = ({ + label, + value, + setValue, + }: { + label: string; + value: string; + setValue: (val: string) => void; + }) => ( + + ); + + const [rangeLine, setRangeLine] = useState("1 Day"); + const [rangeChart, setRangeChart] = useState("1 Day"); + const [rangeCalendar, setRangeCalendar] = useState("1 Day"); + const [rangeLineChart, setRangeLineChart] = useState("1 Day"); + const [rangeMedsos, setRangeMedsos] = useState("1 Day"); + + const lineData = Array.from({ length: 24 }).map((_, i) => ({ + time: `${i}:00`, + value: Math.floor(Math.random() * 100), + })); + + const radarData = [ + { subject: "Instagram", humas: 90, polda: 85 }, + { subject: "Facebook", humas: 70, polda: 40 }, + { subject: "Twitter (X)", humas: 50, polda: 80 }, + { subject: "TikTok", humas: 60, polda: 55 }, + { subject: "YouTube", humas: 65, polda: 60 }, + ]; + + const colorsChart = ["#2563EB", "#10B981"]; + + const FilterButtonLine = ({ label }: { label: string }) => ( + + ); return ( -
-
- - - - Nama Lengkap - Email - Tanggal Daftar - Status - Tindakan - - +
+ {/* Header */} +
+

Analitik Campaignpool

+ +
- - {data.map((row, i) => ( - - {row.fullName} - - {row.email} - - {row.createdAt} +
+ {/* Chart 1 */} + + +
+

Pengguna Paling Aktif

- - + + + + +
+
+ +
+ + + + + + + + +
+ + + + {/* Chart 2 */} + + +
+

Media Paling Favorit

+ +
+ + + + +
+
+ +
+ + + - {row.status} - - + {mediaData.map((_, index) => ( + + ))} + + + + +
- -
- - - -
-
-
- ))} -
-
+ {/* Legend */} +
+ {mediaData.map((item, i) => ( +
+ + {item.name} +
+ ))} +
+ +
+ + +
+

Heatmap Order Publish

- {/* Pagination */} -
-
- Rows per page: - -
- -
- 1–1 of 1 -
- - +
+ + + + +
-
-
- {/* ✅ Dialog terpisah */} - -
+ {/* Heatmap Grid */} +
+
+ {[ + "", + "Jan", + "Feb", + "Mar", + "Apr", + "Mei", + "Jun", + "Jul", + "Agu", + "Sep", + "Okt", + "Nov", + "Des", + ].map((m, i) => ( +
+ {m} +
+ ))} + + {["Sen", "Sel", "Rab", "Kam", "Jum", "Sab", "Min"].map( + (day, rowIndex) => ( + <> +
+ {day} +
+ {Array.from({ length: 12 }).map((_, colIndex) => { + const intensity = Math.floor(Math.random() * 5); + const colors = [ + "bg-gray-200", + "bg-blue-200", + "bg-blue-400", + "bg-blue-600", + "bg-blue-800", + ]; + return ( +
+ ); + })} + + ), + )} +
+
+ + {/* Legend */} +
+ Less + {[0, 1, 2, 3, 4].map((i) => ( +
+ ))} + More +
+ + +
+ {/* Line Chart */} + + +
+

Produksi Konten Internal

+
+ + + + +
+
+ +
+ + + + + + + + + + + + + + + +
+
+
+ + {/* RADAR CHART (FIXED) */} + + +
+

Engagement Media Sosial

+
+ + + + +
+
+ +
+ + + + + + + + + + +
+
+
+
+
); } diff --git a/components/table/approver-table.tsx b/components/table/approver-table.tsx index 2784cbf..5cd2905 100644 --- a/components/table/approver-table.tsx +++ b/components/table/approver-table.tsx @@ -31,7 +31,7 @@ export default function ApproverTable() { { id: 1, no: 1, - media: "Media Online", + media: "Online Media", title: "Lorem ipsum dolor sit amet consectetur. Tempor mi scelerisque enim semper sed nibh. Eget sit molestie.", status: "Tertunda", @@ -39,7 +39,7 @@ export default function ApproverTable() { { id: 2, no: 2, - media: "Media Sosial", + media: "Social Media", title: "Lorem ipsum dolor sit amet consectetur. Ultricies pellentesque ullamcorper mattis pellentesque. Amet eu ut.", status: "Tertunda", @@ -82,7 +82,7 @@ export default function ApproverTable() { const filteredData = useMemo(() => { if (activeCategory === "Semua") return data; return data.filter( - (item) => item.media.toLowerCase() === activeCategory.toLowerCase() + (item) => item.media.toLowerCase() === activeCategory.toLowerCase(), ); }, [activeCategory]); @@ -100,7 +100,7 @@ export default function ApproverTable() { key={cat} value={cat} className={cn( - "data-[state=active]:bg-white data-[state=active]:text-black data-[state=active]:font-semibold text-gray-300 rounded-lg text-sm sm:text-base transition-all px-4 py-2 whitespace-nowrap" + "data-[state=active]:bg-white data-[state=active]:text-black data-[state=active]:font-semibold text-gray-300 rounded-lg text-sm sm:text-base transition-all px-4 py-2 whitespace-nowrap", )} > {cat} @@ -146,7 +146,7 @@ export default function ApproverTable() { "px-2 sm:px-3 py-1 rounded-full text-[10px] sm:text-xs font-medium whitespace-nowrap", item.status === "Tertunda" ? "bg-gray-200 text-gray-600" - : "bg-green-100 text-green-800" + : "bg-green-100 text-green-800", )} > {item.status} diff --git a/components/table/supervisor-data.tsx b/components/table/supervisor-data.tsx index 4e90667..47376e3 100644 --- a/components/table/supervisor-data.tsx +++ b/components/table/supervisor-data.tsx @@ -19,6 +19,7 @@ export default function SupervisorData() { type: "bar", toolbar: { show: false }, }, + colors: ["#4E79A7"], // 👈 tambahkan ini plotOptions: { bar: { borderRadius: 4, @@ -51,19 +52,19 @@ export default function SupervisorData() { breakpoint: 768, options: { plotOptions: { - bar: { - columnWidth: "60%", - }, + bar: { columnWidth: "60%" }, }, xaxis: { - labels: { rotate: -30, style: { fontSize: "9px" } }, + labels: { + rotate: -30, + style: { fontSize: "9px" }, + }, }, dataLabels: { enabled: false }, }, }, ], }; - const chartDataSatker = [ { name: "Total Konten", diff --git a/components/table/user-management-table.tsx b/components/table/user-management-table.tsx new file mode 100644 index 0000000..13fd6ac --- /dev/null +++ b/components/table/user-management-table.tsx @@ -0,0 +1,127 @@ +"use client"; + +import { useState } from "react"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import DialogUserDetail from "../dialog/admin-detail"; + +export default function UserManagementTable() { + const [selectedUser, setSelectedUser] = useState(null); + const [isDialogOpen, setIsDialogOpen] = useState(false); + + const data = [ + { + createdAt: "14 Januari 2025 13:00", + fullName: "Novan Farhandi", + email: "novanfarhandi@example.com", + status: "Approved", + }, + { + createdAt: "14 Januari 2025 13:00", + fullName: "Salma Husna", + email: "salmahusna@example.com", + status: "Tertunda", + }, + ]; + + const openDialog = (user: any) => { + setSelectedUser(user); + setIsDialogOpen(true); + }; + + const closeDialog = () => { + setIsDialogOpen(false); + setSelectedUser(null); + }; + + return ( +
+
+ + + + Nama Lengkap + Email + Tanggal Daftar + Status + Tindakan + + + + + {data.map((row, i) => ( + + {row.fullName} + + {row.email} + + {row.createdAt} + + + + {row.status} + + + + +
+ + + +
+
+
+ ))} +
+
+
+ + {/* Pagination */} +
+
+ Rows per page: + +
+ +
+ 1–1 of 1 +
+ + +
+
+
+ + {/* ✅ Dialog terpisah */} + +
+ ); +} diff --git a/components/table/user-table.tsx b/components/table/user-table.tsx index 0301d68..5420fc1 100644 --- a/components/table/user-table.tsx +++ b/components/table/user-table.tsx @@ -47,7 +47,6 @@ export default function UserTable() { return ( <>
-

Daftar Campaign