feat: comment in index detail

This commit is contained in:
sabdayagra 2025-01-23 00:13:44 +07:00
parent 4651672fee
commit 4018988014
5 changed files with 282 additions and 36 deletions

View File

@ -1,18 +1,27 @@
"use client";
import { Textarea } from "@/components/ui/textarea";
import { useParams, usePathname, useRouter } from "next/navigation";
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 } from "@/i18n/routing";
import { getDetailIndeks, publicDetailBlog } from "@/service/landing/landing";
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";
const IndeksDetail = () => {
const searchParams = useSearchParams();
const id = searchParams?.get("id");
const [indeksData, setIndeksData] = useState<any>();
const params = useParams();
const slug = params?.slug;
const [relatedPost, setRelatedPost] = useState<any>();
const [indexData, setIndexData] = useState<any>();
const [message, setMessage] = useState("");
const userId = getCookiesDecrypt("uie");
const userRoleId = getCookiesDecrypt("urie");
const router = useRouter();
const [listComments, setListComments] = useState([]);
useEffect(() => {
initFetch();
@ -21,7 +30,7 @@ const IndeksDetail = () => {
const initFetch = async () => {
const response = await getDetailIndeks();
console.log(response);
setRelatedPost(response?.data?.data?.content);
setIndexData(response?.data?.data?.content);
};
const detailFetch = async () => {
const response = await publicDetailBlog(slug);
@ -29,6 +38,93 @@ const IndeksDetail = () => {
setIndeksData(response?.data?.data);
};
async function getDataComment(blogId: any) {
const findId = blogId == undefined ? slug : blogId;
const response = await getBlogComments(findId);
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: slug,
message,
parentId: null,
};
const response = await postBlogComments(data);
console.log(response);
setMessage("");
getDataComment(slug);
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: slug,
message: inputMsg,
parentId,
};
console.log(data);
const response = await postBlogComments(data);
console.log(response);
const responseGet = await getPublicSuggestionList(slug);
console.log(responseGet.data?.data);
getDataComment(slug);
$(":input").val("");
close();
}
}
async function deleteDataComment(dataId: any) {
loading();
const response = await deleteBlogComments(dataId);
console.log(response);
getDataComment(dataId);
close();
}
const getInputValue = (e: any) => {
const message = e.target.value;
console.log(message);
setMessage(message);
};
const postData = () => {
if (Number(userRoleId) < 1) {
router.push("/auth");
} else {
sendCommentParent();
}
};
const postDataChild = (id: any) => {
if (Number(userRoleId) < 1) {
router.push("/auth");
} else {
sendCommentChild(slug);
}
};
const deleteData = (dataId: any) => {
deleteDataComment(dataId);
console.log(dataId);
};
return (
<>
<div className="p-4 lg:px-60 lg:p-12">
@ -59,8 +155,137 @@ const IndeksDetail = () => {
<div className="flex flex-col py-5 p-10 bg-[#f7f7f7]">
<div className="gap-5 flex flex-col px-4 lg:px-16">
<p className="flex items-start text-lg">Berikan Komentar</p>
<Textarea placeholder="Type your comments here." className="flex w-full" />
<button className="flex items-start bg-[#bb3523] text-white rounded-lg w-fit px-4 py-1">Kirim</button>
<Textarea placeholder="Type your comments here." className="flex w-full" onChange={getInputValue} />
<button className="flex items-start bg-[#bb3523] text-white rounded-lg w-fit px-4 py-1" onClick={() => postData()}>
Kirim
</button>
</div>
<div className="border-b-2 border-slate-300 mt-4 w-auto"></div>
<div>
{listComments?.map((data: any) => (
<div className="flex flex-col">
<div className="flex flex-row mt-2 px-4 lg:px-14">
<img className="h-10 w-10" src="/assets/img/user-avatar-yellow.svg" alt="#" />
<div className="border border-slate-300 w-full p-4 bg-white gap-1">
<p className="text-slate-500 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 mb-4">{data.message}</p>
<div>
<a href="javascript:void(0)" className="btn btn-link btn-suggestion-reply" onClick={() => showInput(`comment-id-${data.id}`)}>
Balas
</a>
<a
href="javascript:void(0)"
style={
data.commentFrom?.id == userId
? {}
: {
display: "none",
}
}
className="btn btn-link btn-suggestion-delete"
onClick={() => deleteData(data.id)}
>
Hapus
</a>
</div>
</div>
</div>
<div className="px-4 lg:px-28 mt-2" id={`comment-id-${data.id}`}>
<Textarea id={`input-comment-${data.id}`} className="p-4 focus:outline-none focus:border-sky-500" placeholder="Masukkan balasan anda" />
<a href="javascript:void(0)" className="btn btn-warning btn-send-comment" onClick={() => postDataChild(data.id)}>
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:px-32">
<img className="h-10 w-10" src="/assets/img/user-avatar-yellow.svg" alt="#" />
<div className="border border-slate-300 w-full p-4 bg-white gap-1">
<p className="text-slate-500 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>
<a href="javascript:void(0)" className="btn btn-link btn-suggestion-reply" onClick={() => showInput(`comment-id-${child1.id}`)}>
Balas
</a>
<a
href="javascript:void(0)"
className="btn btn-link btn-suggestion-delete"
style={
Number(child1.commentFrom?.id) == Number(userId)
? {}
: {
display: "none",
}
}
onClick={() => deleteData(child1.id)}
>
Hapus
</a>
</div>
</div>
</div>
<div className="px-4 lg:px-28 mt-2" id={`comment-id-${child1.id}`}>
<Textarea id={`input-comment-${child1.id}`} className="p-4 focus:outline-none focus:border-sky-500" placeholder="Masukkan balasan anda" />
<a href="javascript:void(0)" className="btn btn-warning btn-send-comment" onClick={() => postDataChild(child1.id)}>
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:px-48">
<img className="h-10 w-10" src="/assets/img/user-avatar-yellow.svg" alt="#" />
<div className="border border-slate-300 w-full p-4 bg-white gap-1">
<p className="text-slate-500 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="btn btn-link btn-suggestion-delete"
style={
Number(child2.commentFrom?.id) == Number(userId)
? {}
: {
display: "none",
}
}
onClick={() => deleteData(child2.id)}
>
Hapus
</a>
</div>
</div>
</div>
<div className="px-4 lg:px-28 mt-2" id={`comment-id-${child2.id}`}>
<Textarea id={`comment-id-${child2.id}`} className="p-4 focus:outline-none focus:border-sky-500" placeholder="Masukkan balasan anda" />
<a href="javascript:void(0)" className="btn btn-warning btn-send-comment" onClick={() => postDataChild(child1.id)}>
Send
</a>
</div>
</div>
))
: ""}
</div>
))
: ""}
</div>
))}
</div>
</div>
@ -69,7 +294,7 @@ const IndeksDetail = () => {
<h1 className="font-bold text-base lg:text-xl px-4 lg:px-8">Post Terkait</h1>
<Carousel>
<CarouselContent className="w-full max-w-7xl">
{relatedPost?.map((relate: any) => (
{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">
<img src={relate?.thumbnailLink} className="w-full rounded-lg h-40 lg:h-60 object-cover group-hover:scale-100 transition-transform duration-300" />

View File

@ -595,7 +595,7 @@ const DetailVideo = () => {
</div>
</div>
</div>
<div id={`comment-id-${data.id}`} className="px-4 lg:px-28 mt-2">
<div id={`comment-id-${data.id}`} className="px-4 lg:px-28 mt-2">
<Textarea id={`input-comment-${data.id}`} className="p-4 focus:outline-none focus:border-sky-500" placeholder="Masukkan balasan anda" />
<div className="flex flex-row gap-3">
<a onClick={() => postDataChild(data.id)}>

View File

@ -594,10 +594,10 @@ const page = () => {
}
}
>
<label htmlFor="association" className="mb-2">
<Label htmlFor="association" className="mb-2">
Jenis Keanggotaan <span className="text-red-500">*</span>
</label>
<select className={`py-3 px-2 rounded-md border border-black ${errors.association ? "block" : ""}`} {...register("association")} id="association" onChange={(e) => setAssociation(e.target.value)}>
</Label>
<select className={`py-3 px-2 rounded-md border border-slate-300 bg-white ${errors.association ? "block" : ""}`} {...register("association")} id="association" onChange={(e) => setAssociation(e.target.value)}>
<option disabled selected>
Pilih Asosiasi
</option>
@ -695,10 +695,10 @@ const page = () => {
<div>
{Number(category) == 6 || Number(category) == 7 ? (
<div className="px-[34px]">
<label className="mb-2">
<Label className="mb-2">
{`${Number(category) == 6 ? "Nomor Sertifikasi Wartawan" : "NRP"}`}
<span className="text-red-500">*</span>
</label>
</Label>
<Input
type="text"
autoComplete="off"
@ -714,16 +714,16 @@ const page = () => {
""
)}
<div className="mb-4 px-[34px]">
<label className="mb-2">
<Label className="mb-2">
Nama Lengkap <span className="text-red-500">*</span>
</label>
</Label>
<Input type="text" autoComplete="off" className={` ${errors.firstName ? "block" : ""}`} {...register("firstName")} placeholder="Masukan Nama Lengkap Anda" />
<div className="text-red-500">{errors.firstName?.message}</div>
</div>
<div className="mb-4 px-[34px]">
<label className="mb-2">
<Label className="mb-2">
Username <span className="text-red-500">*</span>
</label>
</Label>
<Input
id="username"
type="text"
@ -743,34 +743,34 @@ const page = () => {
<div className="text-red-500">{errors.username?.message}</div>
</div>
<div className="mb-4 px-[34px]">
<label className="mb-2">
<Label className="mb-2">
Email <span className="text-red-500">*</span>
</label>
</Label>
<Input type="email" autoComplete="off" className={`${errors.email ? "block" : ""}`} {...register("email")} placeholder="Masukan Email Anda" disabled />
<div className="text-red-500">{errors.email?.message}</div>
</div>
</div>
<div className="flex flex-col px-[34px]">
<label className="mb-2">
<Label className="mb-2">
No. HP<span className="text-red-500">*</span>
</label>
</Label>
<Input type="number" autoComplete="off" className={`mb-3 ${errors.phoneNumber ? "block" : ""}`} {...register("phoneNumber")} placeholder="Masukan Nomor Telepon Anda" />
<div className="text-red-500">{errors.phoneNumber?.message}</div>
</div>
<div className="mb-4 px-[34px]">
<label htmlFor="address" className="mb-2">
<Label htmlFor="address" className="mb-2">
Alamat <span className="text-red-500">*</span>
</label>
</Label>
<Textarea className={` ${errors.address ? "block" : ""}`} {...register("address")} placeholder="Masukan Alamat Lengkap Anda" rows={3} />
<div className="text-red-500">{errors.address?.message}</div>
</div>
{Number(category) == 6 ? (
<div className="flex flex-col gap-3 px-[34px]">
<div className="flex flex-col mb-2">
<label htmlFor="provinsi">
<Label htmlFor="provinsi">
Institusi <span className="text-red-500">*</span>
</label>
<select className="mb-3 py-2" id="provinsi" onChange={(event) => handleInstituteOption(event)}>
</Label>
<select className="mb-3 p-2 border rounded-md border-slate-300 bg-white cursor-pointer" id="provinsi" onChange={(event) => handleInstituteOption(event)}>
<option disabled selected>
Pilih Institusi
</option>
@ -794,15 +794,15 @@ const page = () => {
: {}
}
>
<label htmlFor="alamat" className="mb-2">
<Label htmlFor="alamat" className="mb-2">
Nama Institusi <span className="text-red-500">*</span>
</label>
</Label>
<Input className="mb-3" autoComplete="off" placeholder="Masukan Nama Lengkap Institusi Anda" type="text" onChange={(event) => setCustomInstituteName(event.target.value)} />
</div>
<div className="">
<label htmlFor="alamat" className="mb-2">
<Label htmlFor="alamat" className="mb-2">
Alamat Institusi <span className="text-red-500">*</span>
</label>
</Label>
<Textarea className="mb-3" placeholder="Masukan Alamat Lengkap Institusi Anda" rows={3} value={institusiAddress} onChange={(event) => setInstitusiAddress(event.target.value)} />
</div>
</div>
@ -813,7 +813,7 @@ const page = () => {
<label htmlFor="provinsi" className="mb-2">
Provinsi <span className="text-red-500">*</span>
</label>
<select className={`mb-3 py-2 ${errors.provinsi ? "block" : ""}`} {...register("provinsi")} id="provinsi" name="provinsi" onChange={(event) => getCity(event.target.value)}>
<select className={`mb-3 p-2 border rounded-md border-slate-300 bg-white cursor-pointer ${errors.provinsi ? "block" : ""}`} {...register("provinsi")} id="provinsi" name="provinsi" onChange={(event) => getCity(event.target.value)}>
<option disabled selected>
Pilih Provinsi
</option>
@ -829,7 +829,7 @@ const page = () => {
<label htmlFor="kota" className="mb-2">
Kota/Kabupaten <span className="text-red-500">*</span>
</label>
<select className={`mb-3 py-2 ${errors.kota ? "block" : ""}`} {...register("kota")} id="kota" onChange={(event) => getDistricts(event.target.value)}>
<select className={`mb-3 p-2 border rounded-md border-slate-300 bg-white cursor-pointer ${errors.kota ? "block" : ""}`} {...register("kota")} id="kota" onChange={(event) => getDistricts(event.target.value)}>
<option disabled selected>
Pilih Kota/Kabupaten
</option>
@ -845,7 +845,7 @@ const page = () => {
<label htmlFor="kecamatan" className="mb-2">
Kecamatan <span className="text-red-500">*</span>
</label>
<select className={`py-2 ${errors.kecamatan ? "block" : ""}`} {...register("kecamatan")} id="kecamatan">
<select className={`p-2 border rounded-md border-slate-300 bg-white cursor-pointer ${errors.kecamatan ? "block" : ""}`} {...register("kecamatan")} id="kecamatan">
<option disabled selected>
Pilih Kecamatan
</option>

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30">
<path d="M15,3C8.373,3,3,8.373,3,15c0,6.627,5.373,12,12,12s12-5.373,12-12C27,8.373,21.627,3,15,3z M8,22.141 c1.167-3.5,4.667-2.134,5.25-4.03v-1.264c-0.262-0.141-1.013-1.109-1.092-1.865c-0.207-0.018-0.531-0.223-0.627-1.034 c-0.051-0.435,0.153-0.68,0.276-0.757c0,0-0.308-0.702-0.308-1.399C11.5,9.72,12.526,8,15,8c1.336,0,1.75,0.947,1.75,0.947 c1.194,0,1.75,1.309,1.75,2.844c0,0.765-0.308,1.399-0.308,1.399c0.124,0.077,0.328,0.322,0.277,0.757 c-0.096,0.811-0.42,1.016-0.627,1.034c-0.079,0.756-0.829,1.724-1.092,1.865v1.264c0.583,1.897,4.083,0.531,5.25,4.031 c0,0-2.618,2.859-7,2.859C10.593,25,8,22.141,8,22.141z" fill="#EA8B12" />
</svg>

After

Width:  |  Height:  |  Size: 697 B

View File

@ -180,5 +180,23 @@ export async function createPublicSuggestion(data: any) {
export async function deletePublicSuggestion(slug: any) {
const url = `media/public/suggestion?id=${slug}`;
return httpDeleteInterceptor( url );
}
return httpDeleteInterceptor(url);
}
export async function postBlogComments(data: any) {
const url = "blog/comments";
return httpPostInterceptor(url, data);
}
export async function getBlogComments(slug: any) {
const url = `blog/comments?blogId=${slug}`;
const headers = {
"content-Type": "application/json",
};
return httpGet(url, headers);
}
export async function deleteBlogComments(slug: any) {
const url = `blog/comments?id=${slug}`;
return httpDeleteInterceptor(url);
}