"use client"; import React, { ChangeEvent, Fragment, useEffect, useRef, useState, } from "react"; import { useForm, Controller } from "react-hook-form"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; import { Label } from "@/components/ui/label"; import { Card } from "@/components/ui/card"; import { zodResolver } from "@hookform/resolvers/zod"; import * as z from "zod"; import Swal from "sweetalert2"; import withReactContent from "sweetalert2-react-content"; import { useParams, useRouter } from "next/navigation"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Checkbox } from "@/components/ui/checkbox"; import { CloudUpload, MailIcon } from "lucide-react"; import dynamic from "next/dynamic"; import { useDropzone } from "react-dropzone"; import Image from "next/image"; import Cookies from "js-cookie"; import { error, loading, close } from "@/lib/swal"; import { Upload } from "tus-js-client"; import { htmlToString } from "@/utils/globals"; import { getCookiesDecrypt } from "@/lib/utils"; import { createMedia, deleteFile, getTagsBySubCategoryId, listEnableCategory, uploadThumbnail, getArticleDetail, updateArticle, } from "@/service/content/content"; import { getCsrfToken } from "@/service/auth"; import { getUserLevelForAssignments } from "@/service/task"; import { v4 as uuidv4 } from "uuid"; import { Switch } from "@/components/ui/switch"; import { Dialog, DialogClose, DialogContent, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; import { Icon } from "@iconify/react/dist/iconify.js"; import { useTranslations } from "next-intl"; const CustomEditor = dynamic( () => import("@/components/editor/custom-editor"), { ssr: false } ); const imageSchema = z.object({ title: z.string().min(1, { message: "Judul diperlukan" }), description: z .string() .min(2, { message: "Narasi harus lebih dari 2 karakter." }), creatorName: z.string().min(1, { message: "Creator diperlukan" }), }); type ImageSchema = z.infer; type Category = { id: string; name: string }; type Option = { id: string; name: string }; export default function FormImageUpdate() { const MySwal = withReactContent(Swal); const router = useRouter(); const { id } = useParams() as { id: string }; const roleId = getCookiesDecrypt("urie"); const editor = useRef(null); const t = useTranslations("Form"); const [detail, setDetail] = useState(null); const [categories, setCategories] = useState([]); const [selectedTarget, setSelectedTarget] = useState(""); const [tags, setTags] = useState([]); const [files, setFiles] = useState([]); const [thumbnailFile, setThumbnailFile] = useState(null); const [publishedFor, setPublishedFor] = useState([]); const [translatedContent, setTranslatedContent] = useState(""); const [isLoadingTranslate, setIsLoadingTranslate] = useState(false); const [selectedLang, setSelectedLang] = useState<"id" | "en">("id"); const [filePlacements, setFilePlacements] = useState([]); const inputRef = useRef(null); const { getRootProps, getInputProps } = useDropzone({ onDrop: (acceptedFiles) => setFiles((prev) => [ ...prev, ...acceptedFiles.map((f) => Object.assign(f, { id: uuidv4(), preview: URL.createObjectURL(f) }) ), ]), accept: { "image/*": [] }, }); const { control, handleSubmit, setValue, formState: { errors }, getValues, } = useForm({ resolver: zodResolver(imageSchema), }); // 🔹 Get initial data (article + categories) useEffect(() => { async function init() { try { const [resArticle, resCategory] = await Promise.all([ getArticleDetail(Number(id)), listEnableCategory("1"), ]); const article = resArticle?.data?.data; const categoryList: Category[] = resCategory?.data?.data?.content || []; setCategories(categoryList); if (!article) return; // 🧩 Map article to state setDetail(article); setSelectedTarget(String(article.categories?.[0]?.id || "")); setValue("title", article.title); setValue("description", article.htmlDescription); setValue("creatorName", article.createdByName); if (article.tags) setTags(article.tags.split(",").map((t: string) => t.trim())); if (article.publishedFor) setPublishedFor(article.publishedFor.split(",")); if (article.files) setFiles(article.files); } catch (err) { console.error("Error getArticleDetail:", err); } } init(); }, [id, setValue]); const options: Option[] = [ { id: "all", name: "SEMUA" }, { id: "4", name: "UMUM" }, { id: "5", name: "JOURNALIS" }, ]; const handleAddTag = (e: React.KeyboardEvent) => { if (e.key === "Enter" && e.currentTarget.value.trim()) { e.preventDefault(); const newTag = e.currentTarget.value.trim(); if (!tags.includes(newTag)) setTags((prev) => [...prev, newTag]); if (inputRef.current) inputRef.current.value = ""; } }; const handleRemoveTag = (index: number) => setTags((prev) => prev.filter((_, i) => i !== index)); const handleCheckboxChange = (id: string) => { if (id === "all") { const allOptions = options .filter((opt) => opt.id !== "all") .map((opt) => opt.id); setPublishedFor( publishedFor.length === allOptions.length ? [] : allOptions ); } else { setPublishedFor((prev) => prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id] ); } }; const handleDeleteFile = async (fileId: number) => { MySwal.fire({ title: "Hapus file?", text: "Apakah Anda yakin ingin menghapus file ini?", icon: "warning", showCancelButton: true, confirmButtonText: "Ya, hapus", }).then(async (res) => { if (res.isConfirmed) { const response = await deleteFile({ id: fileId }); if (response?.error) return error(response.message); setFiles((prev) => prev.filter((f) => f.id !== fileId)); Swal.fire("Dihapus!", "File berhasil dihapus.", "success"); } }); }; // const save = async (data: ImageSchema) => { // loading(); // const descFinal = // selectedLang === "en" && translatedContent // ? translatedContent // : data.description; // const payload = { // ...data, // id: detail?.id, // title: data.title, // description: htmlToString(descFinal), // htmlDescription: descFinal, // categoryId: selectedTarget, // publishedFor: publishedFor.join(","), // creatorName: data.creatorName, // tags: tags.join(", "), // isYoutube: false, // isInternationalMedia: false, // }; // const res = await createMedia(payload); // if (res?.error) return error(res.message); // if (thumbnailFile) { // const form = new FormData(); // form.append("file", thumbnailFile); // await uploadThumbnail(id, form); // } // close(); // Swal.fire("Sukses", "Artikel berhasil diperbarui.", "success").then(() => { // router.push("/admin/content/image"); // }); // }; // 🔹 ganti fungsi save di FormImageUpdate.tsx const save = async (data: ImageSchema) => { loading(); try { const descFinal = selectedLang === "en" && translatedContent ? translatedContent : data.description; // ✅ payload sesuai ArticlesUpdateRequest const payload = { aiArticleId: detail?.aiArticleId ?? null, categoryIds: selectedTarget ? String(selectedTarget) : "", createdAt: detail?.createdAt ?? new Date().toISOString(), createdById: detail?.createdById ?? null, description: htmlToString(descFinal), htmlDescription: descFinal, isDraft: false, isPublish: true, slug: detail?.slug ?? data.title ?.toLowerCase() .replace(/[^a-z0-9]+/g, "-") .replace(/(^-|-$)+/g, ""), statusId: detail?.statusId ?? 1, tags: tags, title: data.title, typeId: 1, // 1 = image (sesuai struktur kamu) }; console.log("📤 Payload Update Article:", payload); // ✅ pakai updateArticle (PUT /articles/:id) const res = await updateArticle(Number(id), payload); if (res?.error) { error(res.message || "Gagal memperbarui artikel."); return; } // ✅ upload thumbnail jika user ganti gambar if (thumbnailFile) { const form = new FormData(); form.append("file", thumbnailFile); const thumbRes = await uploadThumbnail(id, form); if (thumbRes?.error) { error(thumbRes.message); return; } } close(); Swal.fire({ icon: "success", title: "Sukses", text: "Artikel berhasil diperbarui.", }).then(() => { router.push("/admin/content/image"); }); } catch (err) { close(); error("Terjadi kesalahan saat memperbarui artikel."); console.error("Update error:", err); } }; const onSubmit = (data: ImageSchema) => { MySwal.fire({ title: "Simpan Data", text: "Apakah Anda yakin ingin menyimpan data ini?", icon: "warning", showCancelButton: true, confirmButtonText: "Simpan", }).then((result) => { if (result.isConfirmed) save(data); }); }; return (
{detail && (
{/* Kolom Kiri */}

{t("form-image", { defaultValue: "Form Image" })}

{/* Title */}
( )} /> {errors.title && (

{errors.title.message}

)}
{/* Category */} {/*
*/}
{/* Description */}
( )} /> {errors.description && (

{errors.description.message}

)}
{/* File Upload */}

Drag File

{files.length > 0 && (
{files.map((file, index) => (
{file.fileName

{file.fileName}

Lihat File
))}
)}
{/* Kolom Kanan */}
( )} /> {errors.creatorName && (

{errors.creatorName.message}

)}
{ const file = e.target.files?.[0]; if (file) setThumbnailFile(file); }} /> Thumbnail
{tags.map((tag, i) => ( {tag} ))}
{options.map((opt) => (
o.id !== "all").length : publishedFor.includes(opt.id) } onCheckedChange={() => handleCheckboxChange(opt.id)} />
))}
)}
); }