This commit is contained in:
Anang Yusman 2025-10-17 16:31:33 +08:00
parent 87e391a5bf
commit 6fb6e977e9
1 changed files with 183 additions and 17 deletions

View File

@ -19,6 +19,7 @@ import GetSeoScore from "./get-seo-score-form";
import Link from "next/link"; import Link from "next/link";
import Cookies from "js-cookie"; import Cookies from "js-cookie";
import { import {
createArticleSchedule,
deleteArticleFiles, deleteArticleFiles,
getArticleByCategory, getArticleByCategory,
getArticleById, getArticleById,
@ -55,6 +56,8 @@ import {
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
import DatePicker from "react-datepicker";
import { Switch } from "@/components/ui/switch";
const ViewEditor = dynamic( const ViewEditor = dynamic(
() => { () => {
@ -147,8 +150,14 @@ export default function EditArticleForm(props: { isDetail: boolean }) {
const [approvalStatus, setApprovalStatus] = useState<number>(2); const [approvalStatus, setApprovalStatus] = useState<number>(2);
const [approvalMessage, setApprovalMessage] = useState(""); const [approvalMessage, setApprovalMessage] = useState("");
const [detailData, setDetailData] = useState<any>(); const [detailData, setDetailData] = useState<any>();
const [startDateValue, setStartDateValue] = useState<any>(null); // const [startDateValue, setStartDateValue] = useState<any>(null);
const [timeValue, setTimeValue] = useState("00:00"); // const [timeValue, setTimeValue] = useState("00:00");
const [status, setStatus] = useState<"publish" | "draft" | "scheduled">(
"publish"
);
const [isScheduled, setIsScheduled] = useState(false);
const [startDateValue, setStartDateValue] = useState<Date | undefined>();
const [startTimeValue, setStartTimeValue] = useState<string>("");
const { getRootProps, getInputProps } = useDropzone({ const { getRootProps, getInputProps } = useDropzone({
onDrop: (acceptedFiles) => { onDrop: (acceptedFiles) => {
@ -196,7 +205,7 @@ export default function EditArticleForm(props: { isDetail: boolean }) {
const cleanDescription = data?.htmlDescription const cleanDescription = data?.htmlDescription
? data.htmlDescription ? data.htmlDescription
.replace(/\\"/g, '"') .replace(/\\"/g, '"')
.replace(/\\n/g, "\n", "\\") // ubah newline escaped .replace(/\\n/g, "\n", "\\")
.trim() .trim()
: ""; : "";
setValue("description", cleanDescription); setValue("description", cleanDescription);
@ -261,21 +270,28 @@ export default function EditArticleForm(props: { isDetail: boolean }) {
const doPublish = async () => { const doPublish = async () => {
MySwal.fire({ MySwal.fire({
title: "Publish Artikel?", title: isScheduled ? "Jadwalkan Publikasi?" : "Publish Artikel Sekarang?",
text: "", text: isScheduled
? "Artikel akan dipublish otomatis sesuai tanggal dan waktu yang kamu pilih."
: "",
icon: "warning", icon: "warning",
showCancelButton: true, showCancelButton: true,
cancelButtonColor: "#d33", cancelButtonColor: "#d33",
confirmButtonColor: "#3085d6", confirmButtonColor: "#3085d6",
confirmButtonText: "Submit", confirmButtonText: isScheduled ? "Jadwalkan" : "Publish",
}).then((result) => { }).then((result) => {
if (result.isConfirmed) { if (result.isConfirmed) {
publish(); if (isScheduled) {
setStatus("scheduled");
publishScheduled();
} else {
publishNow();
}
} }
}); });
}; };
const publish = async () => { const publishNow = async () => {
const response = await updateArticle(String(id), { const response = await updateArticle(String(id), {
id: Number(id), id: Number(id),
isPublish: true, isPublish: true,
@ -292,8 +308,67 @@ export default function EditArticleForm(props: { isDetail: boolean }) {
if (response?.error) { if (response?.error) {
error(response.message); error(response.message);
return false; return;
} }
successSubmit("/admin/article");
};
const publishScheduled = async () => {
if (!startDateValue) {
error("Tanggal belum dipilih!");
return;
}
const [hours, minutes] = startTimeValue
? startTimeValue.split(":").map(Number)
: [0, 0];
const combinedDate = new Date(startDateValue);
combinedDate.setHours(hours, minutes, 0, 0);
const formattedDateTime = `${combinedDate.getFullYear()}-${String(
combinedDate.getMonth() + 1
).padStart(2, "0")}-${String(combinedDate.getDate()).padStart(
2,
"0"
)} ${String(combinedDate.getHours()).padStart(2, "0")}:${String(
combinedDate.getMinutes()
).padStart(2, "0")}:00`;
const response = await updateArticle(String(id), {
id: Number(id),
isPublish: false,
title: detailData?.title,
typeId: 1,
slug: detailData?.slug,
categoryIds: getValues("category")
.map((val) => val.id)
.join(","),
tags: getValues("tags").join(","),
description: htmlToString(getValues("description")),
htmlDescription: getValues("description"),
});
if (response?.error) {
error(response.message);
return;
}
const articleId = response?.data?.data?.id ?? id;
const scheduleReq = {
id: articleId,
date: formattedDateTime,
};
console.log("📅 Mengirim jadwal publish:", scheduleReq);
const res = await createArticleSchedule(scheduleReq);
if (res?.error) {
error("Gagal membuat jadwal publikasi.");
return;
}
successSubmit("/admin/article"); successSubmit("/admin/article");
}; };
@ -311,16 +386,16 @@ export default function EditArticleForm(props: { isDetail: boolean }) {
// createdAt: `${startDateValue} ${timeValue}:00`, // createdAt: `${startDateValue} ${timeValue}:00`,
}; };
if (startDateValue && timeValue) { // if (startDateValue && timeValue) {
formData.createdAt = `${startDateValue} ${timeValue}:00`; // formData.createdAt = `${startDateValue} ${timeValue}:00`;
} // }
const response = await updateArticle(String(id), formData); const response = await updateArticle(String(id), formData);
if (response?.error) { if (response?.error) {
error(response.message); error(response.message);
return false; return false;
} }
const articleId = response?.data?.data?.id;
const formFiles = new FormData(); const formFiles = new FormData();
if (files?.length > 0) { if (files?.length > 0) {
@ -337,6 +412,36 @@ export default function EditArticleForm(props: { isDetail: boolean }) {
const resFile = await uploadArticleThumbnail(String(id), formFiles); const resFile = await uploadArticleThumbnail(String(id), formFiles);
} }
if (status === "scheduled" && startDateValue) {
// ambil waktu, default 00:00 jika belum diisi
const [hours, minutes] = startTimeValue
? startTimeValue.split(":").map(Number)
: [0, 0];
// gabungkan tanggal + waktu
const combinedDate = new Date(startDateValue);
combinedDate.setHours(hours, minutes, 0, 0);
// format: 2025-10-08 14:30:00
const formattedDateTime = `${combinedDate.getFullYear()}-${String(
combinedDate.getMonth() + 1
).padStart(2, "0")}-${String(combinedDate.getDate()).padStart(
2,
"0"
)} ${String(combinedDate.getHours()).padStart(2, "0")}:${String(
combinedDate.getMinutes()
).padStart(2, "0")}:00`;
const request = {
id: articleId,
date: formattedDateTime,
};
console.log("📤 Sending schedule request:", request);
const res = await createArticleSchedule(request);
console.log("✅ Schedule response:", res);
}
close(); close();
successSubmit("/admin/article"); successSubmit("/admin/article");
}; };
@ -940,7 +1045,63 @@ export default function EditArticleForm(props: { isDetail: boolean }) {
{errors?.tags && ( {errors?.tags && (
<p className="text-red-400 text-sm mb-3">{errors.tags?.message}</p> <p className="text-red-400 text-sm mb-3">{errors.tags?.message}</p>
)} )}
{!isDetail && username === "admin-mabes" && ( <div className="flex flex-col gap-2 mt-3">
<div className="flex items-center space-x-2">
<Switch
id="schedule-switch"
checked={isScheduled}
onCheckedChange={setIsScheduled}
/>
<label htmlFor="schedule-switch" className="text-black text-sm">
Publish dengan Jadwal
</label>
</div>
{isScheduled && (
<div className="flex flex-col lg:flex-row gap-3 mt-2">
{/* Pilih tanggal */}
<div className="w-full lg:w-[140px] flex flex-col gap-2">
<p className="text-sm">Tanggal</p>
<Popover>
<PopoverTrigger>
<Button
type="button"
className="w-full !h-[37px] lg:h-[37px] border-1 rounded-lg text-black"
variant="outline"
>
{startDateValue
? startDateValue.toISOString().split("T")[0]
: "-"}
</Button>
</PopoverTrigger>
<PopoverContent className="bg-transparent p-0">
<DatePicker
selected={startDateValue}
onChange={(date) =>
setStartDateValue(date ?? undefined)
}
dateFormat="yyyy-MM-dd"
className="w-full border rounded-lg px-2 py-1 text-black cursor-pointer h-[150px]"
placeholderText="Pilih tanggal"
/>
</PopoverContent>
</Popover>
</div>
{/* Pilih waktu */}
<div className="w-full lg:w-[140px] flex flex-col gap-2">
<p className="text-sm">Waktu</p>
<input
type="time"
value={startTimeValue}
onChange={(e) => setStartTimeValue(e.target.value)}
className="w-full border rounded-lg px-2 py-[6px] text-black"
/>
</div>
</div>
)}
</div>
{/* {!isDetail && username === "admin-mabes" && (
<> <>
<p className="text-sm">Ubah Waktu Pembuatan</p> <p className="text-sm">Ubah Waktu Pembuatan</p>
<div className="flex flex-row gap-2"> <div className="flex flex-row gap-2">
@ -972,7 +1133,7 @@ export default function EditArticleForm(props: { isDetail: boolean }) {
/> />
</div> </div>
</> </>
)} )} */}
</div> </div>
<div className="flex flex-row justify-end gap-3"> <div className="flex flex-row justify-end gap-3">
@ -1010,8 +1171,13 @@ export default function EditArticleForm(props: { isDetail: boolean }) {
</Button> </Button>
)} )}
{detailData?.isPublish === false && ( {detailData?.isPublish === false && (
<Button type="button" color="primary" onClick={doPublish}> <Button
Publish type="button"
color="primary"
onClick={doPublish}
disabled={isScheduled && !startDateValue}
>
{isScheduled ? "Jadwalkan" : "Publish"}
</Button> </Button>
)} )}
{/* {!isDetail && ( {/* {!isDetail && (