fix:dashboard with api

This commit is contained in:
Rama Priyanto 2025-06-28 23:39:22 +07:00
parent 9cb945d161
commit 39cc916259
6 changed files with 233 additions and 108 deletions

View File

@ -16,7 +16,7 @@ function getRangeAcrossMonths(
const sortedData = data.sort((a, b) => a.month - b.month); const sortedData = data.sort((a, b) => a.month - b.month);
console.log("sorted,data", sortedData); console.log("sorted,data", sortedData);
for (const monthData of sortedData) { for (const monthData of sortedData) {
const { month, users: u } = monthData; const { month, user_levels: u } = monthData;
if (month < startMonth || month > endMonth) continue; if (month < startMonth || month > endMonth) continue;
console.log("uuu", month, startMonth, endMonth, u.length); console.log("uuu", month, startMonth, endMonth, u.length);
@ -70,7 +70,6 @@ const ApexMultiLineChart = (props: {
useEffect(() => { useEffect(() => {
initFetch(); initFetch();
console.log("type", type);
}, [date, type, range.start, range.end]); }, [date, type, range.start, range.end]);
const initFetch = async () => { const initFetch = async () => {
@ -91,18 +90,11 @@ const ApexMultiLineChart = (props: {
); );
console.log("fetch", res?.data?.data); console.log("fetch", res?.data?.data);
data = res?.data?.data; data = res?.data?.data;
data = dummy.data; // data = dummy.data;
setDatas(data); setDatas(data);
} }
if (type === "daily") { if (type === "daily") {
console.log(
"aaa",
range.start.month,
range.start.day,
range.end.month,
range.end.day
);
const mappedData = getRangeAcrossMonths( const mappedData = getRangeAcrossMonths(
data, data,
range.start.month, range.start.month,
@ -121,8 +113,8 @@ const ApexMultiLineChart = (props: {
a.month == Number(splitDate[0]) && a.year === Number(splitDate[1]) a.month == Number(splitDate[0]) && a.year === Number(splitDate[1])
); );
if (getDatas) { if (getDatas) {
console.log("datanya", getDatas.users); console.log("datanya", getDatas.user_levels);
setSeries(getDatas.users); setSeries(getDatas.user_levels);
} else { } else {
setSeries([]); setSeries([]);
} }
@ -226,7 +218,7 @@ const ApexMultiLineChart = (props: {
text: "Articles", text: "Articles",
}, },
min: 0, min: 0,
max: 50, max: 70,
}, },
legend: { legend: {
position: "right", position: "right",

View File

@ -1023,7 +1023,7 @@ export default function DashboardContainer() {
</div> </div>
{roleId && Number(roleId) < 3 && ( {roleId && Number(roleId) < 3 && (
<div> <div>
<IndonesiaMap data={rawData} /> <IndonesiaMap />
<div className="border-1 shadow-sm w-full rounded-lg p-6 flex flex-col mt-4 h-[600px]"> <div className="border-1 shadow-sm w-full rounded-lg p-6 flex flex-col mt-4 h-[600px]">
<div className="flex justify-between mb-3"> <div className="flex justify-between mb-3">

View File

@ -34,8 +34,6 @@ export const Breadcrumb = () => {
return capitalizedWords.join(" "); return capitalizedWords.join(" ");
}); });
console.log("pathname : ", pathnameTransformed);
useEffect(() => { useEffect(() => {
setCurrentPage(pathnameSplit[pathnameSplit.length - 1]); setCurrentPage(pathnameSplit[pathnameSplit.length - 1]);
}, [pathnameSplit]); }, [pathnameSplit]);

View File

@ -1,4 +1,4 @@
import React, { useEffect, useRef, useState } from "react"; import React, { useEffect, useMemo, useRef, useState } from "react";
import * as echarts from "echarts"; import * as echarts from "echarts";
import indonesiaGeo from "../../public/assets/geo/indonesia.json"; import indonesiaGeo from "../../public/assets/geo/indonesia.json";
import { getStatisticForMaps } from "@/services/article"; import { getStatisticForMaps } from "@/services/article";
@ -9,8 +9,33 @@ import {
parseZonedDateTime, parseZonedDateTime,
parseAbsoluteToLocal, parseAbsoluteToLocal,
} from "@internationalized/date"; } from "@internationalized/date";
import {
Button,
DateRangePicker,
Popover,
PopoverContent,
PopoverTrigger,
Select,
SelectItem,
} from "@heroui/react";
import { format } from "date-fns";
import { ChevronLeftIcon, ChevronRightIcon } from "../icons";
const months = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
];
const IndonesiaMap = (props: { data: any }) => { const IndonesiaMap = () => {
const chartRef = useRef<HTMLDivElement>(null); const chartRef = useRef<HTMLDivElement>(null);
const myChart = useRef<echarts.EChartsType | null>(null); const myChart = useRef<echarts.EChartsType | null>(null);
const [selectedProvince, setSelectedProvince] = useState(""); const [selectedProvince, setSelectedProvince] = useState("");
@ -31,11 +56,15 @@ const IndonesiaMap = (props: { data: any }) => {
end: parseDate(convertDateFormatNoTimeV2(today)), end: parseDate(convertDateFormatNoTimeV2(today)),
}); });
const [data, setData] = useState([]); const handleMonthClick = (monthIndex: number) => {
setSelectedMonth(new Date(year, monthIndex, 1));
};
const [minMax, setMinMax] = useState({ min: 0, max: 0 });
const [data, setData] = useState<{ name: string; value: number }[]>([]);
useEffect(() => { useEffect(() => {
fetchData(); fetchData();
}, []); }, [viewsDailyDate]);
const fetchData = async () => { const fetchData = async () => {
const getDate = (data: any) => { const getDate = (data: any) => {
@ -48,53 +77,76 @@ const IndonesiaMap = (props: { data: any }) => {
getDate(viewsDailyDate.start), getDate(viewsDailyDate.start),
getDate(viewsDailyDate.end) getDate(viewsDailyDate.end)
); );
setData(res?.data?.data); if (res?.data?.data) {
const temp = [];
let min = Infinity;
let max = -Infinity;
for (const element of res?.data?.data) {
const value = element.totalVisitor;
const now = {
name: element.regionName.toUpperCase(),
value,
};
if (value < min) min = value;
if (value > max) max = value;
temp.push(now);
}
setData(temp);
setMinMax({ min: min, max: max });
} else {
setData([]);
setMinMax({ min: 0, max: 0 });
}
}; };
const option = { const option = useMemo(
backgroundColor: "#d3d3d3", () => ({
title: { backgroundColor: "#d3d3d3",
text: "Sebaran Data", title: {
left: "center", text: "Sebaran Data",
textStyle: { color: "#000" }, left: "center",
}, textStyle: { color: "#000" },
visualMap: {
min: 0,
max: 100,
show: true,
seriesIndex: 0,
inRange: {
color: ["#ff0000", "#ffffff"],
}, },
}, visualMap: {
series: [ min: minMax.min,
{ max: minMax.max,
type: "map", show: true,
map: "indonesia", seriesIndex: 0,
inRange: {
roam: true, color: ["#ff0000", "#ffffff"],
zoom: 1.2,
center: [118, -2],
label: {
show: false,
color: "#000",
}, },
itemStyle: { },
borderColor: "#999", series: [
}, {
emphasis: { type: "map",
map: "indonesia",
roam: true,
zoom: 1.2,
center: [118, -2],
label: { label: {
show: true, show: false,
color: "#000", color: "#000",
}, },
itemStyle: { itemStyle: {
areaColor: "#ffcccc", borderColor: "#999",
}, },
emphasis: {
label: {
show: true,
color: "#000",
},
itemStyle: {
areaColor: "#ffcccc",
},
},
data: data,
}, },
data: data, ],
}, }),
], [data, minMax]
}; );
useEffect(() => { useEffect(() => {
if (!chartRef.current) return; if (!chartRef.current) return;
@ -127,7 +179,15 @@ const IndonesiaMap = (props: { data: any }) => {
}; };
}, []); }, []);
useEffect(() => {
if (!myChart.current) return;
chartOptionRef.current = option;
myChart.current.setOption(option);
}, [option]);
const highlightProvince = (name: string) => { const highlightProvince = (name: string) => {
console.log("nameeed", name);
if (!myChart.current || !chartOptionRef.current) return; if (!myChart.current || !chartOptionRef.current) return;
myChart.current.clear(); myChart.current.clear();
@ -144,6 +204,7 @@ const IndonesiaMap = (props: { data: any }) => {
}); });
selectedProvinceRef.current = name; selectedProvinceRef.current = name;
setSelectedProvince(name);
}; };
return ( return (
@ -152,24 +213,98 @@ const IndonesiaMap = (props: { data: any }) => {
<div ref={chartRef} style={{ height: "100%", width: "100%" }} /> <div ref={chartRef} style={{ height: "100%", width: "100%" }} />
</div> </div>
<div className="w-screen md:w-[30%] h-[360px] lg:h-[600px] overflow-auto flex flex-col"> <div className="w-screen md:w-[30%] h-[360px] lg:h-[600px] overflow-auto flex flex-col">
{props.data.map((list: any) => ( <div className="flex flex-col lg:flex-row gap-2">
<a {/* <Select
key={list.name} className="w-full md:w-[140px] text-xs lg:text-sm h-[30px] lg:h-[40px]"
onClick={() => highlightProvince(list.name)} label=""
className={`w-full flex flex-row cursor-pointer gap-2 ${ labelPlacement="outside"
selectedProvince === list.name ? "bg-slate-300" : "" selectedKeys={[typeDate]}
}`} onChange={(e) =>
e.target.value !== "" && setTypeDate(e.target.value)
}
> >
<p className="w-4/5">{list.name}</p>{" "} <SelectItem key="monthly">Bulanan</SelectItem>
<p <SelectItem key="daily">Harian</SelectItem>
className={`w-1/5 ${ </Select> */}
selectedProvince === list.name ? "bg-slate-300" : "bg-[#a9d7e4]"
} text-black border-white text-center`} {typeDate === "monthly" ? (
<Popover placement="bottom" showArrow={true} className="w-full">
<PopoverTrigger>
<Button className="w-[140px] text-xs lg:text-sm h-[30px] lg:h-[40px] rounded-sm lg:rounded-lg">
{" "}
{selectedMonth
? format(selectedMonth, "MMMM yyyy")
: "Pilih Bulan"}
</Button>
</PopoverTrigger>
<PopoverContent className="p-4 w-[200px]">
<div className="flex items-center justify-between mb-2 px-1 w-full">
<button
className="text-gray-500 hover:text-black"
onClick={() => setYear((prev) => prev - 1)}
>
<ChevronLeftIcon />
</button>
<span className="font-semibold text-center">{year}</span>
<button
className="text-gray-500 hover:text-black"
onClick={() => setYear((prev) => prev + 1)}
>
<ChevronRightIcon />
</button>
</div>
<div className="grid grid-cols-3 gap-2 w-full">
{months.map((month, idx) => (
<button
key={idx}
onClick={() => handleMonthClick(idx)}
className={`py-1 rounded-md text-sm transition-colors ${
selectedMonth &&
selectedMonth.getMonth() === idx &&
selectedMonth.getFullYear() === year
? "bg-blue-500 text-white"
: "hover:bg-gray-200 text-gray-700"
}`}
>
{month}
</button>
))}
</div>
</PopoverContent>
</Popover>
) : (
<div className="w-full mb-3">
<DateRangePicker
className="h-[40px] self-end"
value={viewsDailyDate}
onChange={(e) => e !== null && setViewsDailyDate(e)}
label=""
/>
</div>
)}
</div>
{data?.length > 0 &&
data?.map((list: any) => (
<a
key={list.name}
onClick={() => highlightProvince(list.name)}
className={`w-full flex flex-row cursor-pointer gap-2 ${
selectedProvince === list.name ? "bg-slate-300" : ""
}`}
> >
{list.value} <p className="w-4/5">{list.name}</p>{" "}
</p> <p
</a> className={`w-1/5 ${
))} selectedProvince === list.name
? "bg-slate-300"
: "bg-[#a9d7e4]"
} text-black border-white text-center`}
>
{list.value}
</p>
</a>
))}
</div> </div>
</div> </div>
); );

View File

@ -1283,7 +1283,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "72", "PROVINSI": "Sulawesi Tengah" }, "properties": { "KODE_PROV": "72", "PROVINSI": "CENTRAL SULAWESI" },
"id": "72" "id": "72"
}, },
{ {
@ -1540,7 +1540,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "76", "PROVINSI": "Sulawesi Barat" }, "properties": { "KODE_PROV": "76", "PROVINSI": "WEST SULAWESI" },
"id": "76" "id": "76"
}, },
{ {
@ -2189,7 +2189,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "73", "PROVINSI": "Sulawesi Selatan" }, "properties": { "KODE_PROV": "73", "PROVINSI": "SOUTH SULAWESI" },
"id": "73" "id": "73"
}, },
{ {
@ -2731,7 +2731,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "91", "PROVINSI": "Papua Tengah" }, "properties": { "KODE_PROV": "91", "PROVINSI": "CENTRAL PAPUA" },
"id": "91-D" "id": "91-D"
}, },
{ {
@ -4021,7 +4021,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "92", "PROVINSI": "Papua Barat" }, "properties": { "KODE_PROV": "92", "PROVINSI": "WEST PAPUA" },
"id": "92-A" "id": "92-A"
}, },
{ {
@ -5616,7 +5616,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "91", "PROVINSI": "Papua Selatan" }, "properties": { "KODE_PROV": "91", "PROVINSI": "SOUTH PAPUA" },
"id": "91-C" "id": "91-C"
}, },
{ {
@ -5691,7 +5691,7 @@
}, },
"properties": { "properties": {
"KODE_PROV": "34", "KODE_PROV": "34",
"PROVINSI": "Daerah Istimewa Yogyakarta" "PROVINSI": "YOGYAKARTA"
}, },
"id": "34" "id": "34"
}, },
@ -6288,7 +6288,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "13", "PROVINSI": "Sumatera Barat" }, "properties": { "KODE_PROV": "13", "PROVINSI": "WEST SUMATRA" },
"id": "13" "id": "13"
}, },
{ {
@ -6332,7 +6332,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "31", "PROVINSI": "DKI Jakarta" }, "properties": { "KODE_PROV": "31", "PROVINSI": "JAKARTA" },
"id": "31" "id": "31"
}, },
{ {
@ -8497,7 +8497,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "81", "PROVINSI": "Maluku" }, "properties": { "KODE_PROV": "81", "PROVINSI": "MALUKU" },
"id": "81" "id": "81"
}, },
{ {
@ -10070,7 +10070,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "91", "PROVINSI": "Papua" }, "properties": { "KODE_PROV": "91", "PROVINSI": "PAPUA" },
"id": "91-A" "id": "91-A"
}, },
{ {
@ -11167,7 +11167,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "21", "PROVINSI": "Kepulauan Riau" }, "properties": { "KODE_PROV": "21", "PROVINSI": "RIAU ISLANDS" },
"id": "21" "id": "21"
}, },
{ {
@ -11714,7 +11714,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "52", "PROVINSI": "Nusa Tenggara Barat" }, "properties": { "KODE_PROV": "52", "PROVINSI": "WEST NUSA TENGGARA" },
"id": "52" "id": "52"
}, },
{ {
@ -12027,7 +12027,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "15", "PROVINSI": "Jambi" }, "properties": { "KODE_PROV": "15", "PROVINSI": "JAMBI" },
"id": "15" "id": "15"
}, },
{ {
@ -12168,7 +12168,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "51", "PROVINSI": "Bali" }, "properties": { "KODE_PROV": "51", "PROVINSI": "BALI" },
"id": "51" "id": "51"
}, },
{ {
@ -12866,7 +12866,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "35", "PROVINSI": "Jawa Timur" }, "properties": { "KODE_PROV": "35", "PROVINSI": "EAST JAVA" },
"id": "35" "id": "35"
}, },
{ {
@ -13685,7 +13685,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "92", "PROVINSI": "Papua Barat Daya" }, "properties": { "KODE_PROV": "92", "PROVINSI": "SOUTHWEST PAPUA" },
"id": "92-B" "id": "92-B"
}, },
{ {
@ -14339,7 +14339,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "12", "PROVINSI": "Sumatera Utara" }, "properties": { "KODE_PROV": "12", "PROVINSI": "NORTH SUMATRA" },
"id": "12" "id": "12"
}, },
{ {
@ -15158,7 +15158,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "74", "PROVINSI": "Sulawesi Tenggara" }, "properties": { "KODE_PROV": "74", "PROVINSI": "SOUTHEAST SULAWESI" },
"id": "74" "id": "74"
}, },
{ {
@ -16418,7 +16418,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "53", "PROVINSI": "Nusa Tenggara Timur" }, "properties": { "KODE_PROV": "53", "PROVINSI": "EAST NUSA TENGGARA" },
"id": "53" "id": "53"
}, },
{ {
@ -16830,7 +16830,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "63", "PROVINSI": "Kalimantan Selatan" }, "properties": { "KODE_PROV": "63", "PROVINSI": "SOUTH KALIMANTAN" },
"id": "63" "id": "63"
}, },
{ {
@ -17371,7 +17371,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "11", "PROVINSI": "Aceh" }, "properties": { "KODE_PROV": "11", "PROVINSI": "ACEH" },
"id": "11" "id": "11"
}, },
{ {
@ -17988,7 +17988,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "62", "PROVINSI": "Kalimantan Tengah" }, "properties": { "KODE_PROV": "62", "PROVINSI": "CENTRAL KALIMANTAN" },
"id": "62" "id": "62"
}, },
{ {
@ -18458,7 +18458,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "91", "PROVINSI": "Papua Pegunungan" }, "properties": { "KODE_PROV": "91", "PROVINSI": "HIGHLAND PAPUA" },
"id": "91-B" "id": "91-B"
}, },
{ {
@ -18847,7 +18847,7 @@
}, },
"properties": { "properties": {
"KODE_PROV": "19", "KODE_PROV": "19",
"PROVINSI": "Kepulauan Bangka Belitung" "PROVINSI": "BANGKA BELITUNG ISLANDS"
}, },
"id": "19" "id": "19"
}, },
@ -19364,7 +19364,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "16", "PROVINSI": "Sumatera Selatan" }, "properties": { "KODE_PROV": "16", "PROVINSI": "SOUTH SUMATRA" },
"id": "16" "id": "16"
}, },
{ {
@ -19587,7 +19587,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "36", "PROVINSI": "Banten" }, "properties": { "KODE_PROV": "36", "PROVINSI": "BANTEN" },
"id": "36" "id": "36"
}, },
{ {
@ -20073,7 +20073,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "71", "PROVINSI": "Sulawesi Utara" }, "properties": { "KODE_PROV": "71", "PROVINSI": "NORTH SULAWESI" },
"id": "71" "id": "71"
}, },
{ {
@ -20901,7 +20901,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "65", "PROVINSI": "Kalimantan Utara" }, "properties": { "KODE_PROV": "65", "PROVINSI": "NORTH KALIMANTAN" },
"id": "65" "id": "65"
}, },
{ {
@ -22194,7 +22194,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "64", "PROVINSI": "Kalimantan Timur" }, "properties": { "KODE_PROV": "64", "PROVINSI": "EAST KALIMANTAN" },
"id": "64" "id": "64"
}, },
{ {
@ -22544,7 +22544,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "33", "PROVINSI": "Jawa Tengah" }, "properties": { "KODE_PROV": "33", "PROVINSI": "CENTRAL JAVA" },
"id": "33" "id": "33"
}, },
{ {
@ -23769,7 +23769,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "82", "PROVINSI": "Maluku Utara" }, "properties": { "KODE_PROV": "82", "PROVINSI": "NORTH MALUKU" },
"id": "82" "id": "82"
}, },
{ {
@ -24822,7 +24822,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "61", "PROVINSI": "Kalimantan Barat" }, "properties": { "KODE_PROV": "61", "PROVINSI": "WEST KALIMANTAN" },
"id": "61" "id": "61"
}, },
{ {
@ -25065,7 +25065,7 @@
] ]
] ]
}, },
"properties": { "KODE_PROV": "32", "PROVINSI": "Jawa Barat" }, "properties": { "KODE_PROV": "32", "PROVINSI": "WEST JAVA" },
"id": "32" "id": "32"
} }
] ]

View File

@ -222,7 +222,7 @@ export async function getStatisticForMaps(startDate: string, endDate: string) {
// Authorization: `Bearer ${token}`, // Authorization: `Bearer ${token}`,
}; };
return await httpGet( return await httpGet(
`/activity-logs/visitors-by-reesgion-stats?startDate=${startDate}&endDate=${endDate}`, `/activity-logs/visitors-by-region-stats?startDate=${startDate}&endDate=${endDate}`,
headers headers
); );
} }