573 lines
24 KiB
TypeScript
573 lines
24 KiB
TypeScript
"use client";
|
|
import { Textarea } from "@/components/ui/textarea";
|
|
import { useParams, usePathname, useSearchParams } from "next/navigation";
|
|
import React, { useEffect, useState } from "react";
|
|
import {
|
|
Carousel,
|
|
CarouselContent,
|
|
CarouselItem,
|
|
CarouselNext,
|
|
CarouselPrevious,
|
|
} from "@/components/ui/carousel";
|
|
import { Link, useRouter } from "@/i18n/routing";
|
|
import {
|
|
deleteBlogComments,
|
|
getBlogComments,
|
|
getDetailIndeks,
|
|
getPublicSuggestionList,
|
|
postBlogComments,
|
|
publicDetailBlog,
|
|
} from "@/service/landing/landing";
|
|
import { formatDateToIndonesian } from "@/utils/globals";
|
|
import { Icon } from "@iconify/react/dist/iconify.js";
|
|
import { getCookiesDecrypt } from "@/lib/utils";
|
|
import { close, loading } from "@/config/swal";
|
|
import { Input } from "@/components/ui/input";
|
|
import { useTranslations } from "next-intl";
|
|
import Image from "next/image";
|
|
|
|
const IndeksDetail = () => {
|
|
const searchParams = useSearchParams();
|
|
const id = searchParams?.get("id");
|
|
const [indeksData, setIndeksData] = useState<any>();
|
|
const params = useParams();
|
|
const slug = params?.slug;
|
|
const [indexData, setIndexData] = useState<any>();
|
|
const [message, setMessage] = useState("");
|
|
const [messageChild, setMessageChild] = useState("");
|
|
const userId = getCookiesDecrypt("uie");
|
|
const userRoleId = getCookiesDecrypt("urie");
|
|
const router: any = useRouter();
|
|
const [listComments, setListComments] = useState([]);
|
|
const t = useTranslations("LandingPage");
|
|
|
|
useEffect(() => {
|
|
initFetch();
|
|
detailFetch();
|
|
}, []);
|
|
const initFetch = async () => {
|
|
const response = await getDetailIndeks();
|
|
console.log(response);
|
|
setIndexData(response?.data?.data?.content);
|
|
};
|
|
const detailFetch = async () => {
|
|
const response = await publicDetailBlog(slug);
|
|
console.log(response);
|
|
setIndeksData(response?.data?.data);
|
|
getDataComment(response?.data?.data?.id);
|
|
};
|
|
|
|
async function getDataComment(id?: any) {
|
|
const response = await getBlogComments(id || indeksData?.id);
|
|
console.log(response.data?.data);
|
|
setListComments(response.data?.data);
|
|
}
|
|
|
|
const showInput = (e: any) => {
|
|
console.log(document.querySelector(`#${e}`)?.classList);
|
|
document.querySelector(`#${e}`)?.classList.toggle("hidden");
|
|
};
|
|
|
|
async function sendCommentParent() {
|
|
if (message?.length > 3) {
|
|
loading();
|
|
const data = {
|
|
blogId: indeksData?.id,
|
|
message: message,
|
|
parentId: null,
|
|
};
|
|
|
|
const response = await postBlogComments(data);
|
|
|
|
console.log(response);
|
|
setMessage("");
|
|
getDataComment();
|
|
close();
|
|
}
|
|
}
|
|
|
|
// async function sendCommentChild(parentId: any) {
|
|
// if (messageChild.length > 3) {
|
|
// loading();
|
|
// const data = {
|
|
// blogId: indeksData?.id,
|
|
// message: messageChild,
|
|
// parentId,
|
|
// };
|
|
|
|
// console.log(data);
|
|
// const response = await postBlogComments(data);
|
|
// console.log(response);
|
|
// const responseGet = await getPublicSuggestionList(slug);
|
|
// console.log(responseGet?.data?.data);
|
|
// setMessageChild("");
|
|
// // $(":input").val("");
|
|
// close();
|
|
// }
|
|
// }
|
|
|
|
async function sendCommentChild(parentId: any) {
|
|
const inputMsg = document.querySelector(
|
|
`#input-comment-${parentId}`
|
|
) as HTMLInputElement;
|
|
|
|
if (inputMsg && inputMsg.value.length > 3) {
|
|
loading();
|
|
const data = {
|
|
blogId: indeksData?.id,
|
|
message: inputMsg.value,
|
|
parentId,
|
|
};
|
|
|
|
console.log(data);
|
|
const response = await postBlogComments(data);
|
|
console.log(response);
|
|
const responseGet = await getPublicSuggestionList(slug);
|
|
console.log(responseGet?.data?.data);
|
|
getDataComment();
|
|
inputMsg.value = "";
|
|
close();
|
|
}
|
|
}
|
|
|
|
async function deleteDataComment(dataId: any) {
|
|
loading();
|
|
const response = await deleteBlogComments(dataId);
|
|
console.log(response);
|
|
getDataComment();
|
|
close();
|
|
}
|
|
|
|
const getInputValue = (e: any) => {
|
|
const message = e.target.value;
|
|
console.log(message);
|
|
setMessage(message);
|
|
getDataComment();
|
|
};
|
|
|
|
const postData = () => {
|
|
if (Number(userRoleId) < 1) {
|
|
router.push("/auth");
|
|
} else {
|
|
sendCommentParent();
|
|
}
|
|
getDataComment();
|
|
};
|
|
|
|
const postDataChild = (id: any) => {
|
|
if (Number(userRoleId) < 1) {
|
|
router.push("/auth");
|
|
} else {
|
|
sendCommentChild(id);
|
|
}
|
|
};
|
|
|
|
const deleteData = (dataId: any) => {
|
|
deleteDataComment(dataId);
|
|
console.log(dataId);
|
|
};
|
|
|
|
const shimmer = (w: number, h: number) => `
|
|
<svg width="${w}" height="${h}" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
<defs>
|
|
<linearGradient id="g">
|
|
<stop stop-color="#bcbcbd" offset="20%" />
|
|
<stop stop-color="#f9fafb" offset="50%" />
|
|
<stop stop-color="#bcbcbd" offset="70%" />
|
|
</linearGradient>
|
|
</defs>
|
|
<rect width="${w}" height="${h}" fill="#bcbcbd" />
|
|
<rect id="r" width="${w}" height="${h}" fill="url(#g)" />
|
|
<animate xlink:href="#r" attributeName="x" from="-${w}" to="${w}" dur="1s" repeatCount="indefinite" />
|
|
</svg>`;
|
|
|
|
const toBase64 = (str: string) =>
|
|
typeof window === "undefined"
|
|
? Buffer.from(str).toString("base64")
|
|
: window.btoa(str);
|
|
|
|
return (
|
|
<>
|
|
<div className="p-4 w-full lg:p-12">
|
|
{/* Judul */}
|
|
<div className="flex flex-col px-4 lg:px-[300px] mb-5">
|
|
<h1 className="text-base lg:text-lg mb-2">Index / Detail</h1>
|
|
<h1 className="flex flex-row font-bold text-center text-lg lg:text-2xl">
|
|
{indeksData?.title}
|
|
</h1>
|
|
</div>
|
|
{/* Gambar Utama */}
|
|
<div className="flex items-center justify-center">
|
|
<Image
|
|
placeholder={`data:image/svg+xml;base64,${toBase64(
|
|
shimmer(700, 475)
|
|
)}`}
|
|
width={2560}
|
|
height={1440}
|
|
src={indeksData?.thumbnailLink}
|
|
alt="Main"
|
|
className="w-full max-h-[550px] object-contain rounded-xl"
|
|
/>
|
|
</div>
|
|
|
|
{/* Footer Informasi */}
|
|
<div className="px-4 lg:px-[300px]">
|
|
<div className="text-gray-500 flex border-t mt-4">
|
|
<div className="flex mt-2">
|
|
<p className="text-xs lg:text-sm mb-2 ">
|
|
{t("by", { defaultValue: "By" })}
|
|
<span className="font-semibold text-gray-500">
|
|
{indeksData?.uploaderName}
|
|
</span>
|
|
| {t("updatedOn", { defaultValue: "Updated On" })} {indeksData?.createdAt} WIB
|
|
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Keterangan */}
|
|
<div className="w-full px-4 lg:px-[300px]">
|
|
<p
|
|
className="font-light text-base lg:text-lg text-justify"
|
|
dangerouslySetInnerHTML={{ __html: indeksData?.description }}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Comment */}
|
|
<div className="w-full ">
|
|
<div className="flex flex-col py-5 p-0 lg:p-10 bg-[#f7f7f7] dark:bg-slate-600">
|
|
<div className="gap-5 flex flex-col px-4 lg:px-[300px]">
|
|
<p className="flex items-start text-bases lg:text-lg">
|
|
{t("comment", { defaultValue: "Comment" })}
|
|
</p>
|
|
<Textarea
|
|
placeholder="Type your comments here."
|
|
className="flex w-full"
|
|
onChange={getInputValue}
|
|
value={message}
|
|
/>
|
|
<button
|
|
className="flex items-start bg-[#bb3523] text-white rounded-lg text-sm lg:text-base w-fit px-3 lg:px-4 py-1"
|
|
onClick={() => postData()}
|
|
>
|
|
{t("send", { defaultValue: "Send" })}
|
|
</button>
|
|
</div>
|
|
|
|
<div className="px-4 lg:px-[300px]">
|
|
<div className="border-b-2 border-slate-300 mt-4"></div>
|
|
</div>
|
|
|
|
<div className="px-4 lg:px-[230px]">
|
|
{listComments?.map((data: any) => (
|
|
<div className="flex flex-col">
|
|
<div className="flex flex-row mt-2 px-4 lg:px-14">
|
|
<Image
|
|
placeholder={`data:image/svg+xml;base64,${toBase64(
|
|
shimmer(700, 475)
|
|
)}`}
|
|
width={512}
|
|
height={512}
|
|
className="h-10 lg:h-20 w-10 lg:w-20"
|
|
src="/assets/img/user-avatar-yellow.svg"
|
|
alt="#"
|
|
/>
|
|
<div className="border border-slate-300 w-full p-4 bg-white gap-1">
|
|
<p className="flex justify-between text-sm text-slate-500 lg:text-base border-b-2 border-slate-200 mb-2">
|
|
<b>
|
|
{Number(data.commentFrom?.roleId) == 2 ||
|
|
Number(data.commentFrom?.roleId) == 3 ||
|
|
Number(data.commentFrom?.roleId) == 4
|
|
? "HUMAS POLRI"
|
|
: data.commentFrom?.fullname}
|
|
</b>
|
|
{`${new Date(data.createdAt).getDate()}/${
|
|
new Date(data.createdAt).getMonth() + 1
|
|
}/${new Date(data.createdAt).getFullYear()} ${new Date(
|
|
data.createdAt
|
|
).getHours()}:${new Date(data.createdAt).getMinutes()}`}
|
|
</p>
|
|
<p className="text-slate-500 text-sm lg:text-base mb-4">
|
|
{data.message}
|
|
</p>
|
|
<div className="gap-3">
|
|
<a
|
|
href="javascript:void(0)"
|
|
className="text-xs lg:text-sm mr-2 bg-blue-500 text-white py-1 px-2 hover:bg-blue-300 hover:text-black rounded-md"
|
|
onClick={() => showInput(`comment-id-${data.id}`)}
|
|
>
|
|
{t("reply", { defaultValue: "Reply" })}
|
|
</a>
|
|
<a
|
|
href="javascript:void(0)"
|
|
style={
|
|
data.commentFrom?.id == userId
|
|
? {}
|
|
: {
|
|
display: "none",
|
|
}
|
|
}
|
|
className="text-xs lg:text-sm bg-red-500 text-white py-1 px-2 hover:bg-red-300 hover:text-black rounded-md"
|
|
onClick={() => deleteData(data.id)}
|
|
>
|
|
{t("delete", { defaultValue: "Delete" })}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div
|
|
className="flex flex-row px-4 pl-[55px] lg:px-14 lg:pl-[135px] mt-2"
|
|
id={`comment-id-${data.id}`}
|
|
>
|
|
<Input
|
|
type="text"
|
|
id={`input-comment-${data.id}`}
|
|
className="p-4 focus:outline-none focus:border-sky-500"
|
|
placeholder={t("enterReply", { defaultValue: "Enter Reply" })}
|
|
/>
|
|
<a
|
|
href="javascript:void(0)"
|
|
className="flex py-1 px-2 rounded-md items-center ml-2 bg-[#f7b357] text-white text-sm lg:text-base"
|
|
onClick={() => postDataChild(data.id)}
|
|
>
|
|
{t("send", { defaultValue: "Send" })}
|
|
</a>
|
|
</div>
|
|
{data.children.length > 0
|
|
? data.children?.map((child1: any) => (
|
|
<div className="flex flex-col">
|
|
<div className="flex flex-row mt-2 px-4 lg:pr-14 pl-12 lg:pl-32">
|
|
<Image
|
|
placeholder={`data:image/svg+xml;base64,${toBase64(
|
|
shimmer(700, 475)
|
|
)}`}
|
|
width={512}
|
|
height={512}
|
|
className="h-10 lg:h-20 w-10 lg:w-20"
|
|
src="/assets/img/user-avatar-yellow.svg"
|
|
alt="#"
|
|
/>
|
|
<div className="border border-slate-300 w-full p-4 bg-white gap-1">
|
|
<p className="flex justify-between text-slate-500 text-sm lg:text-base border-b-2 border-slate-200 mb-2">
|
|
<b>
|
|
{Number(child1.commentFrom?.roleId) == 2 ||
|
|
Number(child1.commentFrom?.roleId) == 3 ||
|
|
Number(child1.commentFrom?.roleId) == 4
|
|
? "HUMAS POLRI"
|
|
: child1.commentFrom?.fullname}
|
|
</b>
|
|
{`${new Date(child1.createdAt).getDate()}/${
|
|
new Date(child1.createdAt).getMonth() + 1
|
|
}/${new Date(
|
|
child1.createdAt
|
|
).getFullYear()} ${new Date(
|
|
child1.createdAt
|
|
).getHours()}:${new Date(
|
|
child1.createdAt
|
|
).getMinutes()}`}
|
|
</p>
|
|
<p className="text-slate-500 text-sm mb-4">
|
|
{child1.message}
|
|
</p>
|
|
<div className="gap-3">
|
|
<a
|
|
href="javascript:void(0)"
|
|
className="mr-2 text-xs lg:text-sm bg-blue-500 text-white py-1 px-2 hover:bg-blue-300 hover:text-black rounded-md"
|
|
onClick={() =>
|
|
showInput(`comment-id-${child1.id}`)
|
|
}
|
|
>
|
|
{t("reply", { defaultValue: "Reply" })}
|
|
</a>
|
|
<a
|
|
href="javascript:void(0)"
|
|
className="text-xs lg:text-sm bg-red-500 text-white py-1 px-2 hover:bg-red-300 hover:text-black rounded-md"
|
|
style={
|
|
Number(child1.commentFrom?.id) ==
|
|
Number(userId)
|
|
? {}
|
|
: {
|
|
display: "none",
|
|
}
|
|
}
|
|
onClick={() => deleteData(child1.id)}
|
|
>
|
|
{t("delete", { defaultValue: "Delete" })}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div
|
|
className="flex flex-row justify-center px-4 pl-[87px] lg:px-14 lg:pl-[205px] mt-2"
|
|
id={`comment-id-${child1.id}`}
|
|
>
|
|
<Input
|
|
type="text"
|
|
id={`input-comment-${child1.id}`}
|
|
className="p-4 focus:outline-none focus:border-sky-500"
|
|
placeholder={t("enterReply", { defaultValue: "Enter Reply" })}
|
|
/>
|
|
<a
|
|
href="javascript:void(0)"
|
|
className="flex text-sm lg:text-base py-1 px-2 rounded-md items-center ml-2 bg-[#f7b357] text-white"
|
|
onClick={() => postDataChild(child1.id)}
|
|
>
|
|
{t("send", { defaultValue: "Send" })}
|
|
</a>
|
|
</div>
|
|
{child1.children.length > 0
|
|
? child1.children?.map((child2: any) => (
|
|
<div className="flex flex-col">
|
|
<div className="flex flex-row mt-2 px-4 lg:pr-14 pl-20 lg:pl-48">
|
|
<Image
|
|
placeholder={`data:image/svg+xml;base64,${toBase64(
|
|
shimmer(700, 475)
|
|
)}`}
|
|
width={512}
|
|
height={512}
|
|
className="h-10 lg:h-20 w-10 lg:w-20"
|
|
src="/assets/img/user-avatar-yellow.svg"
|
|
alt="#"
|
|
/>
|
|
<div className="border border-slate-300 w-full p-4 bg-white gap-2">
|
|
<p className="flex justify-between text-slate-500 text-xs lg:text-base border-b-2 border-slate-200 mb-2">
|
|
<b>
|
|
{Number(child2.commentFrom?.roleId) ==
|
|
2 ||
|
|
Number(child2.commentFrom?.roleId) ==
|
|
3 ||
|
|
Number(child2.commentFrom?.roleId) == 4
|
|
? "HUMAS POLRI"
|
|
: child2.commentFrom?.fullname}
|
|
</b>
|
|
{`${new Date(
|
|
child2.createdAt
|
|
).getDate()}/${
|
|
new Date(child2.createdAt).getMonth() +
|
|
1
|
|
}/${new Date(
|
|
child2.createdAt
|
|
).getFullYear()} ${new Date(
|
|
child2.createdAt
|
|
).getHours()}:${new Date(
|
|
child2.createdAt
|
|
).getMinutes()}`}
|
|
</p>
|
|
<p className="text-slate-500 text-sm mb-4">
|
|
{child2.message}
|
|
</p>
|
|
<div>
|
|
<a
|
|
href="javascript:void(0)"
|
|
className="mr-2 text-xs lg:text-sm bg-blue-500 text-white py-1 px-2 hover:bg-blue-300 hover:text-black rounded-md"
|
|
onClick={() =>
|
|
showInput("comment-id-" + child2.id)
|
|
}
|
|
>
|
|
{t("reply", { defaultValue: "Reply" })}
|
|
</a>
|
|
<a
|
|
href="javascript:void(0)"
|
|
className="text-xs lg:text-sm bg-red-500 text-white py-1 px-2 hover:bg-red-300 hover:text-black rounded-md"
|
|
style={
|
|
Number(child2.commentFrom?.id) ==
|
|
Number(userId)
|
|
? {}
|
|
: {
|
|
display: "none",
|
|
}
|
|
}
|
|
onClick={() => deleteData(child2.id)}
|
|
>
|
|
{t("delete", { defaultValue: "Delete" })}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div
|
|
className="flex flex-row px-4 pl-[120px] lg:px-14 lg:pl-[270px] mt-2"
|
|
id={`comment-id-${child2.id}`}
|
|
>
|
|
<Input
|
|
type="text"
|
|
id={`comment-id-${child2.id}`}
|
|
className="p-4 focus:outline-none focus:border-sky-500"
|
|
placeholder={t("enterReply", { defaultValue: "Enter Reply" })}
|
|
/>
|
|
<a
|
|
href="javascript:void(0)"
|
|
className="flex text-sm lg:text-base py-1 px-2 rounded-md items-center ml-2 bg-[#f7b357] text-white"
|
|
onClick={() => postDataChild(child1.id)}
|
|
>
|
|
{t("send", { defaultValue: "Send" })}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
))
|
|
: ""}
|
|
</div>
|
|
))
|
|
: ""}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Konten Serupa */}
|
|
<div className="space-x-5 flex flex-col px-4 lg:px-[300px] py-16 gap-5">
|
|
<h1 className="font-bold text-base lg:text-xl px-4 lg:px-8">
|
|
{" "}
|
|
{t("relatedPosts", { defaultValue: "Related Posts" })}
|
|
</h1>
|
|
<Carousel>
|
|
<CarouselContent className="w-full max-w-7xl">
|
|
{indexData?.map((relate: any) => (
|
|
<CarouselItem
|
|
key={relate?.id}
|
|
className="md:basis-1/2 lg:basis-1/3"
|
|
>
|
|
<Link
|
|
href={`/indeks/detail/${relate?.slug}`}
|
|
className="relative group overflow-hidden shadow-md hover:shadow-lg"
|
|
>
|
|
<Image
|
|
placeholder={`data:image/svg+xml;base64,${toBase64(
|
|
shimmer(700, 475)
|
|
)}`}
|
|
alt=""
|
|
width={2560}
|
|
height={1440}
|
|
src={relate?.thumbnailLink}
|
|
className="w-full rounded-lg h-40 lg:h-60 object-cover group-hover:scale-100 transition-transform duration-300"
|
|
/>
|
|
<div className="absolute bottom-0 left-0 right-0 bg-gray-600 border-l-4 border-[#bb3523] rounded-lg backdrop-blur-sm text-white p-2">
|
|
<span className="text-white bg-[#bb3523] rounded-md w-full h-full font-semibold uppercase text-sm px-4 py-1">
|
|
{relate?.categoryName}
|
|
</span>
|
|
<h1 className="text-sm lg:text-lg mb-2 font-semibold h-5 hover:h-auto truncate hover:whitespace-normal hover:overflow-visible">
|
|
{relate?.title}
|
|
</h1>
|
|
<p className="flex flex-row items-center text-[10px] gap-2">
|
|
{formatDateToIndonesian(new Date(relate?.createdAt))}{" "}
|
|
{relate?.timezone ? relate?.timezone : "WIB"} |{" "}
|
|
<Icon icon="formkit:eye" width="15" height="15" />{" "}
|
|
{relate.clickCount}{" "}
|
|
</p>
|
|
</div>
|
|
</Link>
|
|
</CarouselItem>
|
|
))}
|
|
</CarouselContent>
|
|
<CarouselPrevious />
|
|
<CarouselNext />
|
|
</Carousel>
|
|
</div>
|
|
</div>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default IndeksDetail;
|