feat:comment article, fix:polda filter
This commit is contained in:
parent
308e708a3f
commit
049f0cf8fc
|
|
@ -107,7 +107,7 @@ export const SendIcon: React.FC<IconSvgProps> = ({
|
|||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g clip-path="url(#clip0_1012_36617)">
|
||||
<g clipPath="url(#clip0_1012_36617)">
|
||||
<g clip-path="url(#clip1_1012_36617)">
|
||||
<path
|
||||
d="M15.0053 0.0999837L0.520926 8.45623C-0.0446989 8.78123 0.0271761 9.56873 0.589676 9.80623L3.91155 11.2L12.8897 3.28748C13.0616 3.13436 13.3053 3.36873 13.1584 3.54686L5.6303 12.7187V15.2344C5.6303 15.9719 6.52093 16.2625 6.95843 15.7281L8.9428 13.3125L12.8366 14.9437C13.2803 15.1312 13.7866 14.8531 13.8678 14.375L16.1178 0.874984C16.2241 0.243734 15.5459 -0.212516 15.0053 0.0999837Z"
|
||||
|
|
@ -2254,7 +2254,7 @@ export const SquareFacebookIcon = ({
|
|||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
fill-rule="evenodd"
|
||||
fillRule="evenodd"
|
||||
d="M15.725 22v-7.745h2.6l.389-3.018h-2.99V9.31c0-.874.243-1.47 1.497-1.47h1.598v-2.7a21 21 0 0 0-2.33-.12c-2.304 0-3.881 1.407-3.881 3.99v2.227H10v3.018h2.607V22H3.104C2.494 22 2 21.506 2 20.896V3.104C2 2.494 2.494 2 3.104 2h17.792C21.506 2 22 2.494 22 3.104v17.792c0 .61-.494 1.104-1.104 1.104z"
|
||||
/>
|
||||
</svg>
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ export default function HeaderNews() {
|
|||
key={data?.id}
|
||||
className="hidden lg:block"
|
||||
>
|
||||
{data.title}{" "}
|
||||
{textEllipsis(data.title, 66)}
|
||||
</Link>
|
||||
<div className="flex flex-row gap-2 text-[10px]">
|
||||
<p className="py-[2px]">
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ export default function NewsTicker() {
|
|||
<div className="fixed bottom-0 z-50 flex flex-row h-[60px] gap-3 w-full justify-between dark:bg-stone-800 bg-gray-50">
|
||||
<div className="relative px-4 py-2 font-semibold text-xs lg:text-sm flex items-center bg-amber-500 text-white w-[30%] lg:w-[10%]">
|
||||
<span className="mr-2"></span> BREAKING NEWS
|
||||
<div className="absolute right-0 top-0 h-full w-4 bg-amber-500 transform translate-x-full clip-path-triangle"></div>
|
||||
<div className="absolute right-0 top-0 h-full w-4 bg-amber-500 transform translate-x-full clipPath-triangle"></div>
|
||||
</div>
|
||||
<div
|
||||
className={`w-full px-5 py-1 flex flex-col gap-1 transition-transform duration-300 ${
|
||||
|
|
|
|||
|
|
@ -298,6 +298,14 @@ export default function RegionalNews() {
|
|||
// };
|
||||
// }, [list]);
|
||||
|
||||
const changeNameToSlug = (name: string) => {
|
||||
const cleaned = name.replace("Polda ", "").trim();
|
||||
const slug = cleaned.includes(" ")
|
||||
? cleaned.toLowerCase().replace(/\s+/g, "-")
|
||||
: cleaned;
|
||||
return slug;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="text-center rounded-md lg:rounded-lg h-auto lg:h-[338px] flex flex-col p-6 bg-[#DD8306]">
|
||||
<div className="text-xl text-white w-full justify-center flex">
|
||||
|
|
@ -312,7 +320,10 @@ export default function RegionalNews() {
|
|||
</div> */}
|
||||
<div className="gap-2 md:gap-4 lg:gap-6 grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6">
|
||||
{listPolda.map((item: any, index: any) => (
|
||||
<Link href={item.path} key={item.path}>
|
||||
<Link
|
||||
href={`/news/all?polda-name=${changeNameToSlug(item.title)}`}
|
||||
key={item.path}
|
||||
>
|
||||
<div
|
||||
key={item.id}
|
||||
className="w-[157px] h-[141px] flex flex-col items-center justify-evenly"
|
||||
|
|
@ -367,7 +378,11 @@ export default function RegionalNews() {
|
|||
key={index.id}
|
||||
className="w-[140px] h-[115px] flex flex-col items-center justify-center rounded-lg shadow-sm"
|
||||
>
|
||||
<Link href={item.path}>
|
||||
<Link
|
||||
href={`/news/all?polda-name=${changeNameToSlug(
|
||||
item.title
|
||||
)}`}
|
||||
>
|
||||
<div className="flex flex-col items-center ">
|
||||
<Image
|
||||
radius="lg"
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ export default function SidebarNav() {
|
|||
onClick={() => setSelectedTab("media")}
|
||||
className={
|
||||
selectedTab === "media"
|
||||
? "text-black dark:text-white border-b-3 border-red-400 cursor-pointer py-2"
|
||||
? "text-black border-b-3 border-red-400 cursor-pointer py-2"
|
||||
: "text-slate-300 cursor-pointer py-2"
|
||||
}
|
||||
>
|
||||
|
|
@ -40,7 +40,7 @@ export default function SidebarNav() {
|
|||
onClick={() => setSelectedTab("video")}
|
||||
className={
|
||||
selectedTab === "video"
|
||||
? "text-black dark:text-white border-b-3 border-red-400 cursor-pointer py-2"
|
||||
? "text-black border-b-3 border-red-400 cursor-pointer py-2"
|
||||
: "text-slate-300 cursor-pointer py-2"
|
||||
}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -86,7 +86,6 @@ const ApexChartColumn = (props: {
|
|||
})
|
||||
);
|
||||
} else {
|
||||
console.log("sadadad", getDatas.visit, getDatas.view, getDatas.share);
|
||||
setSeriesVisit(getDatas.visit);
|
||||
setSeriesView(getDatas.view);
|
||||
setSeriesShare(getDatas.share);
|
||||
|
|
|
|||
|
|
@ -1,14 +1,25 @@
|
|||
import { Button } from "@nextui-org/button";
|
||||
import { Input, Textarea } from "@nextui-org/input";
|
||||
import React, { useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import * as z from "zod";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { otpRequest, otpValidation } from "@/service/master-user";
|
||||
import {
|
||||
deleteArticleComment,
|
||||
editArticleComment,
|
||||
getArticleComment,
|
||||
otpRequest,
|
||||
otpValidation,
|
||||
postArticleComment,
|
||||
} from "@/service/master-user";
|
||||
import { error } from "@/config/swal";
|
||||
import { UserProfileIcon } from "@/components/icons/globals";
|
||||
import { convertDateFormat } from "@/utils/global";
|
||||
import Cookies from "js-cookie";
|
||||
import OTPInput from "react-otp-input";
|
||||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import { SendIcon, TimesIcon } from "@/components/icons";
|
||||
|
||||
const userId = Cookies.get("uie");
|
||||
|
||||
|
|
@ -29,26 +40,17 @@ const commentSchema = z.object({
|
|||
}),
|
||||
});
|
||||
|
||||
const dummyData = [
|
||||
{
|
||||
id: 1,
|
||||
createdByName: "User 2",
|
||||
comment: "test comment",
|
||||
createdAt: "2025-01-30T00:09:39.352384Z",
|
||||
createdById: 32,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
createdByName: "User 2",
|
||||
comment: "test comment 22",
|
||||
createdAt: "2025-01-31T00:10:50.352384Z",
|
||||
createdById: 23,
|
||||
},
|
||||
];
|
||||
export default function Comment(props: { id: string | null }) {
|
||||
const { id } = props;
|
||||
const MySwal = withReactContent(Swal);
|
||||
|
||||
export default function Comment() {
|
||||
const [needOtp, setNeedOtp] = useState(false);
|
||||
const [otpValue, setOtpValue] = useState("");
|
||||
const [commentList, setCommentList] = useState<any>([]);
|
||||
const [openCommentId, setOpenCommentId] = useState(0);
|
||||
const [editCommentId, setEditCommentId] = useState(0);
|
||||
const [replyValue, setReplyValue] = useState("");
|
||||
const [editValue, setEditValue] = useState("");
|
||||
const formOptions = {
|
||||
resolver: zodResolver(commentSchema),
|
||||
};
|
||||
|
|
@ -60,9 +62,18 @@ export default function Comment() {
|
|||
setValue,
|
||||
} = useForm<UserSettingSchema>(formOptions);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, [id]);
|
||||
|
||||
const fetchData = async () => {
|
||||
const res = await getArticleComment(String(id));
|
||||
setCommentList(res?.data?.data);
|
||||
};
|
||||
|
||||
const onSubmit = async (values: z.infer<typeof commentSchema>) => {
|
||||
if (!needOtp) {
|
||||
const res = await otpRequest(values.email);
|
||||
const res = await otpRequest(values.email, values?.name);
|
||||
if (res?.error) {
|
||||
error(res.message);
|
||||
return false;
|
||||
|
|
@ -74,168 +85,400 @@ export default function Comment() {
|
|||
error("OTP Tidak Sesuai");
|
||||
return false;
|
||||
}
|
||||
const req = {
|
||||
email: values.email,
|
||||
name: values.name,
|
||||
comment: values.comment,
|
||||
|
||||
const data = {
|
||||
articleId: Number(id),
|
||||
isPublic: true,
|
||||
message: values.comment,
|
||||
parentId: 0,
|
||||
};
|
||||
console.log("req", req);
|
||||
const res = await postArticleComment(data);
|
||||
if (res?.error) {
|
||||
error(res?.message);
|
||||
return false;
|
||||
}
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className="py-5 px-8 flex flex-col gap-3">
|
||||
<div className="flex flex-col gap-2 text-black">
|
||||
{dummyData.map((list) => (
|
||||
<div
|
||||
key={list?.id}
|
||||
className="flex justify-between items-center border-b-2 py-3 shadow-md px-4 rounded-md"
|
||||
>
|
||||
<div className="flex flex-row gap-2 ">
|
||||
<UserProfileIcon size={44} />
|
||||
<div className="flex flex-col gap-1">
|
||||
<p className="text-sm font-semibold">{list.createdByName}</p>
|
||||
<p className="text-sm">{list.comment}</p>
|
||||
|
||||
const handleDelete = async (id: number) => {
|
||||
MySwal.fire({
|
||||
title: "Delete Comment",
|
||||
text: "",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "Simpan",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
doDelete(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const doDelete = async (id: number) => {
|
||||
const res = await deleteArticleComment(id);
|
||||
if (res?.error) {
|
||||
error(res?.message);
|
||||
return false;
|
||||
}
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
}
|
||||
});
|
||||
fetchData();
|
||||
};
|
||||
|
||||
const sendComment = async (idComment: number) => {
|
||||
const data = {
|
||||
articleId: Number(id),
|
||||
isPublic: true,
|
||||
message: replyValue,
|
||||
parentId: idComment,
|
||||
};
|
||||
|
||||
const res = await postArticleComment(data);
|
||||
if (res?.error) {
|
||||
error(res?.message);
|
||||
return false;
|
||||
}
|
||||
fetchData();
|
||||
};
|
||||
const editComment = async (idComment: number, parentId: number) => {
|
||||
const data = {
|
||||
articleId: Number(id),
|
||||
isPublic: true,
|
||||
id: idComment,
|
||||
message: editValue,
|
||||
parentId: parentId,
|
||||
};
|
||||
|
||||
const res = await editArticleComment(data, idComment);
|
||||
if (res?.error) {
|
||||
error(res?.message);
|
||||
return false;
|
||||
}
|
||||
setEditCommentId(0);
|
||||
fetchData();
|
||||
};
|
||||
|
||||
const childComment = (parentId: number) => {
|
||||
const filteredComment = commentList.filter(
|
||||
(a: any) => a.parentId === parentId
|
||||
);
|
||||
|
||||
return filteredComment.length > 0 ? (
|
||||
<div className="flex flex-col gap-2 ml-4 w-full">
|
||||
{filteredComment.map((list: any) => (
|
||||
<div className="flex flex-row gap-2 " key={list?.id}>
|
||||
<UserProfileIcon size={44} />
|
||||
<div className="flex flex-col w-full pr-4">
|
||||
<div className="flex justify-between gap-1 w-full">
|
||||
<p className="text-sm font-semibold">{list?.commentFromName}</p>
|
||||
<p className="text-xs">{convertDateFormat(list?.updatedAt)}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1 text-right">
|
||||
<p className="text-xs">{convertDateFormat(list.createdAt)}</p>
|
||||
{(userId === String(list.createdById) || userId === "16") && (
|
||||
<a className="text-danger cursor-pointer text-xs">Hapus</a>
|
||||
{editCommentId === list?.id ? (
|
||||
<div className="flex flex-row gap-2 items-center">
|
||||
<Input
|
||||
type="text"
|
||||
id="editComment"
|
||||
placeholder=""
|
||||
label=""
|
||||
value={editValue}
|
||||
onValueChange={setEditValue}
|
||||
endContent={
|
||||
<div className="flex flex-row gap-2">
|
||||
<a
|
||||
className="cursor-pointer"
|
||||
onClick={() => editComment(list?.id, list?.parentId)}
|
||||
>
|
||||
<SendIcon />
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
labelPlacement="outside"
|
||||
className="w-full "
|
||||
classNames={{
|
||||
inputWrapper: [
|
||||
"border-1 rounded-lg",
|
||||
"dark:group-data-[focused=false]:bg-transparent !border-1 dark:!border-gray-400",
|
||||
],
|
||||
}}
|
||||
variant="bordered"
|
||||
/>
|
||||
<a
|
||||
className="cursor-pointer text-warning"
|
||||
onClick={() => setEditCommentId(0)}
|
||||
>
|
||||
<TimesIcon />
|
||||
</a>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex justify-between gap-1 text-right">
|
||||
<p className="text-sm">{list?.message}</p>
|
||||
|
||||
<div className="flex flex-row gap-2 justify-end">
|
||||
{userId === "16" && (
|
||||
<a
|
||||
className="text-primary cursor-pointer text-xs"
|
||||
onClick={() => {
|
||||
setEditValue(list?.message);
|
||||
setEditCommentId(list?.id);
|
||||
}}
|
||||
>
|
||||
Edit
|
||||
</a>
|
||||
)}
|
||||
{(userId === String(list?.commentFromId) ||
|
||||
userId === "16") && (
|
||||
<a
|
||||
className="text-danger cursor-pointer text-xs"
|
||||
onClick={() => handleDelete(list?.id)}
|
||||
>
|
||||
Hapus
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
""
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="px-0 lg:px-3 flex flex-col gap-3">
|
||||
<form
|
||||
className="py-3 px-4 flex flex-col gap-3 bg-gray-50 text-black dark:bg-stone-900 dark:text-white rounded-lg shadow-md"
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
>
|
||||
<b>Tinggalkan balasan</b>
|
||||
<p className="text-xs">
|
||||
Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai{" "}
|
||||
<span className="text-red-600">*</span>
|
||||
</p>
|
||||
<div className="flex flex-col gap-1">
|
||||
<p className="text-sm">Komentar</p>
|
||||
<Controller
|
||||
control={control}
|
||||
name="comment"
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<Textarea
|
||||
type="text"
|
||||
id="comment"
|
||||
placeholder=""
|
||||
label=""
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
labelPlacement="outside"
|
||||
className="w-full "
|
||||
classNames={{
|
||||
inputWrapper: [
|
||||
"border-1 rounded-lg",
|
||||
"dark:group-data-[focused=false]:bg-transparent !border-1 dark:!border-gray-400",
|
||||
],
|
||||
}}
|
||||
variant="bordered"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors?.comment && (
|
||||
<p className="text-red-400 text-sm mb-3">
|
||||
{errors.comment?.message}
|
||||
{!needOtp ? (
|
||||
<>
|
||||
<b>Tinggalkan balasan</b>
|
||||
<p className="text-xs">
|
||||
Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib
|
||||
ditandai <span className="text-red-600">*</span>
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<p className="text-sm">
|
||||
Nama <span className="text-red-600">*</span>
|
||||
</p>
|
||||
<div className="flex flex-col gap-1">
|
||||
<p className="text-sm">Komentar</p>
|
||||
<Controller
|
||||
control={control}
|
||||
name="comment"
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<Textarea
|
||||
type="text"
|
||||
id="comment"
|
||||
placeholder=""
|
||||
label=""
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
labelPlacement="outside"
|
||||
className="w-full "
|
||||
classNames={{
|
||||
inputWrapper: [
|
||||
"border-1 rounded-lg",
|
||||
"dark:group-data-[focused=false]:bg-transparent !border-1 dark:!border-gray-400",
|
||||
],
|
||||
}}
|
||||
variant="bordered"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors?.comment && (
|
||||
<p className="text-red-400 text-sm mb-3">
|
||||
{errors.comment?.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<p className="text-sm">
|
||||
Nama <span className="text-red-600">*</span>
|
||||
</p>
|
||||
|
||||
<Controller
|
||||
control={control}
|
||||
name="name"
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<Input
|
||||
type="text"
|
||||
id="name"
|
||||
placeholder=""
|
||||
label=""
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
labelPlacement="outside"
|
||||
className="w-full "
|
||||
classNames={{
|
||||
inputWrapper: [
|
||||
"border-1 rounded-lg",
|
||||
"dark:group-data-[focused=false]:bg-transparent !border-1 dark:!border-gray-400",
|
||||
],
|
||||
}}
|
||||
variant="bordered"
|
||||
<Controller
|
||||
control={control}
|
||||
name="name"
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<Input
|
||||
type="text"
|
||||
id="name"
|
||||
placeholder=""
|
||||
label=""
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
labelPlacement="outside"
|
||||
className="w-full "
|
||||
classNames={{
|
||||
inputWrapper: [
|
||||
"border-1 rounded-lg",
|
||||
"dark:group-data-[focused=false]:bg-transparent !border-1 dark:!border-gray-400",
|
||||
],
|
||||
}}
|
||||
variant="bordered"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors?.name && (
|
||||
<p className="text-red-400 text-sm mb-3">{errors.name?.message}</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<p className="text-sm">
|
||||
Email <span className="text-red-600">*</span>
|
||||
</p>
|
||||
<Controller
|
||||
control={control}
|
||||
name="email"
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<Input
|
||||
type="email"
|
||||
id="email"
|
||||
placeholder=""
|
||||
label=""
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
labelPlacement="outside"
|
||||
className="w-full "
|
||||
classNames={{
|
||||
inputWrapper: [
|
||||
"border-1 rounded-lg",
|
||||
"dark:group-data-[focused=false]:bg-transparent !border-1 dark:!border-gray-400",
|
||||
],
|
||||
}}
|
||||
variant="bordered"
|
||||
{errors?.name && (
|
||||
<p className="text-red-400 text-sm mb-3">
|
||||
{errors.name?.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<p className="text-sm">
|
||||
Email <span className="text-red-600">*</span>
|
||||
</p>
|
||||
<Controller
|
||||
control={control}
|
||||
name="email"
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<Input
|
||||
type="email"
|
||||
id="email"
|
||||
placeholder=""
|
||||
label=""
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
labelPlacement="outside"
|
||||
className="w-full "
|
||||
classNames={{
|
||||
inputWrapper: [
|
||||
"border-1 rounded-lg",
|
||||
"dark:group-data-[focused=false]:bg-transparent !border-1 dark:!border-gray-400",
|
||||
],
|
||||
}}
|
||||
variant="bordered"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors?.email && (
|
||||
<p className="text-red-400 text-sm mb-3">{errors.email?.message}</p>
|
||||
)}
|
||||
</div>
|
||||
{needOtp && (
|
||||
{errors?.email && (
|
||||
<p className="text-red-400 text-sm mb-3">
|
||||
{errors.email?.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div className="flex flex-col gap-1">
|
||||
<p className="text-xs">
|
||||
Kode verifikasi sudah dikirmkan. Silahkan cek Email Anda!
|
||||
</p>
|
||||
<p>OTP</p>
|
||||
<Input
|
||||
type="number"
|
||||
id="otp"
|
||||
placeholder=""
|
||||
label=""
|
||||
|
||||
<OTPInput
|
||||
value={otpValue}
|
||||
onValueChange={setOtpValue}
|
||||
labelPlacement="outside"
|
||||
className="w-[100px] "
|
||||
classNames={{
|
||||
inputWrapper: [
|
||||
"border-1 rounded-lg",
|
||||
"dark:group-data-[focused=false]:bg-transparent !border-1 dark:!border-gray-400",
|
||||
],
|
||||
}}
|
||||
variant="bordered"
|
||||
onChange={setOtpValue}
|
||||
numInputs={6}
|
||||
renderSeparator={<span>-</span>}
|
||||
renderInput={(props) => (
|
||||
<input
|
||||
{...props}
|
||||
className="!w-[30px] h-[30px] bg-stone-900 dark:bg-white text-white dark:text-black rounded-sm"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Button className="bg-[#DD8306] text-white" radius="md" type="submit">
|
||||
<Button className="bg-[#DD8306] text-white" radius="sm" type="submit">
|
||||
Kirim
|
||||
</Button>
|
||||
</form>
|
||||
<div className="flex flex-col gap-2 text-black">
|
||||
{commentList?.map(
|
||||
(list: any) =>
|
||||
list?.parentId === 0 && (
|
||||
<div
|
||||
key={list?.id}
|
||||
className="flex flex-col gap-3 w-full bg-white text-black dark:bg-stone-900 dark:text-white shadow-md rounded-md border-b-2 py-3 px-4 "
|
||||
>
|
||||
<div className="flex justify-between items-center">
|
||||
<div className="flex flex-row gap-2">
|
||||
<UserProfileIcon size={44} />
|
||||
<div className="flex flex-col gap-1">
|
||||
<p className="text-sm font-semibold">
|
||||
{list?.commentFromName}
|
||||
</p>
|
||||
<p className="text-sm">{list?.message}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1 text-right">
|
||||
<p className="text-xs">
|
||||
{convertDateFormat(list?.updatedAt)}
|
||||
</p>
|
||||
<div className="flex flex-row gap-2 justify-end">
|
||||
{userId === "16" && (
|
||||
<a
|
||||
className="text-primary cursor-pointer text-xs"
|
||||
onClick={() => setOpenCommentId(list?.id)}
|
||||
>
|
||||
Balas
|
||||
</a>
|
||||
)}
|
||||
{(userId === String(list?.commentFromId) ||
|
||||
userId === "16") && (
|
||||
<a
|
||||
className="text-danger cursor-pointer text-xs"
|
||||
onClick={() => handleDelete(list?.id)}
|
||||
>
|
||||
Hapus
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{childComment(list?.id)}
|
||||
{openCommentId === list?.id && (
|
||||
<div className="flex flex-row gap-2 items-center">
|
||||
<Input
|
||||
type="text"
|
||||
id="comment"
|
||||
placeholder=""
|
||||
label=""
|
||||
value={replyValue}
|
||||
onValueChange={setReplyValue}
|
||||
endContent={
|
||||
<div className="flex flex-row gap-2">
|
||||
<a
|
||||
className="cursor-pointer"
|
||||
onClick={() => sendComment(list?.id)}
|
||||
>
|
||||
<SendIcon />
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
labelPlacement="outside"
|
||||
className="w-full "
|
||||
classNames={{
|
||||
inputWrapper: [
|
||||
"border-1 rounded-lg",
|
||||
"dark:group-data-[focused=false]:bg-transparent !border-1 dark:!border-gray-400",
|
||||
],
|
||||
}}
|
||||
variant="bordered"
|
||||
/>
|
||||
<a
|
||||
className="cursor-pointer text-warning"
|
||||
onClick={() => setOpenCommentId(0)}
|
||||
>
|
||||
<TimesIcon />
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import Link from "next/link";
|
|||
import { useEffect, useRef, useState } from "react";
|
||||
import { getListArticle } from "@/service/article";
|
||||
import { formatMonthString, htmlToString, textEllipsis } from "@/utils/global";
|
||||
import Image from "next/image";
|
||||
|
||||
export default function ListNews() {
|
||||
const [article, setArticle] = useState<any>([]);
|
||||
|
|
@ -87,12 +88,16 @@ export default function ListNews() {
|
|||
>
|
||||
<div className="">
|
||||
<img
|
||||
src={news.thumbnailUrl}
|
||||
src={
|
||||
news.thumbnailUrl == ""
|
||||
? "/no-image.jpg"
|
||||
: news.thumbnailUrl
|
||||
}
|
||||
alt="thumbnail"
|
||||
className="rounded-md"
|
||||
className="rounded-t-md h-[27vh] w-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
<div className="p-2 lg:p-5 bg-[#f0f0f0] rounded-md">
|
||||
<div className="p-2 lg:p-5 bg-[#f0f0f0] rounded-b-md">
|
||||
<div className="font-semibold text-lg">{news?.title}</div>
|
||||
<div className="flex flex-row items-center py-1 text-xs gap-2">
|
||||
<div className="flex flex-row items-center gap-1">
|
||||
|
|
|
|||
|
|
@ -51,8 +51,8 @@ export default function NewsDetailPage() {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className="w-[70%] h-auto my-2 md:my-5 lg:my-10 px-3">
|
||||
<Comment />
|
||||
<div className="w-full lg:w-[70%] h-auto my-2 md:my-5 lg:my-10 px-0 lg:px-3">
|
||||
<Comment id={id?.split("-")[0]} />
|
||||
</div>
|
||||
|
||||
<div className="bg-gray-50 text-black dark:bg-stone-900 dark:text-white lg:px-24 my-4 lg:my-8 pt-3 lg:pb-4 rounded-lg shadow-md h-fit ">
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
"use client";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useEffect } from "react";
|
||||
|
||||
const GPRKominfo = () => {
|
||||
const t = useTranslations("Landing");
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window !== "undefined") {
|
||||
const script = document.createElement("script");
|
||||
|
|
@ -14,12 +18,34 @@ const GPRKominfo = () => {
|
|||
}
|
||||
}, []);
|
||||
|
||||
// useEffect(() => {
|
||||
// const handleResize = () => {
|
||||
// const bodyElement = document.getElementById("gpr-kominfo-widget-body");
|
||||
// if (bodyElement) {
|
||||
// bodyElement.style.height = "67vh";
|
||||
// }
|
||||
// };
|
||||
|
||||
// window.addEventListener("resize", handleResize);
|
||||
|
||||
// handleResize();
|
||||
|
||||
// return () => {
|
||||
// window.removeEventListener("resize", handleResize);
|
||||
// };
|
||||
// }, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div id="gpr-kominfo-widget-header"></div>
|
||||
<div className="flex flex-col justify-between">
|
||||
<div
|
||||
id="gpr-kominfo-widget-header"
|
||||
className="text-center flex justify-center items-center text-lg font-bold text-white rounded-t-xl"
|
||||
>
|
||||
{t("topik")}
|
||||
</div>
|
||||
<div id="gpr-kominfo-widget-body"></div>
|
||||
<div id="gpr-kominfo-widget-footer"></div>
|
||||
</>
|
||||
{/* <div id="gpr-kominfo-widget-footer"></div> */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
"lebihBanyak": "See More",
|
||||
"kategoriSatker": "Satker Cateogry",
|
||||
"beritaWilayah": "Regional News",
|
||||
"tutup": "Close"
|
||||
"tutup": "Close",
|
||||
"topik": "Main Topic"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
"lebihBanyak": "Lihat Lebih Banyak",
|
||||
"kategoriSatker": "Kategori Satker",
|
||||
"beritaWilayah": "Berita Wilayah",
|
||||
"tutup": "Tutup"
|
||||
"tutup": "Tutup",
|
||||
"topik": "Topik Utama"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@
|
|||
"react-dropzone": "^14.3.5",
|
||||
"react-hook-form": "^7.50.1",
|
||||
"react-icons": "^5.0.1",
|
||||
"react-otp-input": "^3.1.1",
|
||||
"react-password-checklist": "^1.8.1",
|
||||
"react-select": "^5.8.3",
|
||||
"react-sweetalert2": "^0.6.0",
|
||||
|
|
@ -9091,6 +9092,15 @@
|
|||
"react-dom": "^15.5.x || ^16.x || ^17.x || ^18.x"
|
||||
}
|
||||
},
|
||||
"node_modules/react-otp-input": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/react-otp-input/-/react-otp-input-3.1.1.tgz",
|
||||
"integrity": "sha512-bjPavgJ0/Zmf/AYi4onj8FbH93IjeD+e8pWwxIJreDEWsU1ILR5fs8jEJmMGWSBe/yyvPP6X/W6Mk9UkOCkTPw==",
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.6 || ^17.0.0 || ^18.0.0",
|
||||
"react-dom": ">=16.8.6 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-password-checklist": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/react-password-checklist/-/react-password-checklist-1.8.1.tgz",
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@
|
|||
"react-dropzone": "^14.3.5",
|
||||
"react-hook-form": "^7.50.1",
|
||||
"react-icons": "^5.0.1",
|
||||
"react-otp-input": "^3.1.1",
|
||||
"react-password-checklist": "^1.8.1",
|
||||
"react-select": "^5.8.3",
|
||||
"react-sweetalert2": "^0.6.0",
|
||||
|
|
|
|||
|
|
@ -73,11 +73,11 @@ export async function checkUsernames(username: string) {
|
|||
return await httpPost(`/users/forgot-password`, headers, { username });
|
||||
}
|
||||
|
||||
export async function otpRequest(email: string) {
|
||||
export async function otpRequest(email: string, name: string) {
|
||||
const headers = {
|
||||
"content-type": "application/json",
|
||||
};
|
||||
return await httpPost(`/users/otp-request`, headers, { email });
|
||||
return await httpPost(`/users/otp-request`, headers, { email, name });
|
||||
}
|
||||
|
||||
export async function otpValidation(email: string, otpCode: string) {
|
||||
|
|
@ -86,3 +86,30 @@ export async function otpValidation(email: string, otpCode: string) {
|
|||
};
|
||||
return await httpPost(`/users/otp-validation`, headers, { email, otpCode });
|
||||
}
|
||||
|
||||
export async function postArticleComment(data: any) {
|
||||
const headers = {
|
||||
"content-type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
};
|
||||
return await httpPost(`/article-comments`, headers, data);
|
||||
}
|
||||
|
||||
export async function editArticleComment(data: any, id: number) {
|
||||
const headers = {
|
||||
"content-type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
};
|
||||
return await httpPut(`/article-comments/${id}`, headers, data);
|
||||
}
|
||||
|
||||
export async function getArticleComment(id: string) {
|
||||
const headers = {
|
||||
"content-type": "application/json",
|
||||
};
|
||||
return await httpGet(`/article-comments?articleId=${id}`, headers);
|
||||
}
|
||||
|
||||
export async function deleteArticleComment(id: number) {
|
||||
return await httpDeleteInterceptor(`/article-comments/${id}`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,3 +92,7 @@ main {
|
|||
height: 100vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.komdigi-styling #gpr-kominfo-widget-body {
|
||||
height: 67vh !important;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue