426 lines
13 KiB
TypeScript
426 lines
13 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { Card, CardContent } from "@/components/ui/card";
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
BarChart,
|
|
Bar,
|
|
XAxis,
|
|
YAxis,
|
|
Tooltip,
|
|
ResponsiveContainer,
|
|
PieChart,
|
|
Pie,
|
|
Cell,
|
|
RadarChart,
|
|
PolarGrid,
|
|
PolarAngleAxis,
|
|
PolarRadiusAxis,
|
|
Radar,
|
|
Legend,
|
|
AreaChart,
|
|
CartesianGrid,
|
|
Area,
|
|
} from "recharts";
|
|
|
|
export default function AdminDashboard() {
|
|
const [range, setRange] = useState("1 Day");
|
|
|
|
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 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 colors = [
|
|
"#1D4ED8",
|
|
"#10B981",
|
|
"#F59E0B",
|
|
"#F97316",
|
|
"#86EFAC",
|
|
"#A78BFA",
|
|
];
|
|
|
|
const FilterButton = ({
|
|
label,
|
|
value,
|
|
setValue,
|
|
}: {
|
|
label: string;
|
|
value: string;
|
|
setValue: (val: string) => void;
|
|
}) => (
|
|
<button
|
|
onClick={() => setValue(label)}
|
|
className={`px-3 py-1 rounded-md text-sm ${
|
|
value === label ? "bg-white text-black" : "text-gray-300"
|
|
}`}
|
|
>
|
|
{label}
|
|
</button>
|
|
);
|
|
|
|
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 }) => (
|
|
<button
|
|
onClick={() => setRange(label)}
|
|
className={`px-3 py-1 rounded-md text-sm ${
|
|
range === label ? "bg-white text-black" : "text-gray-300"
|
|
}`}
|
|
>
|
|
{label}
|
|
</button>
|
|
);
|
|
|
|
return (
|
|
<section className="p-6 space-y-6">
|
|
{/* Header */}
|
|
<div className="flex justify-between items-center">
|
|
<h1 className="text-xl font-semibold">Analitik Campaignpool</h1>
|
|
<Button className="bg-blue-600 text-white rounded-sm">
|
|
Unduh Laporan
|
|
</Button>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
{/* Chart 1 */}
|
|
<Card className="rounded-2xl shadow-sm">
|
|
<CardContent className="p-4">
|
|
<div className="flex justify-between items-center mb-4">
|
|
<h2 className="font-semibold">Pengguna Paling Aktif</h2>
|
|
|
|
<div className="bg-black rounded-lg flex gap-2 p-1">
|
|
<FilterButton
|
|
label="1 Day"
|
|
value={rangeLine}
|
|
setValue={setRangeLine}
|
|
/>
|
|
<FilterButton
|
|
label="7 Days"
|
|
value={rangeLine}
|
|
setValue={setRangeLine}
|
|
/>
|
|
<FilterButton
|
|
label="30 Days"
|
|
value={rangeLine}
|
|
setValue={setRangeLine}
|
|
/>
|
|
<FilterButton
|
|
label="Custom"
|
|
value={rangeLine}
|
|
setValue={setRangeLine}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="h-64">
|
|
<ResponsiveContainer width="100%" height="100%">
|
|
<BarChart data={userData} layout="vertical">
|
|
<XAxis type="number" hide />
|
|
<YAxis dataKey="name" type="category" />
|
|
<Tooltip />
|
|
<Bar dataKey="value" fill="#4E79A7" radius={[6, 6, 6, 6]} />
|
|
</BarChart>
|
|
</ResponsiveContainer>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Chart 2 */}
|
|
<Card className="rounded-2xl shadow-sm">
|
|
<CardContent className="p-4">
|
|
<div className="flex justify-between items-center mb-4">
|
|
<h2 className="font-semibold">Media Paling Favorit</h2>
|
|
|
|
<div className="bg-black rounded-lg flex gap-2 p-1">
|
|
<FilterButton
|
|
label="1 Day"
|
|
value={rangeChart}
|
|
setValue={setRangeChart}
|
|
/>
|
|
<FilterButton
|
|
label="7 Days"
|
|
value={rangeChart}
|
|
setValue={setRangeChart}
|
|
/>
|
|
<FilterButton
|
|
label="30 Days"
|
|
value={rangeChart}
|
|
setValue={setRangeChart}
|
|
/>
|
|
<FilterButton
|
|
label="Custom"
|
|
value={rangeChart}
|
|
setValue={setRangeChart}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="h-64 flex items-center justify-center">
|
|
<ResponsiveContainer width="100%" height="100%">
|
|
<PieChart>
|
|
<Pie
|
|
data={mediaData}
|
|
innerRadius={60}
|
|
outerRadius={90}
|
|
paddingAngle={4}
|
|
dataKey="value"
|
|
>
|
|
{mediaData.map((_, index) => (
|
|
<Cell key={index} fill={colors[index % colors.length]} />
|
|
))}
|
|
</Pie>
|
|
<Tooltip />
|
|
</PieChart>
|
|
</ResponsiveContainer>
|
|
</div>
|
|
|
|
{/* Legend */}
|
|
<div className="flex flex-wrap justify-center gap-4 mt-4 text-sm">
|
|
{mediaData.map((item, i) => (
|
|
<div key={i} className="flex items-center gap-2">
|
|
<span
|
|
className="w-3 h-3 rounded-sm"
|
|
style={{ backgroundColor: colors[i] }}
|
|
/>
|
|
{item.name}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
<Card className="rounded-2xl shadow-sm">
|
|
<CardContent className="p-4">
|
|
<div className="flex justify-between items-center mb-4 ">
|
|
<h2 className="font-semibold">Heatmap Order Publish</h2>
|
|
|
|
<div className="bg-black rounded-lg flex gap-2 p-1">
|
|
<FilterButton
|
|
label="1 Day"
|
|
value={rangeCalendar}
|
|
setValue={setRangeCalendar}
|
|
/>
|
|
<FilterButton
|
|
label="7 Days"
|
|
value={rangeCalendar}
|
|
setValue={setRangeCalendar}
|
|
/>
|
|
<FilterButton
|
|
label="30 Days"
|
|
value={rangeCalendar}
|
|
setValue={setRangeCalendar}
|
|
/>
|
|
<FilterButton
|
|
label="Custom"
|
|
value={rangeCalendar}
|
|
setValue={setRangeCalendar}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Heatmap Grid */}
|
|
<div className="overflow-x-auto">
|
|
<div className="grid grid-cols-13 gap-2 text-sm items-center">
|
|
{[
|
|
"",
|
|
"Jan",
|
|
"Feb",
|
|
"Mar",
|
|
"Apr",
|
|
"Mei",
|
|
"Jun",
|
|
"Jul",
|
|
"Agu",
|
|
"Sep",
|
|
"Okt",
|
|
"Nov",
|
|
"Des",
|
|
].map((m, i) => (
|
|
<div key={i} className="text-center text-gray-500">
|
|
{m}
|
|
</div>
|
|
))}
|
|
|
|
{["Sen", "Sel", "Rab", "Kam", "Jum", "Sab", "Min"].map(
|
|
(day, rowIndex) => (
|
|
<>
|
|
<div key={day} className="text-gray-500">
|
|
{day}
|
|
</div>
|
|
{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 (
|
|
<div
|
|
key={colIndex}
|
|
className={`h-6 rounded ${colors[intensity]}`}
|
|
/>
|
|
);
|
|
})}
|
|
</>
|
|
),
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Legend */}
|
|
<div className="flex justify-end items-center gap-2 mt-4 text-sm text-gray-500">
|
|
<span>Less</span>
|
|
{[0, 1, 2, 3, 4].map((i) => (
|
|
<div
|
|
key={i}
|
|
className={`w-4 h-4 rounded ${
|
|
[
|
|
"bg-gray-200",
|
|
"bg-blue-200",
|
|
"bg-blue-400",
|
|
"bg-blue-600",
|
|
"bg-blue-800",
|
|
][i]
|
|
}`}
|
|
/>
|
|
))}
|
|
<span>More</span>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
{/* Line Chart */}
|
|
<Card className="rounded-2xl shadow-sm">
|
|
<CardContent className="p-4">
|
|
<div className="flex justify-between items-center mb-4">
|
|
<h2 className="font-semibold">Produksi Konten Internal</h2>
|
|
<div className="bg-black rounded-lg flex gap-2 p-1">
|
|
<FilterButton
|
|
label="1 Day"
|
|
value={rangeLineChart}
|
|
setValue={setRangeLineChart}
|
|
/>
|
|
<FilterButton
|
|
label="7 Days"
|
|
value={rangeLineChart}
|
|
setValue={setRangeLineChart}
|
|
/>
|
|
<FilterButton
|
|
label="30 Days"
|
|
value={rangeLineChart}
|
|
setValue={setRangeLineChart}
|
|
/>
|
|
<FilterButton
|
|
label="Custom"
|
|
value={rangeLineChart}
|
|
setValue={setRangeLineChart}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="h-64">
|
|
<ResponsiveContainer width="100%" height="100%">
|
|
<AreaChart data={lineData}>
|
|
<defs>
|
|
<linearGradient id="color" x1="0" y1="0" x2="0" y2="1">
|
|
<stop offset="5%" stopColor="#2563EB" stopOpacity={0.4} />
|
|
<stop offset="95%" stopColor="#2563EB" stopOpacity={0} />
|
|
</linearGradient>
|
|
</defs>
|
|
<CartesianGrid strokeDasharray="3 3" />
|
|
<XAxis dataKey="time" />
|
|
<YAxis />
|
|
<Tooltip />
|
|
<Area
|
|
type="monotone"
|
|
dataKey="value"
|
|
stroke="#2563EB"
|
|
fill="url(#color)"
|
|
strokeWidth={3}
|
|
dot={{ r: 4 }}
|
|
/>
|
|
</AreaChart>
|
|
</ResponsiveContainer>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* RADAR CHART (FIXED) */}
|
|
<Card className="rounded-2xl shadow-sm">
|
|
<CardContent className="p-4">
|
|
<div className="flex justify-between items-center mb-4">
|
|
<h2 className="font-semibold">Engagement Media Sosial</h2>
|
|
<div className="bg-black rounded-lg flex gap-2 p-1">
|
|
<FilterButtonLine label="1 Day" />
|
|
<FilterButtonLine label="7 Days" />
|
|
<FilterButtonLine label="30 Days" />
|
|
<FilterButtonLine label="Custom" />
|
|
</div>
|
|
</div>
|
|
|
|
<div className="h-64">
|
|
<ResponsiveContainer width="100%" height="100%">
|
|
<RadarChart data={radarData}>
|
|
<PolarGrid />
|
|
<PolarAngleAxis dataKey="subject" />
|
|
<PolarRadiusAxis />
|
|
<Radar
|
|
name="Humas Mabes"
|
|
dataKey="humas"
|
|
stroke="#2563EB"
|
|
fill="#2563EB"
|
|
fillOpacity={0.4}
|
|
/>
|
|
<Radar
|
|
name="Polda"
|
|
dataKey="polda"
|
|
stroke="#10B981"
|
|
fill="#10B981"
|
|
fillOpacity={0.4}
|
|
/>
|
|
<Legend />
|
|
</RadarChart>
|
|
</ResponsiveContainer>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|