"use client"; import React, { ChangeEvent, useEffect, useRef, Fragment, 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 { Upload } from "tus-js-client"; import Swal from "sweetalert2"; import withReactContent from "sweetalert2-react-content"; import { redirect, useParams, useRouter } from "next/navigation"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Checkbox } from "@/components/ui/checkbox"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { register } from "module"; import { Switch } from "@/components/ui/switch"; import Cookies from "js-cookie"; import { createMedia, getTagsBySubCategoryId, listEnableCategory, uploadThumbnail, } from "@/service/content/content"; import { uploadThumbnailBlog } from "@/service/blog/blog"; import { Textarea } from "@/components/ui/textarea"; import { generateDataArticle, getDetailArticle, getGenerateKeywords, getGenerateTitle, } from "@/service/content/ai"; import { getCookiesDecrypt } from "@/lib/utils"; import { useDropzone } from "react-dropzone"; import { Icon } from "@iconify/react"; import { CloudUpload, Trash2 } from "lucide-react"; import Image from "next/image"; import { error, loading } from "@/config/swal"; import { Item } from "@radix-ui/react-dropdown-menu"; import { data } from "jquery"; import { options } from "@fullcalendar/core/preact.js"; import dynamic from "next/dynamic"; import { getCsrfToken } from "@/service/auth"; import { Link } from "@/i18n/routing"; import { request } from "http"; import { useTranslations } from "next-intl"; import FileUploader from "../shared/file-uploader"; import { AudioRecorder } from "react-audio-voice-recorder"; import { getTaskTa } from "@/service/task"; import { taskDetail } from "./task-ta-form"; interface FileWithPreview extends File { preview: string; } type Category = { id: string; name: string; }; type Option = { id: string; label: string; }; const CustomEditor = dynamic( () => { return import("@/components/editor/custom-editor"); }, { ssr: false } ); export default function FormTaskTaNew() { const MySwal = withReactContent(Swal); const router = useRouter(); type ImageSchema = z.infer; const t = useTranslations("Form"); const [selectedFiles, setSelectedFiles] = useState([]); const taskId = Cookies.get("taskId"); const scheduleId = Cookies.get("scheduleId"); const scheduleType = Cookies.get("scheduleType"); const roleId = getCookiesDecrypt("urie"); const { id } = useParams() as { id: string }; const [categories, setCategories] = useState([]); const [selectedCategory, setSelectedCategory] = useState(); const [tags, setTags] = useState([]); const [thumbnail, setThumbnail] = useState(null); const [preview, setPreview] = useState(null); const [title, setTitle] = useState(""); const [isLoadingData, setIsLoadingData] = useState(false); const [articleBody, setArticleBody] = useState(""); const [isSwitchOn, setIsSwitchOn] = useState(false); const inputRef = useRef(null); const [imageFiles, setImageFiles] = useState([]); const [videoFiles, setVideoFiles] = useState([]); const [textFiles, setTextFiles] = useState([]); const [audioFiles, setAudioFiles] = useState([]); const [isImageUploadFinish, setIsImageUploadFinish] = useState(false); const [isVideoUploadFinish, setIsVideoUploadFinish] = useState(false); const [isTextUploadFinish, setIsTextUploadFinish] = useState(false); const [isAudioUploadFinish, setIsAudioUploadFinish] = useState(false); const [audioFile, setAudioFile] = useState(null); const [isRecording, setIsRecording] = useState(false); const [links, setLinks] = useState([""]); const [timer, setTimer] = useState(120); const [fileTypeId, setFileTypeId] = useState(""); const [files, setFiles] = useState([]); const [publishedFor, setPublishedFor] = useState([]); const [detail, setDetail] = useState(); const [refresh] = useState(false); const options: Option[] = [ { id: "all", label: "SEMUA" }, { id: "5", label: "UMUM" }, { id: "6", label: "JOURNALIS" }, { id: "7", label: "POLRI" }, { id: "8", label: "KSP" }, ]; const { getRootProps, getInputProps } = useDropzone({ onDrop: (acceptedFiles) => { setFiles(acceptedFiles.map((file) => Object.assign(file))); }, }); const imageSchema = z.object({ title: z.string().optional(), description: z .string() .min(2, { message: "Narasi Penugasan harus lebih dari 2 karakter." }) .or( z.literal(articleBody || "").refine((val) => val.length > 0, { message: "Deskripsi diperlukan.", }) ), // creatorName: z.string().min(1, { message: "Creator diperlukan" }), // tags: z.string().min(1, { message: "Judul diperlukan" }), }); const { control, handleSubmit, getValues, setValue, formState: { errors }, } = useForm({ resolver: zodResolver(imageSchema), }); const handleLinkChange = (index: number, value: string) => { const updatedLinks = [...links]; updatedLinks[index] = value; setLinks(updatedLinks); }; const handleAddRow = () => { setLinks([...links, ""]); }; // Remove a specific link row const handleRemoveRow = (index: number) => { const updatedLinks = links.filter((_: any, i: any) => i !== index); setLinks(updatedLinks); }; const addAudioElement = (blob: Blob) => { const url = URL.createObjectURL(blob); const audio = document.createElement("audio"); audio.src = url; audio.controls = true; document.body.appendChild(audio); // Convert Blob to File and add preview const fileWithPreview: FileWithPreview = Object.assign( new File([blob], "voiceNote.webm", { type: "audio/webm" }), { preview: url } ); // Add to state setAudioFile(fileWithPreview); setAudioFiles((prev) => [...prev, fileWithPreview]); }; const handleDeleteAudio = (index: number) => { setAudioFiles((prev) => prev.filter((_, idx) => idx !== index)); }; 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((prevTags) => [...prevTags, newTag]); // Add new tag if (inputRef.current) { inputRef.current.value = ""; // Clear input field } } } }; const handleRemoveTag = (index: number) => { setTags((prevTags) => prevTags.filter((_, i) => i !== index)); // Remove tag }; const handleRemoveImage = (index: number) => { setSelectedFiles((prevImages) => prevImages.filter((_, i) => i !== index)); }; useEffect(() => { async function initState() { getCategories(); // setVideoActive(fileTypeId == '2'); // getRoles(); } initState(); }, []); const getCategories = async () => { try { const category = await listEnableCategory(fileTypeId); const resCategory: Category[] = category?.data.data.content; setCategories(resCategory); console.log("data category", resCategory); if (scheduleId && scheduleType === "3") { const findCategory = resCategory.find((o) => o.name.toLowerCase().includes("pers rilis") ); if (findCategory) { // setValue("categoryId", findCategory.id); setSelectedCategory(findCategory.id); // Set the selected category const response = await getTagsBySubCategoryId(findCategory.id); setTags(response?.data?.data); } } } catch (error) { console.error("Failed to fetch categories:", error); } }; const handleCheckboxChange = (id: string): void => { if (id === "all") { if (publishedFor.includes("all")) { // Uncheck all checkboxes setPublishedFor([]); } else { // Select all checkboxes setPublishedFor( options .filter((opt: any) => opt.id !== "all") .map((opt: any) => opt.id) ); } } else { const updatedPublishedFor = publishedFor.includes(id) ? publishedFor.filter((item) => item !== id) : [...publishedFor, id]; // Remove "all" if any checkbox is unchecked if (publishedFor.includes("all") && id !== "all") { setPublishedFor(updatedPublishedFor.filter((item) => item !== "all")); } else { setPublishedFor(updatedPublishedFor); } } }; useEffect(() => { async function initState() { if (id) { const response = await getTaskTa(id); const details = response?.data?.data; setDetail(details); // Add more state setting here based on other fields like broadcastType, taskOutput, etc. } } initState(); }, [id, refresh]); const save = async (data: ImageSchema) => { loading(); const finalTags = tags.join(", "); const finalTitle = data.title || detail?.title || ""; const finalDescription = articleBody || data.description; if (!finalDescription.trim()) { MySwal.fire("Error", "Deskripsi tidak boleh kosong.", "error"); return; } let requestData: { assignmentExpertId: any; title: string; description: string; htmlDescription: string; fileTypeId: string; categoryId: any; subCategoryId: any; uploadedBy: string; statusId: string; publishedFor: string; creatorName: string; tags: string; isYoutube: boolean; isInternationalMedia: boolean; attachFromScheduleId?: number; // ✅ Tambahkan properti ini } = { ...data, assignmentExpertId: detail?.id || null, title: finalTitle, description: finalDescription, htmlDescription: finalDescription, fileTypeId: fileTypeId, categoryId: "235", subCategoryId: selectedCategory, uploadedBy: "2b7c8d83-d298-4b19-9f74-b07924506b58", statusId: "1", publishedFor: publishedFor.join(","), creatorName: "Penugasan-Ta", tags: "penugasan-Ta", isYoutube: false, isInternationalMedia: false, }; let id = Cookies.get("idCreate"); if (scheduleId !== undefined) { requestData.attachFromScheduleId = Number(scheduleId); // ✅ Tambahkan nilai ini } if (id == undefined) { const response = await createMedia(requestData); console.log("Form Data Submitted:", requestData); Cookies.set("idCreate", response?.data?.data, { expires: 1 }); id = response?.data?.data; // Upload Thumbnail loading(); if (imageFiles?.length == 0) { setIsImageUploadFinish(true); } imageFiles?.map(async (item: any, index: number) => { await uploadResumableFile(index, String(id), item, "1", "0"); }); if (videoFiles?.length == 0) { setIsVideoUploadFinish(true); } videoFiles?.map(async (item: any, index: number) => { await uploadResumableFile(index, String(id), item, "2", "0"); }); if (textFiles?.length == 0) { setIsTextUploadFinish(true); } textFiles?.map(async (item: any, index: number) => { await uploadResumableFile(index, String(id), item, "3", "0"); }); if (audioFiles?.length == 0) { setIsAudioUploadFinish(true); } audioFiles.map(async (item: FileWithPreview, index: number) => { await uploadResumableFile( index, String(id), item, // Use .file to access the actual File object "4", "0" // Optional: Replace with actual duration if available ); }); } }; const onSubmit = (data: ImageSchema) => { MySwal.fire({ title: "Simpan Data", text: "Apakah Anda yakin ingin menyimpan data ini?", icon: "warning", showCancelButton: true, cancelButtonColor: "#d33", confirmButtonColor: "#3085d6", confirmButtonText: "Simpan", }).then((result) => { if (result.isConfirmed) { save(data); } }); }; async function uploadResumableFile( idx: number, id: string, file: any, fileTypeId: string, duration: string ) { console.log(idx, id, file, fileTypeId, duration); const resCsrf = await getCsrfToken(); const csrfToken = resCsrf?.data?.token; console.log("CSRF TOKEN : ", csrfToken); const headers = { "X-XSRF-TOKEN": csrfToken, }; const upload = new Upload(file, { endpoint: `${process.env.NEXT_PUBLIC_API}/media/file/upload`, headers: headers, retryDelays: [0, 3000, 6000, 12_000, 24_000], chunkSize: 20_000, metadata: { mediaid: id, filename: file.name, contentType: file.type, fileTypeId: fileTypeId, duration, isWatermark: "true", }, onBeforeRequest: function (req) { var xhr = req.getUnderlyingObject(); xhr.withCredentials = true; }, onError: async (e: any) => { console.log("Error upload :", e); error(e); }, onChunkComplete: ( chunkSize: any, bytesAccepted: any, bytesTotal: any ) => { // const uploadPersen = Math.floor((bytesAccepted / bytesTotal) * 100); // progressInfo[idx].percentage = uploadPersen; // counterUpdateProgress++; // console.log(counterUpdateProgress); // setProgressList(progressInfo); // setCounterProgress(counterUpdateProgress); }, onSuccess: async () => { // uploadPersen = 100; // progressInfo[idx].percentage = 100; // counterUpdateProgress++; // setCounterProgress(counterUpdateProgress); successTodo(); if (fileTypeId == "1") { setIsImageUploadFinish(true); } else if (fileTypeId == "2") { setIsVideoUploadFinish(true); } if (fileTypeId == "3") { setIsTextUploadFinish(true); } if (fileTypeId == "4") { setIsAudioUploadFinish(true); } }, }); upload.start(); } useEffect(() => { successTodo(); }, [ isImageUploadFinish, isVideoUploadFinish, isAudioUploadFinish, isTextUploadFinish, ]); function successTodo() { if ( isImageUploadFinish && isVideoUploadFinish && isAudioUploadFinish && isTextUploadFinish ) { successSubmit("/in/contributor/task-ta"); } } const successSubmit = (redirect: string) => { MySwal.fire({ title: "Sukses", text: "Data berhasil disimpan.", icon: "success", confirmButtonColor: "#3085d6", confirmButtonText: "OK", }).then(() => { router.push(redirect); }); }; // function successTodo() { // let counter = 0; // for (const element of progressInfo) { // if (element.percentage == 100) { // counter++; // } // } // if (counter == progressInfo.length) { // setIsStartUpload(false); // // hideProgress(); // Cookies.remove("idCreate"); // successSubmit("in/contributor/content/image/"); // } // } const handleImageChange = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (file) { setThumbnail(file); console.log("Selected Thumbnail:", file); } if (file) { setPreview(URL.createObjectURL(file)); } }; const renderFilePreview = (file: FileWithPreview) => { if (file.type.startsWith("image")) { return ( {file.name} ); } else { return ; } }; const handleRemoveFile = (file: FileWithPreview) => { const uploadedFiles = files; const filtered = uploadedFiles.filter((i) => i.name !== file.name); setFiles([...filtered]); }; const fileList = files.map((file) => (
{renderFilePreview(file)}
{file.name}
{Math.round(file.size / 100) / 10 > 1000 ? ( <>{(Math.round(file.size / 100) / 10000).toFixed(1)} ) : ( <>{(Math.round(file.size / 100) / 10).toFixed(1)} )} {" kb"}
)); const handleRemoveAllFiles = () => { setFiles([]); }; useEffect(() => { // Jika input title kosong, isi dengan hasil generate title if (!getValues("title") && title) { setValue("title", title); } }, [title, getValues, setValue]); return (
{detail !== undefined ? (
{/* Input Title */}
( )} /> {errors.title?.message && (

{errors.title.message}

)}
{/*
*/}
isLoadingData ? (

Loading Proses Data...

) : ( ) } /> {errors.description?.message && (

{errors.description.message}

)}
{fileTypeId === "2" && (
setVideoFiles(files)} />
)} {fileTypeId === "1" && (
setImageFiles(files)} />
)} {fileTypeId === "3" && (
setTextFiles(files)} />
)} {fileTypeId === "4" && (
setAudioFiles((prev) => [...prev, ...files]) } className="mt-2" />
)} {fileTypeId === "4" && audioFiles?.map((audio: any, idx: any) => (

{t("voice-note", { defaultValue: "Voice Note" })}

))} {isRecording && (

Recording... {timer} seconds remaining

)}
{/*
*/} {/*
( )} /> {errors.creatorName?.message && (

{errors.creatorName.message}

)}
{tags.map((tag, index) => ( {tag}{" "} ))}
{options.map((option) => (
opt.id !== "all") .length : publishedFor.includes(option.id) } onCheckedChange={() => handleCheckboxChange(option.id) } />
))}
*/} {/*
*/}
) : ( "" )}
); }