[QUDO-221, 195] feat:new ui rekap admin dashboard, fix:landing mobile ver

This commit is contained in:
Rama Priyanto 2025-06-13 15:01:48 +07:00
parent ace3decdaa
commit 581712953e
4 changed files with 165 additions and 25 deletions

View File

@ -222,7 +222,7 @@ export default function BannerHumasNew() {
return ( return (
<div className="h-fit relative text-white overflow-hidden"> <div className="h-fit relative text-white overflow-hidden">
<div <div
className="flex w-full h-[45vh] lg:h-[93vh] transition-transform duration-700 ease-in-out" className="flex w-full h-[60vh] lg:h-[93vh] transition-transform duration-700 ease-in-out"
style={{ transform: `translateX(-${currentIndex * 100}%)` }} style={{ transform: `translateX(-${currentIndex * 100}%)` }}
> >
{jumbotronList?.length > 0 ? ( {jumbotronList?.length > 0 ? (
@ -241,7 +241,7 @@ export default function BannerHumasNew() {
alt={`humasbanner-${index}`} alt={`humasbanner-${index}`}
width={1960} width={1960}
height={1080} height={1080}
className="w-screen h-[45vh] lg:h-[93vh] object-cover object-center opacity-[25] dark:opacity-70 rounded-none" className="w-screen h-[60vh] lg:h-[93vh] object-cover object-center opacity-[25] dark:opacity-70 rounded-none"
/> />
</Link> </Link>
)) ))

View File

@ -9,6 +9,8 @@ import {
} from "@/components/icons/dashboard-icon"; } from "@/components/icons/dashboard-icon";
import { Submenu1Icon } from "@/components/icons/sidebar-icon"; import { Submenu1Icon } from "@/components/icons/sidebar-icon";
import { import {
Accordion,
AccordionItem,
Button, Button,
Calendar, Calendar,
Checkbox, Checkbox,
@ -21,6 +23,7 @@ import {
Select, Select,
SelectItem, SelectItem,
SelectSection, SelectSection,
Skeleton,
} from "@heroui/react"; } from "@heroui/react";
import ApexChartColumn from "./chart/column-chart"; import ApexChartColumn from "./chart/column-chart";
import ApexChartDonut from "./chart/donut-chart"; import ApexChartDonut from "./chart/donut-chart";
@ -103,6 +106,10 @@ export default function DashboardContainer() {
const [topPages, setTopPages] = useState<TopPages[]>([]); const [topPages, setTopPages] = useState<TopPages[]>([]);
const [postCount, setPostCount] = useState<PostCount[]>([]); const [postCount, setPostCount] = useState<PostCount[]>([]);
const [polresData, setPolresData] = useState<any>({});
const [selectedAccordion, setSelectedAccordion] = useState<any>(new Set([]));
const roleId = Cookies.get("urie");
useEffect(() => { useEffect(() => {
fetchSummary(); fetchSummary();
@ -171,7 +178,7 @@ export default function DashboardContainer() {
getDate(postContentDate.startDate), getDate(postContentDate.startDate),
getDate(postContentDate.endDate) getDate(postContentDate.endDate)
); );
setPostCount(getTableNumber(10, res?.data?.data)); setPostCount(getTableNumberStats(res?.data?.data));
} }
const getTableNumber = (limit: number, data: any) => { const getTableNumber = (limit: number, data: any) => {
@ -187,6 +194,18 @@ export default function DashboardContainer() {
} }
}; };
const getTableNumberStats = (data: any) => {
if (data) {
let iterate = 0;
const newData = data.map((value: any) => {
iterate++;
value.no = iterate;
return value;
});
return newData;
}
};
const getMonthYear = (date: any) => { const getMonthYear = (date: any) => {
return date.month + " " + date.year; return date.month + " " + date.year;
}; };
@ -213,6 +232,50 @@ export default function DashboardContainer() {
return month + " " + year; return month + " " + year;
}; };
useEffect(() => {
const temp = Array.from(selectedAccordion);
console.log("selecette", temp);
if (temp.length > 0) {
for (const element of temp) {
getPolresData(Number(element));
}
}
}, [postContentDate]);
const getPolresData = async (id: number) => {
const getDate = (data: any) => {
return `${data.year}-${data.month < 10 ? `0${data.month}` : data.month}-${
data.day < 10 ? `0${data.day}` : data.day
}`;
};
const res = await getUserLevelDataStat(
getDate(postContentDate.startDate),
getDate(postContentDate.endDate),
id
);
const polresNowData = getTableNumberStats(res?.data?.data);
setPolresData((prev: any) => ({
...prev,
[id]: polresNowData,
}));
};
const handleSelectionChange = (e: any) => {
const prev = selectedAccordion;
const current = e;
const currentArray = Array.from(current);
const added = Number(currentArray.filter((item) => !prev.has(item))[0]);
setSelectedAccordion(current);
if (added) {
getPolresData(added);
}
};
return ( return (
<div className="px-2 lg:p-8 flex justify-center"> <div className="px-2 lg:p-8 flex justify-center">
<div className="w-full flex flex-col gap-6"> <div className="w-full flex flex-col gap-6">
@ -330,22 +393,86 @@ export default function DashboardContainer() {
</div> </div>
</div> </div>
<div className="flex flex-col gap-1 lg:h-[500px] overflow-y-auto"> <div className="flex flex-col gap-1 lg:h-[500px] overflow-y-auto">
{postCount?.map((list) => ( {roleId && Number(roleId) < 3 ? (
<div <Accordion
key={list.userLevelId} selectedKeys={selectedAccordion}
className="flex flex-row border-b-1 gap-1 py-1" onSelectionChange={(e) => handleSelectionChange(e)}
selectionMode="multiple"
className="w-full"
> >
<div className="w-[5%]">{list?.no}</div> {postCount?.map((list) => (
<div className="w-[85%]">{list?.userLevelName}</div> <AccordionItem
key={list.userLevelId}
aria-label={list.userLevelName}
title={
<div
key={list.userLevelId}
className="flex flex-row gap-1 py-1"
>
<div className="w-[5%]">{list?.no}</div>
<div className="w-[85%]">{list?.userLevelName}</div>
<div
className={`w-[10%] text-center ${
list?.totalArticle === 0 &&
"bg-red-600 text-white"
}`}
>
{list?.totalArticle}
</div>
</div>
}
>
{polresData[list?.userLevelId] ? (
polresData[list?.userLevelId]?.map(
(child: any, index: number) => (
<div
key={child.userLevelId}
className={`flex flex-row gap-1 py-1 ${
index ===
polresData[list?.userLevelId].length - 1
? ""
: "border-b-1"
}`}
>
<div className="w-[5%]"></div>
<div className="w-[85%]">
{child?.userLevelName}
</div>
<div
className={`w-[10%] text-start ${
list?.totalArticle === 0 &&
"bg-red-600 text-white"
}`}
>
{child?.totalArticle}
</div>
</div>
)
)
) : (
<Skeleton className="h-3 w-full rounded-lg" />
)}
</AccordionItem>
))}
</Accordion>
) : (
postCount?.map((list) => (
<div <div
className={`w-[10%] text-center ${ key={list.userLevelId}
list?.totalArticle === 0 && "bg-red-600 text-white" className="flex flex-row border-b-1 gap-1 py-1"
}`}
> >
{list?.totalArticle} <div className="w-[5%]">{list?.no}</div>
<div className="w-[85%]">{list?.userLevelName}</div>
<div
className={`w-[10%] text-center ${
list?.totalArticle === 0 && "bg-red-600 text-white"
}`}
>
{list?.totalArticle}
</div>
</div> </div>
</div> ))
))} )}
</div> </div>
</div> </div>
<div className="flex flex-col w-full lg:w-[45%] gap-6 shadow-md bg-white dark:bg-[#18181b] rounded-lg p-8 text-sm"> <div className="flex flex-col w-full lg:w-[45%] gap-6 shadow-md bg-white dark:bg-[#18181b] rounded-lg p-8 text-sm">

View File

@ -7,6 +7,10 @@ import {
} from "./http-config/axios-base-service"; } from "./http-config/axios-base-service";
import Cookies from "js-cookie"; import Cookies from "js-cookie";
import { stat } from "fs"; import { stat } from "fs";
import {
httpGetInterceptor,
httpPostInterceptor,
} from "./http-config/http-interceptor-services";
const token = Cookies.get("access_token"); const token = Cookies.get("access_token");
export async function getListArticle(props: PaginationRequest) { export async function getListArticle(props: PaginationRequest) {
@ -184,14 +188,19 @@ export async function deleteArticleFiles(id: number) {
return await httpPut(`article-files/delete/${id}`, headers); return await httpPut(`article-files/delete/${id}`, headers);
} }
export async function getUserLevelDataStat(startDate: string, endDate: string) { export async function getUserLevelDataStat(
const headers = { startDate: string,
"content-type": "application/json", endDate: string,
Authorization: `Bearer ${token}`, levelId?: number
}; ) {
return await httpGet( // const headers = {
`/articles/statistic/user-levels?startDate=${startDate}&endDate=${endDate}`, // "content-type": "application/json",
headers // Authorization: `Bearer ${token}`,
// };
return await httpGetInterceptor(
`/articles/statistic/user-levels?startDate=${startDate}&endDate=${endDate}&userLevelId=${
levelId || ""
}`
); );
} }
export async function getStatisticMonthly(year: string) { export async function getStatisticMonthly(year: string) {

View File

@ -1,6 +1,6 @@
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import axiosInterceptorInstance from "./axios-interceptor-instance";
import Cookies from "js-cookie"; import Cookies from "js-cookie";
import axiosInterceptorInstance from "./axios-interceptor-service";
export async function httpGetInterceptor(pathUrl: any) { export async function httpGetInterceptor(pathUrl: any) {
const response = await axiosInterceptorInstance const response = await axiosInterceptorInstance
@ -28,7 +28,11 @@ export async function httpGetInterceptor(pathUrl: any) {
} }
} }
export async function httpPostInterceptor(pathUrl: any, data: any, headers?: any) { export async function httpPostInterceptor(
pathUrl: any,
data: any,
headers?: any
) {
const response = await axiosInterceptorInstance const response = await axiosInterceptorInstance
.post(pathUrl, data, { headers }) .post(pathUrl, data, { headers })
.catch((error) => error.response); .catch((error) => error.response);