From 1fc236bff3765ff900f32cabb740d69de38f2d0c Mon Sep 17 00:00:00 2001 From: Rama Priyanto Date: Mon, 23 Jun 2025 17:57:30 +0700 Subject: [PATCH] fix:dashboard analytics --- .../main/dashboard/chart/column-chart.tsx | 103 +++- .../main/dashboard/chart/visitor-chart.tsx | 226 +++++++++ .../main/dashboard/dashboard-container.tsx | 455 +++++++++++------- 3 files changed, 607 insertions(+), 177 deletions(-) create mode 100644 components/main/dashboard/chart/visitor-chart.tsx diff --git a/components/main/dashboard/chart/column-chart.tsx b/components/main/dashboard/chart/column-chart.tsx index c5b5458..75b0578 100644 --- a/components/main/dashboard/chart/column-chart.tsx +++ b/components/main/dashboard/chart/column-chart.tsx @@ -43,27 +43,88 @@ function processMonthlyData(count: number[]): { }; } +function getRangeAcrossMonths( + data: any[], + startMonth: number, + startDay: number, + endMonth: number, + endDay: number +) { + const view: number[] = []; + const comment: number[] = []; + const share: number[] = []; + const labels: string[] = []; + + const sortedData = data.sort((a, b) => a.month - b.month); + console.log("sorted data", sortedData); + for (const monthData of sortedData) { + const { month, view: v, comment: c, share: s } = monthData; + + if (month < startMonth || month > endMonth) continue; + + let startIndex = 0; + let endIndex = v.length - 1; + + if (month === startMonth) startIndex = startDay - 1; + if (month === endMonth) endIndex = endDay - 1; + + for (let i = startIndex; i <= endIndex; i++) { + view.push(v[i]); + comment.push(c[i]); + share.push(s[i]); + + const label = `${(i + 1).toString().padStart(2, "0")} - ${month + .toString() + .padStart(2, "0")} `; + labels.push(label); + } + } + + return { view, comment, share, labels }; +} + const ApexChartColumn = (props: { type: string; date: string; view: string[]; + range: { start: any; end: any }; }) => { - const { date, type, view } = props; + const { date, type, view, range } = props; const [categories, setCategories] = useState([]); const [series, setSeries] = useState<{ name: string; data: number[] }[]>([]); const [seriesComment, setSeriesComment] = useState([]); const [seriesView, setSeriesView] = useState([]); const [seriesShare, setSeriesShare] = useState([]); + const [years, setYear] = useState(""); + const [datas, setDatas] = useState([]); useEffect(() => { initFetch(); - }, [date, type, view]); + }, [date, type, view, range]); const initFetch = async () => { const splitDate = date.split(" "); - - const res = await getStatisticMonthly(splitDate[1]); - const data = res?.data?.data; + const splitDateDaily = String(range.start.year); + let data = []; + console.log( + "aaawwww", + type === "monthly" && splitDate[1] === years, + type === "daily" && splitDateDaily === years + ); + if ( + (type === "monthly" && splitDate[1] === years) || + (type === "daily" && splitDateDaily === years) + ) { + console.log("if", datas); + data = datas; + } else { + const res = await getStatisticMonthly( + type === "monthly" ? splitDate[1] : splitDateDaily + ); + data = res?.data?.data; + setDatas(data); + } + console.log("datas", data); const getDatas = data?.find( (a: any) => a.month == Number(splitDate[0]) && a.year === Number(splitDate[1]) @@ -94,16 +155,32 @@ const ApexChartColumn = (props: { setSeriesView(getDatas.view); setSeriesShare(getDatas.share); } - if (type === "weekly") { - const category = []; - for (let i = 1; i <= temp1.weeks.length; i++) { - category.push(`Week ${i}`); - } - setCategories(category); + if (type === "daily") { + const mappedData = getRangeAcrossMonths( + data, + range.start.month, + range.start.day, + range.end.month, + range.end.day + ); + + setSeriesComment(mappedData.comment); + setSeriesView(mappedData.view); + setSeriesShare(mappedData.share); + setCategories(mappedData.labels); } + // if (type === "weekly") { + // const category = []; + // for (let i = 1; i <= temp1.weeks.length; i++) { + // category.push(`Week ${i}`); + // } + // setCategories(category); + // } } else { setSeriesComment([]); } + + setYear(type === "monthly" ? splitDate[1] : splitDateDaily); }; useEffect(() => { @@ -122,8 +199,6 @@ const ApexChartColumn = (props: { }, ]; - console.log("temp", temp); - setSeries(temp); }, [view, seriesShare, seriesView, seriesComment]); @@ -143,7 +218,7 @@ const ApexChartColumn = (props: { enabled: false, }, xaxis: { - categories: type == "weekly" ? categories : [], + categories: type == "daily" ? categories : [], }, }} series={series} diff --git a/components/main/dashboard/chart/visitor-chart.tsx b/components/main/dashboard/chart/visitor-chart.tsx new file mode 100644 index 0000000..58e57af --- /dev/null +++ b/components/main/dashboard/chart/visitor-chart.tsx @@ -0,0 +1,226 @@ +"use client"; +import React, { Component, useEffect, useState } from "react"; +import ReactApexChart from "react-apexcharts"; +import dummyData from "../../../../const/dummy.json"; +import { getStatisticMonthly } from "@/services/article"; + +type WeekData = { + week: number; + days: number[]; + total: number; +}; + +type RemainingDays = { + days: number[]; + total: number; +}; + +function processMonthlyData(count: number[]): { + weeks: WeekData[]; + remaining_days: RemainingDays; +} { + const weeks: WeekData[] = []; + let weekIndex = 1; + + for (let i = 0; i < count.length; i += 7) { + const weekData = count.slice(i, i + 7); + weeks.push({ + week: weekIndex, + days: weekData, + total: weekData.reduce((sum, day) => sum + day, 0), + }); + weekIndex++; + } + + const remainingDays: RemainingDays = { + days: count.length % 7 === 0 ? [] : count.slice(-count.length % 7), + total: count.slice(-count.length % 7).reduce((sum, day) => sum + day, 0), + }; + + return { + weeks, + remaining_days: remainingDays, + }; +} + +function getRangeAcrossMonths( + data: any[], + startMonth: number, + startDay: number, + endMonth: number, + endDay: number +) { + const view: number[] = []; + const comment: number[] = []; + const share: number[] = []; + const labels: string[] = []; + + const sortedData = data.sort((a, b) => a.month - b.month); + console.log("sorted data", sortedData); + for (const monthData of sortedData) { + const { month, view: v, comment: c, share: s } = monthData; + + if (month < startMonth || month > endMonth) continue; + + let startIndex = 0; + let endIndex = v.length - 1; + + if (month === startMonth) startIndex = startDay - 1; + if (month === endMonth) endIndex = endDay - 1; + + for (let i = startIndex; i <= endIndex; i++) { + view.push(v[i]); + comment.push(c[i]); + share.push(s[i]); + + const label = `${(i + 1).toString().padStart(2, "0")} - ${month + .toString() + .padStart(2, "0")} `; + labels.push(label); + } + } + + return { view, comment, share, labels }; +} + +const ApexChartColumnVisitors = (props: { + type: string; + date: string; + view: string[]; + range: { start: any; end: any }; +}) => { + const { date, type, view, range } = props; + const [categories, setCategories] = useState([]); + const [series, setSeries] = useState<{ name: string; data: number[] }[]>([]); + const [seriesComment, setSeriesComment] = useState([]); + const [seriesView, setSeriesView] = useState([]); + const [seriesShare, setSeriesShare] = useState([]); + const [years, setYear] = useState(""); + const [datas, setDatas] = useState([]); + + useEffect(() => { + initFetch(); + }, [date, type, view, range]); + + const initFetch = async () => { + const splitDate = date.split(" "); + const splitDateDaily = String(range.start.year); + let data = []; + console.log( + "aaawwww", + type === "monthly" && splitDate[1] === years, + type === "daily" && splitDateDaily === years + ); + if ( + (type === "monthly" && splitDate[1] === years) || + (type === "daily" && splitDateDaily === years) + ) { + console.log("if", datas); + data = datas; + } else { + const res = await getStatisticMonthly( + type === "monthly" ? splitDate[1] : splitDateDaily + ); + data = res?.data?.data; + setDatas(data); + } + console.log("datas", data); + const getDatas = data?.find( + (a: any) => + a.month == Number(splitDate[0]) && a.year === Number(splitDate[1]) + ); + if (getDatas) { + const temp1 = processMonthlyData(getDatas?.comment); + const temp2 = processMonthlyData(getDatas?.view); + const temp3 = processMonthlyData(getDatas?.share); + + if (type == "weekly") { + setSeriesComment( + temp1.weeks.map((list) => { + return list.total; + }) + ); + setSeriesView( + temp2.weeks.map((list) => { + return list.total; + }) + ); + setSeriesShare( + temp3.weeks.map((list) => { + return list.total; + }) + ); + } else { + setSeriesComment(getDatas.comment); + setSeriesView(getDatas.view); + setSeriesShare(getDatas.share); + } + if (type === "daily") { + const mappedData = getRangeAcrossMonths( + data, + range.start.month, + range.start.day, + range.end.month, + range.end.day + ); + + setSeriesComment(mappedData.comment); + setSeriesView(mappedData.view); + setSeriesShare(mappedData.share); + setCategories(mappedData.labels); + } + // if (type === "weekly") { + // const category = []; + // for (let i = 1; i <= temp1.weeks.length; i++) { + // category.push(`Week ${i}`); + // } + // setCategories(category); + // } + } else { + setSeriesComment([]); + } + + setYear(type === "monthly" ? splitDate[1] : splitDateDaily); + }; + + useEffect(() => { + const temp = [ + { + name: "Visitors", + data: view.includes("visitor") ? seriesView : [], + }, + ]; + + setSeries(temp); + }, [view, seriesShare, seriesView, seriesComment]); + + return ( +
+
+ +
+
+
+ ); +}; + +export default ApexChartColumnVisitors; diff --git a/components/main/dashboard/dashboard-container.tsx b/components/main/dashboard/dashboard-container.tsx index 36fd5dd..6a4b695 100644 --- a/components/main/dashboard/dashboard-container.tsx +++ b/components/main/dashboard/dashboard-container.tsx @@ -60,7 +60,14 @@ import { parseAbsoluteToLocal, } from "@internationalized/date"; import { Input } from "@heroui/input"; -import { EyeIconMdi, SearchIcons } from "@/components/icons"; +import { + ChevronLeftIcon, + ChevronRightIcon, + EyeIconMdi, + SearchIcons, +} from "@/components/icons"; +import { format } from "date-fns"; +import ApexChartColumnVisitors from "./chart/visitor-chart"; type ArticleData = Article & { no: number; @@ -81,6 +88,21 @@ interface PostCount { totalArticle: number; } +const months = [ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", +]; + export default function DashboardContainer() { const { isOpen, onOpen, onOpenChange } = useDisclosure(); @@ -121,7 +143,6 @@ export default function DashboardContainer() { endDate: parseDate(convertDateFormatNoTimeV2(new Date())), }); - const [typeDate, setTypeDate] = useState("monthly"); const [summary, setSummary] = useState(); const [topPages, setTopPages] = useState([]); @@ -134,10 +155,37 @@ export default function DashboardContainer() { name: string; }>(); const roleId = Cookies.get("urie"); + const today = new Date(); const [recapArticlePage, setRecapArticlePage] = useState(1); const [recapArticleTotalPage, setRecapArticleTotalPage] = useState(1); + const [typeDate, setTypeDate] = useState("daily"); + const [year, setYear] = useState(today.getFullYear()); + const [selectedMonth, setSelectedMonth] = useState(today); + const [viewsDailyDate, setViewsDailyDate] = useState({ + start: parseDate(convertDateFormatNoTimeV2(today)), + end: parseDate(convertDateFormatNoTimeV2(today)), + }); + + const [typeDateVisitor, setTypeDateVisitor] = useState("daily"); + const [visitorYear, setVisitorYear] = useState(today.getFullYear()); + const [visitorSelectedMonth, setVisitorSelectedMonth] = useState( + today + ); + const [visitorDailyDate, setVisitorDailyDate] = useState({ + start: parseDate(convertDateFormatNoTimeV2(today)), + end: parseDate(convertDateFormatNoTimeV2(today)), + }); + + const handleMonthClick = (monthIndex: number) => { + setSelectedMonth(new Date(year, monthIndex, 1)); + }; + + const handleMonthClickVisitor = (monthIndex: number) => { + setVisitorSelectedMonth(new Date(year, monthIndex, 1)); + }; + useEffect(() => { fetchSummary(); }, []); @@ -246,32 +294,6 @@ export default function DashboardContainer() { } }; - const getMonthYear = (date: any) => { - return date.month + " " + date.year; - }; - const getMonthYearName = (date: any) => { - const newDate = new Date(date); - - const months = [ - "Januari", - "Februari", - "Maret", - "April", - "Mei", - "Juni", - "Juli", - "Agustus", - "September", - "Oktober", - "November", - "Desember", - ]; - const year = newDate.getFullYear(); - - const month = months[newDate.getMonth()]; - return month + " " + year; - }; - useEffect(() => { const temp = Array.from(selectedAccordion); console.log("selecette", temp); @@ -587,141 +609,6 @@ export default function DashboardContainer() { )} -
-
-

Recent Article

- - - -
- {article?.map((list: any) => ( -
- thumbnail -
-

{textEllipsis(list?.title, 78)}

-

- {convertDateFormat(list?.createdAt)} -

-
-
- ))} -
- setPage(page)} - /> -
-
- -
-
-
-
- Analytics -
- - - Comment - - - View - - - Share - - - - - Comment - - - View - - - Share - - -
-
-
- - -
- - - - - - - - -
-
-
-
-
- -
-
-

Top Pages

@@ -811,6 +698,248 @@ export default function DashboardContainer() { )}
+
+
+
+
+ Engagement Analytics +
+ + + Comment + + + View + + + Share + + + + + Comment + + + View + + + Share + + +
+
+
+ + + {typeDate === "monthly" ? ( + + + + + +
+ + + {year} + + +
+ +
+ {months.map((month, idx) => ( + + ))} +
+
+
+ ) : ( +
+ e !== null && setViewsDailyDate(e)} + label="" + /> +
+ )} +
+
+
+
+ +
+
+
+
+
+
+ Visitor Analytics +
+
+ + + {typeDateVisitor === "monthly" ? ( + + + + + +
+ + + {year} + + +
+ +
+ {months.map((month, idx) => ( + + ))} +
+
+
+ ) : ( +
+ e !== null && setViewsDailyDate(e)} + label="" + /> +
+ )} +
+
+
+
+ +
+
+
+