feat:dashboard analytics
This commit is contained in:
parent
c02c6661f7
commit
28c94c5230
|
|
@ -201,14 +201,16 @@ export default function HeaderNews() {
|
||||||
radius="lg"
|
radius="lg"
|
||||||
className="border-none h-[67vh] shadow-none"
|
className="border-none h-[67vh] shadow-none"
|
||||||
>
|
>
|
||||||
<img
|
<Image
|
||||||
alt="headernews"
|
alt="headernews"
|
||||||
|
width={1440}
|
||||||
|
height={1080}
|
||||||
src={
|
src={
|
||||||
newsItem?.thumbnailUrl == ""
|
newsItem?.thumbnailUrl == ""
|
||||||
? "no-image.jpg"
|
? "/no-image.jpg"
|
||||||
: newsItem?.thumbnailUrl
|
: newsItem?.thumbnailUrl
|
||||||
}
|
}
|
||||||
className="w-full h-[67vh] object-cover rounded-lg"
|
className="w-full !h-[67vh] object-cover rounded-lg"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<CardFooter className="mb-1 max-h-[20vh] before:bg-white/10 border-white/20 border-1 overflow-hidden py-1 md:absolute before:rounded-xl rounded-large bottom-1 w-[calc(100%_-_8px)] shadow-small ml-1 z-10">
|
<CardFooter className="mb-1 max-h-[20vh] before:bg-white/10 border-white/20 border-1 overflow-hidden py-1 md:absolute before:rounded-xl rounded-large bottom-1 w-[calc(100%_-_8px)] shadow-small ml-1 z-10">
|
||||||
|
|
@ -216,7 +218,7 @@ export default function HeaderNews() {
|
||||||
<Link
|
<Link
|
||||||
href={`news/detail/${newsItem.id}-${newsItem?.slug}`}
|
href={`news/detail/${newsItem.id}-${newsItem?.slug}`}
|
||||||
>
|
>
|
||||||
<p className="text-left font-semibold text-2xl">
|
<p className="text-left font-semibold text-lg lg:text-2xl">
|
||||||
{newsItem.title}
|
{newsItem.title}
|
||||||
</p>
|
</p>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
||||||
|
|
@ -228,7 +228,7 @@ export default function MedolUpdate() {
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</Tab>
|
</Tab>
|
||||||
{/* <Tab key="inp" title="Indonesia Nasional Police Update">
|
<Tab key="inp" title="Indonesia Nasional Police Update">
|
||||||
<Swiper
|
<Swiper
|
||||||
navigation={true}
|
navigation={true}
|
||||||
modules={[Navigation, Pagination]}
|
modules={[Navigation, Pagination]}
|
||||||
|
|
@ -297,7 +297,7 @@ export default function MedolUpdate() {
|
||||||
</Button>
|
</Button>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</Tab> */}
|
</Tab>
|
||||||
<Tab key="polritv" title="Polri TV Update">
|
<Tab key="polritv" title="Polri TV Update">
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<div className="w-[40%] mx-auto">
|
<div className="w-[40%] mx-auto">
|
||||||
|
|
|
||||||
|
|
@ -33,11 +33,86 @@ type ArticleData = Article & {
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface TopPages {
|
||||||
|
id: number;
|
||||||
|
no: number;
|
||||||
|
title: string;
|
||||||
|
visits: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PostCount {
|
||||||
|
id: number;
|
||||||
|
no: number;
|
||||||
|
name: string;
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dummyTopPages = [
|
||||||
|
{ id: 1, title: "Home Page", visits: 830 },
|
||||||
|
{ id: 2, title: "Media Update", visits: 762 },
|
||||||
|
{ id: 3, title: "Polda Metro Jaya", visits: 532 },
|
||||||
|
{ id: 4, title: "Kapolri: Transformasi Menuju Polri Presisi", visits: 500 },
|
||||||
|
{ id: 5, title: "Polda Jawa Barat Ungkap Kasus Narkoba", visits: 480 },
|
||||||
|
{ id: 6, title: "Polri Perketat Pengamanan Jelang Pemilu", visits: 460 },
|
||||||
|
{ id: 7, title: "Polda Jawa Tengah Berhasil Tangkap Buronan", visits: 440 },
|
||||||
|
{
|
||||||
|
id: 8,
|
||||||
|
title: "Divisi Humas Polri Rilis Data Kejahatan Terbaru",
|
||||||
|
visits: 420,
|
||||||
|
},
|
||||||
|
{ id: 9, title: "Polda Sumatera Utara Gerebek Pabrik Narkoba", visits: 400 },
|
||||||
|
{
|
||||||
|
id: 10,
|
||||||
|
title: "Kapolda Bali Imbau Wisatawan Waspada Kejahatan",
|
||||||
|
visits: 380,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const dummyPostCount = [
|
||||||
|
{ id: 1, name: "Polda Sumatera Utara", count: 132 },
|
||||||
|
{ id: 2, name: "Polda Metro Jaya", count: 128 },
|
||||||
|
{ id: 3, name: "Polda Jawa Barat", count: 120 },
|
||||||
|
{ id: 4, name: "Polda Jawa Timur", count: 115 },
|
||||||
|
{ id: 5, name: "Polda Bali", count: 110 },
|
||||||
|
{ id: 6, name: "Polda Daerah Istimewa Yogyakarta", count: 105 },
|
||||||
|
{ id: 7, name: "Polda Riau", count: 98 },
|
||||||
|
{ id: 8, name: "Polda Sulawesi Selatan", count: 92 },
|
||||||
|
{ id: 9, name: "Polda Kalimantan Timur", count: 85 },
|
||||||
|
{ id: 10, name: "Polda Jawa Tengah", count: 78 },
|
||||||
|
{ id: 11, name: "Polda Kalimantan Selatan", count: 72 },
|
||||||
|
{ id: 12, name: "Polda Sumatera Barat", count: 65 },
|
||||||
|
{ id: 13, name: "Polda Papua", count: 60 },
|
||||||
|
{ id: 14, name: "Polda Nusa Tenggara Barat", count: 54 },
|
||||||
|
{ id: 15, name: "Polda Maluku", count: 49 },
|
||||||
|
{ id: 16, name: "Polda Bengkulu", count: 43 },
|
||||||
|
{ id: 17, name: "Polda Lampung", count: 37 },
|
||||||
|
{ id: 18, name: "Polda Sulawesi Tenggara", count: 30 },
|
||||||
|
{ id: 19, name: "Polda Gorontalo", count: 24 },
|
||||||
|
{ id: 20, name: "Polda Kalimantan Barat", count: 18 },
|
||||||
|
{ id: 21, name: "Polda Kepulauan Riau", count: 10 },
|
||||||
|
{ id: 22, name: "Polda Sulawesi Barat", count: 8 },
|
||||||
|
{ id: 23, name: "Polda Papua Barat", count: 5 },
|
||||||
|
{ id: 24, name: "Polda Maluku Utara", count: 3 },
|
||||||
|
{ id: 25, name: "Polda Nusa Tenggara Timur", count: 2 },
|
||||||
|
{ id: 26, name: "Polda Kalimantan Tengah", count: 1 },
|
||||||
|
{ id: 27, name: "Polda Sulawesi Tengah", count: 1 },
|
||||||
|
{ id: 28, name: "Polda Bangka Belitung", count: 1 },
|
||||||
|
{ id: 29, name: "Polda Jambi", count: 0 },
|
||||||
|
{ id: 30, name: "Polda Banten", count: 0 },
|
||||||
|
{ id: 31, name: "Polda Aceh", count: 0 },
|
||||||
|
{ id: 32, name: "Polda Kalimantan Utara", count: 0 },
|
||||||
|
{ id: 33, name: "Polda Sulawesi Utara", count: 0 },
|
||||||
|
{ id: 34, name: "Polda Kepulauan Bangka Belitung", count: 0 },
|
||||||
|
{ id: 35, name: "Polda Sumatera Selatan", count: 0 },
|
||||||
|
];
|
||||||
|
|
||||||
export default function DashboardContainer() {
|
export default function DashboardContainer() {
|
||||||
const username = Cookies.get("username");
|
const username = Cookies.get("username");
|
||||||
const fullname = Cookies.get("ufne");
|
const fullname = Cookies.get("ufne");
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
const [totalPage, setTotalPage] = useState(1);
|
const [totalPage, setTotalPage] = useState(1);
|
||||||
|
const [topPagespage, setTopPagesPage] = useState(1);
|
||||||
|
const [topPagesTotalPage, setTopPagesTotalPage] = useState(1);
|
||||||
const [article, setArticle] = useState<ArticleData[]>([]);
|
const [article, setArticle] = useState<ArticleData[]>([]);
|
||||||
const [analyticsView, setAnalyticView] = useState<string[]>([
|
const [analyticsView, setAnalyticView] = useState<string[]>([
|
||||||
"visit",
|
"visit",
|
||||||
|
|
@ -49,10 +124,20 @@ export default function DashboardContainer() {
|
||||||
endDate: new Date(),
|
endDate: new Date(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [postContentDate, setPostContentDate] = useState({
|
||||||
|
startDate: new Date(new Date().setDate(new Date().getDate() - 7)),
|
||||||
|
endDate: new Date(),
|
||||||
|
});
|
||||||
|
|
||||||
const [typeDate, setTypeDate] = useState("monthly");
|
const [typeDate, setTypeDate] = useState("monthly");
|
||||||
|
|
||||||
|
const [topPages, setTopPages] = useState<TopPages[]>([]);
|
||||||
|
const [postCount, setPostCount] = useState<PostCount[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
initState();
|
initState();
|
||||||
|
fetchTopPages();
|
||||||
|
fetchPostCount();
|
||||||
}, [page]);
|
}, [page]);
|
||||||
|
|
||||||
async function initState() {
|
async function initState() {
|
||||||
|
|
@ -66,6 +151,28 @@ export default function DashboardContainer() {
|
||||||
setTotalPage(res?.data?.meta?.totalPage);
|
setTotalPage(res?.data?.meta?.totalPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function fetchTopPages() {
|
||||||
|
setTopPages(getTableNumber(10, dummyTopPages));
|
||||||
|
setTopPagesTotalPage(1);
|
||||||
|
}
|
||||||
|
async function fetchPostCount() {
|
||||||
|
setPostCount(getTableNumber(10, dummyPostCount));
|
||||||
|
setTopPagesTotalPage(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTableNumber = (limit: number, data: any) => {
|
||||||
|
if (data) {
|
||||||
|
const startIndex = limit * (page - 1);
|
||||||
|
let iterate = 0;
|
||||||
|
const newData = data.map((value: any) => {
|
||||||
|
iterate++;
|
||||||
|
value.no = startIndex + iterate;
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
return newData;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const getMonthYear = (date: Date | string) => {
|
const getMonthYear = (date: Date | string) => {
|
||||||
const newDate = new Date(date);
|
const newDate = new Date(date);
|
||||||
|
|
||||||
|
|
@ -140,6 +247,89 @@ export default function DashboardContainer() {
|
||||||
<div className="font-semibold text-lg">530</div>
|
<div className="font-semibold text-lg">530</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="w-full flex flex-col lg:flex-row gap-6 justify-center ">
|
||||||
|
<div className="border-1 shadow-sm w-screen rounded-lg lg:w-[55%] p-6 flex flex-col text-xs lg:text-sm">
|
||||||
|
<div className="flex justify-between mb-4 items-center">
|
||||||
|
<p className="font-semibold">
|
||||||
|
Rekapitulasi Post Berita Polda Pada Website
|
||||||
|
</p>
|
||||||
|
<div className="w-[220px]">
|
||||||
|
<Datepicker
|
||||||
|
value={postContentDate}
|
||||||
|
displayFormat="DD/MM/YYYY"
|
||||||
|
asSingle={false}
|
||||||
|
useRange={true}
|
||||||
|
onChange={(e: any) => setPostContentDate(e)}
|
||||||
|
inputClassName="z-50 w-full text-xs lg:text-sm bg-transparent border-1 border-gray-200 px-2 py-[6px] rounded-sm lg:rounded-lg h-[30px] lg:h-[40px] text-gray-600 dark:text-gray-300"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-row border-b-1 gap-1">
|
||||||
|
<div className="w-[5%]">NO</div>
|
||||||
|
<div className="w-[50%] lg:w-[70%]">POLDA</div>
|
||||||
|
<div className="w-[45%] lg:w-[25%] text-right">
|
||||||
|
JUMLAH POST BERITA
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col gap-1 lg:h-[500px] overflow-y-auto">
|
||||||
|
{postCount?.map((list) => (
|
||||||
|
<div key={list.id} className="flex flex-row border-b-1 gap-1">
|
||||||
|
<div className="w-[5%]">{list?.no}</div>
|
||||||
|
<div className="w-[85%]">{list?.name}</div>
|
||||||
|
<div
|
||||||
|
className={`w-[10%] text-center ${
|
||||||
|
list?.count === 0 && "bg-red-600 text-white"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{list?.count}
|
||||||
|
</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 justify-between font-semibold">
|
||||||
|
<p>Recent Article</p>
|
||||||
|
<Link href="/admin/article/create">
|
||||||
|
<Button color="primary" variant="bordered">
|
||||||
|
Buat Article
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
{article?.map((list: any) => (
|
||||||
|
<div
|
||||||
|
key={list?.id}
|
||||||
|
className="flex flex-row gap-2 items-center border-b-2 py-2"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={list?.thumbnailUrl || `/no-image.jpg`}
|
||||||
|
className="h-[70px] w-[70px] object-cover rounded-lg"
|
||||||
|
/>
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
<p>{textEllipsis(list?.title, 78)}</p>
|
||||||
|
<p className="text-xs">
|
||||||
|
{convertDateFormat(list?.createdAt)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
<div className="my-2 w-full flex justify-center">
|
||||||
|
<Pagination
|
||||||
|
isCompact
|
||||||
|
showControls
|
||||||
|
showShadow
|
||||||
|
color="primary"
|
||||||
|
classNames={{
|
||||||
|
base: "bg-transparent",
|
||||||
|
wrapper: "bg-transparent",
|
||||||
|
}}
|
||||||
|
page={page}
|
||||||
|
total={totalPage}
|
||||||
|
onChange={(page) => setPage(page)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className="w-full flex flex-col lg:flex-row gap-6 justify-center ">
|
<div className="w-full flex flex-col lg:flex-row gap-6 justify-center ">
|
||||||
<div className="border-1 shadow-sm w-screen rounded-lg lg:w-[55%] p-6 flex flex-col">
|
<div className="border-1 shadow-sm w-screen rounded-lg lg:w-[55%] p-6 flex flex-col">
|
||||||
<div className="flex justify-between mb-3">
|
<div className="flex justify-between mb-3">
|
||||||
|
|
@ -221,30 +411,20 @@ export default function DashboardContainer() {
|
||||||
</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">
|
<div className="flex flex-col w-full lg:w-[45%] gap-6 shadow-md bg-white dark:bg-[#18181b] rounded-lg p-8 text-xs lg:text-sm">
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between font-semibold">
|
||||||
<p>Recent Article</p>
|
<p>Top Pages</p>
|
||||||
<Link href="/admin/article/create">
|
|
||||||
<Button color="primary" variant="bordered">
|
|
||||||
Buat Article
|
|
||||||
</Button>
|
|
||||||
</Link>
|
|
||||||
</div>
|
</div>
|
||||||
{article?.map((list: any) => (
|
<div className="flex flex-row border-b-1">
|
||||||
<div
|
<div className="w-[5%]">No</div>
|
||||||
key={list?.id}
|
<div className="w-[85%]">Title</div>
|
||||||
className="flex flex-row gap-2 items-center border-b-2 py-2"
|
<div className="w-[10%]">Visits</div>
|
||||||
>
|
</div>
|
||||||
<img
|
{topPages?.map((list) => (
|
||||||
src={list?.thumbnailUrl || `/no-image.jpg`}
|
<div key={list.id} className="flex flex-row border-b-1">
|
||||||
className="h-[70px] w-[70px] object-cover rounded-lg"
|
<div className="w-[5%]">{list?.no}</div>
|
||||||
/>
|
<div className="w-[85%]">{list?.title}</div>
|
||||||
<div className="flex flex-col gap-2">
|
<div className="w-[10%]">{list?.visits}</div>
|
||||||
<p>{textEllipsis(list?.title, 58)}</p>
|
|
||||||
<p className="text-xs">
|
|
||||||
{convertDateFormat(list?.createdAt)}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
<div className="my-2 w-full flex justify-center">
|
<div className="my-2 w-full flex justify-center">
|
||||||
|
|
@ -257,9 +437,9 @@ export default function DashboardContainer() {
|
||||||
base: "bg-transparent",
|
base: "bg-transparent",
|
||||||
wrapper: "bg-transparent",
|
wrapper: "bg-transparent",
|
||||||
}}
|
}}
|
||||||
page={page}
|
page={topPagespage}
|
||||||
total={totalPage}
|
total={topPagesTotalPage}
|
||||||
onChange={(page) => setPage(page)}
|
onChange={(page) => setTopPagesPage(page)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue