web-humas-fe/components/main/dashboard/chart/column-chart.tsx

296 lines
7.7 KiB
TypeScript

"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";
import { getUnixTimestamp } from "@/utils/global";
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[],
startYear: number,
startMonth: number,
startDay: number,
endYear: number,
endMonth: number,
endDay: number
) {
const view: number[] = [];
const comment: number[] = [];
const share: number[] = [];
const labels: string[] = [];
const sortedData = [...data].sort(
(a, b) => a.year - b.year || a.month - b.month
);
for (const monthData of sortedData) {
const { year, month, view: v, comment: c, share: s } = monthData;
if (year < startYear || (year === startYear && month < startMonth))
continue;
if (year > endYear || (year === endYear && month > endMonth)) continue;
let startIndex = 0;
let endIndex = v.length - 1;
if (year === startYear && month === startMonth) {
startIndex = startDay - 1;
}
if (year === endYear && month === endMonth) {
endIndex = endDay - 1;
}
for (let i = startIndex; i <= endIndex; i++) {
if (v[i] == null) continue;
view.push(v[i]);
comment.push(c[i]);
share.push(s[i]);
labels.push(
`${String(i + 1).padStart(2, "0")}-${String(month).padStart(
2,
"0"
)}-${year}`
);
}
}
return { view, comment, share, labels };
}
const ApexChartColumn = (props: {
type: string;
date: string;
view: string[];
range: { start: any; end: any };
}) => {
const { date, type, view, range } = props;
const [categories, setCategories] = useState<string[]>([]);
const [series, setSeries] = useState<{ name: string; data: number[] }[]>([]);
const [seriesComment, setSeriesComment] = useState<number[]>([]);
const [seriesView, setSeriesView] = useState<number[]>([]);
const [seriesShare, setSeriesShare] = useState<number[]>([]);
const [years, setYear] = useState("");
const [datas, setDatas] = useState<any>([]);
const [totalChart, setTotalChart] = useState({
views: 0,
comment: 0,
share: 0,
});
useEffect(() => {
initFetch();
}, [date, type, view, range]);
const counting = (data: number[]) => {
const total = data.reduce((a: number, b: number) => a + b, 0);
return total;
};
const initFetch = async () => {
const splitDate = date.split(" ");
const splitDateDaily = String(range.start.year);
const splitDateDailyEnd = String(range.end.year);
const isAccrossYear = splitDateDaily !== splitDateDailyEnd;
let data = [];
if (
(type === "monthly" && splitDate[1] === years) ||
(type === "daily" && splitDateDaily === years && !isAccrossYear)
) {
data = datas;
} else {
if (isAccrossYear && type === "daily") {
const resStart = await getStatisticMonthly(
splitDateDaily,
getUnixTimestamp()
);
const resEnd = await getStatisticMonthly(
splitDateDailyEnd,
getUnixTimestamp()
);
data = [...resStart?.data?.data, ...resEnd?.data?.data];
setDatas(data);
} else {
const res = await getStatisticMonthly(
type === "monthly" ? splitDate[1] : splitDateDaily,
getUnixTimestamp()
);
data = res?.data?.data;
setDatas(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);
const totalChartNow = {
views: counting(getDatas.view),
share: counting(getDatas.share),
comment: counting(getDatas.comment),
};
setTotalChart(totalChartNow);
}
if (type === "daily") {
const mappedData = getRangeAcrossMonths(
data,
range.start.year,
range.start.month,
range.start.day,
range.end.year,
range.end.month,
range.end.day
);
setSeriesComment(mappedData.comment);
setSeriesView(mappedData.view);
setSeriesShare(mappedData.share);
setCategories(mappedData.labels);
const totalChartNow = {
views: counting(mappedData.view),
share: counting(mappedData.share),
comment: counting(mappedData.comment),
};
setTotalChart(totalChartNow);
}
// 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: "Comment",
data: view.includes("comment") ? seriesComment : [],
},
{
name: "View",
data: view.includes("view") ? seriesView : [],
},
{
name: "Share",
data: view.includes("share") ? seriesShare : [],
},
];
setSeries(temp);
}, [view, seriesShare, seriesView, seriesComment]);
return (
<div className="h-full flex flex-col">
<div id="chart" className="h-full">
<ReactApexChart
options={{
chart: {
height: "100%",
type: "area",
},
stroke: {
curve: "smooth",
},
dataLabels: {
enabled: false,
},
xaxis: {
categories: type == "daily" ? categories : [],
},
}}
series={series}
type="area"
height="100%"
/>
</div>
<div id="html-dist"></div>
<div className="flex flex-row gap-2 mt-5 border-1 p-5 rounded-lg">
<div className="w-1/5 text-center">Chart Total</div>
<div className="w-4/5 text-center">
{totalChart.views} {totalChart.views > 1 ? "Views" : "View"}{" "}
{totalChart.comment} {totalChart.comment > 1 ? "Comments" : "Comment"}{" "}
{totalChart.share} {totalChart.share > 1 ? "Shares" : "Share"}{" "}
</div>
</div>{" "}
</div>
);
};
export default ApexChartColumn;