feat:approval

This commit is contained in:
Rama Priyanto 2025-02-17 23:32:20 +07:00
parent 33fcdd670c
commit e4dd1da844
7 changed files with 184 additions and 28 deletions

View File

@ -18,13 +18,22 @@ import {
deleteArticleFiles,
getArticleByCategory,
getArticleById,
submitApproval,
updateArticle,
uploadArticleFile,
uploadArticleThumbnail,
} from "@/service/article";
import ReactSelect from "react-select";
import makeAnimated from "react-select/animated";
import { Chip } from "@heroui/react";
import {
Chip,
Modal,
ModalBody,
ModalContent,
ModalFooter,
ModalHeader,
useDisclosure,
} from "@heroui/react";
import GenerateSingleArticleForm from "./generate-ai-single-form";
import { htmlToString } from "@/utils/global";
import { close, error, loading } from "@/config/swal";
@ -112,6 +121,10 @@ export default function EditArticleForm(props: { isDetail: boolean }) {
null
);
const [thumbnailValidation, setThumbnailValidation] = useState("");
const { isOpen, onOpen, onOpenChange } = useDisclosure();
const [approvalStatus, setApprovalStatus] = useState<number>(2);
const [approvalMessage, setApprovalMessage] = useState("");
const [detailData, setDetailData] = useState<any>();
const { getRootProps, getInputProps } = useDropzone({
onDrop: (acceptedFiles) => {
@ -151,6 +164,7 @@ export default function EditArticleForm(props: { isDetail: boolean }) {
loading();
const res = await getArticleById(id);
const data = res.data?.data;
setDetailData(data);
setValue("title", data?.title);
setValue("slug", data?.slug);
setValue("description", data?.htmlDescription);
@ -161,15 +175,14 @@ export default function EditArticleForm(props: { isDetail: boolean }) {
setupInitCategory(data?.categories);
close();
console.log("Data Aritcle", data?.files);
}
const setupInitCategory = (data: any) => {
const temp: CategoryType[] = [];
for (let i = 0; i < data.length; i++) {
for (let i = 0; i < data?.length; i++) {
const datas = listCategory.filter((a) => a.id == data[i].id);
if (datas[0]) {
temp.push(datas[0]); // Hanya tambahkan jika datas[0] ada
temp.push(datas[0]);
}
}
setValue("category", temp as [CategoryType, ...CategoryType[]]);
@ -373,6 +386,49 @@ export default function EditArticleForm(props: { isDetail: boolean }) {
}
};
const approval = async () => {
loading();
const req = {
articleId: Number(id),
message: approvalMessage,
statusId: approvalStatus,
};
const res = await submitApproval(req);
if (res?.error) {
error(res.message);
return false;
}
close();
initState();
MySwal.fire({
title: "Sukses",
icon: "success",
confirmButtonColor: "#3085d6",
confirmButtonText: "OK",
}).then((result) => {
if (result.isConfirmed) {
}
});
};
const doApproval = () => {
MySwal.fire({
title: "Submit Data?",
text: "",
icon: "warning",
showCancelButton: true,
cancelButtonColor: "#d33",
confirmButtonColor: "#3085d6",
confirmButtonText: "Submit",
}).then((result) => {
if (result.isConfirmed) {
approval();
}
});
};
return (
<form
className="flex flex-col lg:flex-row gap-8 text-black"
@ -767,6 +823,30 @@ export default function EditArticleForm(props: { isDetail: boolean }) {
)}
</div>
<div className="flex flex-row justify-end gap-3">
{isDetail && detailData?.statusId === 1 && (
<Button
color="primary"
type="button"
onPress={() => {
setApprovalStatus(2);
onOpen();
}}
>
Setujui
</Button>
)}
{isDetail && detailData?.statusId === 1 && (
<Button
color="danger"
type="button"
onPress={() => {
setApprovalStatus(3);
onOpen();
}}
>
Tolak
</Button>
)}
{!isDetail && (
<Button color="primary" type="submit">
Publish
@ -783,6 +863,57 @@ export default function EditArticleForm(props: { isDetail: boolean }) {
</Button>
</Link>
</div>
<Modal isOpen={isOpen} onOpenChange={onOpenChange}>
<ModalContent>
{(onClose) => (
<>
<ModalHeader className="flex flex-col">Approval</ModalHeader>
<ModalBody>
<p className="text-sm">
Status :
<span
className={
approvalStatus === 3 ? "text-primary" : "text-danger"
}
>
{" "}
{approvalStatus === 3 ? "Disetujui" : "Ditolak"}
</span>
</p>
<Textarea
labelPlacement="outside"
label="Pesan "
placeholder="Masukkan pesan"
variant="bordered"
classNames={{
inputWrapper: [
"border-1 rounded-lg",
"dark:group-data-[focused=false]:bg-transparent !border-1 dark:!border-gray-400",
],
}}
value={approvalMessage}
onValueChange={setApprovalMessage}
/>
</ModalBody>
<ModalFooter>
<Button color="primary" onPress={doApproval}>
Submit
</Button>
<Button
color="danger"
variant="light"
onPress={() => {
setApprovalMessage("");
onClose();
}}
>
Close
</Button>
</ModalFooter>
</>
)}
</ModalContent>
</Modal>
</div>
</form>
);

View File

@ -104,10 +104,10 @@ export default function ENewsPolri() {
</div>
</div>
<Link
className="flex items-center gap-2 text-[#DD8306] mt-3"
className="flex items-center gap-2 text-[#bb3523] mt-3"
href="/e-majalah-polri/daftar-majalah"
>
Lihat Semua <ChevronRightIcon color="[#DD8306]" />
Lihat Semua <ChevronRightIcon color="[#bb3523]" />
</Link>
</div>
);

View File

@ -40,7 +40,12 @@ export default function HeaderNews() {
}, []);
async function getArticle() {
const req = { page: 1, search: "", limit: "10", sort: "desc" };
const req = {
page: 1,
search: "",
limit: "10",
sort: "desc",
};
const response = await getListArticle(req);
setArticle(response?.data?.data);
}

View File

@ -46,6 +46,7 @@ const columns = [
{ name: "Kategori", uid: "category" },
{ name: "Tanggal Unggah", uid: "createdAt" },
{ name: "Kreator", uid: "createdByName" },
// { name: "Status", uid: "isPublish" },
{ name: "Aksi", uid: "actions" },
];
@ -89,7 +90,6 @@ export default function ArticleTable() {
}
async function initState() {
console.log("seeecle", Array.from(selectedCategories));
const req = {
limit: showData,
page: page,
@ -98,6 +98,8 @@ export default function ArticleTable() {
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);
getTableNumber(parseInt(showData), res.data?.data);
@ -148,25 +150,21 @@ export default function ArticleTable() {
const renderCell = useCallback(
(article: any, columnKey: Key) => {
const cellValue = article[columnKey as keyof any];
const statusColorMap: Record<string, ChipProps["color"]> = {
active: "primary",
cancel: "danger",
pending: "success",
};
switch (columnKey) {
case "status":
case "isPublish":
return (
<Chip
className="capitalize "
color={statusColorMap[article.status]}
size="lg"
variant="flat"
>
<div className="flex flex-row items-center gap-2 justify-center">
{article.status}
</div>
</Chip>
// <Chip
// className="capitalize "
// color={statusColorMap[article.status]}
// size="lg"
// variant="flat"
// >
// <div className="flex flex-row items-center gap-2 justify-center">
// {article.status}
// </div>
// </Chip>
<p>{article.isPublish ? "Publish" : "Draft"}</p>
);
case "createdAt":
return <p>{convertDateFormat(article.createdAt)}</p>;

View File

@ -24,7 +24,7 @@ export function loading(msg?: any) {
timerProgressBar: true,
didOpen: () => {
MySwal.showLoading();
timerInterval = setInterval(() => { }, 100);
timerInterval = setInterval(() => {}, 100);
},
willClose: () => {
clearInterval(timerInterval);
@ -37,6 +37,10 @@ export function error(msg?: any) {
icon: "error",
title: "Failed...",
text: msg || "Unknown Error",
customClass: {
popup: "custom-popup",
confirmButton: "custom-button",
},
});
}
@ -91,5 +95,3 @@ export function successToast(title: string, text: string) {
text: text,
});
}

View File

@ -84,7 +84,7 @@ export async function getArticleByCategory() {
"content-type": "application/json",
Authorization: `Bearer ${token}`,
};
return await httpGet(`/article-categories?limit=50`, headers);
return await httpGet(`/article-categories?limit=200`, headers);
}
export async function getCategoryPagination(data: any) {
const headers = {
@ -139,3 +139,15 @@ export async function getStatisticSummary() {
};
return await httpGet(`/articles/statistic/summary`, headers);
}
export async function submitApproval(data: {
articleId: number;
message: string;
statusId: number;
}) {
const headers = {
"content-type": "multipart/form-data",
Authorization: `Bearer ${token}`,
};
return await httpPost(`/article-approvals`, headers, data);
}

View File

@ -96,3 +96,11 @@ main {
.komdigi-styling #gpr-kominfo-widget-body {
height: 67vh !important;
}
.custom-popup {
color: black;
}
.custom-button {
color: black !important;
}