feat:approval
This commit is contained in:
parent
33fcdd670c
commit
e4dd1da844
|
|
@ -18,13 +18,22 @@ import {
|
||||||
deleteArticleFiles,
|
deleteArticleFiles,
|
||||||
getArticleByCategory,
|
getArticleByCategory,
|
||||||
getArticleById,
|
getArticleById,
|
||||||
|
submitApproval,
|
||||||
updateArticle,
|
updateArticle,
|
||||||
uploadArticleFile,
|
uploadArticleFile,
|
||||||
uploadArticleThumbnail,
|
uploadArticleThumbnail,
|
||||||
} from "@/service/article";
|
} from "@/service/article";
|
||||||
import ReactSelect from "react-select";
|
import ReactSelect from "react-select";
|
||||||
import makeAnimated from "react-select/animated";
|
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 GenerateSingleArticleForm from "./generate-ai-single-form";
|
||||||
import { htmlToString } from "@/utils/global";
|
import { htmlToString } from "@/utils/global";
|
||||||
import { close, error, loading } from "@/config/swal";
|
import { close, error, loading } from "@/config/swal";
|
||||||
|
|
@ -112,6 +121,10 @@ export default function EditArticleForm(props: { isDetail: boolean }) {
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
const [thumbnailValidation, setThumbnailValidation] = useState("");
|
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({
|
const { getRootProps, getInputProps } = useDropzone({
|
||||||
onDrop: (acceptedFiles) => {
|
onDrop: (acceptedFiles) => {
|
||||||
|
|
@ -151,6 +164,7 @@ export default function EditArticleForm(props: { isDetail: boolean }) {
|
||||||
loading();
|
loading();
|
||||||
const res = await getArticleById(id);
|
const res = await getArticleById(id);
|
||||||
const data = res.data?.data;
|
const data = res.data?.data;
|
||||||
|
setDetailData(data);
|
||||||
setValue("title", data?.title);
|
setValue("title", data?.title);
|
||||||
setValue("slug", data?.slug);
|
setValue("slug", data?.slug);
|
||||||
setValue("description", data?.htmlDescription);
|
setValue("description", data?.htmlDescription);
|
||||||
|
|
@ -161,15 +175,14 @@ export default function EditArticleForm(props: { isDetail: boolean }) {
|
||||||
|
|
||||||
setupInitCategory(data?.categories);
|
setupInitCategory(data?.categories);
|
||||||
close();
|
close();
|
||||||
console.log("Data Aritcle", data?.files);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const setupInitCategory = (data: any) => {
|
const setupInitCategory = (data: any) => {
|
||||||
const temp: CategoryType[] = [];
|
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);
|
const datas = listCategory.filter((a) => a.id == data[i].id);
|
||||||
if (datas[0]) {
|
if (datas[0]) {
|
||||||
temp.push(datas[0]); // Hanya tambahkan jika datas[0] ada
|
temp.push(datas[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setValue("category", temp as [CategoryType, ...CategoryType[]]);
|
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 (
|
return (
|
||||||
<form
|
<form
|
||||||
className="flex flex-col lg:flex-row gap-8 text-black"
|
className="flex flex-col lg:flex-row gap-8 text-black"
|
||||||
|
|
@ -767,6 +823,30 @@ export default function EditArticleForm(props: { isDetail: boolean }) {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row justify-end gap-3">
|
<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 && (
|
{!isDetail && (
|
||||||
<Button color="primary" type="submit">
|
<Button color="primary" type="submit">
|
||||||
Publish
|
Publish
|
||||||
|
|
@ -783,6 +863,57 @@ export default function EditArticleForm(props: { isDetail: boolean }) {
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -104,10 +104,10 @@ export default function ENewsPolri() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Link
|
<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"
|
href="/e-majalah-polri/daftar-majalah"
|
||||||
>
|
>
|
||||||
Lihat Semua <ChevronRightIcon color="[#DD8306]" />
|
Lihat Semua <ChevronRightIcon color="[#bb3523]" />
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,12 @@ export default function HeaderNews() {
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
async function getArticle() {
|
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);
|
const response = await getListArticle(req);
|
||||||
setArticle(response?.data?.data);
|
setArticle(response?.data?.data);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ const columns = [
|
||||||
{ name: "Kategori", uid: "category" },
|
{ name: "Kategori", uid: "category" },
|
||||||
{ name: "Tanggal Unggah", uid: "createdAt" },
|
{ name: "Tanggal Unggah", uid: "createdAt" },
|
||||||
{ name: "Kreator", uid: "createdByName" },
|
{ name: "Kreator", uid: "createdByName" },
|
||||||
|
// { name: "Status", uid: "isPublish" },
|
||||||
{ name: "Aksi", uid: "actions" },
|
{ name: "Aksi", uid: "actions" },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -89,7 +90,6 @@ export default function ArticleTable() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function initState() {
|
async function initState() {
|
||||||
console.log("seeecle", Array.from(selectedCategories));
|
|
||||||
const req = {
|
const req = {
|
||||||
limit: showData,
|
limit: showData,
|
||||||
page: page,
|
page: page,
|
||||||
|
|
@ -98,6 +98,8 @@ export default function ArticleTable() {
|
||||||
startDateValue.startDate === null ? "" : startDateValue.startDate,
|
startDateValue.startDate === null ? "" : startDateValue.startDate,
|
||||||
endDate: startDateValue.endDate === null ? "" : startDateValue.endDate,
|
endDate: startDateValue.endDate === null ? "" : startDateValue.endDate,
|
||||||
category: Array.from(selectedCategories).join(","),
|
category: Array.from(selectedCategories).join(","),
|
||||||
|
sort: "desc",
|
||||||
|
sortBy: "created_at",
|
||||||
};
|
};
|
||||||
const res = await getListArticle(req);
|
const res = await getListArticle(req);
|
||||||
getTableNumber(parseInt(showData), res.data?.data);
|
getTableNumber(parseInt(showData), res.data?.data);
|
||||||
|
|
@ -148,25 +150,21 @@ export default function ArticleTable() {
|
||||||
const renderCell = useCallback(
|
const renderCell = useCallback(
|
||||||
(article: any, columnKey: Key) => {
|
(article: any, columnKey: Key) => {
|
||||||
const cellValue = article[columnKey as keyof any];
|
const cellValue = article[columnKey as keyof any];
|
||||||
const statusColorMap: Record<string, ChipProps["color"]> = {
|
|
||||||
active: "primary",
|
|
||||||
cancel: "danger",
|
|
||||||
pending: "success",
|
|
||||||
};
|
|
||||||
|
|
||||||
switch (columnKey) {
|
switch (columnKey) {
|
||||||
case "status":
|
case "isPublish":
|
||||||
return (
|
return (
|
||||||
<Chip
|
// <Chip
|
||||||
className="capitalize "
|
// className="capitalize "
|
||||||
color={statusColorMap[article.status]}
|
// color={statusColorMap[article.status]}
|
||||||
size="lg"
|
// size="lg"
|
||||||
variant="flat"
|
// variant="flat"
|
||||||
>
|
// >
|
||||||
<div className="flex flex-row items-center gap-2 justify-center">
|
// <div className="flex flex-row items-center gap-2 justify-center">
|
||||||
{article.status}
|
// {article.status}
|
||||||
</div>
|
// </div>
|
||||||
</Chip>
|
// </Chip>
|
||||||
|
<p>{article.isPublish ? "Publish" : "Draft"}</p>
|
||||||
);
|
);
|
||||||
case "createdAt":
|
case "createdAt":
|
||||||
return <p>{convertDateFormat(article.createdAt)}</p>;
|
return <p>{convertDateFormat(article.createdAt)}</p>;
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ export function loading(msg?: any) {
|
||||||
timerProgressBar: true,
|
timerProgressBar: true,
|
||||||
didOpen: () => {
|
didOpen: () => {
|
||||||
MySwal.showLoading();
|
MySwal.showLoading();
|
||||||
timerInterval = setInterval(() => { }, 100);
|
timerInterval = setInterval(() => {}, 100);
|
||||||
},
|
},
|
||||||
willClose: () => {
|
willClose: () => {
|
||||||
clearInterval(timerInterval);
|
clearInterval(timerInterval);
|
||||||
|
|
@ -37,6 +37,10 @@ export function error(msg?: any) {
|
||||||
icon: "error",
|
icon: "error",
|
||||||
title: "Failed...",
|
title: "Failed...",
|
||||||
text: msg || "Unknown Error",
|
text: msg || "Unknown Error",
|
||||||
|
customClass: {
|
||||||
|
popup: "custom-popup",
|
||||||
|
confirmButton: "custom-button",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,5 +95,3 @@ export function successToast(title: string, text: string) {
|
||||||
text: text,
|
text: text,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ export async function getArticleByCategory() {
|
||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
Authorization: `Bearer ${token}`,
|
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) {
|
export async function getCategoryPagination(data: any) {
|
||||||
const headers = {
|
const headers = {
|
||||||
|
|
@ -139,3 +139,15 @@ export async function getStatisticSummary() {
|
||||||
};
|
};
|
||||||
return await httpGet(`/articles/statistic/summary`, headers);
|
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);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -96,3 +96,11 @@ main {
|
||||||
.komdigi-styling #gpr-kominfo-widget-body {
|
.komdigi-styling #gpr-kominfo-widget-body {
|
||||||
height: 67vh !important;
|
height: 67vh !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.custom-popup {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-button {
|
||||||
|
color: black !important;
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue