feat:user analytic
This commit is contained in:
parent
cc45c2dabb
commit
686d29439c
|
|
@ -69,98 +69,98 @@ export default function Login() {
|
||||||
error("Username & Password Wajib Diisi !");
|
error("Username & Password Wajib Diisi !");
|
||||||
} else {
|
} else {
|
||||||
// login dengan otp
|
// login dengan otp
|
||||||
loading();
|
// loading();
|
||||||
const response: any = await emailValidation(data);
|
// const response: any = await emailValidation(data);
|
||||||
if (response?.error) {
|
// if (response?.error) {
|
||||||
console.log("error", response);
|
// console.log("error", response);
|
||||||
if (response?.message?.messages[0]?.includes("failed to send mail")) {
|
// if (response?.message?.messages[0]?.includes("failed to send mail")) {
|
||||||
error("Gagal Mengirim OTP");
|
// error("Gagal Mengirim OTP");
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (response?.message?.messages[0]?.includes("username")) {
|
// if (response?.message?.messages[0]?.includes("username")) {
|
||||||
error("Username / Password Tidak Sesuai");
|
// error("Username / Password Tidak Sesuai");
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
error("Unknown Error");
|
// error("Unknown Error");
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
close();
|
// close();
|
||||||
if (response?.data?.messages[0] === "Continue to setup email") {
|
// if (response?.data?.messages[0] === "Continue to setup email") {
|
||||||
setFirstLogin(true);
|
// setFirstLogin(true);
|
||||||
} else {
|
// } else {
|
||||||
setNeedOtp(true);
|
// setNeedOtp(true);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// login tanpa otp
|
// login tanpa otp
|
||||||
// loading();
|
loading();
|
||||||
// const response = await postSignIn(data);
|
const response = await postSignIn(data);
|
||||||
// if (response?.error) {
|
if (response?.error) {
|
||||||
// error("Username / Password Tidak Sesuai");
|
error("Username / Password Tidak Sesuai");
|
||||||
// } else {
|
} else {
|
||||||
// const profile = await getProfile(response?.data?.data?.access_token);
|
const profile = await getProfile(response?.data?.data?.access_token);
|
||||||
// const dateTime: any = new Date();
|
const dateTime: any = new Date();
|
||||||
|
|
||||||
// const newTime: any = dateTime.getTime() + 10 * 60 * 1000;
|
const newTime: any = dateTime.getTime() + 10 * 60 * 1000;
|
||||||
|
|
||||||
// Cookies.set("access_token", response?.data?.data?.access_token, {
|
Cookies.set("access_token", response?.data?.data?.access_token, {
|
||||||
// expires: 1,
|
expires: 1,
|
||||||
// });
|
});
|
||||||
// Cookies.set("refresh_token", response?.data?.data?.refresh_token, {
|
Cookies.set("refresh_token", response?.data?.data?.refresh_token, {
|
||||||
// expires: 1,
|
expires: 1,
|
||||||
// });
|
});
|
||||||
// Cookies.set("time_refresh", newTime, {
|
Cookies.set("time_refresh", newTime, {
|
||||||
// expires: 1,
|
expires: 1,
|
||||||
// });
|
});
|
||||||
// Cookies.set("is_first_login", "true", {
|
Cookies.set("is_first_login", "true", {
|
||||||
// secure: true,
|
secure: true,
|
||||||
// sameSite: "strict",
|
sameSite: "strict",
|
||||||
// });
|
});
|
||||||
// const resActivity = await saveActivity(
|
const resActivity = await saveActivity(
|
||||||
// {
|
{
|
||||||
// activityTypeId: 1,
|
activityTypeId: 1,
|
||||||
// url: "https://kontenhumas.com/auth",
|
url: "https://kontenhumas.com/auth",
|
||||||
// userId: profile?.data?.data?.id,
|
userId: profile?.data?.data?.id,
|
||||||
// },
|
},
|
||||||
// accessData?.id_token
|
accessData?.id_token
|
||||||
// );
|
);
|
||||||
// Cookies.set("profile_picture", profile?.data?.data?.profilePictureUrl, {
|
Cookies.set("profile_picture", profile?.data?.data?.profilePictureUrl, {
|
||||||
// expires: 1,
|
expires: 1,
|
||||||
// });
|
});
|
||||||
// Cookies.set("uie", profile?.data?.data?.id, {
|
Cookies.set("uie", profile?.data?.data?.id, {
|
||||||
// expires: 1,
|
expires: 1,
|
||||||
// });
|
});
|
||||||
// Cookies.set("ufne", profile?.data?.data?.fullname, {
|
Cookies.set("ufne", profile?.data?.data?.fullname, {
|
||||||
// expires: 1,
|
expires: 1,
|
||||||
// });
|
});
|
||||||
// Cookies.set("ulie", profile?.data?.data?.userLevelGroup, {
|
Cookies.set("ulie", profile?.data?.data?.userLevelGroup, {
|
||||||
// expires: 1,
|
expires: 1,
|
||||||
// });
|
});
|
||||||
// Cookies.set("username", profile?.data?.data?.username, {
|
Cookies.set("username", profile?.data?.data?.username, {
|
||||||
// expires: 1,
|
expires: 1,
|
||||||
// });
|
});
|
||||||
// Cookies.set("urie", profile?.data?.data?.userRoleId, {
|
Cookies.set("urie", profile?.data?.data?.userRoleId, {
|
||||||
// expires: 1,
|
expires: 1,
|
||||||
// });
|
});
|
||||||
// Cookies.set("masterPoldaId", profile?.data?.data?.masterPoldaId, {
|
Cookies.set("masterPoldaId", profile?.data?.data?.masterPoldaId, {
|
||||||
// expires: 1,
|
expires: 1,
|
||||||
// });
|
});
|
||||||
// Cookies.set("ulne", profile?.data?.data?.userLevelId, {
|
Cookies.set("ulne", profile?.data?.data?.userLevelId, {
|
||||||
// expires: 1,
|
expires: 1,
|
||||||
// });
|
});
|
||||||
// // Cookies.set("urce", profile?.data?.data?.roleCode, {
|
// Cookies.set("urce", profile?.data?.data?.roleCode, {
|
||||||
// // expires: 1,
|
|
||||||
// // });
|
|
||||||
// Cookies.set("email", profile?.data?.data?.email, {
|
|
||||||
// expires: 1,
|
|
||||||
// });
|
|
||||||
// router.push("/admin/dashboard");
|
|
||||||
// Cookies.set("status", "login", {
|
|
||||||
// expires: 1,
|
// expires: 1,
|
||||||
// });
|
// });
|
||||||
|
Cookies.set("email", profile?.data?.data?.email, {
|
||||||
|
expires: 1,
|
||||||
|
});
|
||||||
|
router.push("/admin/dashboard");
|
||||||
|
Cookies.set("status", "login", {
|
||||||
|
expires: 1,
|
||||||
|
});
|
||||||
|
|
||||||
// close();
|
close();
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,6 @@ function getRangeAcrossMonths(
|
||||||
const labels: string[] = [];
|
const labels: string[] = [];
|
||||||
|
|
||||||
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);
|
|
||||||
for (const monthData of sortedData) {
|
for (const monthData of sortedData) {
|
||||||
const { month, view: v, comment: c, share: s } = monthData;
|
const { month, view: v, comment: c, share: s } = monthData;
|
||||||
|
|
||||||
|
|
@ -75,7 +74,7 @@ function getRangeAcrossMonths(
|
||||||
|
|
||||||
const label = `${(i + 1).toString().padStart(2, "0")} - ${month
|
const label = `${(i + 1).toString().padStart(2, "0")} - ${month
|
||||||
.toString()
|
.toString()
|
||||||
.padStart(2, "0")} `;
|
.padStart(2, "0")}`;
|
||||||
labels.push(label);
|
labels.push(label);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -106,16 +105,11 @@ const ApexChartColumn = (props: {
|
||||||
const splitDate = date.split(" ");
|
const splitDate = date.split(" ");
|
||||||
const splitDateDaily = String(range.start.year);
|
const splitDateDaily = String(range.start.year);
|
||||||
let data = [];
|
let data = [];
|
||||||
console.log(
|
|
||||||
"aaawwww",
|
|
||||||
type === "monthly" && splitDate[1] === years,
|
|
||||||
type === "daily" && splitDateDaily === years
|
|
||||||
);
|
|
||||||
if (
|
if (
|
||||||
(type === "monthly" && splitDate[1] === years) ||
|
(type === "monthly" && splitDate[1] === years) ||
|
||||||
(type === "daily" && splitDateDaily === years)
|
(type === "daily" && splitDateDaily === years)
|
||||||
) {
|
) {
|
||||||
console.log("if", datas);
|
|
||||||
data = datas;
|
data = datas;
|
||||||
} else {
|
} else {
|
||||||
const res = await getStatisticMonthly(
|
const res = await getStatisticMonthly(
|
||||||
|
|
@ -124,7 +118,6 @@ const ApexChartColumn = (props: {
|
||||||
data = res?.data?.data;
|
data = res?.data?.data;
|
||||||
setDatas(data);
|
setDatas(data);
|
||||||
}
|
}
|
||||||
console.log("datas", data);
|
|
||||||
const getDatas = data?.find(
|
const getDatas = data?.find(
|
||||||
(a: any) =>
|
(a: any) =>
|
||||||
a.month == Number(splitDate[0]) && a.year === Number(splitDate[1])
|
a.month == Number(splitDate[0]) && a.year === Number(splitDate[1])
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,369 @@
|
||||||
|
import React, { useState, useCallback, useEffect, useRef } from "react";
|
||||||
|
import ReactApexChart from "react-apexcharts";
|
||||||
|
import ApexCharts from "apexcharts";
|
||||||
|
import { init } from "next/dist/compiled/webpack/webpack";
|
||||||
|
|
||||||
|
const wilayah = ["sumut", "bali", "jateng", "jabar", "metro", "papua", "riau"];
|
||||||
|
|
||||||
|
type TypeItem = {
|
||||||
|
year: number;
|
||||||
|
month: number;
|
||||||
|
user: {
|
||||||
|
list: { name: string; count: number }[];
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
|
||||||
|
interface MappedData {
|
||||||
|
result: { x: string; y: number }[] | [];
|
||||||
|
details: { name: string; count: number }[][];
|
||||||
|
}
|
||||||
|
|
||||||
|
const generateDummyData = () => {
|
||||||
|
const getDaysInMonth = (year: number, month: number) => {
|
||||||
|
return new Date(year, month, 0).getDate();
|
||||||
|
};
|
||||||
|
|
||||||
|
const dummy = [];
|
||||||
|
|
||||||
|
for (let month = 1; month <= 7; month++) {
|
||||||
|
const userData = [];
|
||||||
|
const daysInMonth = getDaysInMonth(2025, month);
|
||||||
|
|
||||||
|
for (let day = 1; day <= daysInMonth; day++) {
|
||||||
|
// Buat 2-4 wilayah acak per hari
|
||||||
|
const regionCount = Math.floor(Math.random() * 3) + 2;
|
||||||
|
const usedRegions = wilayah
|
||||||
|
.sort(() => 0.5 - Math.random())
|
||||||
|
.slice(0, regionCount);
|
||||||
|
|
||||||
|
const list = usedRegions.map((name) => ({
|
||||||
|
name,
|
||||||
|
count: Math.floor(Math.random() * 10) + 1,
|
||||||
|
}));
|
||||||
|
|
||||||
|
userData.push({ list });
|
||||||
|
}
|
||||||
|
|
||||||
|
dummy.push({
|
||||||
|
year: 2025,
|
||||||
|
month,
|
||||||
|
user: userData,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return dummy;
|
||||||
|
};
|
||||||
|
|
||||||
|
const dummy = generateDummyData();
|
||||||
|
|
||||||
|
const colors = ["#008FFB"];
|
||||||
|
|
||||||
|
export const makeDataByMonth = (
|
||||||
|
data: TypeItem[],
|
||||||
|
month: number
|
||||||
|
): MappedData => {
|
||||||
|
const result: { x: string; y: number }[] = [];
|
||||||
|
const details: { name: string; count: number }[][] = [];
|
||||||
|
|
||||||
|
const filtered = data.find((entry) => entry.month === month);
|
||||||
|
|
||||||
|
if (!filtered) return { result: [], details: [] };
|
||||||
|
|
||||||
|
filtered.user.forEach((u, idx) => {
|
||||||
|
const total = u.list.reduce((sum, item) => sum + item.count, 0);
|
||||||
|
details.push(u.list);
|
||||||
|
console.log("u.list", u.list);
|
||||||
|
result.push({
|
||||||
|
x: (idx + 1).toString(),
|
||||||
|
y: total,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return { result, details };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const makeDataByRange = (
|
||||||
|
data: TypeItem[],
|
||||||
|
startMonth: number,
|
||||||
|
startDay: number,
|
||||||
|
endMonth: number,
|
||||||
|
endDay: number
|
||||||
|
) => {
|
||||||
|
const user: number[] = [];
|
||||||
|
const labels: string[] = [];
|
||||||
|
const details = [];
|
||||||
|
const result: { x: string; y: number }[] = [];
|
||||||
|
const sortedData = data.sort((a, b) => a.month - b.month);
|
||||||
|
for (const monthData of sortedData) {
|
||||||
|
const { month, user: u } = monthData;
|
||||||
|
|
||||||
|
if (month < startMonth || month > endMonth) continue;
|
||||||
|
|
||||||
|
let startIndex = 0;
|
||||||
|
let endIndex = u.length - 1;
|
||||||
|
|
||||||
|
if (month === startMonth) startIndex = startDay - 1;
|
||||||
|
if (month === endMonth) endIndex = endDay - 1;
|
||||||
|
|
||||||
|
for (let i = startIndex; i <= endIndex; i++) {
|
||||||
|
const userEntry = u[i];
|
||||||
|
|
||||||
|
if (!userEntry) continue;
|
||||||
|
|
||||||
|
const total = userEntry.list.reduce((sum, item) => sum + item.count, 0);
|
||||||
|
user.push(total);
|
||||||
|
details.push(userEntry.list);
|
||||||
|
const label = `${(i + 1).toString().padStart(2, "0")} - ${month
|
||||||
|
.toString()
|
||||||
|
.padStart(2, "0")}`;
|
||||||
|
labels.push(label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < user.length; i++) {
|
||||||
|
result.push({ x: labels[i], y: user[i] });
|
||||||
|
}
|
||||||
|
|
||||||
|
return { result, details };
|
||||||
|
};
|
||||||
|
|
||||||
|
const ApexChartDynamic = (props: {
|
||||||
|
type: string;
|
||||||
|
date: string;
|
||||||
|
range: { start: any; end: any };
|
||||||
|
}) => {
|
||||||
|
const { date, type, range } = props;
|
||||||
|
const [state, setState] = useState<{
|
||||||
|
series: ApexAxisChartSeries;
|
||||||
|
options: ApexCharts.ApexOptions;
|
||||||
|
seriesQuarter: ApexAxisChartSeries;
|
||||||
|
}>({
|
||||||
|
series: [{ data: [] }],
|
||||||
|
options: {
|
||||||
|
chart: {
|
||||||
|
id: "barYear",
|
||||||
|
height: 600,
|
||||||
|
width: "100%",
|
||||||
|
type: "bar",
|
||||||
|
events: {
|
||||||
|
dataPointSelection: function (e, chart, opts) {
|
||||||
|
const quarterChartEl = document.querySelector("#chart-quarter");
|
||||||
|
const yearChartEl = document.querySelector("#chart-year");
|
||||||
|
|
||||||
|
if (!quarterChartEl || !yearChartEl) return;
|
||||||
|
|
||||||
|
if (opts.selectedDataPoints[0].length === 1) {
|
||||||
|
if (quarterChartEl.classList.contains("active")) {
|
||||||
|
updateQuarterChart(chart, "barQuarter");
|
||||||
|
} else {
|
||||||
|
yearChartEl.classList.add("chart-quarter-activated");
|
||||||
|
quarterChartEl.classList.add("active");
|
||||||
|
updateQuarterChart(chart, "barQuarter");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
updateQuarterChart(chart, "barQuarter");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.selectedDataPoints[0].length === 0) {
|
||||||
|
yearChartEl.classList.remove("chart-quarter-activated");
|
||||||
|
quarterChartEl.classList.remove("active");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updated: function (chart) {
|
||||||
|
updateQuarterChart(chart, "barQuarter");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plotOptions: {
|
||||||
|
bar: {
|
||||||
|
distributed: true,
|
||||||
|
horizontal: true,
|
||||||
|
barHeight: "100%",
|
||||||
|
dataLabels: {
|
||||||
|
position: "bottom",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
dataLabels: {
|
||||||
|
enabled: true,
|
||||||
|
textAnchor: "start",
|
||||||
|
style: {
|
||||||
|
colors: ["#fff"],
|
||||||
|
},
|
||||||
|
formatter: function (_val, opt) {
|
||||||
|
return opt.w.globals.labels[opt.dataPointIndex];
|
||||||
|
},
|
||||||
|
offsetX: 0,
|
||||||
|
dropShadow: {
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
colors: colors,
|
||||||
|
states: {
|
||||||
|
normal: {
|
||||||
|
filter: {
|
||||||
|
type: "desaturate",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
active: {
|
||||||
|
allowMultipleDataPointsSelection: false,
|
||||||
|
filter: {
|
||||||
|
type: "darken",
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
x: { show: false },
|
||||||
|
y: {
|
||||||
|
title: {
|
||||||
|
formatter: ((_seriesName: string, opts: any) =>
|
||||||
|
opts.w.globals.labels[opts.dataPointIndex]) as (
|
||||||
|
seriesName: string
|
||||||
|
) => string,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
yaxis: {
|
||||||
|
labels: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
seriesQuarter: [{ data: [] }],
|
||||||
|
});
|
||||||
|
|
||||||
|
const [years, setYear] = useState("");
|
||||||
|
const [datas, setDatas] = useState<any>([]);
|
||||||
|
const [details, setDetails] = useState<{ name: string; count: number }[][]>(
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
const detailsRef = useRef(details);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
detailsRef.current = details;
|
||||||
|
}, [details]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
initFetch();
|
||||||
|
}, [date, range.start, range.end, type]);
|
||||||
|
|
||||||
|
const initFetch = async () => {
|
||||||
|
const splitDate = date.split(" ");
|
||||||
|
const splitDateDaily = String(range.start.year);
|
||||||
|
const currentYear = type === "monthly" ? splitDate[1] : splitDateDaily;
|
||||||
|
|
||||||
|
let data = [];
|
||||||
|
|
||||||
|
if (currentYear === years) {
|
||||||
|
console.log("if", datas);
|
||||||
|
data = datas;
|
||||||
|
} else {
|
||||||
|
// const res = await getStatisticMonthly(
|
||||||
|
// type === "monthly" ? splitDate[1] : splitDateDaily
|
||||||
|
// );
|
||||||
|
// data = res?.data?.data;
|
||||||
|
data = dummy;
|
||||||
|
console.log("dataaa", data);
|
||||||
|
setDatas(data);
|
||||||
|
setYear(currentYear);
|
||||||
|
}
|
||||||
|
// console.log("datas", data);
|
||||||
|
if (data) {
|
||||||
|
if (type == "monthly") {
|
||||||
|
const mappedData: MappedData = makeDataByMonth(
|
||||||
|
data,
|
||||||
|
Number(splitDate[0])
|
||||||
|
);
|
||||||
|
console.log("mapped month", mappedData);
|
||||||
|
setDetails(mappedData.details);
|
||||||
|
setState((prev) => ({
|
||||||
|
...prev,
|
||||||
|
series: [{ data: mappedData.result }],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == "daily") {
|
||||||
|
const mappedData = makeDataByRange(
|
||||||
|
data,
|
||||||
|
range.start.month,
|
||||||
|
range.start.day,
|
||||||
|
range.end.month,
|
||||||
|
range.end.day
|
||||||
|
);
|
||||||
|
console.log("mmapped,", mappedData.details);
|
||||||
|
setDetails(mappedData.details);
|
||||||
|
setState((prev) => ({
|
||||||
|
...prev,
|
||||||
|
series: [{ data: mappedData.result }],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setState((prev) => ({
|
||||||
|
...prev,
|
||||||
|
series: [{ data: [] }],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateQuarterChart = useCallback(
|
||||||
|
(chart: any, id: string) => {
|
||||||
|
const selectedIndex = chart?.w?.config?.series[0]?.data?.findIndex(
|
||||||
|
(d: any, i: number) => {
|
||||||
|
return chart.w.globals.selectedDataPoints[0]?.includes(i);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (selectedIndex !== -1) {
|
||||||
|
const counts = detailsRef.current[selectedIndex];
|
||||||
|
console.log("countres", counts, detailsRef);
|
||||||
|
|
||||||
|
const quarterData = [
|
||||||
|
{
|
||||||
|
name: `${selectedIndex + 1}`,
|
||||||
|
data: counts,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
ApexCharts.exec(id, "updateSeries", quarterData);
|
||||||
|
|
||||||
|
setState((prev: any) => ({
|
||||||
|
...prev,
|
||||||
|
seriesQuarter: quarterData,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[detailsRef]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="lg:h-[600px]">
|
||||||
|
<div id="wrap" className="flex flex-col lg:flex-row gap-2">
|
||||||
|
<div id="chart-year" className="lg:w-[80%] h-[600px]">
|
||||||
|
<ReactApexChart
|
||||||
|
options={state.options}
|
||||||
|
series={state.series}
|
||||||
|
type="bar"
|
||||||
|
height={600}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="chart-quarter" className="w-full lg:w-[20%]">
|
||||||
|
<div className="flex flex-col gap-1">
|
||||||
|
{state.seriesQuarter[0].data.map((list: any, index) => (
|
||||||
|
<div key={index} className="flex flex-row gap-2">
|
||||||
|
<p className="font-semibold capitalize">{list?.name} : </p>
|
||||||
|
<p>{list?.count}</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ApexChartDynamic;
|
||||||
|
|
@ -56,7 +56,6 @@ function getRangeAcrossMonths(
|
||||||
const labels: string[] = [];
|
const labels: string[] = [];
|
||||||
|
|
||||||
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);
|
|
||||||
for (const monthData of sortedData) {
|
for (const monthData of sortedData) {
|
||||||
const { month, view: v, comment: c, share: s } = monthData;
|
const { month, view: v, comment: c, share: s } = monthData;
|
||||||
|
|
||||||
|
|
@ -106,16 +105,11 @@ const ApexChartColumnVisitors = (props: {
|
||||||
const splitDate = date.split(" ");
|
const splitDate = date.split(" ");
|
||||||
const splitDateDaily = String(range.start.year);
|
const splitDateDaily = String(range.start.year);
|
||||||
let data = [];
|
let data = [];
|
||||||
console.log(
|
|
||||||
"aaawwww",
|
|
||||||
type === "monthly" && splitDate[1] === years,
|
|
||||||
type === "daily" && splitDateDaily === years
|
|
||||||
);
|
|
||||||
if (
|
if (
|
||||||
(type === "monthly" && splitDate[1] === years) ||
|
(type === "monthly" && splitDate[1] === years) ||
|
||||||
(type === "daily" && splitDateDaily === years)
|
(type === "daily" && splitDateDaily === years)
|
||||||
) {
|
) {
|
||||||
console.log("if", datas);
|
|
||||||
data = datas;
|
data = datas;
|
||||||
} else {
|
} else {
|
||||||
const res = await getStatisticMonthly(
|
const res = await getStatisticMonthly(
|
||||||
|
|
@ -124,7 +118,6 @@ const ApexChartColumnVisitors = (props: {
|
||||||
data = res?.data?.data;
|
data = res?.data?.data;
|
||||||
setDatas(data);
|
setDatas(data);
|
||||||
}
|
}
|
||||||
console.log("datas", data);
|
|
||||||
const getDatas = data?.find(
|
const getDatas = data?.find(
|
||||||
(a: any) =>
|
(a: any) =>
|
||||||
a.month == Number(splitDate[0]) && a.year === Number(splitDate[1])
|
a.month == Number(splitDate[0]) && a.year === Number(splitDate[1])
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,7 @@ import {
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import ApexChartColumnVisitors from "./chart/visitor-chart";
|
import ApexChartColumnVisitors from "./chart/visitor-chart";
|
||||||
import { IndonesiaMap } from "@/components/ui/maps-charts";
|
import { IndonesiaMap } from "@/components/ui/maps-charts";
|
||||||
|
import ApexChartDynamic from "./chart/dynamic-bar-char";
|
||||||
|
|
||||||
type ArticleData = Article & {
|
type ArticleData = Article & {
|
||||||
no: number;
|
no: number;
|
||||||
|
|
@ -198,7 +199,11 @@ export default function DashboardContainer() {
|
||||||
today
|
today
|
||||||
);
|
);
|
||||||
const [visitorDailyDate, setVisitorDailyDate] = useState({
|
const [visitorDailyDate, setVisitorDailyDate] = useState({
|
||||||
start: parseDate(convertDateFormatNoTimeV2(today)),
|
start: parseDate(
|
||||||
|
convertDateFormatNoTimeV2(
|
||||||
|
new Date(new Date().setDate(new Date().getDate() - 30))
|
||||||
|
)
|
||||||
|
),
|
||||||
end: parseDate(convertDateFormatNoTimeV2(today)),
|
end: parseDate(convertDateFormatNoTimeV2(today)),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -722,7 +727,7 @@ export default function DashboardContainer() {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full flex flex-col lg:flex-row gap-6 justify-center min-h-[480px]">
|
<div className="w-full flex flex-col lg:flex-row gap-6 justify-center lg:h-[700px]">
|
||||||
<div className="border-1 shadow-sm w-screen rounded-lg lg:w-[50%] p-6 flex flex-col">
|
<div className="border-1 shadow-sm w-screen rounded-lg lg:w-[50%] p-6 flex flex-col">
|
||||||
<div className="flex justify-between mb-3">
|
<div className="flex justify-between mb-3">
|
||||||
<div className="font-semibold flex flex-col">
|
<div className="font-semibold flex flex-col">
|
||||||
|
|
@ -861,11 +866,9 @@ export default function DashboardContainer() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="border-1 shadow-sm w-screen rounded-lg md:w-[50%] p-6 flex flex-col">
|
<div className="border-1 shadow-sm w-screen rounded-lg md:w-[50%] p-6 flex flex-col h-[700px]">
|
||||||
<div className="flex justify-between mb-3">
|
<div className="flex justify-between mb-3">
|
||||||
<div className="font-semibold flex flex-col">
|
<div className="font-semibold flex flex-col">Users Analytics</div>
|
||||||
Visitor Analytics
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-col lg:flex-row gap-2">
|
<div className="flex flex-col lg:flex-row gap-2">
|
||||||
<Select
|
<Select
|
||||||
className="w-full md:w-[140px] text-xs lg:text-sm h-[30px] lg:h-[40px]"
|
className="w-full md:w-[140px] text-xs lg:text-sm h-[30px] lg:h-[40px]"
|
||||||
|
|
@ -937,7 +940,136 @@ export default function DashboardContainer() {
|
||||||
<DateRangePicker
|
<DateRangePicker
|
||||||
className="h-[40px]"
|
className="h-[40px]"
|
||||||
value={visitorDailyDate}
|
value={visitorDailyDate}
|
||||||
onChange={(e) => e !== null && setViewsDailyDate(e)}
|
onChange={(e) => e !== null && setVisitorDailyDate(e)}
|
||||||
|
label=""
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-row w-full h-full">
|
||||||
|
<div className="w-full h-[30vh] lg:h-full text-black">
|
||||||
|
<ApexChartDynamic
|
||||||
|
key={`${
|
||||||
|
convertDateFormatNoTimeV2(
|
||||||
|
String(visitorSelectedMonth)
|
||||||
|
).split("-")[1]
|
||||||
|
} ${
|
||||||
|
convertDateFormatNoTimeV2(
|
||||||
|
String(visitorSelectedMonth)
|
||||||
|
).split("-")[0]
|
||||||
|
}-${typeDateVisitor}-${visitorDailyDate}`}
|
||||||
|
type={typeDateVisitor}
|
||||||
|
date={`${
|
||||||
|
convertDateFormatNoTimeV2(
|
||||||
|
String(visitorSelectedMonth)
|
||||||
|
).split("-")[1]
|
||||||
|
} ${
|
||||||
|
convertDateFormatNoTimeV2(
|
||||||
|
String(visitorSelectedMonth)
|
||||||
|
).split("-")[0]
|
||||||
|
}`}
|
||||||
|
range={visitorDailyDate}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{roleId && Number(roleId) < 3 && (
|
||||||
|
<div>
|
||||||
|
<div className="flex flex-col lg:flex-row gap-6 w-full pr-2 md:pr-0">
|
||||||
|
<div className="w-screen md:w-[80%] h-[360px] lg:h-[600px]">
|
||||||
|
<IndonesiaMap />
|
||||||
|
</div>
|
||||||
|
<div className="w-screen md:w-[300px] h-[360px] lg:h-[600px] overflow-auto gap-2 flex flex-col">
|
||||||
|
{dummyData.map((list) => (
|
||||||
|
<div key={list.id} className="w-full flex flex-row gap-2">
|
||||||
|
<p className="w-1/2">{list.name}</p>{" "}
|
||||||
|
<p className="w-1/2 bg-[#0e7490] text-white border-white ">
|
||||||
|
{list.value}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<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="font-semibold flex flex-col">
|
||||||
|
Visitor Analytics
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col lg:flex-row gap-2">
|
||||||
|
<Select
|
||||||
|
className="w-full md:w-[140px] text-xs lg:text-sm h-[30px] lg:h-[40px]"
|
||||||
|
label=""
|
||||||
|
labelPlacement="outside"
|
||||||
|
selectedKeys={[typeDateVisitor]}
|
||||||
|
onChange={(e) =>
|
||||||
|
e.target.value !== "" &&
|
||||||
|
setTypeDateVisitor(e.target.value)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<SelectItem key="monthly">Bulanan</SelectItem>
|
||||||
|
<SelectItem key="daily">Harian</SelectItem>
|
||||||
|
</Select>
|
||||||
|
|
||||||
|
{typeDateVisitor === "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">
|
||||||
|
{" "}
|
||||||
|
{visitorSelectedMonth
|
||||||
|
? format(visitorSelectedMonth, "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={() => setVisitorYear((prev) => prev - 1)}
|
||||||
|
>
|
||||||
|
<ChevronLeftIcon />
|
||||||
|
</button>
|
||||||
|
<span className="font-semibold text-center">
|
||||||
|
{year}
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
className="text-gray-500 hover:text-black"
|
||||||
|
onClick={() => setVisitorYear((prev) => prev + 1)}
|
||||||
|
>
|
||||||
|
<ChevronRightIcon />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-3 gap-2 w-full">
|
||||||
|
{months.map((month, idx) => (
|
||||||
|
<button
|
||||||
|
key={idx}
|
||||||
|
onClick={() => handleMonthClickVisitor(idx)}
|
||||||
|
className={`py-1 rounded-md text-sm transition-colors ${
|
||||||
|
visitorSelectedMonth &&
|
||||||
|
visitorSelectedMonth.getMonth() === idx &&
|
||||||
|
visitorSelectedMonth.getFullYear() === year
|
||||||
|
? "bg-blue-500 text-white"
|
||||||
|
: "hover:bg-gray-200 text-gray-700"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{month}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
) : (
|
||||||
|
<div className="w-[220px]">
|
||||||
|
<DateRangePicker
|
||||||
|
className="h-[40px]"
|
||||||
|
value={visitorDailyDate}
|
||||||
|
onChange={(e) => e !== null && setVisitorDailyDate(e)}
|
||||||
label=""
|
label=""
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -964,22 +1096,6 @@ export default function DashboardContainer() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{roleId && Number(roleId) < 3 && (
|
|
||||||
<div className="flex flex-row gap-6 w-full">
|
|
||||||
<div className="w-screen md:w-[80%] h-[360px] lg:h-[600px]">
|
|
||||||
<IndonesiaMap />
|
|
||||||
</div>
|
|
||||||
<div className="w-screen md:w-[300px] h-[360px] lg:h-[600px] overflow-auto gap-2 flex flex-col">
|
|
||||||
{dummyData.map((list) => (
|
|
||||||
<div key={list.id} className="w-full flex flex-row gap-2">
|
|
||||||
<p className="w-1/2">{list.name}</p>{" "}
|
|
||||||
<p className="w-1/2 bg-[#0e7490] text-white border-white ">
|
|
||||||
{list.value}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<Modal isOpen={isOpen} onOpenChange={onOpenChange} size="3xl">
|
<Modal isOpen={isOpen} onOpenChange={onOpenChange} size="3xl">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue