From eaa1628fde05a4a9d8316a73d1208a9e4ef0e13c Mon Sep 17 00:00:00 2001 From: Sabda Yagra Date: Sat, 8 Nov 2025 23:55:07 +0700 Subject: [PATCH] fix: file placements in spit --- .../management-user/internal/create/page.tsx | 12 +- components/form/content/image-update-form.tsx | 5706 +++++++++++------ components/form/content/spit-convert-form.tsx | 1302 +++- 3 files changed, 5030 insertions(+), 1990 deletions(-) diff --git a/app/[locale]/(protected)/admin/management-user/internal/create/page.tsx b/app/[locale]/(protected)/admin/management-user/internal/create/page.tsx index dd7e7b97..9ed5150e 100644 --- a/app/[locale]/(protected)/admin/management-user/internal/create/page.tsx +++ b/app/[locale]/(protected)/admin/management-user/internal/create/page.tsx @@ -289,7 +289,17 @@ export default function CreateUserForm() { }; if (data.role == "OPT-ID") { - req.handledSocialMedia = data?.sns ? data.sns.join(",") : ""; + // req.handledSocialMedia = data?.sns ? data.sns.join(",") : ""; + if (data.role == "OPT-ID") { + let snsValue = data?.sns ? data.sns.join(",") : ""; + + // ✅ Jika hanya 1 value → tambahkan koma agar backend tidak error + if (data?.sns && data.sns.length === 1) { + snsValue = snsValue + ","; + } + + req.handledSocialMedia = snsValue; + } } if (data.role == "KUR-ID") { diff --git a/components/form/content/image-update-form.tsx b/components/form/content/image-update-form.tsx index d3538375..cdfe338b 100644 --- a/components/form/content/image-update-form.tsx +++ b/components/form/content/image-update-form.tsx @@ -29,9 +29,7 @@ import Cookies from "js-cookie"; import { createMedia, deleteFile, - deleteMedia, getTagsBySubCategoryId, - listEnableCategory, listEnableCategoryNew, updateFilePlacements, uploadThumbnail, @@ -61,877 +59,365 @@ import { getCookiesDecrypt } from "@/lib/utils"; import { translateText } from "@/service/content/ai"; import { close } from "@/config/swal"; +// ================== Types & Schema ================== + const imageSchema = z.object({ title: z.string().min(1, { message: "Judul diperlukan" }), description: z .string() .min(2, { message: "Narasi Penugasan harus lebih dari 2 karakter." }), creatorName: z.string().min(1, { message: "Creator diperlukan" }), - // tags: z.string().min(1, { message: "Judul diperlukan" }), }); +type ImageSchema = z.infer; -type Category = { - id: string; - name: string; -}; +type Category = { id: string; name: string }; -type PlacementType = "all" | "mabes" | "polda" | "international" | string; - -interface FilePlacement { - mediaFileId: number; - placements?: PlacementType[]; -} - -interface TempFileItem { - id: number | string; -} +type PlacementType = + | "all" + | "mabes" + | "polda" + | "international" + | "wilayah" + | "nasional" + | "satker" + | string; type Detail = { id: string; title: string; description: string; - htmldescription: string; + htmlDescription: string; slug: string; categoryId: number; - category: { - id: string; - name: string; - }; + category: { id: string; name: string }; publishedFor: string; - - publishedForObject: { - id: number; - name: string; - }; + publishedForObject: { id: number; name: string }; creatorName: string; categoryName: string; thumbnailLink: string; tags: string; + files?: Array<{ + id: number | string; + fileName: string; + size: number; + thumbnailFileUrl?: string; + url: string; + placements?: string; // "all,mabes,polda,..." + customLocationPlacements?: string; // "2,6,7" + }>; }; -type Option = { - id: string; - name: string; -}; +type Option = { id: string; name: string }; + interface Destination { id: string; name: string; - subDestination?: SubDestination[]; + levelNumber?: number; + subDestination?: Array<{ id: string; name: string }>; } -interface SubDestination { - id: string; - name: string; -} - -const CustomEditor = dynamic( - () => { - return import("@/components/editor/custom-editor"); - }, - { ssr: false } -); - interface FileWithPreview extends File { id: string; preview: string; } +const CustomEditor = dynamic( + () => import("@/components/editor/custom-editor"), + { ssr: false } +); + export default function FormImageUpdate() { const MySwal = withReactContent(Swal); const router = useRouter(); const { id } = useParams() as { id: string }; - const editor = useRef(null); + const t = useTranslations("Form"); const roleId = getCookiesDecrypt("urie"); - type ImageSchema = z.infer; let progressInfo: any = []; let counterUpdateProgress = 0; const [progressList, setProgressList] = useState([]); let uploadPersen = 0; - - // const isDetailOfRegionShowed = false; - const [isDetailOfRegionShowed, setIsDetailOfRegionShowed] = useState(false); - const [isStartUpload, setIsStartUpload] = useState(false); const [counterProgress, setCounterProgress] = useState(0); - const t = useTranslations("Form"); - const [selectedFiles, setSelectedFiles] = useState([]); - const taskId = Cookies.get("taskId"); - const scheduleId = Cookies.get("scheduleId"); - const scheduleType = Cookies.get("scheduleType"); const [categories, setCategories] = useState([]); - const [selectedCategory, setSelectedCategory] = useState(); - const [tags, setTags] = useState([]); - const [detail, setDetail] = useState(); - const [refresh, setRefresh] = useState(false); - const [selectedPublishers, setSelectedPublishers] = useState([]); - const [articleBody, setArticleBody] = useState(""); - const [files, setFiles] = useState([]); - const [filesTemp, setFilesTemp] = useState([]); - const [publishedFor, setPublishedFor] = useState([]); - const [thumbnailFile, setThumbnailFile] = useState(null); - const inputRef = useRef(null); - const [isLoadingTranslate, setIsLoadingTranslate] = useState(false); - const [translatedContent, setTranslatedContent] = React.useState(""); - const [selectedLang, setSelectedLang] = React.useState<"id" | "en">("id"); - - // 🔹 State untuk translate judul - const [translatedTitle, setTranslatedTitle] = useState(""); - const [isLoadingTranslateTitle, setIsLoadingTranslateTitle] = useState(false); - - const handleThumbnailChange = (e: React.ChangeEvent) => { - const file = e.target.files?.[0]; - if (file) { - setThumbnailFile(file); - } - }; - const [fileUnitSelections, setFileUnitSelections] = useState< - Array<{ - semua: boolean; - nasional: boolean; - wilayah: boolean; - international: boolean; - polda: boolean; - satker: boolean; - }> - >([]); - // State global untuk kompatibilitas (akan dihapus nanti) - const [unitSelection, setUnitSelection] = useState({ - semua: false, - nasional: false, - wilayah: false, - international: false, - polda: false, - satker: false, - }); - const [checkedLevels, setCheckedLevels] = useState>(new Set()); const [listDest, setListDest] = useState([]); - const [isLoading, setIsLoading] = useState(false); - const [expandedPolda, setExpandedPolda] = useState>( + const [expandedPolda, setExpandedPolda] = useState>( {} ); + const [detail, setDetail] = useState(); + const [selectedTarget, setSelectedTarget] = useState(); + const [publishedFor, setPublishedFor] = useState([]); + const [tags, setTags] = useState([]); + const [thumbnailFile, setThumbnailFile] = useState(null); + const [translatedContent, setTranslatedContent] = useState(""); + const [isLoadingTranslate, setIsLoadingTranslate] = useState(false); + const [translatedTitle, setTranslatedTitle] = useState(""); + const [isLoadingTranslateTitle, setIsLoadingTranslateTitle] = useState(false); + const inputRef = useRef(null); + const [files, setFiles] = useState<(FileWithPreview | any)[]>([]); + // fileTypeId: image + const fileTypeId = "1"; + const [filePlacements, setFilePlacements] = useState< + Record + >({}); const [fileCheckedLevels, setFileCheckedLevels] = useState< - Array> - >([]); + Record> + >({}); + const [fileUnitSelections, setFileUnitSelections] = useState< + Record< + string, + { + semua: boolean; + nasional: boolean; + wilayah: boolean; + international: boolean; + polda: boolean; + satker: boolean; + } + > + >({}); + const [isDetailOfRegionShowed, setIsDetailOfRegionShowed] = useState(false); + const [checkedLevels, setCheckedLevels] = useState>(new Set()); + const [isLoading, setIsLoading] = useState(false); const [isUpdatingFromMainCheckbox, setIsUpdatingFromMainCheckbox] = useState(false); const [mainCheckboxChangeType, setMainCheckboxChangeType] = useState(""); - useEffect(() => { - async function fetchPoldaPolres() { - setIsLoading(true); - try { - const response = await getUserLevelForAssignments(); - setListDest(response?.data?.data.list); - const initialExpandedState = response?.data?.data.list.reduce( - (acc: any, polda: any) => { - acc[polda.id] = false; - return acc; - }, - {} - ); - setExpandedPolda(initialExpandedState); - console.log("polres", initialExpandedState); - } catch (error) { - console.error("Error fetching Polda/Polres data:", error); - } finally { - setIsLoading(false); - } - } - fetchPoldaPolres(); - }, []); - - // useEffect untuk sinkronisasi checkbox modal dengan checkbox utama - useEffect(() => { - if ( - listDest.length > 0 && - isUpdatingFromMainCheckbox && - mainCheckboxChangeType - ) { - syncModalWithMainCheckbox(); - } - }, [isUpdatingFromMainCheckbox, mainCheckboxChangeType]); - - // useEffect untuk update checkbox utama ketika pilihan modal berubah - useEffect(() => { - if (!isUpdatingFromMainCheckbox && listDest.length > 0) { - updateMainCheckboxFromModalLegacy(); - } - }, [checkedLevels, isUpdatingFromMainCheckbox]); - - // Fungsi untuk update checkbox utama berdasarkan checkbox modal (global/legacy) - const updateMainCheckboxFromModalLegacy = () => { - if (!isUpdatingFromMainCheckbox && listDest.length > 0) { - // Hitung item yang dipilih berdasarkan checkedLevels - const checkedPoldaCount = listDest.filter( - (item: any) => - item.levelNumber === 2 && - item.name !== "SATKER POLRI" && - checkedLevels.has(Number(item.id)) - ).length; - - const satkerItem: any = listDest.find( - (item: any) => item.name === "SATKER POLRI" - ); - const checkedSatkerCount = satkerItem - ? (checkedLevels.has(Number(satkerItem.id)) ? 1 : 0) + - (satkerItem.subDestination?.filter((sub: any) => - checkedLevels.has(Number(sub.id)) - ).length || 0) - : 0; - - // Checkbox aktif jika ADA item yang dipilih dalam kategori tersebut - const hasSelectedPolda = checkedPoldaCount > 0; - const hasSelectedSatker = checkedSatkerCount > 0; - - // Update unitSelection berdasarkan yang dipilih di modal - setUnitSelection((prev) => { - const newState = { ...prev }; - - // Update individual checkboxes - newState.polda = hasSelectedPolda; - newState.satker = hasSelectedSatker; - - // Update checkbox "semua" berdasarkan semua checkbox yang aktif - newState.semua = - newState.nasional && - newState.wilayah && - newState.international && - hasSelectedPolda && - hasSelectedSatker; - - return newState; - }); - } - }; - - // Fungsi untuk sinkronisasi checkbox modal dengan checkbox utama - const syncModalWithMainCheckbox = () => { - if (isUpdatingFromMainCheckbox) { - const newCheckedLevels = new Set(checkedLevels); - - // Handle checklist actions - menambahkan semua item ke modal - if (mainCheckboxChangeType === "polda_checked") { - // Checklist semua polda - listDest.forEach((item: any) => { - if (item.levelNumber === 2 && item.name !== "SATKER POLRI") { - newCheckedLevels.add(Number(item.id)); - } - }); - } else if (mainCheckboxChangeType === "satker_checked") { - // Checklist satker - const satkerItem: any = listDest.find( - (item: any) => item.name === "SATKER POLRI" - ); - if (satkerItem) { - newCheckedLevels.add(Number(satkerItem.id)); - // Checklist semua sub-item yang ada di bawah SATKER (bukan POLRES) - if (satkerItem.subDestination) { - satkerItem.subDestination.forEach((sub: any) => { - newCheckedLevels.add(Number(sub.id)); - }); - } - } - } else if (mainCheckboxChangeType === "semua_checked") { - // Checklist semua item - listDest.forEach((item: any) => { - newCheckedLevels.add(Number(item.id)); - // Checklist semua sub-item di bawah setiap item - if (item.subDestination) { - item.subDestination.forEach((sub: any) => { - newCheckedLevels.add(Number(sub.id)); - }); - } - }); - } else if (mainCheckboxChangeType === "polda_unchecked") { - // Clear polda dari checkedLevels, tapi jangan hapus SATKER POLRI - listDest.forEach((item: any) => { - if (item.levelNumber === 2 && item.name !== "SATKER POLRI") { - newCheckedLevels.delete(Number(item.id)); - } - }); - } else if (mainCheckboxChangeType === "satker_unchecked") { - // Clear satker dan semua sub-item di bawahnya dari checkedLevels - const satkerItem: any = listDest.find( - (item: any) => item.name === "SATKER POLRI" - ); - if (satkerItem) { - newCheckedLevels.delete(Number(satkerItem.id)); - if (satkerItem.subDestination) { - satkerItem.subDestination.forEach((sub: any) => { - newCheckedLevels.delete(Number(sub.id)); - }); - } - } - } else if (mainCheckboxChangeType === "semua_unchecked") { - // Clear semua - newCheckedLevels.clear(); - } - - setCheckedLevels(newCheckedLevels); - - // Reset flag setelah sinkronisasi selesai - setIsUpdatingFromMainCheckbox(false); - setMainCheckboxChangeType(""); - } - }; - - // Fungsi untuk mengupdate state individual file - const handleFileUnitChange = ( - fileIndex: number, - key: keyof typeof unitSelection, - value: boolean - ) => { - setFileUnitSelections((prev) => { - const newSelections = [...prev]; - const currentSelection = { ...newSelections[fileIndex] }; - - if (key === "semua") { - // Jika klik Semua, set semua value ke true/false - currentSelection.semua = value; - currentSelection.nasional = value; - currentSelection.wilayah = value; - currentSelection.international = value; - currentSelection.polda = value; - currentSelection.satker = value; - - // Update fileCheckedLevels untuk sinkronisasi dengan modal - setFileCheckedLevels((prevLevels) => { - const newArray = [...prevLevels]; - const currentFileLevels = new Set( - newArray[fileIndex] || new Set() - ); - - if (value) { - // Checklist semua item di modal - listDest.forEach((item: any) => { - currentFileLevels.add(Number(item.id)); - if (item.subDestination) { - item.subDestination.forEach((sub: any) => { - currentFileLevels.add(Number(sub.id)); - }); - } - }); - } else { - // Unchecklist semua item di modal - currentFileLevels.clear(); - } - - newArray[fileIndex] = currentFileLevels; - return newArray; - }); - } else { - // Jika wilayah dicentang, auto centang POLDA, SATKER - if (key === "wilayah") { - currentSelection.wilayah = value; - setIsDetailOfRegionShowed(value); - - - if (value) { - // Ketika wilayah dicentang, auto centang POLDA, SATKER - currentSelection.polda = true; - currentSelection.satker = true; - - // Update fileCheckedLevels untuk mengisi semua POLDA dan SATKER POLRI ketika wilayah dicentang - setFileCheckedLevels((prevLevels) => { - const newArray = [...prevLevels]; - const currentFileLevels = new Set( - newArray[fileIndex] || new Set() - ); - - // Checklist semua POLDA di modal - listDest.forEach((item: any) => { - if (item.levelNumber === 2 && item.name !== "SATKER POLRI") { - currentFileLevels.add(Number(item.id)); - } - }); - - // Checklist SATKER POLRI dan semua sub-itemsnya - const satkerItem = listDest.find( - (item: any) => item.name === "SATKER POLRI" - ); - if (satkerItem) { - currentFileLevels.add(Number(satkerItem.id)); - // Checklist semua sub-items di bawah SATKER POLRI - if (satkerItem.subDestination) { - satkerItem.subDestination.forEach((sub: any) => { - currentFileLevels.add(Number(sub.id)); - }); - } - } - - newArray[fileIndex] = currentFileLevels; - return newArray; - }); - } else { - // Ketika wilayah di-uncheck, uncheck POLDA, SATKER dan hapus data POLDA dari fileCheckedLevels - currentSelection.polda = false; - currentSelection.satker = false; - - // Update fileCheckedLevels untuk menghapus semua POLDA dan SATKER POLRI ketika wilayah di-uncheck - setFileCheckedLevels((prevLevels) => { - const newArray = [...prevLevels]; - const currentFileLevels = new Set( - newArray[fileIndex] || new Set() - ); - - // Hapus semua POLDA dari modal - listDest.forEach((item: any) => { - if (item.levelNumber === 2 && item.name !== "SATKER POLRI") { - currentFileLevels.delete(Number(item.id)); - } - }); - - // Hapus SATKER POLRI dan semua sub-itemsnya - const satkerItem = listDest.find( - (item: any) => item.name === "SATKER POLRI" - ); - if (satkerItem) { - currentFileLevels.delete(Number(satkerItem.id)); - // Hapus semua sub-items di bawah SATKER POLRI - if (satkerItem.subDestination) { - satkerItem.subDestination.forEach((sub: any) => { - currentFileLevels.delete(Number(sub.id)); - }); - } - } - - newArray[fileIndex] = currentFileLevels; - return newArray; - }); - } - } else { - // Update salah satu saja - currentSelection[key] = value; - } - - // Cek apakah semua selain "semua" sudah dicentang - const allChecked = [ - "nasional", - "wilayah", - "international", - "polda", - "satker", - ].every((k) => currentSelection[k as keyof typeof unitSelection]); - - currentSelection.semua = allChecked; - } - - newSelections[fileIndex] = currentSelection; - return newSelections; - }); - }; - - // Fungsi untuk mengupdate checklist levels untuk file tertentu - const handleFileCheckboxChangePlacement = ( - fileIndex: number, - levelId: number - ) => { - setFileCheckedLevels((prev) => { - const newArray = [...prev]; - const currentFileLevels = new Set(newArray[fileIndex]); - const isCurrentlyChecked = currentFileLevels.has(levelId); - - if (isCurrentlyChecked) { - currentFileLevels.delete(levelId); - - // Jika ini adalah POLDA yang di-unchecklist, unchecklist juga semua polres di bawahnya - const poldaItem = listDest.find( - (item: any) => Number(item.id) === levelId - ) as any; - if ( - poldaItem && - poldaItem.subDestination && - poldaItem.name !== "SATKER POLRI" - ) { - poldaItem.subDestination.forEach((polres: any) => { - currentFileLevels.delete(Number(polres.id)); - }); - } - - // Jika ini adalah SATKER POLRI yang di-unchecklist, unchecklist juga semua sub-item di bawahnya - if (poldaItem && poldaItem.name === "SATKER POLRI") { - poldaItem.subDestination?.forEach((subItem: any) => { - currentFileLevels.delete(Number(subItem.id)); - }); - } - } else { - currentFileLevels.add(levelId); - - // Jika ini adalah SATKER POLRI yang di-checklist, checklist juga semua sub-item di bawahnya - const satkerItem = listDest.find( - (item: any) => Number(item.id) === levelId - ) as any; - if (satkerItem && satkerItem.name === "SATKER POLRI") { - // Checklist semua sub-item di bawah SATKER POLRI (bukan POLRES) - satkerItem.subDestination?.forEach((subItem: any) => { - currentFileLevels.add(Number(subItem.id)); - }); - } - } - - newArray[fileIndex] = currentFileLevels; - - // Update checkbox utama berdasarkan perubahan di modal - // Pindahkan ke sini agar state sudah ter-update - setTimeout(() => updateMainCheckboxFromModal(fileIndex), 0); - - return newArray; - }); - }; - - // Fungsi untuk mengupdate checkbox utama berdasarkan checklist di modal - const updateMainCheckboxFromModal = (fileIndex: number) => { - setFileUnitSelections((prev) => { - const newSelections = [...prev]; - const currentSelection = { ...newSelections[fileIndex] }; - const currentFileLevels = fileCheckedLevels[fileIndex]; - - if (!currentFileLevels) return prev; - - // Hitung total POLDA yang ada (bukan SATKER POLRI) - const totalPoldaCount = listDest.filter( - (item: any) => item.levelNumber === 2 && item.name !== "SATKER POLRI" - ).length; - - // Hitung berapa banyak POLDA yang ter-checklist (bukan SATKER POLRI) - const checkedPoldaCount = listDest.reduce((total: number, item: any) => { - if ( - item.levelNumber === 2 && - item.name !== "SATKER POLRI" && - currentFileLevels.has(Number(item.id)) - ) { - return total + 1; - } - return total; - }, 0); - - // Cek apakah SATKER POLRI ter-checklist - const satkerItem = listDest.find( - (item: any) => item.name === "SATKER POLRI" - ); - const isSatkerChecked = - satkerItem && currentFileLevels.has(Number(satkerItem.id)); - - // Update checkbox berdasarkan kondisi - // POLDA aktif jika ada minimal 1 POLDA ter-checklist - currentSelection.polda = checkedPoldaCount > 0; - currentSelection.satker = Boolean(isSatkerChecked); - - // Update checkbox "semua" berdasarkan semua checkbox yang aktif - currentSelection.semua = - currentSelection.nasional && - currentSelection.wilayah && - currentSelection.international && - currentSelection.polda && - currentSelection.satker; - - newSelections[fileIndex] = currentSelection; - return newSelections; - }); - }; - - const toggleExpand = (id: number) => { - setExpandedPolda((prev) => ({ - ...prev, - [id]: !prev[id], - })); - }; - - // Fungsi untuk menangani "Pilih Semua" sub-items di bawah SATKER POLRI - const handleSelectAllSubItems = (fileIndex: number, polda: any) => { - setFileCheckedLevels((prev) => { - const newArray = [...prev]; - const currentFileLevels = new Set(newArray[fileIndex]); - - // Cek apakah semua sub-items sudah ter-checklist - const allSubItemsChecked = polda.subDestination?.every((sub: any) => - currentFileLevels.has(Number(sub.id)) - ); - - if (allSubItemsChecked) { - // Jika semua sudah ter-checklist, unchecklist semuanya - polda.subDestination?.forEach((sub: any) => { - currentFileLevels.delete(Number(sub.id)); - }); - } else { - // Jika belum semua ter-checklist, checklist semuanya - // Checklist SATKER POLRI juga jika belum ter-checklist - if (!currentFileLevels.has(Number(polda.id))) { - currentFileLevels.add(Number(polda.id)); - } - // Checklist semua sub-items - polda.subDestination?.forEach((sub: any) => { - currentFileLevels.add(Number(sub.id)); - }); - } - - newArray[fileIndex] = currentFileLevels; - - // Update checkbox utama berdasarkan perubahan di modal - setTimeout(() => updateMainCheckboxFromModal(fileIndex), 0); - - return newArray; - }); - }; - - const options: Option[] = [ - { id: "all", name: "SEMUA" }, - { id: "5", name: "UMUM" }, - { id: "6", name: "JOURNALIS" }, - { id: "7", name: "POLRI" }, - { id: "8", name: "KSP" }, - ]; - - const [selectedTarget, setSelectedTarget] = useState( - detail?.category.id - ); - // const [unitSelection, setUnitSelection] = useState({ - // allUnit: false, - // mabes: false, - // polda: false, - // polres: false, - // }); - - let fileTypeId = "1"; - - // const { getRootProps, getInputProps } = useDropzone({ - // onDrop: (acceptedFiles) => { - // // setFiles(acceptedFiles.map((file) => Object.assign(file))); - // setFiles((prevFiles) => [ - // ...prevFiles, - // ...acceptedFiles.map((file) => - // Object.assign(file, { - // preview: URL.createObjectURL(file), - // }) - // ), - // ]); - // }, - // accept: { - // "image/*": [], - // }, - // }); - const { getRootProps, getInputProps } = useDropzone({ - onDrop: (acceptedFiles) => { - setFiles((prevFiles) => [ - ...prevFiles, - ...acceptedFiles.map((file) => - Object.assign(file, { - id: uuidv4(), // generate unique id - preview: URL.createObjectURL(file), - }) - ), - ]); - }, - accept: { - "image/*": [], - }, - }); - const { control, handleSubmit, setValue, getValues, formState: { errors }, - } = useForm({ - resolver: zodResolver(imageSchema), + } = useForm({ resolver: zodResolver(imageSchema) }); + + // dropzone + const { getRootProps, getInputProps } = useDropzone({ + onDrop: (acceptedFiles) => { + setFiles((prevFiles) => [ + ...prevFiles, + ...acceptedFiles.map((file) => + Object.assign(file, { + id: uuidv4(), + preview: URL.createObjectURL(file), + }) + ), + ]); + }, + accept: { "image/*": [] }, }); - useEffect(() => { - async function initState() { - getCategories(); - } - - initState(); - }, []); - - 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]); - if (inputRef.current) { - inputRef.current.value = ""; - } - } - } + const toFileId = (f: any): string => String(f?.id ?? ""); + const ensureFileUnit = (fid: string) => { + setFileUnitSelections((prev) => { + if (prev[fid]) return prev; + return { + ...prev, + [fid]: { + semua: false, + nasional: false, + wilayah: false, + international: false, + polda: false, + satker: false, + }, + }; + }); }; - - const handleRemoveTag = (index: number) => { - setTags((prevTags) => prevTags.filter((_, i) => i !== index)); + const ensureFilePlacement = (fid: string) => { + setFilePlacements((prev) => (prev[fid] ? prev : { ...prev, [fid]: [] })); }; - - const handleEditTag = (index: number, newValue: string) => { - setTags((prevTags) => - prevTags.map((tag, i) => (i === index ? newValue : tag)) + const ensureFileCheckedLevels = (fid: string) => { + setFileCheckedLevels((prev) => + prev[fid] ? prev : { ...prev, [fid]: new Set() } ); }; - const getCategories = async () => { - try { - const category = await listEnableCategoryNew(fileTypeId); - const resCategory: Category[] = category?.data?.data?.content; + const normalizePlacementsForAPI = (arr: string[]): PlacementType[] => { + return Array.from( + new Set( + arr.map((v) => { + if (v === "nasional") return "mabes"; + if (v === "wilayah") return "polda"; + if (v === "semua") return "all"; + return v; + }) + ) + ) as PlacementType[]; + }; - 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); - const response = await getTagsBySubCategoryId(findCategory.id); - setTags(response?.data?.data); - } - } - } catch (error) { - console.error("Failed to fetch categories:", error); - } + const toggleExpand = (idStr: string) => { + setExpandedPolda((prev) => ({ ...prev, [idStr]: !prev[idStr] })); }; useEffect(() => { - async function initState() { - if (id) { - const response = await detailMedia(id); - const details = response?.data?.data; - - setDetail(details); - - setSelectedTarget(String(details.category.id)); - setTempFile(details?.files); - - setValue("title", details.title); - setValue("description", details.htmlDescription); - setValue("creatorName", details.creatorName); - - setTimeout(() => { - setValue("title", details.title); - setValue("description", details.htmlDescription); - setValue("creatorName", details.creatorName); - }, 500); - - if (details?.files) { - const formattedFiles = details.files.map((file: any) => ({ - ...file, - id: file.id, - fileName: file.fileName, - size: file.size, - thumbnailFileUrl: file.thumbnailFileUrl, - url: file.url, - })); - - setFiles(formattedFiles); - - // Inisialisasi filePlacements dari detail - const initialFilePlacements = details.files.map((file: any) => { - if (file.placements) { - // Map dari format backend ke format internal - const mappedPlacements = file.placements - .split(",") - .map((p: string) => { - const trimmed = p.trim(); - switch (trimmed) { - case "all": - return "all"; - case "mabes": - return "nasional"; - case "polda": - return "wilayah"; - case "satker": - return "satker"; - case "international": - return "international"; - default: - return trimmed; - } - }); - return mappedPlacements; - } - return []; - }); - setFilePlacements(initialFilePlacements); - - // Inisialisasi fileCheckedLevels dari detail - const initialFileCheckedLevels = details.files.map((file: any) => { - if (file.customLocationPlacements) { - const levelIds = file.customLocationPlacements - .split(",") - .map((id: string) => Number(id.trim())) - .filter((id: number) => !isNaN(id)); - return new Set(levelIds); - } - return new Set(); - }); - setFileCheckedLevels(initialFileCheckedLevels); - - // Inisialisasi fileUnitSelections dari detail - const initialFileUnitSelections = details.files.map((file: any) => { - const selection = { - semua: false, - nasional: false, - wilayah: false, - international: false, - polda: false, - satker: false, - }; - - if (file.placements) { - const placements = file.placements - .split(",") - .map((p: string) => p.trim()); - - // Map dari format backend ke checkbox - if (placements.includes("all")) { - selection.semua = true; - selection.nasional = true; - selection.wilayah = true; - selection.international = true; - selection.polda = true; - selection.satker = true; - } else { - if (placements.includes("mabes")) { - selection.nasional = true; - } - if (placements.includes("wilayah")) { - selection.wilayah = true; - } - if (placements.includes("polda")) { - selection.polda = true; - selection.wilayah = true; // Auto-check wilayah when polda is present - } - if (placements.includes("satker")) { - selection.satker = true; - selection.wilayah = true; // Auto-check wilayah when satker is present - } - if (placements.includes("international")) { - selection.international = true; - } - } - } - - return selection; - }); - setFileUnitSelections(initialFileUnitSelections); - } - - if (details?.publishedFor) { - // Split string "7" to an array ["7"] if needed - setPublishedFor(details.publishedFor.split(",")); - } - - if (details?.tags) { - setTags(details.tags.split(",").map((tag: string) => tag.trim())); - } + (async () => { + setIsLoading(true); + try { + const resp = await getUserLevelForAssignments(); + const list = resp?.data?.data?.list || []; + setListDest(list); + const init: Record = {}; + list.forEach((p: any) => (init[String(p.id)] = false)); + setExpandedPolda(init); + } catch (e) { + console.error("Error fetching destinations", e); + } finally { + setIsLoading(false); } - } - initState(); + })(); + }, []); + + useEffect(() => { + (async () => { + try { + const category = await listEnableCategoryNew(fileTypeId); + const resCategory: Category[] = category?.data?.data?.content || []; + setCategories(resCategory); + } catch (e) { + console.error("Failed to fetch categories", e); + } + })(); + }, []); + + useEffect(() => { + (async () => { + if (!id) return; + const response = await detailMedia(id); + const details: Detail = response?.data?.data; + setDetail(details); + + // form defaults + setValue("title", details.title); + setValue("description", details.htmlDescription); + setValue("creatorName", details.creatorName); + setSelectedTarget(String(details.category.id)); + setPublishedFor( + details?.publishedFor ? details.publishedFor.split(",") : [] + ); + + setTags( + details?.tags + ? details.tags + .split(",") + .map((s) => s.trim()) + .filter(Boolean) + : [] + ); + + // files & initial map states + const formattedFiles = (details.files || []).map((file) => ({ + ...file, + id: file.id, + fileName: file.fileName, + size: file.size, + thumbnailFileUrl: file.thumbnailFileUrl, + url: file.url, + })); + setFiles(formattedFiles); + + // init maps based on details + const nextPlacements: Record = {}; + const nextCheckedLevels: Record> = {}; + const nextUnitSel: Record< + string, + { + semua: boolean; + nasional: boolean; + wilayah: boolean; + international: boolean; + polda: boolean; + satker: boolean; + } + > = {}; + + formattedFiles.forEach((f: any) => { + const fid = toFileId(f); + + // placements: backend uses "all,mabes,polda,international,satker?" + const backend = (f.placements || "") + .split(",") + .map((s: string) => s.trim()) + .filter(Boolean); + // map to UI terms + const uiP: string[] = []; + backend.forEach((p: string) => { + if (p === "all") uiP.push("all"); + else if (p === "mabes") uiP.push("nasional"); + else if (p === "polda") { + uiP.push("wilayah"); + uiP.push("polda"); + } else if (p === "international") uiP.push("international"); + else if (p === "satker") { + uiP.push("wilayah"); + uiP.push("satker"); + } + }); + nextPlacements[fid] = Array.from(new Set(uiP)); + + // custom levels + const setIds = new Set(); + if (f.customLocationPlacements) { + f.customLocationPlacements + .split(",") + .map((s: string) => Number(s.trim())) + .filter((n: any) => !isNaN(n)) + .forEach((n: any) => setIds.add(n)); + } + nextCheckedLevels[fid] = setIds; + + // unit selection ticks + const unit = { + semua: false, + nasional: false, + wilayah: false, + international: false, + polda: false, + satker: false, + }; + if (backend.includes("all")) { + unit.semua = + unit.nasional = + unit.wilayah = + unit.international = + unit.polda = + unit.satker = + true; + } else { + if (backend.includes("mabes")) unit.nasional = true; + if (backend.includes("international")) unit.international = true; + if (backend.includes("polda")) { + unit.polda = true; + unit.wilayah = true; + } + if (backend.includes("satker")) { + unit.satker = true; + unit.wilayah = true; + } + unit.semua = + unit.nasional && + unit.wilayah && + unit.international && + unit.polda && + unit.satker; + } + nextUnitSel[fid] = unit; + }); + + setFilePlacements(nextPlacements); + setFileCheckedLevels(nextCheckedLevels); + setFileUnitSelections(nextUnitSel); + })(); }, [id, setValue]); + // ========== Publish Target ========== + const options: Option[] = [ + { id: "all", name: "SEMUA" }, + { id: "5", name: "UMUM" }, + { id: "6", name: "JOURNALIS" }, + { id: "7", name: "POLRI" }, + { id: "8", name: "KSP" }, + ]; const handleCheckboxChange = (id: string) => { if (id === "all") { const allOptions = options @@ -942,71 +428,333 @@ export default function FormImageUpdate() { ); } else { setPublishedFor((prev) => - prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id] + prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id] ); } }; - const [filePlacements, setFilePlacements] = useState([]); - - const getPlacement = () => { - const temp = []; - for (let i = 0; i < filePlacements?.length; i++) { - const file = files[i] as any; - if ( - file.id && - filePlacements[file.id] && - filePlacements[file.id].length > 0 - ) { - const now = filePlacements[file.id]; - const normalizedNow = now.map((item): PlacementType => { - const value = String(item); - if (value === "nasional") return "mabes"; - if (value === "wilayah") return "polda"; - if (value === "semua") return "all"; - return item as PlacementType; - }); - const uniqueNow = Array.from(new Set(normalizedNow)); - const nowArr = uniqueNow.join(","); - - // Dapatkan checked levels untuk file ini - const currentFileCheckedLevels = fileCheckedLevels[file.id] - ? Array.from(fileCheckedLevels[file.id]) - : []; - - const data = { - mediaFileId: file.id, - placements: nowArr, - customLocationPlacements: currentFileCheckedLevels.join(","), - }; - temp.push(data); + // ========== Tags ========== + 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 = ""; } } - return temp; + }; + const handleRemoveTag = (idx: number) => + setTags((prev) => prev.filter((_, i) => i !== idx)); + const handleEditTag = (idx: number, newValue: string) => + setTags((prev) => prev.map((t, i) => (i === idx ? newValue : t))); + + // ========== Placement UI Logic (per fileId) ========== + + const setPlacementChecked = ( + fid: string, + placement: string, + checked: boolean + ) => { + ensureFilePlacement(fid); + ensureFileUnit(fid); + ensureFileCheckedLevels(fid); + + // update placements + setFilePlacements((prev) => { + const now = new Set(prev[fid] || []); + if (checked) { + if (placement === "all") { + now.clear(); + [ + "all", + "nasional", + "wilayah", + "international", + "polda", + "satker", + ].forEach((p) => now.add(p)); + } else { + now.add(placement); + const nonSatkerNonAll = Array.from(now).filter( + (x) => x !== "all" && x !== "satker" + ); + if (!now.has("all") && nonSatkerNonAll.length >= 3) now.add("all"); + } + } else { + if (placement === "all") { + now.clear(); + } else { + now.delete(placement); + if (now.has("all")) { + const nonSatkerNonAll = Array.from(now).filter( + (x) => x !== "all" && x !== "satker" + ); + if (nonSatkerNonAll.length < 3) now.delete("all"); + } + if (placement === "wilayah") { + now.delete("polda"); + now.delete("satker"); + } + } + } + return { ...prev, [fid]: Array.from(now) }; + }); + + // update custom levels for special keys + setFileCheckedLevels((prev) => { + const cur = new Set(prev[fid] || new Set()); + if (checked) { + if (placement === "polda") { + listDest.forEach((d: any) => { + if (d.levelNumber === 2 && d.name !== "SATKER POLRI") + cur.add(Number(d.id)); + }); + } else if (placement === "satker") { + const satkerItem: any = listDest.find( + (d: any) => d.name === "SATKER POLRI" + ); + if (satkerItem) { + cur.add(Number(satkerItem.id)); + (satkerItem.subDestination || []).forEach((sd: any) => + cur.add(Number(sd.id)) + ); + } + } else if (placement === "all") { + listDest.forEach((d: any) => { + cur.add(Number(d.id)); + (d.subDestination || []).forEach((sd: any) => + cur.add(Number(sd.id)) + ); + }); + } + } else { + if (placement === "polda") { + listDest.forEach((d: any) => { + if (d.levelNumber === 2 && d.name !== "SATKER POLRI") + cur.delete(Number(d.id)); + }); + } else if (placement === "satker") { + const satkerItem: any = listDest.find( + (d: any) => d.name === "SATKER POLRI" + ); + if (satkerItem) { + cur.delete(Number(satkerItem.id)); + (satkerItem.subDestination || []).forEach((sd: any) => + cur.delete(Number(sd.id)) + ); + } + } else if (placement === "all") { + cur.clear(); + } + } + return { ...prev, [fid]: cur }; + }); + + // update main checkbox mirrors + setFileUnitSelections((prev) => { + const cur = { ...(prev[fid] || {}) } as any; + if ( + !cur.semua && + !cur.nasional && + !cur.wilayah && + !cur.international && + !cur.polda && + !cur.satker + ) { + cur.semua = false; + cur.nasional = false; + cur.wilayah = false; + cur.international = false; + cur.polda = false; + cur.satker = false; + } + if (placement === "all") { + cur.semua = checked; + cur.nasional = checked; + cur.wilayah = checked; + cur.international = checked; + cur.polda = checked; + cur.satker = checked; + } else { + cur[placement] = checked; + if (placement === "wilayah" && !checked) { + cur.polda = false; + cur.satker = false; + } else if (placement === "wilayah" && checked) { + cur.polda = true; + cur.satker = true; + } + cur.semua = + cur.nasional && + cur.wilayah && + cur.international && + cur.polda && + cur.satker; + } + return { ...prev, [fid]: cur }; + }); }; + // modal checkbox per fileId + const toggleLevelForFile = (fid: string, levelId: number) => { + ensureFileCheckedLevels(fid); + setFileCheckedLevels((prev) => { + const cur = new Set(prev[fid] || new Set()); + if (cur.has(levelId)) { + cur.delete(levelId); + // if POLDA unchecked: also uncheck its children (unless SATKER POLRI) + const poldaItem: any = listDest.find( + (d: any) => Number(d.id) === levelId + ); + if ( + poldaItem && + poldaItem.subDestination && + poldaItem.name !== "SATKER POLRI" + ) { + poldaItem.subDestination.forEach((sd: any) => + cur.delete(Number(sd.id)) + ); + } + if (poldaItem && poldaItem.name === "SATKER POLRI") { + (poldaItem.subDestination || []).forEach((sd: any) => + cur.delete(Number(sd.id)) + ); + } + } else { + cur.add(levelId); + // if SATKER POLRI toggled ON, include all children + const satkerItem: any = listDest.find( + (d: any) => Number(d.id) === levelId + ); + if (satkerItem && satkerItem.name === "SATKER POLRI") { + (satkerItem.subDestination || []).forEach((sd: any) => + cur.add(Number(sd.id)) + ); + } + } + return { ...prev, [fid]: cur }; + }); + + // reflect to unit main toggles + setTimeout(() => { + setFileUnitSelections((prev) => { + const unit = { ...(prev[fid] || {}) } as any; + const totalPoldaCount = listDest.filter( + (d: any) => d.levelNumber === 2 && d.name !== "SATKER POLRI" + ).length; + const curSet = fileCheckedLevels[fid] || new Set(); + let checkedPoldaCount = 0; + listDest.forEach((d: any) => { + if ( + d.levelNumber === 2 && + d.name !== "SATKER POLRI" && + curSet.has(Number(d.id)) + ) + checkedPoldaCount++; + }); + const satkerItem = listDest.find((d: any) => d.name === "SATKER POLRI"); + const isSatkerChecked = satkerItem + ? curSet.has(Number(satkerItem.id)) + : false; + + unit.polda = checkedPoldaCount > 0; + unit.satker = Boolean(isSatkerChecked); + unit.wilayah = unit.polda || unit.satker; + unit.semua = + unit.nasional && + unit.wilayah && + unit.international && + unit.polda && + unit.satker; + + return { ...prev, [fid]: unit }; + }); + }, 0); + }; + + // select all satker sub-items + const toggleAllSubItems = (fid: string, satker: Destination) => { + ensureFileCheckedLevels(fid); + setFileCheckedLevels((prev) => { + const cur = new Set(prev[fid] || new Set()); + const allChecked = (satker.subDestination || []).every((sd: any) => + cur.has(Number(sd.id)) + ); + if (allChecked) { + (satker.subDestination || []).forEach((sd: any) => + cur.delete(Number(sd.id)) + ); + } else { + cur.add(Number(satker.id)); + (satker.subDestination || []).forEach((sd: any) => + cur.add(Number(sd.id)) + ); + } + return { ...prev, [fid]: cur }; + }); + + setTimeout(() => { + setFileUnitSelections((prev) => { + const unit = { ...(prev[fid] || {}) } as any; + unit.satker = true; + unit.wilayah = true; + unit.semua = + unit.nasional && + unit.wilayah && + unit.international && + unit.polda && + unit.satker; + return { ...prev, [fid]: unit }; + }); + }, 0); + }; + + // ========== Build payload for placements ========== + const buildPlacementsPayload = () => { + const payload: Array<{ + mediaFileId: number | string; + placements: string; + customLocationPlacements: string; + }> = []; + + files.forEach((f: any) => { + const fid = toFileId(f); + const plist = filePlacements[fid] || []; + const norm = normalizePlacementsForAPI(plist); + const placementsStr = Array.from(new Set(norm)).join(","); + + const levels = fileCheckedLevels[fid] + ? Array.from(fileCheckedLevels[fid]) + : []; + const customStr = levels.join(","); + + payload.push({ + mediaFileId: f.id, // IMPORTANT: use file.id from backend detail + placements: placementsStr, + customLocationPlacements: customStr, + }); + }); + + return payload; + // Example item: + // { mediaFileId: 3285, placements: "all,mabes,polda,international", customLocationPlacements: "2,6,7" } + }; + + // ========== Save ========== const save = async (data: ImageSchema) => { loading(); + const finalTags = tags.join(", "); - - // const descFinal = - // selectedLang === "en" && translatedContent - // ? translatedContent - // : data.description; const descFinal = translatedContent || data.description; - - const finalTitle = - translatedTitle && translatedTitle.trim() !== "" - ? translatedTitle - : data.title; + const finalTitle = translatedTitle?.trim() ? translatedTitle : data.title; const requestData = { ...data, id: detail?.id, - // title: data.title, title: finalTitle, - description: htmlToString(descFinal), // versi plain text - htmlDescription: descFinal, // versi HTML + description: htmlToString(descFinal), + htmlDescription: descFinal, fileTypeId, categoryId: selectedTarget, subCategoryId: selectedTarget, @@ -1019,50 +767,45 @@ export default function FormImageUpdate() { isInternationalMedia: false, }; - console.log("Form Data Submitted:", requestData); - console.log("getPlacement(): ", getPlacement()); - const response = await createMedia(requestData); if (response?.error) { + close(); error(response?.message); return false; } + // thumbnail upload const formMedia = new FormData(); - const thumbnail = thumbnailFile || files[0]; - formMedia.append("file", thumbnail); - - const responseThumbnail = await uploadThumbnail(id, formMedia); - if (responseThumbnail?.error) { - error(responseThumbnail?.message); - return false; + const thumbnail = + thumbnailFile || (files[0] instanceof File ? files[0] : null); + if (thumbnail) { + formMedia.append("file", thumbnail); + const responseThumbnail = await uploadThumbnail(id, formMedia); + if (responseThumbnail?.error) { + close(); + error(responseThumbnail?.message); + return false; + } } - const progressInfoArr = []; - for (const item of files) { - progressInfoArr.push({ percentage: 0, fileName: item.name }); - } - progressInfo = progressInfoArr; - setIsStartUpload(true); - setProgressList(progressInfoArr); - - // Update file placements - const responseFilePlacements = await updateFilePlacements(getPlacement()); + // update placements (CRITICAL) + const placementsPayload = buildPlacementsPayload(); + const responseFilePlacements = await updateFilePlacements( + placementsPayload + ); if (responseFilePlacements?.error) { + close(); error(responseFilePlacements?.message); return false; } close(); - // showProgress(); - console.log("files:", files); - files.map(async (item: any, index: number) => { - await uploadResumableFile( - index, - String(id), - item, - fileTypeId == "2" || fileTypeId == "4" ? item.duration : "0" - ); + + // resumable uploads for new local files only + files.forEach(async (item: any, index: number) => { + if (item?.preview) { + await uploadResumableFile(index, String(id), item, "0"); + } }); MySwal.fire({ @@ -1076,39 +819,32 @@ export default function FormImageUpdate() { }); }; + // ========== Upload tus ========== async function uploadResumableFile( idx: number, - id: string, + idMedia: string, file: any, duration: string ) { - console.log(idx, id, file, duration); - - // const placements = getPlacement(file.placements); - // console.log("Placementttt: : ", placements); - const resCsrf = await getCsrfToken(); const csrfToken = resCsrf?.data?.token; - console.log("CSRF TOKEN : ", csrfToken); - const headers = { - "X-XSRF-TOKEN": csrfToken, - }; + const headers = { "X-XSRF-TOKEN": csrfToken }; if (!file.secondaryUrl || file.secondaryUrl == "") { 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, + headers, + retryDelays: [0, 3000, 6000, 12000, 24000], + chunkSize: 20000, metadata: { - mediaid: id, + mediaid: idMedia, filename: file.name, filetype: file.type, duration, isWatermark: "true", }, - onBeforeRequest: function (req) { - var xhr = req.getUnderlyingObject(); + onBeforeRequest(req) { + const xhr = req.getUnderlyingObject(); xhr.withCredentials = true; }, onError: async (e: any) => { @@ -1116,19 +852,17 @@ export default function FormImageUpdate() { error(e); }, onChunkComplete: ( - chunkSize: any, + _chunkSize: any, bytesAccepted: any, bytesTotal: any ) => { - const uploadPersen = Math.floor((bytesAccepted / bytesTotal) * 100); - progressInfo[idx].percentage = uploadPersen; + const percent = Math.floor((bytesAccepted / bytesTotal) * 100); + progressInfo[idx].percentage = percent; counterUpdateProgress++; - console.log(counterUpdateProgress); setProgressList(progressInfo); setCounterProgress(counterUpdateProgress); }, onSuccess: async () => { - uploadPersen = 100; progressInfo[idx].percentage = 100; counterUpdateProgress++; setCounterProgress(counterUpdateProgress); @@ -1136,10 +870,42 @@ export default function FormImageUpdate() { }, }); + // init progress list + if (!isStartUpload) { + const pi: any[] = files.map((f: any) => ({ + percentage: 0, + fileName: f.name || f.fileName, + })); + progressInfo = pi; + setIsStartUpload(true); + setProgressList(pi); + } + upload.start(); } } + function successTodo() { + let counter = 0; + for (const element of progressInfo) + if (element.percentage === 100) counter++; + if (counter === progressInfo.length) { + setIsStartUpload(false); + Cookies.remove("idCreate"); + successSubmit("/in/contributor/content/image/"); + } + } + const successSubmit = (redirect: string) => { + MySwal.fire({ + title: "Sukses", + text: "Data berhasil disimpan.", + icon: "success", + confirmButtonColor: "#3085d6", + confirmButtonText: "OK", + }).then(() => router.push(redirect)); + }; + + // ========== UI Handlers ========== const onSubmit = (data: ImageSchema) => { MySwal.fire({ title: "Simpan Data", @@ -1150,43 +916,62 @@ export default function FormImageUpdate() { confirmButtonColor: "#3085d6", confirmButtonText: "Simpan", }).then((result) => { - if (result.isConfirmed) { - save(data); - } + if (result.isConfirmed) save(data); }); }; - const successSubmit = (redirect: string) => { + const handleDeleteFile = (fid: number | string) => { MySwal.fire({ - title: "Sukses", - text: "Data berhasil disimpan.", - icon: "success", - confirmButtonColor: "#3085d6", - confirmButtonText: "OK", - }).then(() => { - router.push(redirect); + title: "Hapus file", + text: "Apakah Anda yakin ingin menghapus file ini?", + icon: "warning", + showCancelButton: true, + cancelButtonColor: "#3085d6", + confirmButtonColor: "#d33", + confirmButtonText: "Hapus", + }).then((result) => { + if (result.isConfirmed) { + doDelete(fid); + } }); }; - function successTodo() { - let counter = 0; - for (const element of progressInfo) { - if (element.percentage == 100) { - counter++; + async function doDelete(fid: number | string) { + try { + const response = await deleteFile({ id: fid }); + if (response?.error) { + error(response.message); + return; } - } - if (counter == progressInfo.length) { - setIsStartUpload(false); - // hideProgress(); - Cookies.remove("idCreate"); - successSubmit("/in/contributor/content/image/"); + setFiles((prev: any[]) => + prev.filter((f) => String(f.id) !== String(fid)) + ); + // clean maps + setFilePlacements((prev) => { + const n = { ...prev }; + delete n[String(fid)]; + return n; + }); + setFileCheckedLevels((prev) => { + const n = { ...prev }; + delete n[String(fid)]; + return n; + }); + setFileUnitSelections((prev) => { + const n = { ...prev }; + delete n[String(fid)]; + return n; + }); + MySwal.fire({ + title: "Sukses", + icon: "success", + confirmButtonText: "OK", + }); + } catch { + error("Terjadi kesalahan saat menghapus file"); } } - const handleRemoveAllFiles = () => { - setFiles([]); - }; - const renderFilePreview = (file: FileWithPreview | any) => { if (file?.preview || file instanceof File) { return ( @@ -1213,662 +998,290 @@ export default function FormImageUpdate() { } }; - const handleRemoveFile = (file: FileWithPreview) => { - const uploadedFiles = files; - const filtered = uploadedFiles.filter((i) => i.name !== file.name); - setFiles([...filtered]); - }; - - const fileList = files.map((file: any) => ( -
-
-
{renderFilePreview(file)}
-
-
- {file.fileName || 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"} -
-
-
- - -
- )); - type PlacementType = "all" | "mabes" | "polda" | "international" | string; - - interface FilePlacement { - mediaFileId: number; - placements?: PlacementType[]; - } - - interface TempFileItem { - id: number | string; - // tambahkan properti lain kalau ada - } - - const [tempFile, setTempFile] = useState([]); - const setupPlacement = ( - index: number, - placement: string, - checked: boolean - ) => { - let temp = [...filePlacements]; - if (checked) { - if (placement === "all") { - temp[index] = ["all", "mabes", "polda", "international"]; - setFileCheckedLevels((prevLevels) => { - const newArray = [...prevLevels]; - const currentFileLevels = new Set( - newArray[index] || new Set() - ); - listDest.forEach((item: any) => { - currentFileLevels.add(Number(item.id)); - if (item.subDestination) { - item.subDestination.forEach((sub: any) => { - currentFileLevels.add(Number(sub.id)); - }); - } - }); - newArray[index] = currentFileLevels; - return newArray; - }); - setFileUnitSelections((prevSelections) => { - const newSelections = [...prevSelections]; - const currentSelection = { ...newSelections[index] }; - currentSelection.nasional = true; - currentSelection.wilayah = true; - currentSelection.international = true; - currentSelection.polda = true; - // currentSelection.polres = true; - currentSelection.satker = true; - currentSelection.semua = true; - - newSelections[index] = currentSelection; - return newSelections; - }); - } else if (placement === "satker") { - const now = temp[index] || []; - if (!now.includes("satker")) { - now.push("satker"); - } - temp[index] = now; - } else { - const now = temp[index] || []; - if (!now.includes(placement)) { - now.push(placement); - } - const nonSatkerItems = now.filter( - (item) => item !== "satker" && item !== "all" - ); - if (nonSatkerItems.length === 3 && !now.includes("all")) { - now.push("all"); - } - temp[index] = now; - } - } else { - if (placement === "all") { - temp[index] = []; - setFileCheckedLevels((prevLevels) => { - const newArray = [...prevLevels]; - const currentFileLevels = new Set( - newArray[index] || new Set() - ); - currentFileLevels.clear(); - - newArray[index] = currentFileLevels; - return newArray; - }); - - // Update fileUnitSelections untuk checkbox tingkat utama - setFileUnitSelections((prevSelections) => { - const newSelections = [...prevSelections]; - const currentSelection = { ...newSelections[index] }; - - // Set semua checkbox tingkat utama ke false - currentSelection.nasional = false; - currentSelection.wilayah = false; - currentSelection.international = false; - currentSelection.polda = false; - // currentSelection.polres = false; - currentSelection.satker = false; - currentSelection.semua = false; - - newSelections[index] = currentSelection; - return newSelections; - }); - } else { - const now = temp[index]?.filter((a) => a !== placement); - console.log("now", now); - temp[index] = now; - if (placement === "wilayah") { - // Ketika wilayah di-uncheck, hapus wilayah, polda, dan satker - const now = temp[index]?.filter( - (a) => a !== "wilayah" && a !== "polda" && a !== "satker" - ); - temp[index] = now; - } else if (placement === "polda") { - // Ketika polda di-uncheck, hapus polda dari filePlacements - const now = temp[index]?.filter((a) => a !== "polda"); - temp[index] = now; - } else if (placement === "satker") { - // Ketika satker di-uncheck, hapus satker dari filePlacements - const now = temp[index]?.filter((a) => a !== "satker"); - temp[index] = now; - } else { - const now = temp[index]?.filter((a) => a !== placement); - temp[index] = now; - } - - // Hapus "all" jika tidak semua item ter-checklist - if (now.includes("all")) { - const nonSatkerItems = now.filter( - (item) => item !== "satker" && item !== "all" - ); - if (nonSatkerItems.length < 3) { - const newData = now.filter((b) => b !== "all"); - temp[index] = newData; - } - } - } - } - setFilePlacements(temp); - - // Update checklist levels di modal berdasarkan placement yang diubah - updateModalChecklistLevels(index, placement, checked); - }; - - // Fungsi untuk mengupdate checklist levels di modal berdasarkan placement - const updateModalChecklistLevels = ( - fileIndex: number, - placement: string, - checked: boolean - ) => { - if (!listDest || listDest.length === 0) return; - - setFileCheckedLevels((prev) => { - const newArray = [...prev]; - const currentFileLevels = new Set(newArray[fileIndex]); - - if (checked) { - if (placement === "polda") { - // Checklist semua POLDA (bukan SATKER POLRI) - listDest.forEach((item: any) => { - if (item.levelNumber === 2 && item.name !== "SATKER POLRI") { - currentFileLevels.add(Number(item.id)); - } - }); - } else if (placement === "satker") { - // Checklist SATKER POLRI dan semua sub-item di bawahnya - const satkerItem: any = listDest.find( - (item: any) => item.name === "SATKER POLRI" - ); - if (satkerItem) { - currentFileLevels.add(Number(satkerItem.id)); - if (satkerItem.subDestination) { - satkerItem.subDestination.forEach((sub: any) => { - currentFileLevels.add(Number(sub.id)); - }); - } - } - } - } else { - if (placement === "polda") { - // Unchecklist semua POLDA - listDest.forEach((item: any) => { - if (item.levelNumber === 2 && item.name !== "SATKER POLRI") { - currentFileLevels.delete(Number(item.id)); - } - }); - } else if (placement === "satker") { - // Unchecklist SATKER POLRI dan semua sub-item di bawahnya - const satkerItem: any = listDest.find( - (item: any) => item.name === "SATKER POLRI" - ); - if (satkerItem) { - currentFileLevels.delete(Number(satkerItem.id)); - if (satkerItem.subDestination) { - satkerItem.subDestination.forEach((sub: any) => { - currentFileLevels.delete(Number(sub.id)); - }); - } - } - } - } - - newArray[fileIndex] = currentFileLevels; - return newArray; - }); - }; - - // const setupPlacement = (id: number | string, placement: PlacementType) => { - // console.log(`FileDestination.leng:: ${id}_${placement}`); - // const arrayFile: FilePlacement[] = []; - - // for (let i = 0; i < tempFile?.length; i++) { - // const element = tempFile[i]; - - // if (element.id == id) { - // const findPlacementIdx = filePlacements.findIndex( - // (o) => Number(o.mediaFileId) === Number(id) - // ); - - // if (findPlacementIdx > -1) { - // const findPlacement = filePlacements[findPlacementIdx]; - - // if (findPlacement?.placements?.includes(placement)) { - // if (placement === "all") { - // findPlacement.placements = undefined; - // } else { - // findPlacement.placements = findPlacement.placements.filter( - // (val) => val !== placement - // ); - // if (findPlacement.placements?.includes("all")) { - // findPlacement.placements = findPlacement.placements.filter( - // (val) => val !== "all" - // ); - // } - // } - // } else if (placement === "all") { - // findPlacement.placements = [ - // "all", - // "mabes", - // "polda", - // "international", - // ]; - // } else if (findPlacement.placements) { - // findPlacement.placements = [...findPlacement.placements, placement]; - // } else { - // findPlacement.placements = [placement]; - // } - // } else { - // const file: FilePlacement = { - // mediaFileId: Number(element.id), - // placements: [placement], - // }; - - // arrayFile.push(file); - // } - // } - // } - - // const finalPlacements = [...filePlacements, ...arrayFile]; - // setFilePlacements(finalPlacements); - // console.log("FileDestination.leng::", finalPlacements); - // }; - - function success() { - MySwal.fire({ - title: "Sukses", - icon: "success", - confirmButtonColor: "#3085d6", - confirmButtonText: "OK", - }).then((result) => { - if (result.isConfirmed) { - // window.location.reload(); - } - }); - } - - const handleDeleteFile = (id: number) => { - MySwal.fire({ - title: "Hapus file", - text: "Apakah Anda yakin ingin menghapus file ini?", - icon: "warning", - showCancelButton: true, - cancelButtonColor: "#3085d6", - confirmButtonColor: "#d33", - confirmButtonText: "Hapus", - }).then((result) => { - if (result.isConfirmed) { - doDelete(id); - } - }); - }; - - async function doDelete(id: number) { - const data = { id }; - - try { - const response = await deleteFile(data); - if (response?.error) { - error(response.message); - return; - } - setFiles((prevFiles: any) => - prevFiles.filter((file: any) => file.id !== id) - ); - success(); - } catch (err) { - error("Terjadi kesalahan saat menghapus file"); - } - } + // ========== Render ========== + if (!detail) return null; return (
- {detail !== undefined ? ( -
- -
-

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

-
- {/* Input Title dengan translate */} -
-
- +
+ {/* LEFT */} + +
+

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

- {roleId === "14" && ( - - )} -
+ {/* Title + Translate */} +
+
+ + {roleId === "14" && ( + + )} +
- {/* Judul Bahasa Indonesia */} -
- - ( - - )} +
+ + ( + -
- - {/* Judul Bahasa Inggris (muncul setelah klik translate) */} - {translatedTitle && ( -
- - setTranslatedTitle(e.target.value)} - placeholder="English version" - /> -
)} + /> +
- {errors.title?.message && ( -

- {errors.title.message} -

- )} -
- - {/*
- - ( - - )} + {translatedTitle && ( +
+ + setTranslatedTitle(e.target.value)} + placeholder="English version" /> - {errors.title?.message && ( -

- {errors.title.message} -

- )} -
*/} -
-
- - -
+ )} -
-
- + {errors.title?.message && ( +

{errors.title.message}

+ )} +
- {roleId === "14" && ( - - )} -
- - {/* Editor Bahasa Indonesia */} -
- - ( - + {/* Category */} +
+
+ + +
+
+ + {/* Description + Translate */} +
+
+ + {roleId === "14" && ( + + )} +
+ +
+ + ( + -
+ )} + /> +
- {/* Editor Bahasa Inggris (muncul setelah klik translate) */} - {translatedContent && ( -
- - setTranslatedContent(val)} - initialData={translatedContent} - /> + {translatedContent && ( +
+ + setTranslatedContent(val)} + initialData={translatedContent} + /> +
+ )} + + {errors.description?.message && ( +

+ {errors.description.message} +

+ )} +
+ + {/* File Selector */} +
+ + +
+ +
+ +

+ {t("drag-file", { defaultValue: "Drag File" })} +

+
+ {t("upload-file-max", { + defaultValue: "Upload File Max", + })}
- )} - - {errors.description?.message && ( -

- {errors.description.message} -

- )} +
- {/*
- - ( - - )} - /> - {errors.description?.message && ( -

- {errors.description.message} -

- )} -
*/} -
- - {/* */} - -
- -
- -

- {/* Drop files here or click to upload. */} - {t("drag-file", { defaultValue: "Drag File" })} -

-
- {t("upload-file-max", { - defaultValue: "Upload File Max", - })} -
-
-
- {files.length ? ( - -
{fileList}
-
-
- -
- + {/* List Files */} + {files.length > 0 && ( + <> +
+ {files.map((file: any) => ( +
+
+
+ {renderFilePreview(file)} +
+
+
+ {file.fileName || 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"} +
- {/* */} + +
- - ) : null} - {files.length > 0 && ( -
- -
- {files.map((file: any, index: any) => ( + ))} +
+ + {/* Placement Per File */} +
+ +
+ {files.map((file: any) => { + const fid = toFileId(file); + const unit = fileUnitSelections[fid] || { + semua: false, + nasional: false, + wilayah: false, + international: false, + polda: false, + satker: false, + }; + const checkedSet = + fileCheckedLevels[fid] || new Set(); + + return (
{file.fileName} -
-
-

{file.fileName}

+
+
+

+ {file.fileName || file.name} +

-
- {/*
- - Pengaturan Distribusi -
*/} - {/* Checkbox Tingkat Utama */} +
+ {/* Main toggles */}
{[ { key: "semua", label: "Semua" }, - { - key: "nasional", - label: "Nasional", - }, + { key: "nasional", label: "Nasional" }, { key: "wilayah", label: "Wilayah" }, { key: "international", label: "Internasional", }, - ].map((item, idx) => ( + ].map((item) => (
{ - handleFileUnitChange( - index, - item.key as keyof typeof unitSelection, - value as boolean - ); - setupPlacement( - index, - item.key, - Boolean(value) - ); + checked={Boolean( + unit[ + item.key as keyof typeof unit + ] + )} + onCheckedChange={(val) => { + // ensure exist + ensureFileUnit(fid); + ensureFilePlacement(fid); + ensureFileCheckedLevels(fid); + + const checked = Boolean(val); + + if (item.key === "semua") { + // mirror all + setPlacementChecked( + fid, + "all", + checked + ); + } else { + // nasional/wilayah/international + setPlacementChecked( + fid, + item.key, + checked + ); + if (item.key === "wilayah") + setIsDetailOfRegionShowed( + checked + ); + } }} /> -
@@ -1950,107 +1366,110 @@ export default function FormImageUpdate() {
{/* Detail Wilayah */} - {fileUnitSelections[index]?.wilayah && - isDetailOfRegionShowed && ( -
-

- Detail Wilayah: -

+ {unit.wilayah && isDetailOfRegionShowed && ( +
+

+ Detail Wilayah: +

+
+ {[ + { key: "polda", label: "POLDA" }, + { key: "satker", label: "SATKER" }, + ].map((item) => ( +
+ + setPlacementChecked( + fid, + item.key, + Boolean(val) + ) + } + /> + +
+ ))} - {/* Checkbox Sub-kategori dengan tombol Kustom sejajar */} -
- {[ - { key: "polda", label: "POLDA" }, - { - key: "satker", - label: "SATKER", - }, - ].map((item, idx) => ( -
- { - handleFileUnitChange( - index, - item.key as keyof typeof unitSelection, - value as boolean - ); - setupPlacement( - index, - item.key, - Boolean(value) - ); - }} - /> -
- ))} + + {t("custom", { + defaultValue: "Kustom", + })} + + + + + + Daftar Wilayah POLDA dan + SATKER + + +
+ {listDest.map( + (polda: any) => { + const pid = String( + polda.id + ); + const isSatker = + polda.name === + "SATKER POLRI"; + const isExpanded = + expandedPolda[pid]; - {/* Tombol Kustom sejajar dengan checkbox */} -
- - - - - - - - Daftar Wilayah POLDA dan - SATKER - - -
- {listDest.map( - (polda: any) => ( + const allSubItemsChecked = + isSatker && + ( + polda.subDestination || + [] + ).every((sub: any) => + ( + fileCheckedLevels[ + fid + ] || + new Set() + ).has(Number(sub.id)) + ); + + return (
- {/* Header POLDA */}
- {/* Tombol expand hanya untuk SATKER POLRI */} - {polda.name === - "SATKER POLRI" && + + {isSatker && polda.subDestination && ( - ); - })()} +
- {polda.subDestination.map( + {( + polda.subDestination || + [] + ).map( ( sub: any ) => (
)}
- ) - )} -
-
- - - - - - -
-
-
-
+ ); + } + )} +
+
+ + + + + + +
+
+
- )} +
+ )}
- ))} -
+ ); + })}
- )} - -
+
+ + )} + +
+
+ + + {/* RIGHT */} +
+ +
+
+ + ( + + )} + /> + {errors.creatorName?.message && ( +

+ {errors.creatorName.message} +

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

- {errors.creatorName.message} -

- )} -
-
- {/*
- - - Thumbnail Gambar Utama - -
*/} -
- - { - const file = e.target.files?.[0]; - if (file) { - setThumbnailFile(file); - } - }} - className="dark:border dark:border-gray-500 dark:rounded-lg" + {/* Thumbnail */} +
+ + { + const f = e.target.files?.[0]; + if (f) setThumbnailFile(f); + }} + className="dark:border dark:border-gray-500 dark:rounded-lg" + /> + + Thumbnail Preview + +
- - Thumbnail Preview - -
- -
-
- - -
- {tags.map((tag, index) => ( + {/* Tags */} +
+
+ + +
+ {tags.map((tag, index) => ( + - {/* Hidden span untuk ukur lebar teks */} - - {tag || " "} - - - handleEditTag(index, e.target.value)} - style={{ - width: `${Math.max(tag.length, 1)}ch`, - }} - className="bg-black text-white border-none focus:outline-none" - /> - - + {tag || " "} - ))} -
- - {/*
- {detail?.tags?.split(",").map((tag, index) => ( - - {tag.trim()} - - ))} -
*/} -
-
-
-
- - {options.map((option: Option) => ( -
- opt.id !== "all").length - : publishedFor.includes(option.id) - } - onCheckedChange={() => handleCheckboxChange(option.id)} + handleEditTag(index, e.target.value)} + style={{ width: `${Math.max(tag.length, 1)}ch` }} + className="bg-black text-white border-none focus:outline-none" /> - -
+ + ))}
-
- -

- {t("suggestion-box", { defaultValue: "Suggestion Box" })} (0) -

-
-
-

{t("information", { defaultValue: "Information" })}:

- {/*

{detail?.status}

*/} -
- -
-
- -
-
- +
+ + {/* Publish Target */} +
+
+ + {options.map((option: Option) => ( +
+ opt.id !== "all").length + : publishedFor.includes(option.id) + } + onCheckedChange={() => handleCheckboxChange(option.id)} + /> + +
+ ))}
+ +
+ +

+ {t("suggestion-box", { defaultValue: "Suggestion Box" })} (0) +

+
+ +
+

{t("information", { defaultValue: "Information" })}:

+
+ + +
+
+ +
+
+ +
- ) : ( - "" - )} +
); } + +// "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 { Switch } from "@/components/ui/switch"; +// import Cookies from "js-cookie"; +// import { +// createMedia, +// deleteFile, +// deleteMedia, +// getTagsBySubCategoryId, +// listEnableCategory, +// listEnableCategoryNew, +// updateFilePlacements, +// uploadThumbnail, +// } from "@/service/content/content"; +// import { detailMedia } from "@/service/curated-content/curated-content"; +// import { CloudUpload, MailIcon } from "lucide-react"; +// import dynamic from "next/dynamic"; +// import { useDropzone } from "react-dropzone"; +// import { Icon } from "@iconify/react/dist/iconify.js"; +// import Image from "next/image"; +// import { error, loading } from "@/lib/swal"; +// import { getCsrfToken } from "@/service/auth"; +// import { Upload } from "tus-js-client"; +// import { useTranslations } from "next-intl"; +// import { htmlToString } from "@/utils/globals"; +// import { getUserLevelForAssignments } from "@/service/task"; +// import { +// Dialog, +// DialogClose, +// DialogContent, +// DialogHeader, +// DialogTitle, +// DialogTrigger, +// } from "@/components/ui/dialog"; +// import { v4 as uuidv4 } from "uuid"; +// import { getCookiesDecrypt } from "@/lib/utils"; +// import { translateText } from "@/service/content/ai"; +// import { close } from "@/config/swal"; + +// const imageSchema = z.object({ +// title: z.string().min(1, { message: "Judul diperlukan" }), +// description: z +// .string() +// .min(2, { message: "Narasi Penugasan harus lebih dari 2 karakter." }), +// creatorName: z.string().min(1, { message: "Creator diperlukan" }), +// // tags: z.string().min(1, { message: "Judul diperlukan" }), +// }); + +// type Category = { +// id: string; +// name: string; +// }; + +// type PlacementType = "all" | "mabes" | "polda" | "international" | string; + +// interface FilePlacement { +// mediaFileId: number; +// placements?: PlacementType[]; +// } + +// interface TempFileItem { +// id: number | string; +// } + +// type Detail = { +// id: string; +// title: string; +// description: string; +// htmldescription: string; +// slug: string; +// categoryId: number; +// category: { +// id: string; +// name: string; +// }; +// publishedFor: string; + +// publishedForObject: { +// id: number; +// name: string; +// }; +// creatorName: string; +// categoryName: string; +// thumbnailLink: string; +// tags: string; +// }; + +// type Option = { +// id: string; +// name: string; +// }; +// interface Destination { +// id: string; +// name: string; +// subDestination?: SubDestination[]; +// } + +// interface SubDestination { +// id: string; +// name: string; +// } + +// const CustomEditor = dynamic( +// () => { +// return import("@/components/editor/custom-editor"); +// }, +// { ssr: false } +// ); + +// interface FileWithPreview extends File { +// id: string; +// preview: string; +// } + +// export default function FormImageUpdate() { +// const MySwal = withReactContent(Swal); +// const router = useRouter(); +// const { id } = useParams() as { id: string }; +// const editor = useRef(null); +// const roleId = getCookiesDecrypt("urie"); +// type ImageSchema = z.infer; +// let progressInfo: any = []; +// let counterUpdateProgress = 0; +// const [progressList, setProgressList] = useState([]); +// let uploadPersen = 0; + +// // const isDetailOfRegionShowed = false; +// const [isDetailOfRegionShowed, setIsDetailOfRegionShowed] = useState(false); + +// const [isStartUpload, setIsStartUpload] = useState(false); +// const [counterProgress, setCounterProgress] = useState(0); +// const t = useTranslations("Form"); +// const [selectedFiles, setSelectedFiles] = useState([]); +// const taskId = Cookies.get("taskId"); +// const scheduleId = Cookies.get("scheduleId"); +// const scheduleType = Cookies.get("scheduleType"); +// const [categories, setCategories] = useState([]); +// const [selectedCategory, setSelectedCategory] = useState(); +// const [tags, setTags] = useState([]); +// const [detail, setDetail] = useState(); +// const [refresh, setRefresh] = useState(false); +// const [selectedPublishers, setSelectedPublishers] = useState([]); +// const [articleBody, setArticleBody] = useState(""); +// const [files, setFiles] = useState([]); +// const [filesTemp, setFilesTemp] = useState([]); +// const [publishedFor, setPublishedFor] = useState([]); +// const [thumbnailFile, setThumbnailFile] = useState(null); +// const inputRef = useRef(null); +// const [isLoadingTranslate, setIsLoadingTranslate] = useState(false); +// const [translatedContent, setTranslatedContent] = React.useState(""); +// const [selectedLang, setSelectedLang] = React.useState<"id" | "en">("id"); + +// // 🔹 State untuk translate judul +// const [translatedTitle, setTranslatedTitle] = useState(""); +// const [isLoadingTranslateTitle, setIsLoadingTranslateTitle] = useState(false); + +// const handleThumbnailChange = (e: React.ChangeEvent) => { +// const file = e.target.files?.[0]; +// if (file) { +// setThumbnailFile(file); +// } +// }; +// const [fileUnitSelections, setFileUnitSelections] = useState< +// Array<{ +// semua: boolean; +// nasional: boolean; +// wilayah: boolean; +// international: boolean; +// polda: boolean; +// satker: boolean; +// }> +// >([]); +// // State global untuk kompatibilitas (akan dihapus nanti) +// const [unitSelection, setUnitSelection] = useState({ +// semua: false, +// nasional: false, +// wilayah: false, +// international: false, +// polda: false, +// satker: false, +// }); +// const [checkedLevels, setCheckedLevels] = useState>(new Set()); +// const [listDest, setListDest] = useState([]); +// const [isLoading, setIsLoading] = useState(false); +// const [expandedPolda, setExpandedPolda] = useState>( +// {} +// ); +// const [fileCheckedLevels, setFileCheckedLevels] = useState< +// Array> +// >([]); +// const [isUpdatingFromMainCheckbox, setIsUpdatingFromMainCheckbox] = +// useState(false); +// const [mainCheckboxChangeType, setMainCheckboxChangeType] = +// useState(""); + +// useEffect(() => { +// async function fetchPoldaPolres() { +// setIsLoading(true); +// try { +// const response = await getUserLevelForAssignments(); +// setListDest(response?.data?.data.list); +// const initialExpandedState = response?.data?.data.list.reduce( +// (acc: any, polda: any) => { +// acc[polda.id] = false; +// return acc; +// }, +// {} +// ); +// setExpandedPolda(initialExpandedState); +// console.log("polres", initialExpandedState); +// } catch (error) { +// console.error("Error fetching Polda/Polres data:", error); +// } finally { +// setIsLoading(false); +// } +// } +// fetchPoldaPolres(); +// }, []); + +// // useEffect untuk sinkronisasi checkbox modal dengan checkbox utama +// useEffect(() => { +// if ( +// listDest.length > 0 && +// isUpdatingFromMainCheckbox && +// mainCheckboxChangeType +// ) { +// syncModalWithMainCheckbox(); +// } +// }, [isUpdatingFromMainCheckbox, mainCheckboxChangeType]); + +// // useEffect untuk update checkbox utama ketika pilihan modal berubah +// useEffect(() => { +// if (!isUpdatingFromMainCheckbox && listDest.length > 0) { +// updateMainCheckboxFromModalLegacy(); +// } +// }, [checkedLevels, isUpdatingFromMainCheckbox]); + +// // Fungsi untuk update checkbox utama berdasarkan checkbox modal (global/legacy) +// const updateMainCheckboxFromModalLegacy = () => { +// if (!isUpdatingFromMainCheckbox && listDest.length > 0) { +// // Hitung item yang dipilih berdasarkan checkedLevels +// const checkedPoldaCount = listDest.filter( +// (item: any) => +// item.levelNumber === 2 && +// item.name !== "SATKER POLRI" && +// checkedLevels.has(Number(item.id)) +// ).length; + +// const satkerItem: any = listDest.find( +// (item: any) => item.name === "SATKER POLRI" +// ); +// const checkedSatkerCount = satkerItem +// ? (checkedLevels.has(Number(satkerItem.id)) ? 1 : 0) + +// (satkerItem.subDestination?.filter((sub: any) => +// checkedLevels.has(Number(sub.id)) +// ).length || 0) +// : 0; + +// // Checkbox aktif jika ADA item yang dipilih dalam kategori tersebut +// const hasSelectedPolda = checkedPoldaCount > 0; +// const hasSelectedSatker = checkedSatkerCount > 0; + +// // Update unitSelection berdasarkan yang dipilih di modal +// setUnitSelection((prev) => { +// const newState = { ...prev }; + +// // Update individual checkboxes +// newState.polda = hasSelectedPolda; +// newState.satker = hasSelectedSatker; + +// // Update checkbox "semua" berdasarkan semua checkbox yang aktif +// newState.semua = +// newState.nasional && +// newState.wilayah && +// newState.international && +// hasSelectedPolda && +// hasSelectedSatker; + +// return newState; +// }); +// } +// }; + +// // Fungsi untuk sinkronisasi checkbox modal dengan checkbox utama +// const syncModalWithMainCheckbox = () => { +// if (isUpdatingFromMainCheckbox) { +// const newCheckedLevels = new Set(checkedLevels); + +// // Handle checklist actions - menambahkan semua item ke modal +// if (mainCheckboxChangeType === "polda_checked") { +// // Checklist semua polda +// listDest.forEach((item: any) => { +// if (item.levelNumber === 2 && item.name !== "SATKER POLRI") { +// newCheckedLevels.add(Number(item.id)); +// } +// }); +// } else if (mainCheckboxChangeType === "satker_checked") { +// // Checklist satker +// const satkerItem: any = listDest.find( +// (item: any) => item.name === "SATKER POLRI" +// ); +// if (satkerItem) { +// newCheckedLevels.add(Number(satkerItem.id)); +// // Checklist semua sub-item yang ada di bawah SATKER (bukan POLRES) +// if (satkerItem.subDestination) { +// satkerItem.subDestination.forEach((sub: any) => { +// newCheckedLevels.add(Number(sub.id)); +// }); +// } +// } +// } else if (mainCheckboxChangeType === "semua_checked") { +// // Checklist semua item +// listDest.forEach((item: any) => { +// newCheckedLevels.add(Number(item.id)); +// // Checklist semua sub-item di bawah setiap item +// if (item.subDestination) { +// item.subDestination.forEach((sub: any) => { +// newCheckedLevels.add(Number(sub.id)); +// }); +// } +// }); +// } else if (mainCheckboxChangeType === "polda_unchecked") { +// // Clear polda dari checkedLevels, tapi jangan hapus SATKER POLRI +// listDest.forEach((item: any) => { +// if (item.levelNumber === 2 && item.name !== "SATKER POLRI") { +// newCheckedLevels.delete(Number(item.id)); +// } +// }); +// } else if (mainCheckboxChangeType === "satker_unchecked") { +// // Clear satker dan semua sub-item di bawahnya dari checkedLevels +// const satkerItem: any = listDest.find( +// (item: any) => item.name === "SATKER POLRI" +// ); +// if (satkerItem) { +// newCheckedLevels.delete(Number(satkerItem.id)); +// if (satkerItem.subDestination) { +// satkerItem.subDestination.forEach((sub: any) => { +// newCheckedLevels.delete(Number(sub.id)); +// }); +// } +// } +// } else if (mainCheckboxChangeType === "semua_unchecked") { +// // Clear semua +// newCheckedLevels.clear(); +// } + +// setCheckedLevels(newCheckedLevels); + +// // Reset flag setelah sinkronisasi selesai +// setIsUpdatingFromMainCheckbox(false); +// setMainCheckboxChangeType(""); +// } +// }; + +// // Fungsi untuk mengupdate state individual file +// const handleFileUnitChange = ( +// fileIndex: number, +// key: keyof typeof unitSelection, +// value: boolean +// ) => { +// setFileUnitSelections((prev) => { +// const newSelections = [...prev]; +// const currentSelection = { ...newSelections[fileIndex] }; + +// if (key === "semua") { +// // Jika klik Semua, set semua value ke true/false +// currentSelection.semua = value; +// currentSelection.nasional = value; +// currentSelection.wilayah = value; +// currentSelection.international = value; +// currentSelection.polda = value; +// currentSelection.satker = value; + +// // Update fileCheckedLevels untuk sinkronisasi dengan modal +// setFileCheckedLevels((prevLevels) => { +// const newArray = [...prevLevels]; +// const currentFileLevels = new Set( +// newArray[fileIndex] || new Set() +// ); + +// if (value) { +// // Checklist semua item di modal +// listDest.forEach((item: any) => { +// currentFileLevels.add(Number(item.id)); +// if (item.subDestination) { +// item.subDestination.forEach((sub: any) => { +// currentFileLevels.add(Number(sub.id)); +// }); +// } +// }); +// } else { +// // Unchecklist semua item di modal +// currentFileLevels.clear(); +// } + +// newArray[fileIndex] = currentFileLevels; +// return newArray; +// }); +// } else { +// // Jika wilayah dicentang, auto centang POLDA, SATKER +// if (key === "wilayah") { +// currentSelection.wilayah = value; +// setIsDetailOfRegionShowed(value); + +// if (value) { +// // Ketika wilayah dicentang, auto centang POLDA, SATKER +// currentSelection.polda = true; +// currentSelection.satker = true; + +// // Update fileCheckedLevels untuk mengisi semua POLDA dan SATKER POLRI ketika wilayah dicentang +// setFileCheckedLevels((prevLevels) => { +// const newArray = [...prevLevels]; +// const currentFileLevels = new Set( +// newArray[fileIndex] || new Set() +// ); + +// // Checklist semua POLDA di modal +// listDest.forEach((item: any) => { +// if (item.levelNumber === 2 && item.name !== "SATKER POLRI") { +// currentFileLevels.add(Number(item.id)); +// } +// }); + +// // Checklist SATKER POLRI dan semua sub-itemsnya +// const satkerItem = listDest.find( +// (item: any) => item.name === "SATKER POLRI" +// ); +// if (satkerItem) { +// currentFileLevels.add(Number(satkerItem.id)); +// // Checklist semua sub-items di bawah SATKER POLRI +// if (satkerItem.subDestination) { +// satkerItem.subDestination.forEach((sub: any) => { +// currentFileLevels.add(Number(sub.id)); +// }); +// } +// } + +// newArray[fileIndex] = currentFileLevels; +// return newArray; +// }); +// } else { +// // Ketika wilayah di-uncheck, uncheck POLDA, SATKER dan hapus data POLDA dari fileCheckedLevels +// currentSelection.polda = false; +// currentSelection.satker = false; + +// // Update fileCheckedLevels untuk menghapus semua POLDA dan SATKER POLRI ketika wilayah di-uncheck +// setFileCheckedLevels((prevLevels) => { +// const newArray = [...prevLevels]; +// const currentFileLevels = new Set( +// newArray[fileIndex] || new Set() +// ); + +// // Hapus semua POLDA dari modal +// listDest.forEach((item: any) => { +// if (item.levelNumber === 2 && item.name !== "SATKER POLRI") { +// currentFileLevels.delete(Number(item.id)); +// } +// }); + +// // Hapus SATKER POLRI dan semua sub-itemsnya +// const satkerItem = listDest.find( +// (item: any) => item.name === "SATKER POLRI" +// ); +// if (satkerItem) { +// currentFileLevels.delete(Number(satkerItem.id)); +// // Hapus semua sub-items di bawah SATKER POLRI +// if (satkerItem.subDestination) { +// satkerItem.subDestination.forEach((sub: any) => { +// currentFileLevels.delete(Number(sub.id)); +// }); +// } +// } + +// newArray[fileIndex] = currentFileLevels; +// return newArray; +// }); +// } +// } else { +// // Update salah satu saja +// currentSelection[key] = value; +// } + +// // Cek apakah semua selain "semua" sudah dicentang +// const allChecked = [ +// "nasional", +// "wilayah", +// "international", +// "polda", +// "satker", +// ].every((k) => currentSelection[k as keyof typeof unitSelection]); + +// currentSelection.semua = allChecked; +// } + +// newSelections[fileIndex] = currentSelection; +// return newSelections; +// }); +// }; + +// // Fungsi untuk mengupdate checklist levels untuk file tertentu +// const handleFileCheckboxChangePlacement = ( +// fileIndex: number, +// levelId: number +// ) => { +// setFileCheckedLevels((prev) => { +// const newArray = [...prev]; +// const currentFileLevels = new Set(newArray[fileIndex]); +// const isCurrentlyChecked = currentFileLevels.has(levelId); + +// if (isCurrentlyChecked) { +// currentFileLevels.delete(levelId); + +// // Jika ini adalah POLDA yang di-unchecklist, unchecklist juga semua polres di bawahnya +// const poldaItem = listDest.find( +// (item: any) => Number(item.id) === levelId +// ) as any; +// if ( +// poldaItem && +// poldaItem.subDestination && +// poldaItem.name !== "SATKER POLRI" +// ) { +// poldaItem.subDestination.forEach((polres: any) => { +// currentFileLevels.delete(Number(polres.id)); +// }); +// } + +// // Jika ini adalah SATKER POLRI yang di-unchecklist, unchecklist juga semua sub-item di bawahnya +// if (poldaItem && poldaItem.name === "SATKER POLRI") { +// poldaItem.subDestination?.forEach((subItem: any) => { +// currentFileLevels.delete(Number(subItem.id)); +// }); +// } +// } else { +// currentFileLevels.add(levelId); + +// // Jika ini adalah SATKER POLRI yang di-checklist, checklist juga semua sub-item di bawahnya +// const satkerItem = listDest.find( +// (item: any) => Number(item.id) === levelId +// ) as any; +// if (satkerItem && satkerItem.name === "SATKER POLRI") { +// // Checklist semua sub-item di bawah SATKER POLRI (bukan POLRES) +// satkerItem.subDestination?.forEach((subItem: any) => { +// currentFileLevels.add(Number(subItem.id)); +// }); +// } +// } + +// newArray[fileIndex] = currentFileLevels; + +// // Update checkbox utama berdasarkan perubahan di modal +// // Pindahkan ke sini agar state sudah ter-update +// setTimeout(() => updateMainCheckboxFromModal(fileIndex), 0); + +// return newArray; +// }); +// }; + +// // Fungsi untuk mengupdate checkbox utama berdasarkan checklist di modal +// const updateMainCheckboxFromModal = (fileIndex: number) => { +// setFileUnitSelections((prev) => { +// const newSelections = [...prev]; +// const currentSelection = { ...newSelections[fileIndex] }; +// const currentFileLevels = fileCheckedLevels[fileIndex]; + +// if (!currentFileLevels) return prev; + +// // Hitung total POLDA yang ada (bukan SATKER POLRI) +// const totalPoldaCount = listDest.filter( +// (item: any) => item.levelNumber === 2 && item.name !== "SATKER POLRI" +// ).length; + +// // Hitung berapa banyak POLDA yang ter-checklist (bukan SATKER POLRI) +// const checkedPoldaCount = listDest.reduce((total: number, item: any) => { +// if ( +// item.levelNumber === 2 && +// item.name !== "SATKER POLRI" && +// currentFileLevels.has(Number(item.id)) +// ) { +// return total + 1; +// } +// return total; +// }, 0); + +// // Cek apakah SATKER POLRI ter-checklist +// const satkerItem = listDest.find( +// (item: any) => item.name === "SATKER POLRI" +// ); +// const isSatkerChecked = +// satkerItem && currentFileLevels.has(Number(satkerItem.id)); + +// // Update checkbox berdasarkan kondisi +// // POLDA aktif jika ada minimal 1 POLDA ter-checklist +// currentSelection.polda = checkedPoldaCount > 0; +// currentSelection.satker = Boolean(isSatkerChecked); + +// // Update checkbox "semua" berdasarkan semua checkbox yang aktif +// currentSelection.semua = +// currentSelection.nasional && +// currentSelection.wilayah && +// currentSelection.international && +// currentSelection.polda && +// currentSelection.satker; + +// newSelections[fileIndex] = currentSelection; +// return newSelections; +// }); +// }; + +// const toggleExpand = (id: number) => { +// setExpandedPolda((prev) => ({ +// ...prev, +// [id]: !prev[id], +// })); +// }; + +// // Fungsi untuk menangani "Pilih Semua" sub-items di bawah SATKER POLRI +// const handleSelectAllSubItems = (fileIndex: number, polda: any) => { +// setFileCheckedLevels((prev) => { +// const newArray = [...prev]; +// const currentFileLevels = new Set(newArray[fileIndex]); + +// // Cek apakah semua sub-items sudah ter-checklist +// const allSubItemsChecked = polda.subDestination?.every((sub: any) => +// currentFileLevels.has(Number(sub.id)) +// ); + +// if (allSubItemsChecked) { +// // Jika semua sudah ter-checklist, unchecklist semuanya +// polda.subDestination?.forEach((sub: any) => { +// currentFileLevels.delete(Number(sub.id)); +// }); +// } else { +// // Jika belum semua ter-checklist, checklist semuanya +// // Checklist SATKER POLRI juga jika belum ter-checklist +// if (!currentFileLevels.has(Number(polda.id))) { +// currentFileLevels.add(Number(polda.id)); +// } +// // Checklist semua sub-items +// polda.subDestination?.forEach((sub: any) => { +// currentFileLevels.add(Number(sub.id)); +// }); +// } + +// newArray[fileIndex] = currentFileLevels; + +// // Update checkbox utama berdasarkan perubahan di modal +// setTimeout(() => updateMainCheckboxFromModal(fileIndex), 0); + +// return newArray; +// }); +// }; + +// const options: Option[] = [ +// { id: "all", name: "SEMUA" }, +// { id: "5", name: "UMUM" }, +// { id: "6", name: "JOURNALIS" }, +// { id: "7", name: "POLRI" }, +// { id: "8", name: "KSP" }, +// ]; + +// const [selectedTarget, setSelectedTarget] = useState( +// detail?.category.id +// ); +// // const [unitSelection, setUnitSelection] = useState({ +// // allUnit: false, +// // mabes: false, +// // polda: false, +// // polres: false, +// // }); + +// let fileTypeId = "1"; + +// // const { getRootProps, getInputProps } = useDropzone({ +// // onDrop: (acceptedFiles) => { +// // // setFiles(acceptedFiles.map((file) => Object.assign(file))); +// // setFiles((prevFiles) => [ +// // ...prevFiles, +// // ...acceptedFiles.map((file) => +// // Object.assign(file, { +// // preview: URL.createObjectURL(file), +// // }) +// // ), +// // ]); +// // }, +// // accept: { +// // "image/*": [], +// // }, +// // }); +// const { getRootProps, getInputProps } = useDropzone({ +// onDrop: (acceptedFiles) => { +// setFiles((prevFiles) => [ +// ...prevFiles, +// ...acceptedFiles.map((file) => +// Object.assign(file, { +// id: uuidv4(), // generate unique id +// preview: URL.createObjectURL(file), +// }) +// ), +// ]); +// }, +// accept: { +// "image/*": [], +// }, +// }); + +// const { +// control, +// handleSubmit, +// setValue, +// getValues, +// formState: { errors }, +// } = useForm({ +// resolver: zodResolver(imageSchema), +// }); + +// useEffect(() => { +// async function initState() { +// getCategories(); +// } + +// initState(); +// }, []); + +// 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]); +// if (inputRef.current) { +// inputRef.current.value = ""; +// } +// } +// } +// }; + +// const handleRemoveTag = (index: number) => { +// setTags((prevTags) => prevTags.filter((_, i) => i !== index)); +// }; + +// const handleEditTag = (index: number, newValue: string) => { +// setTags((prevTags) => +// prevTags.map((tag, i) => (i === index ? newValue : tag)) +// ); +// }; + +// const getCategories = async () => { +// try { +// const category = await listEnableCategoryNew(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); +// const response = await getTagsBySubCategoryId(findCategory.id); +// setTags(response?.data?.data); +// } +// } +// } catch (error) { +// console.error("Failed to fetch categories:", error); +// } +// }; + +// useEffect(() => { +// async function initState() { +// if (id) { +// const response = await detailMedia(id); +// const details = response?.data?.data; + +// setDetail(details); + +// setSelectedTarget(String(details.category.id)); +// setTempFile(details?.files); + +// setValue("title", details.title); +// setValue("description", details.htmlDescription); +// setValue("creatorName", details.creatorName); + +// setTimeout(() => { +// setValue("title", details.title); +// setValue("description", details.htmlDescription); +// setValue("creatorName", details.creatorName); +// }, 500); + +// if (details?.files) { +// const formattedFiles = details.files.map((file: any) => ({ +// ...file, +// id: file.id, +// fileName: file.fileName, +// size: file.size, +// thumbnailFileUrl: file.thumbnailFileUrl, +// url: file.url, +// })); + +// setFiles(formattedFiles); + +// // Inisialisasi filePlacements dari detail +// const initialFilePlacements = details.files.map((file: any) => { +// if (file.placements) { +// // Map dari format backend ke format internal +// const mappedPlacements = file.placements +// .split(",") +// .map((p: string) => { +// const trimmed = p.trim(); +// switch (trimmed) { +// case "all": +// return "all"; +// case "mabes": +// return "nasional"; +// case "polda": +// return "wilayah"; +// case "satker": +// return "satker"; +// case "international": +// return "international"; +// default: +// return trimmed; +// } +// }); +// return mappedPlacements; +// } +// return []; +// }); +// setFilePlacements(initialFilePlacements); + +// // Inisialisasi fileCheckedLevels dari detail +// const initialFileCheckedLevels = details.files.map((file: any) => { +// if (file.customLocationPlacements) { +// const levelIds = file.customLocationPlacements +// .split(",") +// .map((id: string) => Number(id.trim())) +// .filter((id: number) => !isNaN(id)); +// return new Set(levelIds); +// } +// return new Set(); +// }); +// setFileCheckedLevels(initialFileCheckedLevels); + +// // Inisialisasi fileUnitSelections dari detail +// const initialFileUnitSelections = details.files.map((file: any) => { +// const selection = { +// semua: false, +// nasional: false, +// wilayah: false, +// international: false, +// polda: false, +// satker: false, +// }; + +// if (file.placements) { +// const placements = file.placements +// .split(",") +// .map((p: string) => p.trim()); + +// // Map dari format backend ke checkbox +// if (placements.includes("all")) { +// selection.semua = true; +// selection.nasional = true; +// selection.wilayah = true; +// selection.international = true; +// selection.polda = true; +// selection.satker = true; +// } else { +// if (placements.includes("mabes")) { +// selection.nasional = true; +// } +// if (placements.includes("wilayah")) { +// selection.wilayah = true; +// } +// if (placements.includes("polda")) { +// selection.polda = true; +// selection.wilayah = true; // Auto-check wilayah when polda is present +// } +// if (placements.includes("satker")) { +// selection.satker = true; +// selection.wilayah = true; // Auto-check wilayah when satker is present +// } +// if (placements.includes("international")) { +// selection.international = true; +// } +// } +// } + +// return selection; +// }); +// setFileUnitSelections(initialFileUnitSelections); +// } + +// if (details?.publishedFor) { +// // Split string "7" to an array ["7"] if needed +// setPublishedFor(details.publishedFor.split(",")); +// } + +// if (details?.tags) { +// setTags(details.tags.split(",").map((tag: string) => tag.trim())); +// } +// } +// } +// initState(); +// }, [id, setValue]); + +// 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 [filePlacements, setFilePlacements] = useState([]); + +// const getPlacement = () => { +// const temp = []; +// for (let i = 0; i < filePlacements?.length; i++) { +// const file = files[i] as any; +// if ( +// file.id && +// filePlacements[file.id] && +// filePlacements[file.id].length > 0 +// ) { +// const now = filePlacements[file.id]; +// const normalizedNow = now.map((item): PlacementType => { +// const value = String(item); +// if (value === "nasional") return "mabes"; +// if (value === "wilayah") return "polda"; +// if (value === "semua") return "all"; +// return item as PlacementType; +// }); +// const uniqueNow = Array.from(new Set(normalizedNow)); +// const nowArr = uniqueNow.join(","); + +// // Dapatkan checked levels untuk file ini +// const currentFileCheckedLevels = fileCheckedLevels[file.id] +// ? Array.from(fileCheckedLevels[file.id]) +// : []; + +// const data = { +// mediaFileId: file.id, +// placements: nowArr, +// customLocationPlacements: currentFileCheckedLevels.join(","), +// }; +// temp.push(data); +// } +// } +// return temp; +// }; + +// const save = async (data: ImageSchema) => { +// loading(); +// const finalTags = tags.join(", "); + +// // const descFinal = +// // selectedLang === "en" && translatedContent +// // ? translatedContent +// // : data.description; +// const descFinal = translatedContent || data.description; + +// const finalTitle = +// translatedTitle && translatedTitle.trim() !== "" +// ? translatedTitle +// : data.title; + +// const requestData = { +// ...data, +// id: detail?.id, +// // title: data.title, +// title: finalTitle, +// description: htmlToString(descFinal), // versi plain text +// htmlDescription: descFinal, // versi HTML +// fileTypeId, +// categoryId: selectedTarget, +// subCategoryId: selectedTarget, +// uploadedBy: "2b7c8d83-d298-4b19-9f74-b07924506b58", +// statusId: "1", +// publishedFor: publishedFor.join(","), +// creatorName: data.creatorName, +// tags: finalTags, +// isYoutube: false, +// isInternationalMedia: false, +// }; + +// console.log("Form Data Submitted:", requestData); +// console.log("getPlacement(): ", getPlacement()); + +// const response = await createMedia(requestData); +// if (response?.error) { +// error(response?.message); +// return false; +// } + +// const formMedia = new FormData(); +// const thumbnail = thumbnailFile || files[0]; +// formMedia.append("file", thumbnail); + +// const responseThumbnail = await uploadThumbnail(id, formMedia); +// if (responseThumbnail?.error) { +// error(responseThumbnail?.message); +// return false; +// } + +// const progressInfoArr = []; +// for (const item of files) { +// progressInfoArr.push({ percentage: 0, fileName: item.name }); +// } +// progressInfo = progressInfoArr; +// setIsStartUpload(true); +// setProgressList(progressInfoArr); + +// // Update file placements +// const responseFilePlacements = await updateFilePlacements(getPlacement()); +// if (responseFilePlacements?.error) { +// error(responseFilePlacements?.message); +// return false; +// } + +// close(); +// // showProgress(); +// console.log("files:", files); +// files.map(async (item: any, index: number) => { +// await uploadResumableFile( +// index, +// String(id), +// item, +// fileTypeId == "2" || fileTypeId == "4" ? item.duration : "0" +// ); +// }); + +// MySwal.fire({ +// title: "Sukses", +// text: "Data berhasil disimpan.", +// icon: "success", +// confirmButtonColor: "#3085d6", +// confirmButtonText: "OK", +// }).then(() => { +// router.push("/in/contributor/content/image"); +// }); +// }; + +// async function uploadResumableFile( +// idx: number, +// id: string, +// file: any, +// duration: string +// ) { +// console.log(idx, id, file, duration); + +// // const placements = getPlacement(file.placements); +// // console.log("Placementttt: : ", placements); + +// const resCsrf = await getCsrfToken(); +// const csrfToken = resCsrf?.data?.token; +// console.log("CSRF TOKEN : ", csrfToken); +// const headers = { +// "X-XSRF-TOKEN": csrfToken, +// }; + +// if (!file.secondaryUrl || file.secondaryUrl == "") { +// 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, +// filetype: file.type, +// 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(); +// }, +// }); + +// upload.start(); +// } +// } + +// 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); +// } +// }); +// }; + +// 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 handleRemoveAllFiles = () => { +// setFiles([]); +// }; + +// const renderFilePreview = (file: FileWithPreview | any) => { +// if (file?.preview || file instanceof File) { +// return ( +// {file.name} +// ); +// } else if (file.thumbnailFileUrl) { +// return ( +// {file.fileName} +// ); +// } 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: any) => ( +//
+//
+//
{renderFilePreview(file)}
+//
+//
+// {file.fileName || 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"} +//
+//
+//
+ +// +//
+// )); +// type PlacementType = "all" | "mabes" | "polda" | "international" | string; + +// interface FilePlacement { +// mediaFileId: number; +// placements?: PlacementType[]; +// } + +// interface TempFileItem { +// id: number | string; +// // tambahkan properti lain kalau ada +// } + +// const [tempFile, setTempFile] = useState([]); +// const setupPlacement = ( +// index: number, +// placement: string, +// checked: boolean +// ) => { +// let temp = [...filePlacements]; +// if (checked) { +// if (placement === "all") { +// temp[index] = ["all", "mabes", "polda", "international"]; +// setFileCheckedLevels((prevLevels) => { +// const newArray = [...prevLevels]; +// const currentFileLevels = new Set( +// newArray[index] || new Set() +// ); +// listDest.forEach((item: any) => { +// currentFileLevels.add(Number(item.id)); +// if (item.subDestination) { +// item.subDestination.forEach((sub: any) => { +// currentFileLevels.add(Number(sub.id)); +// }); +// } +// }); +// newArray[index] = currentFileLevels; +// return newArray; +// }); +// setFileUnitSelections((prevSelections) => { +// const newSelections = [...prevSelections]; +// const currentSelection = { ...newSelections[index] }; +// currentSelection.nasional = true; +// currentSelection.wilayah = true; +// currentSelection.international = true; +// currentSelection.polda = true; +// // currentSelection.polres = true; +// currentSelection.satker = true; +// currentSelection.semua = true; + +// newSelections[index] = currentSelection; +// return newSelections; +// }); +// } else if (placement === "satker") { +// const now = temp[index] || []; +// if (!now.includes("satker")) { +// now.push("satker"); +// } +// temp[index] = now; +// } else { +// const now = temp[index] || []; +// if (!now.includes(placement)) { +// now.push(placement); +// } +// const nonSatkerItems = now.filter( +// (item) => item !== "satker" && item !== "all" +// ); +// if (nonSatkerItems.length === 3 && !now.includes("all")) { +// now.push("all"); +// } +// temp[index] = now; +// } +// } else { +// if (placement === "all") { +// temp[index] = []; +// setFileCheckedLevels((prevLevels) => { +// const newArray = [...prevLevels]; +// const currentFileLevels = new Set( +// newArray[index] || new Set() +// ); +// currentFileLevels.clear(); + +// newArray[index] = currentFileLevels; +// return newArray; +// }); + +// // Update fileUnitSelections untuk checkbox tingkat utama +// setFileUnitSelections((prevSelections) => { +// const newSelections = [...prevSelections]; +// const currentSelection = { ...newSelections[index] }; + +// // Set semua checkbox tingkat utama ke false +// currentSelection.nasional = false; +// currentSelection.wilayah = false; +// currentSelection.international = false; +// currentSelection.polda = false; +// // currentSelection.polres = false; +// currentSelection.satker = false; +// currentSelection.semua = false; + +// newSelections[index] = currentSelection; +// return newSelections; +// }); +// } else { +// const now = temp[index]?.filter((a) => a !== placement); +// console.log("now", now); +// temp[index] = now; +// if (placement === "wilayah") { +// // Ketika wilayah di-uncheck, hapus wilayah, polda, dan satker +// const now = temp[index]?.filter( +// (a) => a !== "wilayah" && a !== "polda" && a !== "satker" +// ); +// temp[index] = now; +// } else if (placement === "polda") { +// // Ketika polda di-uncheck, hapus polda dari filePlacements +// const now = temp[index]?.filter((a) => a !== "polda"); +// temp[index] = now; +// } else if (placement === "satker") { +// // Ketika satker di-uncheck, hapus satker dari filePlacements +// const now = temp[index]?.filter((a) => a !== "satker"); +// temp[index] = now; +// } else { +// const now = temp[index]?.filter((a) => a !== placement); +// temp[index] = now; +// } + +// // Hapus "all" jika tidak semua item ter-checklist +// if (now.includes("all")) { +// const nonSatkerItems = now.filter( +// (item) => item !== "satker" && item !== "all" +// ); +// if (nonSatkerItems.length < 3) { +// const newData = now.filter((b) => b !== "all"); +// temp[index] = newData; +// } +// } +// } +// } +// setFilePlacements(temp); + +// // Update checklist levels di modal berdasarkan placement yang diubah +// updateModalChecklistLevels(index, placement, checked); +// }; + +// // Fungsi untuk mengupdate checklist levels di modal berdasarkan placement +// const updateModalChecklistLevels = ( +// fileIndex: number, +// placement: string, +// checked: boolean +// ) => { +// if (!listDest || listDest.length === 0) return; + +// setFileCheckedLevels((prev) => { +// const newArray = [...prev]; +// const currentFileLevels = new Set(newArray[fileIndex]); + +// if (checked) { +// if (placement === "polda") { +// // Checklist semua POLDA (bukan SATKER POLRI) +// listDest.forEach((item: any) => { +// if (item.levelNumber === 2 && item.name !== "SATKER POLRI") { +// currentFileLevels.add(Number(item.id)); +// } +// }); +// } else if (placement === "satker") { +// // Checklist SATKER POLRI dan semua sub-item di bawahnya +// const satkerItem: any = listDest.find( +// (item: any) => item.name === "SATKER POLRI" +// ); +// if (satkerItem) { +// currentFileLevels.add(Number(satkerItem.id)); +// if (satkerItem.subDestination) { +// satkerItem.subDestination.forEach((sub: any) => { +// currentFileLevels.add(Number(sub.id)); +// }); +// } +// } +// } +// } else { +// if (placement === "polda") { +// // Unchecklist semua POLDA +// listDest.forEach((item: any) => { +// if (item.levelNumber === 2 && item.name !== "SATKER POLRI") { +// currentFileLevels.delete(Number(item.id)); +// } +// }); +// } else if (placement === "satker") { +// // Unchecklist SATKER POLRI dan semua sub-item di bawahnya +// const satkerItem: any = listDest.find( +// (item: any) => item.name === "SATKER POLRI" +// ); +// if (satkerItem) { +// currentFileLevels.delete(Number(satkerItem.id)); +// if (satkerItem.subDestination) { +// satkerItem.subDestination.forEach((sub: any) => { +// currentFileLevels.delete(Number(sub.id)); +// }); +// } +// } +// } +// } + +// newArray[fileIndex] = currentFileLevels; +// return newArray; +// }); +// }; + +// // const setupPlacement = (id: number | string, placement: PlacementType) => { +// // console.log(`FileDestination.leng:: ${id}_${placement}`); +// // const arrayFile: FilePlacement[] = []; + +// // for (let i = 0; i < tempFile?.length; i++) { +// // const element = tempFile[i]; + +// // if (element.id == id) { +// // const findPlacementIdx = filePlacements.findIndex( +// // (o) => Number(o.mediaFileId) === Number(id) +// // ); + +// // if (findPlacementIdx > -1) { +// // const findPlacement = filePlacements[findPlacementIdx]; + +// // if (findPlacement?.placements?.includes(placement)) { +// // if (placement === "all") { +// // findPlacement.placements = undefined; +// // } else { +// // findPlacement.placements = findPlacement.placements.filter( +// // (val) => val !== placement +// // ); +// // if (findPlacement.placements?.includes("all")) { +// // findPlacement.placements = findPlacement.placements.filter( +// // (val) => val !== "all" +// // ); +// // } +// // } +// // } else if (placement === "all") { +// // findPlacement.placements = [ +// // "all", +// // "mabes", +// // "polda", +// // "international", +// // ]; +// // } else if (findPlacement.placements) { +// // findPlacement.placements = [...findPlacement.placements, placement]; +// // } else { +// // findPlacement.placements = [placement]; +// // } +// // } else { +// // const file: FilePlacement = { +// // mediaFileId: Number(element.id), +// // placements: [placement], +// // }; + +// // arrayFile.push(file); +// // } +// // } +// // } + +// // const finalPlacements = [...filePlacements, ...arrayFile]; +// // setFilePlacements(finalPlacements); +// // console.log("FileDestination.leng::", finalPlacements); +// // }; + +// function success() { +// MySwal.fire({ +// title: "Sukses", +// icon: "success", +// confirmButtonColor: "#3085d6", +// confirmButtonText: "OK", +// }).then((result) => { +// if (result.isConfirmed) { +// // window.location.reload(); +// } +// }); +// } + +// const handleDeleteFile = (id: number) => { +// MySwal.fire({ +// title: "Hapus file", +// text: "Apakah Anda yakin ingin menghapus file ini?", +// icon: "warning", +// showCancelButton: true, +// cancelButtonColor: "#3085d6", +// confirmButtonColor: "#d33", +// confirmButtonText: "Hapus", +// }).then((result) => { +// if (result.isConfirmed) { +// doDelete(id); +// } +// }); +// }; + +// async function doDelete(id: number) { +// const data = { id }; + +// try { +// const response = await deleteFile(data); +// if (response?.error) { +// error(response.message); +// return; +// } +// setFiles((prevFiles: any) => +// prevFiles.filter((file: any) => file.id !== id) +// ); +// success(); +// } catch (err) { +// error("Terjadi kesalahan saat menghapus file"); +// } +// } + +// return ( +//
+// {detail !== undefined ? ( +//
+// +//
+//

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

+//
+// {/* Input Title dengan translate */} +//
+//
+// + +// {roleId === "14" && ( +// +// )} +//
+ +// {/* Judul Bahasa Indonesia */} +//
+// +// ( +// +// )} +// /> +//
+ +// {/* Judul Bahasa Inggris (muncul setelah klik translate) */} +// {translatedTitle && ( +//
+// +// setTranslatedTitle(e.target.value)} +// placeholder="English version" +// /> +//
+// )} + +// {errors.title?.message && ( +//

+// {errors.title.message} +//

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

+// {errors.title.message} +//

+// )} +//
*/} +//
+//
+// +// +//
+//
+ +//
+//
+// + +// {roleId === "14" && ( +// +// )} +//
+ +// {/* Editor Bahasa Indonesia */} +//
+// +// ( +// +// )} +// /> +//
+ +// {/* Editor Bahasa Inggris (muncul setelah klik translate) */} +// {translatedContent && ( +//
+// +// setTranslatedContent(val)} +// initialData={translatedContent} +// /> +//
+// )} + +// {errors.description?.message && ( +//

+// {errors.description.message} +//

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

+// {errors.description.message} +//

+// )} +//
*/} +//
+// +// {/* */} +// +//
+// +//
+// +//

+// {/* Drop files here or click to upload. */} +// {t("drag-file", { defaultValue: "Drag File" })} +//

+//
+// {t("upload-file-max", { +// defaultValue: "Upload File Max", +// })} +//
+//
+//
+// {files.length ? ( +// +//
{fileList}
+//
+//
+// +//
+// +//
+//
+// {/* */} +//
+//
+// ) : null} +// {files.length > 0 && ( +//
+// +//
+// {files.map((file: any, index: any) => ( +//
+// {file.fileName} +//
+// +//
+// {/*
+// +// Pengaturan Distribusi +//
*/} + +// {/* Checkbox Tingkat Utama */} +//
+//
+// {[ +// { key: "semua", label: "Semua" }, +// { +// key: "nasional", +// label: "Nasional", +// }, +// { key: "wilayah", label: "Wilayah" }, +// { +// key: "international", +// label: "Internasional", +// }, +// ].map((item, idx) => ( +//
+// { +// handleFileUnitChange( +// index, +// item.key as keyof typeof unitSelection, +// value as boolean +// ); +// setupPlacement( +// index, +// item.key, +// Boolean(value) +// ); +// }} +// /> +// +//
+// ))} +//
+ +// {/* Detail Wilayah */} +// {fileUnitSelections[index]?.wilayah && +// isDetailOfRegionShowed && ( +//
+//

+// Detail Wilayah: +//

+ +// {/* Checkbox Sub-kategori dengan tombol Kustom sejajar */} +//
+// {[ +// { key: "polda", label: "POLDA" }, +// { +// key: "satker", +// label: "SATKER", +// }, +// ].map((item, idx) => ( +//
+// { +// handleFileUnitChange( +// index, +// item.key as keyof typeof unitSelection, +// value as boolean +// ); +// setupPlacement( +// index, +// item.key, +// Boolean(value) +// ); +// }} +// /> +// +//
+// ))} + +// {/* Tombol Kustom sejajar dengan checkbox */} +//
+// +// +// +// +// +// +// +// Daftar Wilayah POLDA dan +// SATKER +// +// +//
+// {listDest.map( +// (polda: any) => ( +//
+// {/* Header POLDA */} +//
+// +// {/* Tombol expand hanya untuk SATKER POLRI */} +// {polda.name === +// "SATKER POLRI" && +// polda.subDestination && ( +// +// )} +//
+ +// {/* Sub-items hanya untuk SATKER POLRI */} +// {polda.name === +// "SATKER POLRI" && +// polda.subDestination && +// expandedPolda[ +// polda.id +// ] && ( +//
+// {/* Tombol Pilih Semua untuk sub-items */} +//
+// {(() => { +// const allSubItemsChecked = +// polda.subDestination?.every( +// ( +// sub: any +// ) => +// fileCheckedLevels[ +// index +// ]?.has( +// Number( +// sub.id +// ) +// ) +// ); +// return ( +// +// ); +// })()} +//
+//
+// {polda.subDestination.map( +// ( +// sub: any +// ) => ( +// +// ) +// )} +//
+//
+// )} +//
+// ) +// )} +//
+//
+// +// +// +// +// +// +//
+//
+//
+//
+//
+//
+// )} +//
+//
+//
+//
+// ))} +//
+//
+// )} +//
+//
+//
+//
+// +//
+// +//
+//
+// +// ( +// +// )} +// /> +// {errors.creatorName?.message && ( +//

+// {errors.creatorName.message} +//

+// )} +//
+//
+// {/*
+// +// +// Thumbnail Gambar Utama +// +//
*/} +//
+// + +// { +// const file = e.target.files?.[0]; +// if (file) { +// setThumbnailFile(file); +// } +// }} +// className="dark:border dark:border-gray-500 dark:rounded-lg" +// /> + +// +// Thumbnail Preview +// +//
+ +//
+//
+// +// +//
+// {tags.map((tag, index) => ( +// +// {/* Hidden span untuk ukur lebar teks */} +// +// {tag || " "} +// + +// handleEditTag(index, e.target.value)} +// style={{ +// width: `${Math.max(tag.length, 1)}ch`, +// }} +// className="bg-black text-white border-none focus:outline-none" +// /> + +// +// +// ))} +//
+ +// {/*
+// {detail?.tags?.split(",").map((tag, index) => ( +// +// {tag.trim()} +// +// ))} +//
*/} +//
+//
+//
+//
+// +// {options.map((option: Option) => ( +//
+// opt.id !== "all").length +// : publishedFor.includes(option.id) +// } +// onCheckedChange={() => handleCheckboxChange(option.id)} +// /> +// +//
+// ))} +//
+//
+//
+// +//

+// {t("suggestion-box", { defaultValue: "Suggestion Box" })} (0) +//

+//
+//
+//

{t("information", { defaultValue: "Information" })}:

+// {/*

{detail?.status}

*/} +//
+//
+//
+//
+// +//
+//
+// +//
+//
+//
+//
+// ) : ( +// "" +// )} +// +// ); +// } diff --git a/components/form/content/spit-convert-form.tsx b/components/form/content/spit-convert-form.tsx index 8845685d..20863b69 100644 --- a/components/form/content/spit-convert-form.tsx +++ b/components/form/content/spit-convert-form.tsx @@ -13,8 +13,6 @@ import { Label } from "@/components/ui/label"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Alert, AlertDescription } from "@/components/ui/alert"; -import { Separator } from "@/components/ui/separator"; -import { ScrollArea } from "@/components/ui/scroll-area"; import { Select, SelectContent, @@ -55,6 +53,7 @@ import { getTagsBySubCategoryId, listEnableCategory, listEnableCategoryNew, + updateFilePlacements, } from "@/service/content/content"; import { generateDataRewrite, getDetailArticle } from "@/service/content/ai"; import { getCookiesDecrypt } from "@/lib/utils"; @@ -62,6 +61,16 @@ import { error } from "@/lib/swal"; import Swal from "sweetalert2"; import withReactContent from "sweetalert2-react-content"; import { close, loading } from "@/config/swal"; +import { + Dialog, + DialogClose, + DialogContent, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import { Icon } from "@/components/ui/icon"; +import { getUserLevelForAssignments } from "@/service/task"; interface Category { id: number; @@ -90,6 +99,31 @@ interface Option { label: string; } +interface Destination { + id: string; + name: string; + subDestination?: SubDestination[]; +} + +interface SubDestination { + id: string; + name: string; +} + +type PlacementType = + | "all" + | "mabes" + | "polda" + | "international" + | "wilayah" + | "nasional" + | "satker" + | string; + +interface TempFileItem { + id: number | string; +} + // Updated FileType to reflect API response interface FileType { contentId: number; @@ -134,9 +168,9 @@ const WRITING_STYLES = [ ]; const PLACEMENT_OPTIONS = [ - { value: "all", label: "Semua" }, - { value: "mabes", label: "Nasional" }, - { value: "polda", label: "Wilayah" }, + { value: "semua", label: "Semua" }, + { value: "nasional", label: "Nasional" }, + { value: "wilayah", label: "Wilayah" }, { value: "international", label: "Internasional" }, ]; @@ -209,6 +243,79 @@ export default function FormConvertSPIT() { const userLevelId = getCookiesDecrypt("ulie"); const roleId = getCookiesDecrypt("urie"); const [isUserMabesApprover, setIsUserMabesApprover] = useState(false); + const [fileUnitSelections, setFileUnitSelections] = useState< + Array<{ + semua: boolean; + nasional: boolean; + wilayah: boolean; + international: boolean; + polda: boolean; + satker: boolean; + }> + >([]); + const [unitSelection, setUnitSelection] = useState({ + semua: false, + nasional: false, + wilayah: false, + international: false, + polda: false, + satker: false, + }); + const [fileCheckedLevels, setFileCheckedLevels] = useState< + Array> + >([]); + const [listDest, setListDest] = useState([]); + const [isDetailOfRegionShowed, setIsDetailOfRegionShowed] = useState(false); + const [isUpdatingFromMainCheckbox, setIsUpdatingFromMainCheckbox] = + useState(false); + const [mainCheckboxChangeType, setMainCheckboxChangeType] = + useState(""); + const [checkedLevels, setCheckedLevels] = useState>(new Set()); + const [expandedPolda, setExpandedPolda] = useState>( + {} + ); + + useEffect(() => { + async function fetchPoldaPolres() { + setIsLoading(true); + try { + const response = await getUserLevelForAssignments(); + setListDest(response?.data?.data.list); + const initialExpandedState = response?.data?.data.list.reduce( + (acc: any, polda: any) => { + acc[polda.id] = false; + return acc; + }, + {} + ); + setExpandedPolda(initialExpandedState); + console.log("polres", initialExpandedState); + } catch (error) { + console.error("Error fetching Polda/Polres data:", error); + } finally { + setIsLoading(false); + } + } + fetchPoldaPolres(); + }, []); + + // useEffect untuk sinkronisasi checkbox modal dengan checkbox utama + useEffect(() => { + if ( + listDest.length > 0 && + isUpdatingFromMainCheckbox && + mainCheckboxChangeType + ) { + syncModalWithMainCheckbox(); + } + }, [isUpdatingFromMainCheckbox, mainCheckboxChangeType]); + + // useEffect untuk update checkbox utama ketika pilihan modal berubah + useEffect(() => { + if (!isUpdatingFromMainCheckbox && listDest.length > 0) { + updateMainCheckboxFromModalLegacy(); + } + }, [checkedLevels, isUpdatingFromMainCheckbox]); useEffect(() => { initializeComponent(); @@ -537,27 +644,42 @@ export default function FormConvertSPIT() { ); }; - const getPlacementData = (type: string) => { - const placementData: PlacementData[] = []; - if (type == "mabes") { - for (let i = 0; i < filePlacements.length; i++) { - if (filePlacements[i].length > 0) { - const placements = filePlacements[i]; - placementData.push({ - mediaFileId: files[i].contentId, - placements: placements.join(","), - }); - } - } - } else { - for (let i = 0; i < files.length; i++) { - placementData.push({ - mediaFileId: files[i].contentId, - placements: "polda", - }); - } - } - return placementData; + const getPlacementData = () => { + return files.map((file, index) => { + const fid = index; + + // ✅ LEVEL CHECKBOX (POLDA, SATKER, dst.) + const levelSet = fileCheckedLevels[fid] + ? Array.from(fileCheckedLevels[fid]) + : []; + + // ✅ PLACEMENTS UTAMA (nasional, wilayah, international) + const unit = fileUnitSelections[fid] || { + nasional: false, + wilayah: false, + international: false, + polda: false, + satker: false, + semua: false, + }; + + let placements: string[] = []; + + // ✅ Map utama + if (unit.nasional) placements.push("mabes"); + // if (unit.wilayah) placements.push("polda"); + if (unit.international) placements.push("international"); + if (unit.polda) placements.push("polda"); + if (unit.satker) placements.push("satker"); + + placements = Array.from(new Set(placements)); + + return { + mediaFileId: file.contentId, + placements: placements.join(","), // ✅ "polda,satker" + customLocationPlacements: levelSet.join(","), // ✅ "219,220,221,..." + }; + }); }; const checkPlacement = (data: any) => { @@ -617,13 +739,22 @@ export default function FormConvertSPIT() { categoryId: selectedCategoryId, publishedFor: publishedFor.join(","), creator: data.contentCreator, - files: isUserMabesApprover - ? getPlacementData("mabes") - : getPlacementData("polda"), + files: getPlacementData(), }; await convertSPIT(requestData); + // update placements (CRITICAL) + const placementsPayload = buildPlacementsPayload(); + const responseFilePlacements = await updateFilePlacements( + placementsPayload + ); + if (responseFilePlacements?.error) { + close(); + error(responseFilePlacements?.message); + return false; + } + MySwal.fire({ title: "Success", text: "Data saved successfully", @@ -643,6 +774,8 @@ export default function FormConvertSPIT() { } finally { setIsSaving(false); } + + handleFileUnitChange; }; const handleDelete = async () => { @@ -696,6 +829,772 @@ export default function FormConvertSPIT() { ); } + const handleFileUnitChange = ( + fileIndex: number, + key: keyof typeof unitSelection, + value: boolean + ) => { + setFileUnitSelections((prev) => { + const newSelections = [...prev]; + const currentSelection = { ...newSelections[fileIndex] }; + + if (key === "semua") { + // Jika klik Semua, set semua value ke true/false + currentSelection.semua = value; + currentSelection.nasional = value; + currentSelection.wilayah = value; + currentSelection.international = value; + currentSelection.polda = value; + currentSelection.satker = value; + + // Update fileCheckedLevels untuk sinkronisasi dengan modal + setFileCheckedLevels((prevLevels) => { + const newArray = [...prevLevels]; + const currentFileLevels = new Set( + newArray[fileIndex] || new Set() + ); + + if (value) { + // Checklist semua item di modal + listDest.forEach((item: any) => { + currentFileLevels.add(Number(item.id)); + if (item.subDestination) { + item.subDestination.forEach((sub: any) => { + currentFileLevels.add(Number(sub.id)); + }); + } + }); + } else { + // Unchecklist semua item di modal + currentFileLevels.clear(); + } + + newArray[fileIndex] = currentFileLevels; + return newArray; + }); + } else { + // Jika wilayah dicentang, auto centang POLDA, SATKER + if (key === "wilayah") { + currentSelection.wilayah = value; + setIsDetailOfRegionShowed(value); + + if (value) { + // Ketika wilayah dicentang, auto centang POLDA, SATKER + currentSelection.polda = true; + currentSelection.satker = true; + + // Update fileCheckedLevels untuk mengisi semua POLDA dan SATKER POLRI ketika wilayah dicentang + setFileCheckedLevels((prevLevels) => { + const newArray = [...prevLevels]; + const currentFileLevels = new Set( + newArray[fileIndex] || new Set() + ); + + // Checklist semua POLDA di modal + listDest.forEach((item: any) => { + if (item.levelNumber === 2 && item.name !== "SATKER POLRI") { + currentFileLevels.add(Number(item.id)); + } + }); + + // Checklist SATKER POLRI dan semua sub-itemsnya + const satkerItem = listDest.find( + (item: any) => item.name === "SATKER POLRI" + ); + if (satkerItem) { + currentFileLevels.add(Number(satkerItem.id)); + // Checklist semua sub-items di bawah SATKER POLRI + if (satkerItem.subDestination) { + satkerItem.subDestination.forEach((sub: any) => { + currentFileLevels.add(Number(sub.id)); + }); + } + } + + newArray[fileIndex] = currentFileLevels; + return newArray; + }); + } else { + // Ketika wilayah di-uncheck, uncheck POLDA, SATKER dan hapus data POLDA dari fileCheckedLevels + currentSelection.polda = false; + currentSelection.satker = false; + + // Update fileCheckedLevels untuk menghapus semua POLDA dan SATKER POLRI ketika wilayah di-uncheck + setFileCheckedLevels((prevLevels) => { + const newArray = [...prevLevels]; + const currentFileLevels = new Set( + newArray[fileIndex] || new Set() + ); + + // Hapus semua POLDA dari modal + listDest.forEach((item: any) => { + if (item.levelNumber === 2 && item.name !== "SATKER POLRI") { + currentFileLevels.delete(Number(item.id)); + } + }); + + // Hapus SATKER POLRI dan semua sub-itemsnya + const satkerItem = listDest.find( + (item: any) => item.name === "SATKER POLRI" + ); + if (satkerItem) { + currentFileLevels.delete(Number(satkerItem.id)); + // Hapus semua sub-items di bawah SATKER POLRI + if (satkerItem.subDestination) { + satkerItem.subDestination.forEach((sub: any) => { + currentFileLevels.delete(Number(sub.id)); + }); + } + } + + newArray[fileIndex] = currentFileLevels; + return newArray; + }); + } + } else { + // Update salah satu saja + currentSelection[key] = value; + } + + // Cek apakah semua selain "semua" sudah dicentang + const allChecked = [ + "nasional", + "wilayah", + "international", + "polda", + "satker", + ].every((k) => currentSelection[k as keyof typeof unitSelection]); + + currentSelection.semua = allChecked; + } + + newSelections[fileIndex] = currentSelection; + return newSelections; + }); + }; + + const setupPlacement = ( + index: number, + placement: string, + checked: boolean + ) => { + let temp = [...filePlacements]; + if (checked) { + if (placement === "all") { + temp[index] = ["all", "mabes", "polda", "international"]; + setFileCheckedLevels((prevLevels) => { + const newArray = [...prevLevels]; + const currentFileLevels = new Set( + newArray[index] || new Set() + ); + listDest.forEach((item: any) => { + currentFileLevels.add(Number(item.id)); + if (item.subDestination) { + item.subDestination.forEach((sub: any) => { + currentFileLevels.add(Number(sub.id)); + }); + } + }); + newArray[index] = currentFileLevels; + return newArray; + }); + setFileUnitSelections((prevSelections) => { + const newSelections = [...prevSelections]; + const currentSelection = { ...newSelections[index] }; + currentSelection.nasional = true; + currentSelection.wilayah = true; + currentSelection.international = true; + currentSelection.polda = true; + // currentSelection.polres = true; + currentSelection.satker = true; + currentSelection.semua = true; + + newSelections[index] = currentSelection; + return newSelections; + }); + } else if (placement === "satker") { + const now = temp[index] || []; + if (!now.includes("satker")) { + now.push("satker"); + } + temp[index] = now; + } else { + const now = temp[index] || []; + if (!now.includes(placement)) { + now.push(placement); + } + const nonSatkerItems = now.filter( + (item) => item !== "satker" && item !== "all" + ); + if (nonSatkerItems.length === 3 && !now.includes("all")) { + now.push("all"); + } + temp[index] = now; + } + } else { + if (placement === "all") { + temp[index] = []; + setFileCheckedLevels((prevLevels) => { + const newArray = [...prevLevels]; + const currentFileLevels = new Set( + newArray[index] || new Set() + ); + currentFileLevels.clear(); + + newArray[index] = currentFileLevels; + return newArray; + }); + + // Update fileUnitSelections untuk checkbox tingkat utama + setFileUnitSelections((prevSelections) => { + const newSelections = [...prevSelections]; + const currentSelection = { ...newSelections[index] }; + + // Set semua checkbox tingkat utama ke false + currentSelection.nasional = false; + currentSelection.wilayah = false; + currentSelection.international = false; + currentSelection.polda = false; + // currentSelection.polres = false; + currentSelection.satker = false; + currentSelection.semua = false; + + newSelections[index] = currentSelection; + return newSelections; + }); + } else { + const now = temp[index]?.filter((a) => a !== placement); + console.log("now", now); + temp[index] = now; + if (placement === "wilayah") { + // Ketika wilayah di-uncheck, hapus wilayah, polda, dan satker + const now = temp[index]?.filter( + (a) => a !== "wilayah" && a !== "polda" && a !== "satker" + ); + temp[index] = now; + } else if (placement === "polda") { + // Ketika polda di-uncheck, hapus polda dari filePlacements + const now = temp[index]?.filter((a) => a !== "polda"); + temp[index] = now; + } else if (placement === "satker") { + // Ketika satker di-uncheck, hapus satker dari filePlacements + const now = temp[index]?.filter((a) => a !== "satker"); + temp[index] = now; + } else { + const now = temp[index]?.filter((a) => a !== placement); + temp[index] = now; + } + + // Hapus "all" jika tidak semua item ter-checklist + if (now.includes("all")) { + const nonSatkerItems = now.filter( + (item) => item !== "satker" && item !== "all" + ); + if (nonSatkerItems.length < 3) { + const newData = now.filter((b) => b !== "all"); + temp[index] = newData; + } + } + } + } + setFilePlacements(temp); + + // Update checklist levels di modal berdasarkan placement yang diubah + updateModalChecklistLevels(index, placement, checked); + }; + const updateModalChecklistLevels = ( + fileIndex: number, + placement: string, + checked: boolean + ) => { + if (!listDest || listDest.length === 0) return; + + setFileCheckedLevels((prev) => { + const newArray = [...prev]; + const currentFileLevels = new Set(newArray[fileIndex]); + + if (checked) { + if (placement === "polda") { + // Checklist semua POLDA (bukan SATKER POLRI) + listDest.forEach((item: any) => { + if (item.levelNumber === 2 && item.name !== "SATKER POLRI") { + currentFileLevels.add(Number(item.id)); + } + }); + } else if (placement === "satker") { + // Checklist SATKER POLRI dan semua sub-item di bawahnya + const satkerItem: any = listDest.find( + (item: any) => item.name === "SATKER POLRI" + ); + if (satkerItem) { + currentFileLevels.add(Number(satkerItem.id)); + if (satkerItem.subDestination) { + satkerItem.subDestination.forEach((sub: any) => { + currentFileLevels.add(Number(sub.id)); + }); + } + } + } + } else { + if (placement === "polda") { + // Unchecklist semua POLDA + listDest.forEach((item: any) => { + if (item.levelNumber === 2 && item.name !== "SATKER POLRI") { + currentFileLevels.delete(Number(item.id)); + } + }); + } else if (placement === "satker") { + // Unchecklist SATKER POLRI dan semua sub-item di bawahnya + const satkerItem: any = listDest.find( + (item: any) => item.name === "SATKER POLRI" + ); + if (satkerItem) { + currentFileLevels.delete(Number(satkerItem.id)); + if (satkerItem.subDestination) { + satkerItem.subDestination.forEach((sub: any) => { + currentFileLevels.delete(Number(sub.id)); + }); + } + } + } + } + + newArray[fileIndex] = currentFileLevels; + return newArray; + }); + }; + + // Fungsi untuk update checkbox utama berdasarkan checkbox modal (global/legacy) + const updateMainCheckboxFromModalLegacy = () => { + if (!isUpdatingFromMainCheckbox && listDest.length > 0) { + // Hitung item yang dipilih berdasarkan checkedLevels + const checkedPoldaCount = listDest.filter( + (item: any) => + item.levelNumber === 2 && + item.name !== "SATKER POLRI" && + checkedLevels.has(Number(item.id)) + ).length; + + const satkerItem: any = listDest.find( + (item: any) => item.name === "SATKER POLRI" + ); + const checkedSatkerCount = satkerItem + ? (checkedLevels.has(Number(satkerItem.id)) ? 1 : 0) + + (satkerItem.subDestination?.filter((sub: any) => + checkedLevels.has(Number(sub.id)) + ).length || 0) + : 0; + + // Checkbox aktif jika ADA item yang dipilih dalam kategori tersebut + const hasSelectedPolda = checkedPoldaCount > 0; + const hasSelectedSatker = checkedSatkerCount > 0; + + // Update unitSelection berdasarkan yang dipilih di modal + setUnitSelection((prev) => { + const newState = { ...prev }; + + // Update individual checkboxes + newState.polda = hasSelectedPolda; + newState.satker = hasSelectedSatker; + + // Update checkbox "semua" berdasarkan semua checkbox yang aktif + newState.semua = + newState.nasional && + newState.wilayah && + newState.international && + hasSelectedPolda && + hasSelectedSatker; + + return newState; + }); + } + }; + + const updateMainCheckboxFromModal = (fileIndex: number) => { + setFileUnitSelections((prev) => { + const newSelections = [...prev]; + const currentSelection = { ...newSelections[fileIndex] }; + const currentFileLevels = fileCheckedLevels[fileIndex]; + + if (!currentFileLevels) return prev; + + // Hitung total POLDA yang ada (bukan SATKER POLRI) + const totalPoldaCount = listDest.filter( + (item: any) => item.levelNumber === 2 && item.name !== "SATKER POLRI" + ).length; + + // Hitung berapa banyak POLDA yang ter-checklist (bukan SATKER POLRI) + const checkedPoldaCount = listDest.reduce((total: number, item: any) => { + if ( + item.levelNumber === 2 && + item.name !== "SATKER POLRI" && + currentFileLevels.has(Number(item.id)) + ) { + return total + 1; + } + return total; + }, 0); + + // Cek apakah SATKER POLRI ter-checklist + const satkerItem = listDest.find( + (item: any) => item.name === "SATKER POLRI" + ); + const isSatkerChecked = + satkerItem && currentFileLevels.has(Number(satkerItem.id)); + + // Update checkbox berdasarkan kondisi + // POLDA aktif jika ada minimal 1 POLDA ter-checklist + currentSelection.polda = checkedPoldaCount > 0; + currentSelection.satker = Boolean(isSatkerChecked); + + // Update checkbox "semua" berdasarkan semua checkbox yang aktif + currentSelection.semua = + currentSelection.nasional && + currentSelection.wilayah && + currentSelection.international && + currentSelection.polda && + currentSelection.satker; + + newSelections[fileIndex] = currentSelection; + return newSelections; + }); + }; + + const toggleExpand = (id: number) => { + setExpandedPolda((prev) => ({ + ...prev, + [id]: !prev[id], + })); + }; + + const handleFileCheckboxChangePlacement = ( + fileIndex: number, + levelId: number + ) => { + setFileCheckedLevels((prev) => { + const newArray = [...prev]; + const currentFileLevels = new Set(newArray[fileIndex]); + const isCurrentlyChecked = currentFileLevels.has(levelId); + + if (isCurrentlyChecked) { + currentFileLevels.delete(levelId); + + // Jika ini adalah POLDA yang di-unchecklist, unchecklist juga semua polres di bawahnya + const poldaItem = listDest.find( + (item: any) => Number(item.id) === levelId + ) as any; + if ( + poldaItem && + poldaItem.subDestination && + poldaItem.name !== "SATKER POLRI" + ) { + poldaItem.subDestination.forEach((polres: any) => { + currentFileLevels.delete(Number(polres.id)); + }); + } + + // Jika ini adalah SATKER POLRI yang di-unchecklist, unchecklist juga semua sub-item di bawahnya + if (poldaItem && poldaItem.name === "SATKER POLRI") { + poldaItem.subDestination?.forEach((subItem: any) => { + currentFileLevels.delete(Number(subItem.id)); + }); + } + } else { + currentFileLevels.add(levelId); + + // Jika ini adalah SATKER POLRI yang di-checklist, checklist juga semua sub-item di bawahnya + const satkerItem = listDest.find( + (item: any) => Number(item.id) === levelId + ) as any; + if (satkerItem && satkerItem.name === "SATKER POLRI") { + // Checklist semua sub-item di bawah SATKER POLRI (bukan POLRES) + satkerItem.subDestination?.forEach((subItem: any) => { + currentFileLevels.add(Number(subItem.id)); + }); + } + } + + newArray[fileIndex] = currentFileLevels; + + // Update checkbox utama berdasarkan perubahan di modal + // Pindahkan ke sini agar state sudah ter-update + setTimeout(() => updateMainCheckboxFromModal(fileIndex), 0); + + return newArray; + }); + }; + + const handleSelectAllSubItems = (fileIndex: number, polda: any) => { + setFileCheckedLevels((prev) => { + const newArray = [...prev]; + const currentFileLevels = new Set(newArray[fileIndex]); + + // Cek apakah semua sub-items sudah ter-checklist + const allSubItemsChecked = polda.subDestination?.every((sub: any) => + currentFileLevels.has(Number(sub.id)) + ); + + if (allSubItemsChecked) { + // Jika semua sudah ter-checklist, unchecklist semuanya + polda.subDestination?.forEach((sub: any) => { + currentFileLevels.delete(Number(sub.id)); + }); + } else { + // Jika belum semua ter-checklist, checklist semuanya + // Checklist SATKER POLRI juga jika belum ter-checklist + if (!currentFileLevels.has(Number(polda.id))) { + currentFileLevels.add(Number(polda.id)); + } + // Checklist semua sub-items + polda.subDestination?.forEach((sub: any) => { + currentFileLevels.add(Number(sub.id)); + }); + } + + newArray[fileIndex] = currentFileLevels; + + // Update checkbox utama berdasarkan perubahan di modal + setTimeout(() => updateMainCheckboxFromModal(fileIndex), 0); + + return newArray; + }); + }; + + // Fungsi untuk sinkronisasi checkbox modal dengan checkbox utama + const syncModalWithMainCheckbox = () => { + if (isUpdatingFromMainCheckbox) { + const newCheckedLevels = new Set(checkedLevels); + + // Handle checklist actions - menambahkan semua item ke modal + if (mainCheckboxChangeType === "polda_checked") { + // Checklist semua polda + listDest.forEach((item: any) => { + if (item.levelNumber === 2 && item.name !== "SATKER POLRI") { + newCheckedLevels.add(Number(item.id)); + } + }); + } else if (mainCheckboxChangeType === "satker_checked") { + // Checklist satker + const satkerItem: any = listDest.find( + (item: any) => item.name === "SATKER POLRI" + ); + if (satkerItem) { + newCheckedLevels.add(Number(satkerItem.id)); + // Checklist semua sub-item yang ada di bawah SATKER (bukan POLRES) + if (satkerItem.subDestination) { + satkerItem.subDestination.forEach((sub: any) => { + newCheckedLevels.add(Number(sub.id)); + }); + } + } + } else if (mainCheckboxChangeType === "semua_checked") { + // Checklist semua item + listDest.forEach((item: any) => { + newCheckedLevels.add(Number(item.id)); + // Checklist semua sub-item di bawah setiap item + if (item.subDestination) { + item.subDestination.forEach((sub: any) => { + newCheckedLevels.add(Number(sub.id)); + }); + } + }); + } else if (mainCheckboxChangeType === "polda_unchecked") { + // Clear polda dari checkedLevels, tapi jangan hapus SATKER POLRI + listDest.forEach((item: any) => { + if (item.levelNumber === 2 && item.name !== "SATKER POLRI") { + newCheckedLevels.delete(Number(item.id)); + } + }); + } else if (mainCheckboxChangeType === "satker_unchecked") { + // Clear satker dan semua sub-item di bawahnya dari checkedLevels + const satkerItem: any = listDest.find( + (item: any) => item.name === "SATKER POLRI" + ); + if (satkerItem) { + newCheckedLevels.delete(Number(satkerItem.id)); + if (satkerItem.subDestination) { + satkerItem.subDestination.forEach((sub: any) => { + newCheckedLevels.delete(Number(sub.id)); + }); + } + } + } else if (mainCheckboxChangeType === "semua_unchecked") { + // Clear semua + newCheckedLevels.clear(); + } + + setCheckedLevels(newCheckedLevels); + + // Reset flag setelah sinkronisasi selesai + setIsUpdatingFromMainCheckbox(false); + setMainCheckboxChangeType(""); + } + }; + + const toFileId = (f: any): string => String(f?.id ?? ""); + const ensureFileUnit = (fid: any) => { + setFileUnitSelections((prev) => { + if (prev[fid]) return prev; + return { + ...prev, + [fid]: { + semua: false, + nasional: false, + wilayah: false, + international: false, + polda: false, + satker: false, + }, + }; + }); + }; + const ensureFilePlacement = (fid: any) => { + setFilePlacements((prev) => (prev[fid] ? prev : { ...prev, [fid]: [] })); + }; + const ensureFileCheckedLevels = (fid: any) => { + setFileCheckedLevels((prev) => + prev[fid] ? prev : { ...prev, [fid]: new Set() } + ); + }; + + const buildPlacementsPayload = () => { + return files.map((file, index) => { + const fid = index; + + const levelSet = fileCheckedLevels[fid] + ? Array.from(fileCheckedLevels[fid]) + : []; + + const unit = fileUnitSelections[fid] || { + nasional: false, + wilayah: false, + international: false, + polda: false, + satker: false, + semua: false, + }; + + let placements: string[] = []; + + if (unit.nasional) placements.push("mabes"); + // if (unit.wilayah) placements.push("polda"); + if (unit.international) placements.push("international"); + if (unit.polda) placements.push("polda"); + if (unit.satker) placements.push("satker"); + + placements = Array.from(new Set(placements)); + + return { + mediaFileId: file.contentId, + placements: placements.join(","), // ✅ contoh: "polda,satker" + customLocationPlacements: levelSet.join(","), // ✅ contoh: "219,220,..." + }; + }); + }; + + const handleGlobalPlacement = ( + type: "semua" | "nasional" | "wilayah" | "international", + checked: boolean + ) => { + const count = files.length; + + // helper untuk ambil semua id POLDA + SATKER + sub + const getAllLevelIds = () => { + const set = new Set(); + listDest.forEach((d: any) => { + if (d?.id != null) set.add(Number(d.id)); + d?.subDestination?.forEach((sub: any) => { + if (sub?.id != null) set.add(Number(sub.id)); + }); + }); + return set; + }; + + // atur visibilitas panel detail wilayah + if ((type === "wilayah" || type === "semua") && checked) { + setIsDetailOfRegionShowed(true); + } + if (type === "semua" && !checked) { + setIsDetailOfRegionShowed(false); + } + + // ======= fileUnitSelections (checkbox per-bar isian) ======= + setFileUnitSelections( + Array.from({ length: count }, () => { + if (type === "semua") { + // ✅ AllSemua menyalakan SEMUA checkbox + return { + semua: checked, + nasional: checked, + wilayah: checked, + international: checked, + polda: checked, + satker: checked, + }; + } + if (type === "nasional") { + return { + semua: false, + nasional: checked, + wilayah: false, + international: false, + polda: false, + satker: false, + }; + } + if (type === "wilayah") { + return { + semua: false, + nasional: false, + wilayah: checked, + international: false, + polda: checked, // wilayah mengaktifkan polda + satker: checked, // dan satker + }; + } + // type === "international" + return { + semua: false, + nasional: false, + wilayah: false, + international: checked, + polda: false, + satker: false, + }; + }) + ); + + // ======= fileCheckedLevels (customLocationPlacements) ======= + setFileCheckedLevels( + Array.from({ length: count }, () => { + // AllSemua atau AllWilayah: checklist semua level + if (checked && (type === "semua" || type === "wilayah")) { + return getAllLevelIds(); + } + // lainnya: kosongkan (tidak memilih level spesifik) + return new Set(); + }) + ); + + // ======= (opsional) sinkron UI lain yang masih pakai filePlacements ======= + setFilePlacements( + Array.from({ length: count }, () => { + if (!checked) return []; + if (type === "semua") { + return ["all", "mabes", "polda", "international", "satker"]; + } + if (type === "nasional") { + return ["mabes"]; + } + if (type === "wilayah") { + return ["polda", "satker"]; + } + // international + return ["international"]; + }) + ); + }; + return (
{/* Header */} @@ -1125,8 +2024,8 @@ export default function FormConvertSPIT() { - handleSelectAllPlacements( - option.value, + handleGlobalPlacement( + option.value as any, Boolean(checked) ) } @@ -1170,7 +2069,344 @@ export default function FormConvertSPIT() { file.contentFileName || `File ${file.contentId}`}

-
+
+ {/*
+ + Pengaturan Distribusi +
*/} + + {/* Checkbox Tingkat Utama */} +
+
+ {[ + { key: "semua", label: "Semua" }, + { + key: "nasional", + label: "Nasional", + }, + { key: "wilayah", label: "Wilayah" }, + { + key: "international", + label: "Internasional", + }, + ].map((item, idx) => ( +
+ { + handleFileUnitChange( + index, + item.key as keyof typeof unitSelection, + value as boolean + ); + setupPlacement( + index, + item.key, + Boolean(value) + ); + }} + /> + +
+ ))} +
+ + {/* Detail Wilayah */} + {fileUnitSelections[index]?.wilayah && + isDetailOfRegionShowed && ( +
+

+ Detail Wilayah: +

+ + {/* Checkbox Sub-kategori dengan tombol Kustom sejajar */} +
+ {[ + { key: "polda", label: "POLDA" }, + { + key: "satker", + label: "SATKER", + }, + ].map((item, idx) => ( +
+ { + handleFileUnitChange( + index, + item.key as keyof typeof unitSelection, + value as boolean + ); + setupPlacement( + index, + item.key, + Boolean(value) + ); + }} + /> + +
+ ))} + + {/* Tombol Kustom sejajar dengan checkbox */} +
+ + + + + + + + Daftar Wilayah POLDA dan + SATKER + + +
+ {listDest.map( + (polda: any) => ( +
+ {/* Header POLDA */} +
+ + {/* Tombol expand hanya untuk SATKER POLRI */} + {polda.name === + "SATKER POLRI" && + polda.subDestination && ( + + )} +
+ + {/* Sub-items hanya untuk SATKER POLRI */} + {polda.name === + "SATKER POLRI" && + polda.subDestination && + expandedPolda[ + polda.id + ] && ( +
+ {/* Tombol Pilih Semua untuk sub-items */} +
+ {(() => { + const allSubItemsChecked = + polda.subDestination?.every( + ( + sub: any + ) => + fileCheckedLevels[ + index + ]?.has( + Number( + sub.id + ) + ) + ); + return ( + + ); + })()} +
+
+ {polda.subDestination.map( + ( + sub: any + ) => ( + + ) + )} +
+
+ )} +
+ ) + )} +
+
+ + + + + + +
+
+
+
+
+
+ )} +
+
+ + {/*
{PLACEMENT_OPTIONS.map((option) => (
))} -
+
*/}
))}