feat:comment approval
This commit is contained in:
parent
3817131f52
commit
094ac206b6
|
|
@ -1,82 +1,11 @@
|
||||||
"use client";
|
|
||||||
import { AddIcon, CloudUploadIcon, TimesIcon } from "@/components/icons";
|
|
||||||
import AdvertiseTable from "@/components/table/advertise/advertise-table";
|
|
||||||
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
Card,
|
|
||||||
Chip,
|
|
||||||
Input,
|
|
||||||
Modal,
|
|
||||||
ModalBody,
|
|
||||||
ModalContent,
|
|
||||||
ModalFooter,
|
|
||||||
ModalHeader,
|
|
||||||
Switch,
|
|
||||||
Textarea,
|
|
||||||
useDisclosure,
|
|
||||||
} from "@heroui/react";
|
|
||||||
import Link from "next/link";
|
|
||||||
import { useRouter } from "next/navigation";
|
|
||||||
import * as z from "zod";
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
|
||||||
import { Controller, useForm } from "react-hook-form";
|
|
||||||
import { Fragment, useEffect, useState } from "react";
|
|
||||||
import Swal from "sweetalert2";
|
|
||||||
import withReactContent from "sweetalert2-react-content";
|
|
||||||
|
|
||||||
import { useDropzone } from "react-dropzone";
|
|
||||||
import { close, error, loading } from "@/config/swal";
|
|
||||||
import Image from "next/image";
|
|
||||||
import CommentTable from "@/components/table/comment/comment-table";
|
import CommentTable from "@/components/table/comment/comment-table";
|
||||||
|
|
||||||
const createArticleSchema = z.object({
|
|
||||||
title: z.string().min(2, {
|
|
||||||
message: "Judul harus diisi",
|
|
||||||
}),
|
|
||||||
url: z.string().min(2, {
|
|
||||||
message: "Link harus diisi",
|
|
||||||
}),
|
|
||||||
description: z.string().min(2, {
|
|
||||||
message: "Deskripsi harus diisi",
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export default function AdvertisePage() {
|
export default function AdvertisePage() {
|
||||||
const { isOpen, onOpen, onOpenChange, onClose } = useDisclosure();
|
|
||||||
const MySwal = withReactContent(Swal);
|
|
||||||
|
|
||||||
const [refresh, setRefresh] = useState(false);
|
|
||||||
const [isHeader, setIsHeader] = useState(false);
|
|
||||||
|
|
||||||
const [files, setFiles] = useState<File[]>([]);
|
|
||||||
|
|
||||||
const formOptions = {
|
|
||||||
resolver: zodResolver(createArticleSchema),
|
|
||||||
defaultValues: { title: "", description: "", url: "" },
|
|
||||||
};
|
|
||||||
|
|
||||||
const { getRootProps, getInputProps } = useDropzone({
|
|
||||||
onDrop: (acceptedFiles) => {
|
|
||||||
setFiles(acceptedFiles.map((file) => Object.assign(file)));
|
|
||||||
},
|
|
||||||
maxFiles: 1,
|
|
||||||
accept: {
|
|
||||||
"image/*": [],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
type UserSettingSchema = z.infer<typeof createArticleSchema>;
|
|
||||||
const {
|
|
||||||
control,
|
|
||||||
handleSubmit,
|
|
||||||
formState: { errors },
|
|
||||||
} = useForm<UserSettingSchema>(formOptions);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="overflow-x-hidden overflow-y-scroll">
|
<div className="overflow-x-hidden overflow-y-scroll">
|
||||||
<div className="px-2 md:px-4 md:py-4 w-full">
|
<div className="px-2 md:px-4 md:py-4 w-full">
|
||||||
<div className="bg-white shadow-lg dark:bg-[#18181b] rounded-xl p-3">
|
<div className="bg-white shadow-lg dark:bg-[#18181b] rounded-xl p-3">
|
||||||
<CommentTable triggerRefresh={refresh} />
|
<CommentTable />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,245 @@
|
||||||
|
"use client";
|
||||||
|
import { close, error, loading } from "@/config/swal";
|
||||||
|
import { FormEvent, Fragment, useEffect, useRef, useState } from "react";
|
||||||
|
import { Controller, useForm } from "react-hook-form";
|
||||||
|
import * as z from "zod";
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
import withReactContent from "sweetalert2-react-content";
|
||||||
|
import { Input, Textarea } from "@heroui/input";
|
||||||
|
import { Button } from "@heroui/button";
|
||||||
|
import { useParams, useRouter } from "next/navigation";
|
||||||
|
import { getCommentById, saveCommentStatus } from "@/service/comment";
|
||||||
|
import {
|
||||||
|
Modal,
|
||||||
|
ModalBody,
|
||||||
|
ModalContent,
|
||||||
|
ModalFooter,
|
||||||
|
ModalHeader,
|
||||||
|
useDisclosure,
|
||||||
|
} from "@heroui/react";
|
||||||
|
import { getArticleById } from "@/service/article";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { postArticleComment } from "@/service/master-user";
|
||||||
|
|
||||||
|
interface DetailComments {
|
||||||
|
id: number;
|
||||||
|
message: string;
|
||||||
|
articleId: number;
|
||||||
|
commentFromName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ReviewComment() {
|
||||||
|
const MySwal = withReactContent(Swal);
|
||||||
|
const { isOpen, onOpen, onOpenChange } = useDisclosure();
|
||||||
|
|
||||||
|
const params = useParams();
|
||||||
|
const id = Number(params?.id);
|
||||||
|
const router = useRouter();
|
||||||
|
const [replyValue, setReplyValue] = useState("");
|
||||||
|
|
||||||
|
const [detailData, setDetailData] = useState<DetailComments>();
|
||||||
|
const [detailArticle, setDetailArticle] = useState<{
|
||||||
|
id: number;
|
||||||
|
slug: string;
|
||||||
|
title: string;
|
||||||
|
}>();
|
||||||
|
useEffect(() => {
|
||||||
|
initFetch();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const initFetch = async () => {
|
||||||
|
loading();
|
||||||
|
const res = await getCommentById(id);
|
||||||
|
setDetailData(res?.data?.data);
|
||||||
|
const resArticle = await getArticleById(res?.data?.data?.articleId);
|
||||||
|
setDetailArticle(resArticle?.data?.data);
|
||||||
|
console.log("iddd", res?.data?.data);
|
||||||
|
close();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCommentStatus = async (statusId: number) => {
|
||||||
|
MySwal.fire({
|
||||||
|
title: "Submit Data",
|
||||||
|
text: "",
|
||||||
|
icon: "warning",
|
||||||
|
showCancelButton: true,
|
||||||
|
cancelButtonColor: "#d33",
|
||||||
|
confirmButtonColor: "#3085d6",
|
||||||
|
confirmButtonText: "Simpan",
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
saveStatus(statusId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveStatus = async (statusId: number) => {
|
||||||
|
const req = { id: id, statusId: statusId };
|
||||||
|
const res = await saveCommentStatus(req);
|
||||||
|
if (res?.error) {
|
||||||
|
error(res.message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
successSubmit("/admin/comment");
|
||||||
|
};
|
||||||
|
|
||||||
|
function successSubmit(redirect: string) {
|
||||||
|
MySwal.fire({
|
||||||
|
title: "Sukses",
|
||||||
|
icon: "success",
|
||||||
|
confirmButtonColor: "#3085d6",
|
||||||
|
confirmButtonText: "OK",
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
router.push(redirect);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const sendComment = async () => {
|
||||||
|
const data = {
|
||||||
|
articleId: detailData?.articleId,
|
||||||
|
isPublic: true,
|
||||||
|
message: replyValue,
|
||||||
|
parentId: id,
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await postArticleComment(data);
|
||||||
|
if (res?.error) {
|
||||||
|
error(res?.message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
saveStatus(2);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="p-8">
|
||||||
|
<div className="bg-white shadow-lg p-4 rounded-lg flex flex-col gap-3 text-sm w-full lg:w-1/2">
|
||||||
|
<div className="flex flex-col gap-1">
|
||||||
|
<p>Artikel</p>
|
||||||
|
<Link
|
||||||
|
target="_black"
|
||||||
|
className="text-primary hover:underline w-fit"
|
||||||
|
href={`/news/detail/${detailArticle?.id}-${detailArticle?.slug}`}
|
||||||
|
>
|
||||||
|
{detailArticle?.title}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col gap-1">
|
||||||
|
<p>Nama</p>
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
id="username"
|
||||||
|
placeholder=""
|
||||||
|
label=""
|
||||||
|
isReadOnly
|
||||||
|
value={detailData?.commentFromName}
|
||||||
|
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"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col gap-1">
|
||||||
|
<p>Komentar</p>
|
||||||
|
<Textarea
|
||||||
|
type="text"
|
||||||
|
id="address"
|
||||||
|
placeholder=""
|
||||||
|
label=""
|
||||||
|
value={detailData?.message}
|
||||||
|
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"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col gap-1">
|
||||||
|
<p>Status</p>
|
||||||
|
<div className="flex flex-row gap-3">
|
||||||
|
<Button
|
||||||
|
onPress={() => handleCommentStatus(1)}
|
||||||
|
color="success"
|
||||||
|
className="w-fit text-white"
|
||||||
|
>
|
||||||
|
Setujui
|
||||||
|
</Button>
|
||||||
|
<Button onPress={onOpen} color="primary" className="w-fit">
|
||||||
|
Balas
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onPress={() => handleCommentStatus(3)}
|
||||||
|
color="danger"
|
||||||
|
className="w-fit"
|
||||||
|
>
|
||||||
|
Tolak
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-full justify-end flex">
|
||||||
|
<Button
|
||||||
|
onPress={router.back}
|
||||||
|
color="danger"
|
||||||
|
variant="bordered"
|
||||||
|
className="w-fit"
|
||||||
|
>
|
||||||
|
Kembali
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Modal isOpen={isOpen} onOpenChange={onOpenChange}>
|
||||||
|
<ModalContent>
|
||||||
|
{(onClose) => (
|
||||||
|
<>
|
||||||
|
<ModalHeader className="flex flex-col gap-1">
|
||||||
|
Komentar Balasan
|
||||||
|
</ModalHeader>
|
||||||
|
<ModalBody>
|
||||||
|
<Textarea
|
||||||
|
type="text"
|
||||||
|
id="address"
|
||||||
|
placeholder=""
|
||||||
|
label=""
|
||||||
|
value={replyValue}
|
||||||
|
onValueChange={setReplyValue}
|
||||||
|
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"
|
||||||
|
/>
|
||||||
|
</ModalBody>
|
||||||
|
<ModalFooter>
|
||||||
|
<Button color="danger" variant="light" onPress={onClose}>
|
||||||
|
Close
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
isDisabled={replyValue.length < 2}
|
||||||
|
color="primary"
|
||||||
|
onPress={() => sendComment()}
|
||||||
|
>
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</ModalFooter>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</ModalContent>
|
||||||
|
</Modal>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -295,7 +295,7 @@ export default function CreateArticleForm() {
|
||||||
tags: values.tags.join(","),
|
tags: values.tags.join(","),
|
||||||
description: htmlToString(removeImgTags(values.description)),
|
description: htmlToString(removeImgTags(values.description)),
|
||||||
htmlDescription: removeImgTags(values.description),
|
htmlDescription: removeImgTags(values.description),
|
||||||
// aiArticleId: await saveArticleToDise(values),
|
aiArticleId: await saveArticleToDise(values),
|
||||||
isDraft: status === "draft",
|
isDraft: status === "draft",
|
||||||
isPublish: status === "publish",
|
isPublish: status === "publish",
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ export default function Comment(props: { id: string | null }) {
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
articleId: Number(id),
|
articleId: Number(id),
|
||||||
isPublic: true,
|
isPublic: false,
|
||||||
message: values.comment,
|
message: values.comment,
|
||||||
parentId: 0,
|
parentId: 0,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,8 @@ export default function ArticleTable() {
|
||||||
return value;
|
return value;
|
||||||
});
|
});
|
||||||
setArticle(newData);
|
setArticle(newData);
|
||||||
|
} else {
|
||||||
|
setArticle([]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import { close, error, loading, success } from "@/config/swal";
|
||||||
import {
|
import {
|
||||||
deleteArticle,
|
deleteArticle,
|
||||||
getArticleByCategory,
|
getArticleByCategory,
|
||||||
|
getArticleById,
|
||||||
getListArticle,
|
getListArticle,
|
||||||
} from "@/service/article";
|
} from "@/service/article";
|
||||||
import { Article } from "@/types/globals";
|
import { Article } from "@/types/globals";
|
||||||
|
|
@ -56,12 +57,15 @@ import withReactContent from "sweetalert2-react-content";
|
||||||
import { useDropzone } from "react-dropzone";
|
import { useDropzone } from "react-dropzone";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
import { getComments } from "@/service/comment";
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ name: "No", uid: "no" },
|
{ name: "No", uid: "no" },
|
||||||
{ name: "Nama", uid: "name" },
|
{ name: "Nama", uid: "commentFromName" },
|
||||||
{ name: "Email", uid: "email" },
|
{ name: "Komentar", uid: "message" },
|
||||||
{ name: "Komentar", uid: "comment" },
|
{ name: "Article", uid: "articleId" },
|
||||||
|
{ name: "Status", uid: "status" },
|
||||||
|
|
||||||
{ name: "Aksi", uid: "actions" },
|
{ name: "Aksi", uid: "actions" },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -70,101 +74,26 @@ interface Category {
|
||||||
title: string;
|
title: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const createArticleSchema = z.object({
|
export default function CommentTable() {
|
||||||
id: z.string().optional(),
|
|
||||||
title: z.string().min(2, {
|
|
||||||
message: "Judul harus diisi",
|
|
||||||
}),
|
|
||||||
url: z.string().min(2, {
|
|
||||||
message: "Link harus diisi",
|
|
||||||
}),
|
|
||||||
description: z.string().min(2, {
|
|
||||||
message: "Deskripsi harus diisi",
|
|
||||||
}),
|
|
||||||
file: z.string().optional(),
|
|
||||||
});
|
|
||||||
|
|
||||||
export default function CommentTable(props: { triggerRefresh: boolean }) {
|
|
||||||
const MySwal = withReactContent(Swal);
|
const MySwal = withReactContent(Swal);
|
||||||
const { isOpen, onOpen, onOpenChange, onClose } = useDisclosure();
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
const [totalPage, setTotalPage] = useState(1);
|
const [totalPage, setTotalPage] = useState(1);
|
||||||
const [article, setArticle] = useState<any[]>([]);
|
const [comments, setComments] = useState<any[]>([]);
|
||||||
const [showData, setShowData] = useState("10");
|
const [showData, setShowData] = useState("10");
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
const [categories, setCategoies] = useState<any>([]);
|
|
||||||
const [selectedCategories, setSelectedCategories] = useState<any>([]);
|
|
||||||
const [startDateValue, setStartDateValue] = useState({
|
|
||||||
startDate: null,
|
|
||||||
endDate: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
const [isHeader, setIsHeader] = useState(false);
|
|
||||||
|
|
||||||
const [files, setFiles] = useState<File[]>([]);
|
|
||||||
|
|
||||||
const formOptions = {
|
|
||||||
resolver: zodResolver(createArticleSchema),
|
|
||||||
defaultValues: { title: "", description: "", url: "", file: "" },
|
|
||||||
};
|
|
||||||
|
|
||||||
const { getRootProps, getInputProps } = useDropzone({
|
|
||||||
onDrop: (acceptedFiles) => {
|
|
||||||
setFiles(acceptedFiles.map((file) => Object.assign(file)));
|
|
||||||
},
|
|
||||||
maxFiles: 1,
|
|
||||||
accept: {
|
|
||||||
"image/*": [],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
type UserSettingSchema = z.infer<typeof createArticleSchema>;
|
|
||||||
const {
|
|
||||||
control,
|
|
||||||
handleSubmit,
|
|
||||||
setValue,
|
|
||||||
formState: { errors },
|
|
||||||
} = useForm<UserSettingSchema>(formOptions);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
initState();
|
initState();
|
||||||
}, [
|
}, [page, showData]);
|
||||||
page,
|
|
||||||
showData,
|
|
||||||
startDateValue,
|
|
||||||
selectedCategories,
|
|
||||||
props.triggerRefresh,
|
|
||||||
]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
getCategories();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
async function getCategories() {
|
|
||||||
const res = await getArticleByCategory();
|
|
||||||
const data = res?.data?.data;
|
|
||||||
setCategoies(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleRemoveFile = (file: File) => {
|
|
||||||
const uploadedFiles = files;
|
|
||||||
const filtered = uploadedFiles.filter((i) => i.name !== file.name);
|
|
||||||
setFiles([...filtered]);
|
|
||||||
};
|
|
||||||
|
|
||||||
async function initState() {
|
async function initState() {
|
||||||
const req = {
|
const req = {
|
||||||
limit: showData,
|
limit: showData,
|
||||||
page: page,
|
page: page,
|
||||||
search: search,
|
search: search,
|
||||||
startDate:
|
|
||||||
startDateValue.startDate === null ? "" : startDateValue.startDate,
|
|
||||||
endDate: startDateValue.endDate === null ? "" : startDateValue.endDate,
|
|
||||||
category: Array.from(selectedCategories).join(","),
|
|
||||||
sort: "desc",
|
|
||||||
sortBy: "created_at",
|
|
||||||
};
|
};
|
||||||
const res = await getListArticle(req);
|
const res = await getComments(req);
|
||||||
getTableNumber(parseInt(showData), res.data?.data);
|
getTableNumber(parseInt(showData), res.data?.data);
|
||||||
setTotalPage(res?.data?.meta?.totalPage);
|
setTotalPage(res?.data?.meta?.totalPage);
|
||||||
}
|
}
|
||||||
|
|
@ -178,12 +107,14 @@ export default function CommentTable(props: { triggerRefresh: boolean }) {
|
||||||
value.no = startIndex + iterate;
|
value.no = startIndex + iterate;
|
||||||
return value;
|
return value;
|
||||||
});
|
});
|
||||||
setArticle(newData);
|
setComments(newData);
|
||||||
|
} else {
|
||||||
|
setComments([]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
async function doDelete(id: any) {
|
async function doDelete(id: any) {
|
||||||
// loading();
|
loading();
|
||||||
const resDelete = await deleteArticle(id);
|
const resDelete = await deleteArticle(id);
|
||||||
|
|
||||||
if (resDelete?.error) {
|
if (resDelete?.error) {
|
||||||
|
|
@ -210,38 +141,23 @@ export default function CommentTable(props: { triggerRefresh: boolean }) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSubmit = async (values: z.infer<typeof createArticleSchema>) => {
|
const openArticle = async (id: number) => {
|
||||||
loading();
|
const res = await getArticleById(id);
|
||||||
const formData = {
|
if (res?.error) {
|
||||||
title: values.title,
|
MySwal.fire({
|
||||||
description: values.description,
|
title: "Artikel tidak ditemukan atau telah dihapus",
|
||||||
isHeader: isHeader,
|
icon: "warning",
|
||||||
url: values.url,
|
showCancelButton: false,
|
||||||
};
|
cancelButtonColor: "#3085d6",
|
||||||
console.log("dataas", formData);
|
confirmButtonColor: "#d33",
|
||||||
close();
|
confirmButtonText: "Oke",
|
||||||
// setRefresh(!refresh);
|
}).then((result) => {
|
||||||
// MySwal.fire({
|
if (result.isConfirmed) {
|
||||||
// title: "Sukses",
|
}
|
||||||
// icon: "success",
|
});
|
||||||
// confirmButtonColor: "#3085d6",
|
return false;
|
||||||
// confirmButtonText: "OK",
|
}
|
||||||
// }).then((result) => {
|
router.push(`/news/detail/${id}-${res?.data?.data?.slug}`);
|
||||||
// if (result.isConfirmed) {
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
};
|
|
||||||
|
|
||||||
const openModal = async (id: number) => {
|
|
||||||
// const res = await getCategoryById(Number(id));
|
|
||||||
// const data = res?.data?.data;
|
|
||||||
// setValue("id", String(data?.id));
|
|
||||||
// setValue("title", data?.title);
|
|
||||||
// setValue("description", data?.description);
|
|
||||||
// setValue("url", data?.url);
|
|
||||||
// setValue("file", data?.thumbnailUrl);
|
|
||||||
|
|
||||||
onOpen();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderCell = useCallback(
|
const renderCell = useCallback(
|
||||||
|
|
@ -249,17 +165,37 @@ export default function CommentTable(props: { triggerRefresh: boolean }) {
|
||||||
const cellValue = comment[columnKey as keyof any];
|
const cellValue = comment[columnKey as keyof any];
|
||||||
|
|
||||||
switch (columnKey) {
|
switch (columnKey) {
|
||||||
case "url":
|
case "articleId":
|
||||||
return (
|
return (
|
||||||
<Link
|
<a
|
||||||
href={`https://www.google.com/`}
|
onClick={() => openArticle(cellValue)}
|
||||||
target="_blank"
|
className="text-primary underline cursor-pointer"
|
||||||
className="text-primary hover:underline"
|
|
||||||
>
|
>
|
||||||
https://www.google.com/
|
Buka Article
|
||||||
</Link>
|
</a>
|
||||||
|
);
|
||||||
|
case "status":
|
||||||
|
return (
|
||||||
|
<p
|
||||||
|
className={`${
|
||||||
|
comment?.statusId == 1
|
||||||
|
? "bg-success"
|
||||||
|
: comment?.statusId == 1
|
||||||
|
? "bg-primary"
|
||||||
|
: comment?.statusId == 1
|
||||||
|
? "bg-danger"
|
||||||
|
: "bg-warning"
|
||||||
|
} text-white w-[180px] rounded-lg py-1 text-center`}
|
||||||
|
>
|
||||||
|
{comment?.statusId == 1
|
||||||
|
? "Disetujui"
|
||||||
|
: comment?.statusId == 2
|
||||||
|
? "Dibalas"
|
||||||
|
: comment?.statusId == 3
|
||||||
|
? "Ditolak"
|
||||||
|
: "Menunggu Review"}
|
||||||
|
</p>
|
||||||
);
|
);
|
||||||
|
|
||||||
case "actions":
|
case "actions":
|
||||||
return (
|
return (
|
||||||
<div className="relative flex justify-star items-center gap-2">
|
<div className="relative flex justify-star items-center gap-2">
|
||||||
|
|
@ -270,25 +206,24 @@ export default function CommentTable(props: { triggerRefresh: boolean }) {
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownTrigger>
|
</DropdownTrigger>
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
{/* <DropdownItem key="detail">
|
|
||||||
<Link href={`/admin/comment/detail/${article.id}`}>
|
|
||||||
<EyeIconMdi className="inline mr-2 mb-1" />
|
|
||||||
Detail
|
|
||||||
</Link>
|
|
||||||
</DropdownItem> */}
|
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
key="edit"
|
key="edit"
|
||||||
onPress={() =>
|
onPress={() =>
|
||||||
router.push(`/admin/comment/review${comment.id}`)
|
router.push(`/admin/comment/review/${comment.id}`)
|
||||||
}
|
}
|
||||||
|
className={comment.isPublic ? "hidden" : ""}
|
||||||
>
|
>
|
||||||
<CreateIconIon className="inline mr-2 mb-1" />
|
{comment.isPublic == false && (
|
||||||
|
<>
|
||||||
|
<CreateIconIon size={22} className="inline mr-2 mb-1" />
|
||||||
Review
|
Review
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
|
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
key="delete"
|
key="delete"
|
||||||
// onPress={() => handleDelete(article.id)}
|
onPress={() => handleDelete(comment.id)}
|
||||||
>
|
>
|
||||||
<DeleteIcon
|
<DeleteIcon
|
||||||
color="red"
|
color="red"
|
||||||
|
|
@ -306,7 +241,7 @@ export default function CommentTable(props: { triggerRefresh: boolean }) {
|
||||||
return cellValue;
|
return cellValue;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[article]
|
[comments]
|
||||||
);
|
);
|
||||||
|
|
||||||
let typingTimer: NodeJS.Timeout;
|
let typingTimer: NodeJS.Timeout;
|
||||||
|
|
@ -387,7 +322,7 @@ export default function CommentTable(props: { triggerRefresh: boolean }) {
|
||||||
)}
|
)}
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody
|
<TableBody
|
||||||
items={article}
|
items={comments}
|
||||||
emptyContent={"No data to display."}
|
emptyContent={"No data to display."}
|
||||||
loadingContent={<Spinner label="Loading..." />}
|
loadingContent={<Spinner label="Loading..." />}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,8 @@ export default function MagazineTable() {
|
||||||
});
|
});
|
||||||
console.log("daata", data);
|
console.log("daata", data);
|
||||||
setArticle(newData);
|
setArticle(newData);
|
||||||
|
} else {
|
||||||
|
setArticle([]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -172,6 +172,8 @@ export default function CategoriesTable(props: { triggerRefresh: boolean }) {
|
||||||
return value;
|
return value;
|
||||||
});
|
});
|
||||||
setCategories(newData);
|
setCategories(newData);
|
||||||
|
} else {
|
||||||
|
setCategories([]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,13 +61,17 @@ import { useDropzone } from "react-dropzone";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import SuggestionsChart from "@/components/main/dashboard/chart/suggestions-line-chart";
|
import SuggestionsChart from "@/components/main/dashboard/chart/suggestions-line-chart";
|
||||||
import { parseDate } from "@internationalized/date";
|
import { parseDate } from "@internationalized/date";
|
||||||
import { getFeedbacks, getFeedbacksById } from "@/service/feedbacks";
|
import {
|
||||||
|
deleteFeedback,
|
||||||
|
getFeedbacks,
|
||||||
|
getFeedbacksById,
|
||||||
|
} from "@/service/feedbacks";
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ name: "No", uid: "no" },
|
{ name: "No", uid: "no" },
|
||||||
{ name: "Nama", uid: "name" },
|
{ name: "Nama", uid: "commentFromName" },
|
||||||
{ name: "Email", uid: "email" },
|
{ name: "Email", uid: "commentFromEmail" },
|
||||||
{ name: "Kritik & Saran", uid: "suggestions" },
|
{ name: "Kritik & Saran", uid: "message" },
|
||||||
{ name: "Aksi", uid: "actions" },
|
{ name: "Aksi", uid: "actions" },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -135,12 +139,14 @@ export default function SuggestionsTable() {
|
||||||
return value;
|
return value;
|
||||||
});
|
});
|
||||||
setArticle(newData);
|
setArticle(newData);
|
||||||
|
} else {
|
||||||
|
setArticle([]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
async function doDelete(id: any) {
|
async function doDelete(id: number) {
|
||||||
// loading();
|
loading();
|
||||||
const resDelete = await deleteArticle(id);
|
const resDelete = await deleteFeedback(id);
|
||||||
|
|
||||||
if (resDelete?.error) {
|
if (resDelete?.error) {
|
||||||
error(resDelete.message);
|
error(resDelete.message);
|
||||||
|
|
@ -151,7 +157,7 @@ export default function SuggestionsTable() {
|
||||||
initState();
|
initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDelete = (id: any) => {
|
const handleDelete = (id: number) => {
|
||||||
MySwal.fire({
|
MySwal.fire({
|
||||||
title: "Hapus Data",
|
title: "Hapus Data",
|
||||||
icon: "warning",
|
icon: "warning",
|
||||||
|
|
@ -226,17 +232,6 @@ export default function SuggestionsTable() {
|
||||||
const cellValue = suggestion[columnKey as keyof any];
|
const cellValue = suggestion[columnKey as keyof any];
|
||||||
|
|
||||||
switch (columnKey) {
|
switch (columnKey) {
|
||||||
case "commentFromEmail":
|
|
||||||
return (
|
|
||||||
<Link
|
|
||||||
href={`https://www.google.com/`}
|
|
||||||
target="_blank"
|
|
||||||
className="text-primary hover:underline"
|
|
||||||
>
|
|
||||||
https://www.google.com/
|
|
||||||
</Link>
|
|
||||||
);
|
|
||||||
|
|
||||||
case "actions":
|
case "actions":
|
||||||
return (
|
return (
|
||||||
<div className="relative flex justify-star items-center gap-2">
|
<div className="relative flex justify-star items-center gap-2">
|
||||||
|
|
@ -258,12 +253,12 @@ export default function SuggestionsTable() {
|
||||||
onPress={() => openModal(suggestion.id)}
|
onPress={() => openModal(suggestion.id)}
|
||||||
>
|
>
|
||||||
<CreateIconIon className="inline mr-2 mb-1" />
|
<CreateIconIon className="inline mr-2 mb-1" />
|
||||||
Edit
|
Detail
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
|
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
key="delete"
|
key="delete"
|
||||||
// onPress={() => handleDelete(article.id)}
|
onPress={() => handleDelete(suggestion.id)}
|
||||||
>
|
>
|
||||||
<DeleteIcon
|
<DeleteIcon
|
||||||
color="red"
|
color="red"
|
||||||
|
|
@ -399,7 +394,6 @@ export default function SuggestionsTable() {
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
<Button onPress={() => openModal(4)}>test</Button>
|
|
||||||
</div>
|
</div>
|
||||||
<Table
|
<Table
|
||||||
aria-label="micro issue table"
|
aria-label="micro issue table"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
import {
|
||||||
|
httpDeleteInterceptor,
|
||||||
|
httpGet,
|
||||||
|
httpPost,
|
||||||
|
httpPut,
|
||||||
|
} from "./http-config/axios-base-service";
|
||||||
|
import Cookies from "js-cookie";
|
||||||
|
|
||||||
|
const token = Cookies.get("access_token");
|
||||||
|
|
||||||
|
export async function getComments(data: any) {
|
||||||
|
const headers = {
|
||||||
|
"content-type": "application/json",
|
||||||
|
};
|
||||||
|
const pathUrl = `/article-comments?page=${data?.page || 1}&limit=${
|
||||||
|
data?.limit || ""
|
||||||
|
}&message=${data?.search || ""}&parentId=0`;
|
||||||
|
return await httpGet(pathUrl, headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteComment(id: number) {
|
||||||
|
return await httpDeleteInterceptor(`/article-comments/${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getCommentById(id: number) {
|
||||||
|
const headers = {
|
||||||
|
"content-type": "application/json",
|
||||||
|
};
|
||||||
|
const pathUrl = `/article-comments/${id}`;
|
||||||
|
return await httpGet(pathUrl, headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function saveCommentStatus(data: {
|
||||||
|
id: number;
|
||||||
|
statusId: number;
|
||||||
|
}) {
|
||||||
|
const headers = {
|
||||||
|
"content-type": "application/json",
|
||||||
|
};
|
||||||
|
const pathUrl = `/article-comments/approval`;
|
||||||
|
return await httpPost(pathUrl, headers, data);
|
||||||
|
}
|
||||||
|
|
@ -20,9 +20,9 @@ export async function getFeedbacks(data: any) {
|
||||||
const headers = {
|
const headers = {
|
||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
};
|
};
|
||||||
const pathUrl = `/feedbacks?limit=${data?.limit || ""}&message=${
|
const pathUrl = `/feedbacks?page=${data?.page || 1}limit=${
|
||||||
data?.search || ""
|
data?.limit || ""
|
||||||
}`;
|
}&message=${data?.search || ""}`;
|
||||||
return await httpGet(pathUrl, headers);
|
return await httpGet(pathUrl, headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -33,3 +33,6 @@ export async function getFeedbacksById(id: number) {
|
||||||
const pathUrl = `/feedbacks/${id}`;
|
const pathUrl = `/feedbacks/${id}`;
|
||||||
return await httpGet(pathUrl, headers);
|
return await httpGet(pathUrl, headers);
|
||||||
}
|
}
|
||||||
|
export async function deleteFeedback(id: number) {
|
||||||
|
return await httpDeleteInterceptor(`/feedbacks/${id}`);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,10 @@ export async function getArticleComment(id: string) {
|
||||||
const headers = {
|
const headers = {
|
||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
};
|
};
|
||||||
return await httpGet(`/article-comments?articleId=${id}`, headers);
|
return await httpGet(
|
||||||
|
`/article-comments?isPublic=true&articleId=${id}`,
|
||||||
|
headers
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteArticleComment(id: number) {
|
export async function deleteArticleComment(id: number) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue