From 85778aaf593bf8a69774b9b19be9e3d424fcdb1a Mon Sep 17 00:00:00 2001 From: Rama Priyanto Date: Fri, 27 Jun 2025 21:17:17 +0700 Subject: [PATCH] fix:user analytics --- components/form/login.tsx | 172 ++++++------ components/layout/sidebar/sidebar-mobile.tsx | 10 +- components/layout/sidebar/sidebar.tsx | 10 +- .../main/dashboard/chart/multiline-chart.tsx | 246 ++++++++++++++++++ .../main/dashboard/dashboard-container.tsx | 79 +++--- const/dummy.json | 164 +++++++++--- 6 files changed, 519 insertions(+), 162 deletions(-) create mode 100644 components/main/dashboard/chart/multiline-chart.tsx diff --git a/components/form/login.tsx b/components/form/login.tsx index d4d792f..d117ff5 100644 --- a/components/form/login.tsx +++ b/components/form/login.tsx @@ -69,98 +69,98 @@ export default function Login() { error("Username & Password Wajib Diisi !"); } else { // login dengan otp - loading(); - const response: any = await emailValidation(data); - if (response?.error) { - console.log("error", response); - if (response?.message?.messages[0]?.includes("failed to send mail")) { - error("Gagal Mengirim OTP"); - return false; - } + // loading(); + // const response: any = await emailValidation(data); + // if (response?.error) { + // console.log("error", response); + // if (response?.message?.messages[0]?.includes("failed to send mail")) { + // error("Gagal Mengirim OTP"); + // return false; + // } - if (response?.message?.messages[0]?.includes("username")) { - error("Username / Password Tidak Sesuai"); - return false; - } - error("Unknown Error"); - return false; - } - close(); - if (response?.data?.messages[0] === "Continue to setup email") { - setFirstLogin(true); - } else { - setNeedOtp(true); - } + // if (response?.message?.messages[0]?.includes("username")) { + // error("Username / Password Tidak Sesuai"); + // return false; + // } + // error("Unknown Error"); + // return false; + // } + // close(); + // if (response?.data?.messages[0] === "Continue to setup email") { + // setFirstLogin(true); + // } else { + // setNeedOtp(true); + // } // login tanpa otp - // loading(); - // const response = await postSignIn(data); - // if (response?.error) { - // error("Username / Password Tidak Sesuai"); - // } else { - // const profile = await getProfile(response?.data?.data?.access_token); - // const dateTime: any = new Date(); + loading(); + const response = await postSignIn(data); + if (response?.error) { + error("Username / Password Tidak Sesuai"); + } else { + const profile = await getProfile(response?.data?.data?.access_token); + 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, { - // expires: 1, - // }); - // Cookies.set("refresh_token", response?.data?.data?.refresh_token, { - // expires: 1, - // }); - // Cookies.set("time_refresh", newTime, { - // expires: 1, - // }); - // Cookies.set("is_first_login", "true", { - // secure: true, - // sameSite: "strict", - // }); - // const resActivity = await saveActivity( - // { - // activityTypeId: 1, - // url: "https://kontenhumas.com/auth", - // userId: profile?.data?.data?.id, - // }, - // accessData?.id_token - // ); - // Cookies.set("profile_picture", profile?.data?.data?.profilePictureUrl, { - // expires: 1, - // }); - // Cookies.set("uie", profile?.data?.data?.id, { - // expires: 1, - // }); - // Cookies.set("ufne", profile?.data?.data?.fullname, { - // expires: 1, - // }); - // Cookies.set("ulie", profile?.data?.data?.userLevelGroup, { - // expires: 1, - // }); - // Cookies.set("username", profile?.data?.data?.username, { - // expires: 1, - // }); - // Cookies.set("urie", profile?.data?.data?.userRoleId, { - // expires: 1, - // }); - // Cookies.set("masterPoldaId", profile?.data?.data?.masterPoldaId, { - // expires: 1, - // }); - // Cookies.set("ulne", profile?.data?.data?.userLevelId, { - // expires: 1, - // }); - // // 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, - // }); + Cookies.set("access_token", response?.data?.data?.access_token, { + expires: 1, + }); + Cookies.set("refresh_token", response?.data?.data?.refresh_token, { + expires: 1, + }); + Cookies.set("time_refresh", newTime, { + expires: 1, + }); + Cookies.set("is_first_login", "true", { + secure: true, + sameSite: "strict", + }); + const resActivity = await saveActivity( + { + activityTypeId: 1, + url: "https://kontenhumas.com/auth", + userId: profile?.data?.data?.id, + }, + accessData?.id_token + ); + Cookies.set("profile_picture", profile?.data?.data?.profilePictureUrl, { + expires: 1, + }); + Cookies.set("uie", profile?.data?.data?.id, { + expires: 1, + }); + Cookies.set("ufne", profile?.data?.data?.fullname, { + expires: 1, + }); + Cookies.set("ulie", profile?.data?.data?.userLevelGroup, { + expires: 1, + }); + Cookies.set("username", profile?.data?.data?.username, { + expires: 1, + }); + Cookies.set("urie", profile?.data?.data?.userRoleId, { + expires: 1, + }); + Cookies.set("masterPoldaId", profile?.data?.data?.masterPoldaId, { + expires: 1, + }); + Cookies.set("ulne", profile?.data?.data?.userLevelId, { + expires: 1, + }); + // 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, + }); - // close(); - // } + close(); + } } }; diff --git a/components/layout/sidebar/sidebar-mobile.tsx b/components/layout/sidebar/sidebar-mobile.tsx index 32de173..b1fe7a0 100644 --- a/components/layout/sidebar/sidebar-mobile.tsx +++ b/components/layout/sidebar/sidebar-mobile.tsx @@ -581,11 +581,11 @@ const SidebarMobile: React.FC = ({ updateSidebarData }) => { const roles = Cookies.get("ulie"); const rolesId = Cookies.get("urie"); - useEffect(() => { - if (!token) { - onLogout(); - } - }, [token]); + // useEffect(() => { + // if (!token) { + // onLogout(); + // } + // }, [token]); const onLogout = () => { Object.keys(Cookies.get()).forEach((cookieName) => { diff --git a/components/layout/sidebar/sidebar.tsx b/components/layout/sidebar/sidebar.tsx index 90ea078..40cdb2f 100644 --- a/components/layout/sidebar/sidebar.tsx +++ b/components/layout/sidebar/sidebar.tsx @@ -582,11 +582,11 @@ const Sidebar: React.FC = ({ updateSidebarData }) => { const roles = Cookies.get("ulie"); const rolesId = Cookies.get("urie"); - useEffect(() => { - if (!token) { - onLogout(); - } - }, [token]); + // useEffect(() => { + // if (!token) { + // onLogout(); + // } + // }, [token]); const onLogout = () => { Object.keys(Cookies.get()).forEach((cookieName) => { diff --git a/components/main/dashboard/chart/multiline-chart.tsx b/components/main/dashboard/chart/multiline-chart.tsx new file mode 100644 index 0000000..60b2f67 --- /dev/null +++ b/components/main/dashboard/chart/multiline-chart.tsx @@ -0,0 +1,246 @@ +"use client"; +import { useEffect, useState } from "react"; +import ReactApexChart from "react-apexcharts"; +import dummy from "../../../../const/dummy.json"; + +function getRangeAcrossMonths( + data: any[], + startMonth: number, + startDay: number, + endMonth: number, + endDay: number +) { + const labels: string[] = []; + const users: { name: string; data: number[] }[] = []; + const sortedData = data.sort((a, b) => a.month - b.month); + console.log("sorted,data", sortedData); + for (const monthData of sortedData) { + const { month, users: u } = monthData; + if (month < startMonth || month > endMonth) continue; + console.log("uuu", month, startMonth, endMonth, u.length); + + let startIndex = 0; + let endIndex = u[0].data.length - 1; + + if (month === startMonth) startIndex = startDay - 1; + if (month === endMonth) endIndex = endDay - 1; + + console.log("start,eend", startIndex, endIndex, month); + for (let j = 0; j < u.length; j++) { + const now = u[j].data; + // console.log("u.j", now); + const temp = []; + for (let i = startIndex; i <= endIndex; i++) { + temp.push(now[i]); + + if (j == 0) { + const label = `${(i + 1).toString().padStart(2, "0")} - ${month + .toString() + .padStart(2, "0")}`; + + labels.push(label); + } + } + const existing = users.find((item) => item.name === u[j].name); + if (existing) { + existing.data.push(...temp); // gabungkan data + } else { + users.push({ name: u[j].name, data: temp }); // tambahkan baru + } + } + } + + console.log("users", users); + + return { users, labels }; +} + +const ApexMultiLineChart = (props: { + type: string; + date: string; + range: { start: any; end: any }; +}) => { + const { date, type, range } = props; + const [datas, setDatas] = useState([]); + const [years, setYear] = useState(""); + + const [series, setSeries] = useState([]); + const [categories, setCategories] = useState([]); + + useEffect(() => { + initFetch(); + console.log("type", type); + }, [date, type, range.start, range.end]); + + const initFetch = async () => { + const splitDate = date.split(" "); + const splitDateDaily = String(range.start.year); + console.log("split", splitDate); + console.log("daily", splitDateDaily); + let data: any = []; + + if ( + (type === "monthly" && splitDate[1] === years) || + (type === "daily" && splitDateDaily === years) + ) { + data = datas; + } else { + // const res = await getStatisticMonthly( + // type === "monthly" ? splitDate[1] : splitDateDaily + // ); + // data = res?.data?.data; + data = dummy.data; + setDatas(data); + } + + if (type === "daily") { + console.log( + "aaa", + range.start.month, + range.start.day, + range.end.month, + range.end.day + ); + const mappedData = getRangeAcrossMonths( + data, + range.start.month, + range.start.day, + range.end.month, + range.end.day + ); + setSeries(mappedData.users); + setCategories(mappedData.labels); + } + + if (type === "monthly") { + console.log("daaa", data); + const getDatas = data?.find( + (a: any) => + a.month == Number(splitDate[0]) && a.year === Number(splitDate[1]) + ); + if (getDatas) { + console.log("datanya", getDatas.users); + setSeries(getDatas.users); + } else { + setSeries([]); + } + } + + setYear(type === "monthly" ? splitDate[1] : splitDateDaily); + }; + return ( +
+
+ +
+
+
+ ); +}; + +export default ApexMultiLineChart; diff --git a/components/main/dashboard/dashboard-container.tsx b/components/main/dashboard/dashboard-container.tsx index 7e3e963..8b34242 100644 --- a/components/main/dashboard/dashboard-container.tsx +++ b/components/main/dashboard/dashboard-container.tsx @@ -70,6 +70,7 @@ import { format } from "date-fns"; import ApexChartColumnVisitors from "./chart/visitor-chart"; import IndonesiaMap from "@/components/ui/maps-charts"; import ApexChartDynamic from "./chart/dynamic-bar-char"; +import ApexMultiLineChart from "./chart/multiline-chart"; type ArticleData = Article & { no: number; @@ -240,12 +241,29 @@ export default function DashboardContainer() { end: parseDate(convertDateFormatNoTimeV2(today)), }); + const [typeDateUsers, setTypeDateUsers] = useState("daily"); + const [usersYear, setUsersYear] = useState(today.getFullYear()); + const [usersSelectedMonth, setUsersSelectedMonth] = useState( + today + ); + const [usersDailyDate, setUsersDailyDate] = useState({ + start: parseDate( + convertDateFormatNoTimeV2( + new Date(new Date().setDate(new Date().getDate() - 30)) + ) + ), + end: parseDate(convertDateFormatNoTimeV2(today)), + }); + const handleMonthClick = (monthIndex: number) => { setSelectedMonth(new Date(year, monthIndex, 1)); }; const handleMonthClickVisitor = (monthIndex: number) => { - setVisitorSelectedMonth(new Date(year, monthIndex, 1)); + setVisitorSelectedMonth(new Date(visitorYear, monthIndex, 1)); + }; + const handleMonthClickUsers = (monthIndex: number) => { + setUsersSelectedMonth(new Date(usersYear, monthIndex, 1)); }; useEffect(() => { @@ -760,8 +778,8 @@ export default function DashboardContainer() { )} -
-
+
+
Engagement Analytics @@ -899,7 +917,7 @@ export default function DashboardContainer() {
-
+
Users Analytics
@@ -907,16 +925,16 @@ export default function DashboardContainer() { className="w-full md:w-[140px] text-xs lg:text-sm h-[30px] lg:h-[40px]" label="" labelPlacement="outside" - selectedKeys={[typeDateVisitor]} + selectedKeys={[typeDateUsers]} onChange={(e) => - e.target.value !== "" && setTypeDateVisitor(e.target.value) + e.target.value !== "" && setTypeDateUsers(e.target.value) } > Bulanan Harian - {typeDateVisitor === "monthly" ? ( + {typeDateUsers === "monthly" ? ( @@ -934,7 +952,7 @@ export default function DashboardContainer() {
@@ -943,7 +961,7 @@ export default function DashboardContainer() { @@ -953,11 +971,11 @@ export default function DashboardContainer() { {months.map((month, idx) => (
-
diff --git a/const/dummy.json b/const/dummy.json index 1902e24..c648bf0 100644 --- a/const/dummy.json +++ b/const/dummy.json @@ -1,46 +1,148 @@ { "data": [ { - "id": 1, - "year": 2024, - "month": 11, - "suggestions": [ - 14, 32, 10, 21, 15, 18, 24, 30, 12, 25, 19, 28, 14, 17, 22, 31, 27, 13, - 20, 24, 29, 18, 21, 26, 23, 14, 19, 17, 28, 22 - ] - }, - { - "id": 2, - "year": 2024, - "month": 12, - "suggestions": [ - 15, 23, 19, 14, 18, 20, 22, 17, 21, 19, 23, 16, 25, 20, 18, 19, 22, 24, - 15, 18, 21, 26, 28, 23, 17, 20, 19, 22, 22, 42, 32 - ] - }, - { - "id": 3, "year": 2025, - "month": 1, - "suggestions": [ - 14, 32, 10, 21, 15, 18, 24, 30, 12, 25, 19, 28, 14, 17, 22, 31, 27, 13, - 20, 24, 29, 18, 21, 26, 23, 14, 19, 17, 28, 22, 21 + "month": 4, + "users": [ + { + "name": "Polda Aceh", + "data": [ + 12, 7, 5, 19, 3, 8, 15, 4, 9, 6, 14, 11, 13, 10, 2, 18, 7, 5, 8, 17, + 4, 6, 14, 15, 3, 10, 12, 9, 6, 13 + ] + }, + { + "name": "Polda Sumatera Utara", + "data": [ + 10, 4, 6, 7, 9, 8, 14, 13, 5, 12, 11, 3, 17, 16, 7, 9, 10, 8, 5, 14, + 11, 4, 6, 9, 15, 13, 3, 7, 10, 12 + ] + }, + { + "name": "Polda Sumatera Barat", + "data": [ + 7, 6, 3, 8, 12, 4, 6, 10, 11, 14, 13, 5, 9, 10, 6, 7, 8, 13, 15, 6, + 7, 5, 8, 14, 11, 13, 4, 6, 12, 10 + ] + }, + { + "name": "Polda Metro Jaya", + "data": [ + 12, 7, 5, 19, 3, 8, 15, 4, 9, 6, 14, 11, 13, 10, 2, 18, 7, 5, 8, 17, + 4, 6, 9, 6, 13, 5, 14, 15, 3, 10 + ] + }, + { + "name": "Polda Jabar", + "data": [ + 10, 4, 6, 17, 16, 7, 9, 10, 8, 5, 14, 11, 4, 6, 9, 15, 13, 3, 7, 10, + 12, 9, 8, 14, 13, 21, 5, 12, 11 + ] + }, + { + "name": "Polda Jateng", + "data": [ + 7, 6, 3, 13, 5, 9, 10, 6, 7, 8, 13, 15, 6, 7, 5, 8, 14, 11, 13, 4, + 4, 6, 10, 11, 14, 2, 6, 12, 10, 8 + ] + } ] }, { - "id": 4, "year": 2025, - "month": 2, - "suggestions": [ - 15, 23, 19, 14, 18, 20, 22, 17, 21, 19, 23, 16, 25, 20, 18, 19, 22, 24, - 15, 18, 21, 26, 28, 23, 17, 20, 19, 22 + "month": 5, + "users": [ + { + "name": "Polda Aceh", + "data": [ + 12, 7, 5, 19, 3, 8, 15, 4, 9, 6, 14, 11, 13, 10, 2, 18, 7, 5, 8, 17, + 4, 6, 14, 15, 3, 10, 12, 9, 6, 13, 5 + ] + }, + { + "name": "Polda Sumatera Utara", + "data": [ + 10, 4, 6, 7, 5, 12, 11, 3, 17, 16, 7, 9, 10, 8, 5, 14, 11, 4, 6, 9, + 15, 13, 3, 7, 10, 12, 9, 8, 14, 13, 4 + ] + }, + { + "name": "Polda Sumatera Barat", + "data": [ + 7, 6, 3, 13, 5, 9, 10, 6, 7, 8, 13, 15, 6, 7, 5, 8, 14, 11, 13, 4, + 6, 12, 10, 8, 12, 4, 6, 10, 11, 14, 2 + ] + }, + { + "name": "Polda Metro Jaya", + "data": [ + 12, 7, 5, 19, 3, 8, 15, 4, 9, 6, 14, 11, 13, 10, 2, 18, 7, 5, 8, 17, + 4, 6, 9, 6, 13, 5, 14, 15, 3, 10, 12 + ] + }, + { + "name": "Polda Jabar", + "data": [ + 10, 4, 6, 17, 16, 7, 9, 10, 8, 5, 14, 11, 4, 6, 9, 15, 13, 3, 7, 10, + 12, 9, 8, 14, 13, 2, 5, 12, 11, 3, 2 + ] + }, + { + "name": "Polda Jateng", + "data": [ + 7, 6, 3, 13, 5, 9, 10, 6, 7, 8, 13, 15, 6, 7, 5, 8, 14, 11, 13, 4, + 4, 6, 10, 11, 14, 2, 6, 12, 10, 8, 12 + ] + } ] }, { - "id": 5, "year": 2025, - "month": 3, - "suggestions": [14, 32, 10, 21, 15, 18] + "month": 6, + "users": [ + { + "name": "Polda Aceh", + "data": [ + 12, 7, 5, 19, 3, 8, 15, 4, 9, 6, 14, 11, 13, 10, 2, 18, 7, 5, 8, 17, + 4, 6, 14, 15, 3, 10, 12, 9, 6, 13, 5 + ] + }, + { + "name": "Polda Sumatera Utara", + "data": [ + 10, 4, 6, 7, 5, 12, 11, 3, 17, 16, 7, 9, 10, 8, 5, 14, 11, 4, 6, 9, + 15, 13, 3, 7, 10, 12, 9, 8, 14, 13, 4 + ] + }, + { + "name": "Polda Sumatera Barat", + "data": [ + 7, 6, 3, 13, 5, 9, 10, 6, 7, 8, 13, 15, 6, 7, 5, 8, 14, 11, 13, 4, + 6, 12, 10, 8, 12, 4, 6, 10, 11, 14, 2 + ] + }, + { + "name": "Polda Metro Jaya", + "data": [ + 12, 7, 5, 19, 3, 8, 15, 4, 9, 6, 14, 11, 13, 10, 2, 18, 7, 5, 8, 17, + 4, 6, 9, 6, 13, 5, 14, 15, 3, 10, 12 + ] + }, + { + "name": "Polda Jabar", + "data": [ + 10, 4, 6, 17, 16, 7, 9, 10, 8, 5, 14, 11, 4, 6, 9, 15, 13, 3, 7, 10, + 12, 9, 8, 14, 13, 20, 5, 12, 11, 3 + ] + }, + { + "name": "Polda Jateng", + "data": [ + 7, 6, 3, 13, 5, 9, 10, 6, 7, 8, 13, 15, 6, 7, 5, 8, 14, 11, 13, 4, + 4, 6, 10, 11, 14, 2, 6, 12, 10, 8, 12 + ] + } + ] } ] }