fix:isBanneer true banner image, dashboard recap

This commit is contained in:
Rama Priyanto 2025-06-18 11:37:23 +07:00
commit 3742907fd0
5 changed files with 163 additions and 105 deletions

View File

@ -21,6 +21,7 @@ import {
import { getArticleById } from "@/services/article"; import { getArticleById } from "@/services/article";
import Link from "next/link"; import Link from "next/link";
import { postArticleComment } from "@/services/master-user"; import { postArticleComment } from "@/services/master-user";
import Cookies from "js-cookie";
interface DetailComments { interface DetailComments {
id: number; id: number;
@ -98,6 +99,8 @@ export default function ReviewComment() {
const sendComment = async () => { const sendComment = async () => {
const data = { const data = {
commentFromEmail: "ppid@polri.go.id",
commentFromName: "Mabes Polri",
articleId: detailData?.articleId, articleId: detailData?.articleId,
isPublic: true, isPublic: true,
message: replyValue, message: replyValue,

View File

@ -140,7 +140,7 @@ export default function HeaderNews() {
src={ src={
newsItem?.thumbnailUrl === "" newsItem?.thumbnailUrl === ""
? "/no-image.jpg" ? "/no-image.jpg"
: newsItem?.thumbnailUrl : newsItem?.thumbnailUrl + "?isBanner=true"
} }
className={`!object-cover !rounded-none ${ className={`!object-cover !rounded-none ${
portraitMap[index] portraitMap[index]
@ -291,7 +291,7 @@ export default function HeaderNews() {
src={ src={
newsItem?.thumbnailUrl === "" newsItem?.thumbnailUrl === ""
? "/no-image.jpg" ? "/no-image.jpg"
: newsItem?.thumbnailUrl : newsItem?.thumbnailUrl + "?isBanner=true"
} }
className={`!object-cover !rounded-none ${ className={`!object-cover !rounded-none ${
portraitMap[index] portraitMap[index]

View File

@ -16,6 +16,7 @@ import {
Checkbox, Checkbox,
CheckboxGroup, CheckboxGroup,
CheckboxIcon, CheckboxIcon,
DateRangePicker,
Image, Image,
Modal, Modal,
ModalBody, ModalBody,
@ -40,6 +41,7 @@ import { Fragment, useEffect, useState } from "react";
import { import {
getListArticle, getListArticle,
getListArticleAdminPage, getListArticleAdminPage,
getRecapArticleData,
getStatisticSummary, getStatisticSummary,
getTopArticles, getTopArticles,
getUserLevelDataStat, getUserLevelDataStat,
@ -52,8 +54,14 @@ import {
getUnixTimestamp, getUnixTimestamp,
textEllipsis, textEllipsis,
} from "@/utils/global"; } from "@/utils/global";
import { parseDate, getLocalTimeZone } from "@internationalized/date"; import {
parseDate,
getLocalTimeZone,
parseZonedDateTime,
parseAbsoluteToLocal,
} from "@internationalized/date";
import { Input } from "@heroui/input"; import { Input } from "@heroui/input";
import { EyeIconMdi } from "@/components/icons";
type ArticleData = Article & { type ArticleData = Article & {
no: number; no: number;
@ -95,12 +103,14 @@ export default function DashboardContainer() {
); );
const [postContentDate, setPostContentDate] = useState({ const [postContentDate, setPostContentDate] = useState({
startDate: parseDate( start: parseZonedDateTime(
convertDateFormatNoTimeV2( `${convertDateFormatNoTimeV2(
new Date(new Date().setDate(new Date().getDate() - 7)) new Date(new Date().setDate(new Date().getDate() - 7))
) )}T00:00[Asia/Jakarta]`
),
end: parseZonedDateTime(
`${convertDateFormatNoTimeV2(new Date())}T23:59[Asia/Jakarta]`
), ),
endDate: parseDate(convertDateFormatNoTimeV2(new Date())),
}); });
const [topContentDate, setTopContentDate] = useState({ const [topContentDate, setTopContentDate] = useState({
@ -120,10 +130,15 @@ export default function DashboardContainer() {
const [polresData, setPolresData] = useState<any>({}); const [polresData, setPolresData] = useState<any>({});
const [selectedAccordion, setSelectedAccordion] = useState<any>(new Set([])); const [selectedAccordion, setSelectedAccordion] = useState<any>(new Set([]));
const [recapArticleList, setRecapArticleList] = useState<any>([]); const [recapArticleList, setRecapArticleList] = useState<any>([]);
const [timeValue, setTimeValue] = useState("--:--"); const [selectedUnit, setSelectedUnit] = useState<{
const [selectedUnit, setSelectedUnit] = useState(""); id: number;
name: string;
}>();
const roleId = Cookies.get("urie"); const roleId = Cookies.get("urie");
const [recapArticlePage, setRecapArticlePage] = useState(1);
const [recapArticleTotalPage, setRecapArticleTotalPage] = useState(1);
useEffect(() => { useEffect(() => {
fetchSummary(); fetchSummary();
}, []); }, []);
@ -176,13 +191,13 @@ export default function DashboardContainer() {
endDate: getDate(topContentDate.endDate), endDate: getDate(topContentDate.endDate),
}; };
const res = await getTopArticles(req); const res = await getTopArticles(req);
setTopPages(getTableNumber(10, res.data?.data)); setTopPages(getTableNumber(10, res.data?.data, "topPages"));
setTopPagesTotalPage(res?.data?.meta?.totalPage); setTopPagesTotalPage(res?.data?.meta?.totalPage);
} }
useEffect(() => { useEffect(() => {
fetchPostCount(); fetchPostCount();
}, [postContentDate]); }, [postContentDate, selectedCategory]);
async function fetchPostCount() { async function fetchPostCount() {
const getDate = (data: any) => { const getDate = (data: any) => {
@ -191,16 +206,24 @@ export default function DashboardContainer() {
}`; }`;
}; };
const res = await getUserLevelDataStat( const res = await getUserLevelDataStat(
getDate(postContentDate.startDate), getDate(postContentDate.start),
getDate(postContentDate.endDate), getDate(postContentDate.end),
getUnixTimestamp() getUnixTimestamp(),
`${getTime(postContentDate.start.hour)}:${getTime(
postContentDate.start.minute
)}:00`,
`${getTime(postContentDate.end.hour)}:${getTime(
postContentDate.end.minute
)}:00`,
selectedCategory === "polda" ? "" : selectedCategory
); );
setPostCount(getTableNumberStats(res?.data?.data)); setPostCount(getTableNumberStats(res?.data?.data));
} }
const getTableNumber = (limit: number, data: any) => { const getTableNumber = (limit: number, data: any, type: string) => {
if (data) { if (data) {
const startIndex = limit * (topPagespage - 1); const startIndex =
limit * (type == "topPages" ? topPagespage - 1 : recapArticlePage - 1);
let iterate = 0; let iterate = 0;
const newData = data.map((value: any) => { const newData = data.map((value: any) => {
iterate++; iterate++;
@ -264,16 +287,28 @@ export default function DashboardContainer() {
} }
}, [postContentDate]); }, [postContentDate]);
const getTime = (time: number) => {
return time < 10 ? `0${time}` : String(time);
};
const getPolresData = async (id: number) => { const getPolresData = async (id: number) => {
const getDate = (data: any) => { const getDate = (data: any) => {
return `${data.year}-${data.month < 10 ? `0${data.month}` : data.month}-${ return `${data.year}-${data.month < 10 ? `0${data.month}` : data.month}-${
data.day < 10 ? `0${data.day}` : data.day data.day < 10 ? `0${data.day}` : data.day
}`; }`;
}; };
const res = await getUserLevelDataStat( const res = await getUserLevelDataStat(
getDate(postContentDate.startDate), getDate(postContentDate.start),
getDate(postContentDate.endDate), getDate(postContentDate.end),
getUnixTimestamp(), getUnixTimestamp(),
`${getTime(postContentDate.start.hour)}:${getTime(
postContentDate.start.minute
)}:00`,
`${getTime(postContentDate.end.hour)}:${getTime(
postContentDate.end.minute
)}:00`,
"",
id id
); );
const polresNowData = getTableNumberStats(res?.data?.data); const polresNowData = getTableNumberStats(res?.data?.data);
@ -299,18 +334,31 @@ export default function DashboardContainer() {
} }
}; };
const openModalArticle = async (limit: number) => { useEffect(() => {
getRecapArticle();
}, [recapArticlePage]);
const getRecapArticle = async (userLevelId?: number) => {
const req = { const req = {
limit: `${limit}`, id: userLevelId || selectedUnit?.id,
page: topPagespage, page: recapArticlePage,
search: "", startDate: getDate(postContentDate.start),
sort: "desc", endDate: getDate(postContentDate.end),
startDate: getDate(topContentDate.startDate), startTime: `${getTime(postContentDate.start.hour)}:${getTime(
endDate: getDate(topContentDate.endDate), postContentDate.start.minute
)}:00`,
endTime: `${getTime(postContentDate.end.hour)}:${getTime(
postContentDate.end.minute
)}:00`,
}; };
const res = await getTopArticles(req); const res = await getRecapArticleData(req);
setRecapArticleList(getTableNumber(10, res.data?.data)); setRecapArticleList(getTableNumber(10, res.data?.data, "recapArticle"));
// setTopPagesTotalPage(res?.data?.meta?.totalPage); setRecapArticleTotalPage(res?.data?.meta?.totalPage);
};
const openModalArticle = async (userLevelId: number) => {
setRecapArticlePage(1);
getRecapArticle(userLevelId);
onOpen(); onOpen();
}; };
@ -371,75 +419,28 @@ export default function DashboardContainer() {
</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 text-xs lg:text-sm"> <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"> <div className="flex flex-col md:flex-row md:justify-between mb-4 items-center gap-2 md:gap-0">
<p className="font-semibold"> <p className="font-semibold self-start">
Rekapitulasi Post Berita Polda/Polres Pada Website Rekapitulasi Post Berita Polda/Polres Pada Website
</p> </p>
<div className="w-[300px] flex flex-row gap-2 justify-between font-semibold items-center"> <DateRangePicker
<Popover hideTimeZone
placement="bottom" value={postContentDate}
classNames={{ content: ["!bg-transparent", "p-0"] }} onChange={(e) => {
> e && setPostContentDate(e);
<PopoverTrigger> }}
<a className="cursor-pointer"> label="Tanggal dan Waktu"
{convertDateFormatNoTime(postContentDate.startDate)} visibleMonths={2}
</a> hourCycle={24}
</PopoverTrigger> className="w-fit text-sm self-end"
<PopoverContent className="bg-transparent"> classNames={{
<Calendar timeInputLabel: "text-xs",
value={postContentDate.startDate} innerWrapper: "text-xs",
onChange={(e) => inputWrapper: "border-1",
setPostContentDate({ }}
startDate: e, size="sm"
endDate: postContentDate.endDate, variant="bordered"
}) />
}
maxValue={postContentDate.endDate}
/>
</PopoverContent>
</Popover>
-
<Popover
placement="bottom"
classNames={{ content: ["!bg-transparent", "p-0"] }}
>
<PopoverTrigger>
<a className="cursor-pointer ">
{convertDateFormatNoTime(postContentDate.endDate)}
</a>
</PopoverTrigger>
<PopoverContent className="bg-transparent">
<Calendar
value={postContentDate.endDate}
onChange={(e) =>
setPostContentDate({
startDate: postContentDate.startDate,
endDate: e,
})
}
minValue={postContentDate.startDate}
/>
</PopoverContent>
</Popover>
<Input
type="time"
variant="bordered"
className="w-fit "
value={timeValue}
onValueChange={setTimeValue}
endContent={
<a>
<CheckboxIcon />
</a>
}
classNames={{
inputWrapper: [
"border-none rounded-lg !h-[30px] lg:h-[40px]",
"dark:group-data-[focused=false]:bg-transparent border-none",
],
}}
/>
</div>
</div> </div>
<div className="flex flex-row border-b-1 gap-1 py-1 items-center"> <div className="flex flex-row border-b-1 gap-1 py-1 items-center">
<div className="w-[5%]">NO</div> <div className="w-[5%]">NO</div>
@ -474,7 +475,7 @@ 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">
{roleId && Number(roleId) < 3 ? ( {roleId && Number(roleId) < 3 && selectedCategory == "polda" ? (
<Accordion <Accordion
selectedKeys={selectedAccordion} selectedKeys={selectedAccordion}
onSelectionChange={(e) => handleSelectionChange(e)} onSelectionChange={(e) => handleSelectionChange(e)}
@ -522,16 +523,20 @@ export default function DashboardContainer() {
<a <a
onClick={() => { onClick={() => {
if (list?.totalArticle !== 0) { if (list?.totalArticle !== 0) {
setSelectedUnit(child?.userLevelName); setSelectedUnit({
// openModalArticle(list?.totalArticle); name: child?.userLevelName,
id: child.userLevelId,
});
openModalArticle(child.userLevelId);
} }
}} }}
className={`w-[10%] text-start cursor-pointer ${ className={`w-[10%] text-start cursor-pointer flex flex-row gap-1 items-center justify-end ${
list?.totalArticle === 0 && list?.totalArticle === 0 &&
"bg-red-600 text-white cursor-default" "bg-red-600 text-white cursor-default "
}`} }`}
> >
{child?.totalArticle} {child?.totalArticle}
<EyeIconMdi size={12} />
</a> </a>
</div> </div>
) )
@ -555,7 +560,24 @@ export default function DashboardContainer() {
list?.totalArticle === 0 && "bg-red-600 text-white" list?.totalArticle === 0 && "bg-red-600 text-white"
}`} }`}
> >
{list?.totalArticle} <a
onClick={() => {
if (list?.totalArticle !== 0) {
setSelectedUnit({
name: list?.userLevelName,
id: list.userLevelId,
});
openModalArticle(list.userLevelId);
}
}}
className={`w-[10%] text-start cursor-pointer flex flex-row gap-1 items-center justify-end ${
list?.totalArticle === 0 &&
"bg-red-600 text-white cursor-default "
}`}
>
{list?.totalArticle}
<EyeIconMdi />
</a>
</div> </div>
</div> </div>
)) ))
@ -792,9 +814,9 @@ export default function DashboardContainer() {
{(onClose) => ( {(onClose) => (
<> <>
<ModalHeader className="flex flex-col gap-1"> <ModalHeader className="flex flex-col gap-1">
{selectedUnit} List Content {selectedUnit?.name} List Content
</ModalHeader> </ModalHeader>
<ModalBody> <ModalBody className="flex flex-col gap-2">
<div className="grid grid-cols-12 text-xs "> <div className="grid grid-cols-12 text-xs ">
<div className="col-span-1 font-bold">No</div> <div className="col-span-1 font-bold">No</div>
<div className="col-span-9 text-center font-bold">Judul</div> <div className="col-span-9 text-center font-bold">Judul</div>
@ -820,6 +842,25 @@ export default function DashboardContainer() {
))} ))}
</div> </div>
</div> </div>
{recapArticleList?.length > 0 && (
<div className="my-2 w-full flex justify-center">
<Pagination
isCompact
showControls
showShadow
color="primary"
classNames={{
base: "bg-transparent",
wrapper: "bg-transparent",
item: "w-fit px-3",
cursor: "w-fit px-3",
}}
page={recapArticlePage}
total={recapArticleTotalPage}
onChange={(page) => setRecapArticlePage(page)}
/>
</div>
)}
</ModalBody> </ModalBody>
</> </>
)} )}

View File

@ -91,6 +91,8 @@ export default function Comment(props: { id: string | null }) {
} }
const data = { const data = {
commentFromName: values.name,
commentFromEmail: values.email,
articleId: Number(id), articleId: Number(id),
isPublic: false, isPublic: false,
message: values.comment, message: values.comment,

View File

@ -126,6 +126,15 @@ export async function getArticleById(id: any) {
}; };
return await httpGet(`/articles/${id}`, headers); return await httpGet(`/articles/${id}`, headers);
} }
export async function getRecapArticleData(data: any) {
const headers = {
"content-type": "application/json",
};
return await httpGet(
`/articles?page=${data.page}&userLevelId=${data.id}&startDate=${data.startDate}&endDate=${data.endDate}&startTime=${data.startTime}&endTime=${data.endTime}`,
headers
);
}
// export async function deleteArticle(id: string) { // export async function deleteArticle(id: string) {
// const headers = { // const headers = {
@ -191,6 +200,9 @@ export async function getUserLevelDataStat(
startDate: string, startDate: string,
endDate: string, endDate: string,
timeStamp: number, timeStamp: number,
startTime: string,
endTime: string,
levelType: string,
levelId?: number levelId?: number
) { ) {
// const headers = { // const headers = {
@ -198,9 +210,9 @@ export async function getUserLevelDataStat(
// Authorization: `Bearer ${token}`, // Authorization: `Bearer ${token}`,
// }; // };
return await httpGetInterceptor( return await httpGetInterceptor(
`/articles/statistic/user-levels?startDate=${startDate}&endDate=${endDate}&timeStamp=${timeStamp}&userLevelId=${ `/articles/statistic/user-levels?startDate=${startDate}&endDate=${endDate}&startTime=${startTime}&endTime=${endTime}&levelType=${levelType}&userLevelId=${
levelId || "" levelId || ""
}` }&timeStamp=${timeStamp}`
); );
} }
export async function getStatisticMonthly(year: string, timeStamp: number) { export async function getStatisticMonthly(year: string, timeStamp: number) {