mediahub-fe/components/form/content/image-update-form.tsx

4458 lines
178 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"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,
getTagsBySubCategoryId,
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 { Link } from "@/i18n/routing";
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";
// ================== 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" }),
});
type ImageSchema = z.infer<typeof imageSchema>;
type Category = { id: string; name: string };
type PlacementType =
| "all"
| "mabes"
| "polda"
| "international"
| "wilayah"
| "nasional"
| "satker"
| 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;
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 };
interface Destination {
id: string;
name: string;
levelNumber?: number;
subDestination?: Array<{ id: string; name: string }>;
}
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 t = useTranslations("Form");
const roleId = getCookiesDecrypt("urie");
let progressInfo: any = [];
let counterUpdateProgress = 0;
const [progressList, setProgressList] = useState<any>([]);
let uploadPersen = 0;
const [isStartUpload, setIsStartUpload] = useState(false);
const [counterProgress, setCounterProgress] = useState(0);
const [categories, setCategories] = useState<Category[]>([]);
const [listDest, setListDest] = useState<Destination[]>([]);
const [expandedPolda, setExpandedPolda] = useState<Record<string, boolean>>(
{}
);
const [detail, setDetail] = useState<Detail>();
const [selectedTarget, setSelectedTarget] = useState<string | undefined>();
const [publishedFor, setPublishedFor] = useState<string[]>([]);
const [tags, setTags] = useState<string[]>([]);
const [thumbnailFile, setThumbnailFile] = useState<File | null>(null);
const [translatedContent, setTranslatedContent] = useState("");
const [isLoadingTranslate, setIsLoadingTranslate] = useState(false);
const [translatedTitle, setTranslatedTitle] = useState("");
const [isLoadingTranslateTitle, setIsLoadingTranslateTitle] = useState(false);
const inputRef = useRef<HTMLInputElement>(null);
const [files, setFiles] = useState<(FileWithPreview | any)[]>([]);
// fileTypeId: image
const fileTypeId = "1";
const [filePlacements, setFilePlacements] = useState<
Record<string, string[]>
>({});
const [fileCheckedLevels, setFileCheckedLevels] = useState<
Record<string, Set<number>>
>({});
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<Set<number>>(new Set());
const [isLoading, setIsLoading] = useState(false);
const [isUpdatingFromMainCheckbox, setIsUpdatingFromMainCheckbox] =
useState(false);
const [mainCheckboxChangeType, setMainCheckboxChangeType] =
useState<string>("");
const {
control,
handleSubmit,
setValue,
getValues,
formState: { errors },
} = useForm<ImageSchema>({ 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/*": [] },
});
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 ensureFilePlacement = (fid: string) => {
setFilePlacements((prev) => (prev[fid] ? prev : { ...prev, [fid]: [] }));
};
const ensureFileCheckedLevels = (fid: string) => {
setFileCheckedLevels((prev) =>
prev[fid] ? prev : { ...prev, [fid]: new Set<number>() }
);
};
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[];
};
<<<<<<< HEAD
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);
// Set the selected target to the category ID from 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<number>();
});
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()));
}
=======
const toggleExpand = (idStr: string) => {
setExpandedPolda((prev) => ({ ...prev, [idStr]: !prev[idStr] }));
};
useEffect(() => {
(async () => {
setIsLoading(true);
try {
const resp = await getUserLevelForAssignments();
const list = resp?.data?.data?.list || [];
setListDest(list);
const init: Record<string, boolean> = {};
list.forEach((p: any) => (init[String(p.id)] = false));
setExpandedPolda(init);
} catch (e) {
console.error("Error fetching destinations", e);
} finally {
setIsLoading(false);
>>>>>>> 5b6ffd086332104beb9f02b1414b48cda3f030a0
}
})();
}, []);
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<string, string[]> = {};
const nextCheckedLevels: Record<string, Set<number>> = {};
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<number>();
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
.filter((opt) => opt.id !== "all")
.map((opt) => opt.id);
setPublishedFor(
publishedFor.length === allOptions.length ? [] : allOptions
);
} else {
setPublishedFor((prev) =>
prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id]
);
}
};
// ========== Tags ==========
const handleAddTag = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter" && e.currentTarget.value.trim()) {
e.preventDefault();
const newTag = e.currentTarget.value.trim();
if (!tags.includes(newTag)) {
setTags((prev) => [...prev, newTag]);
if (inputRef.current) inputRef.current.value = "";
}
}
};
const handleRemoveTag = (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<number>());
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<number>());
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<number>();
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<number>());
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 = translatedContent || data.description;
const finalTitle = translatedTitle?.trim() ? translatedTitle : data.title;
const requestData = {
...data,
id: detail?.id,
title: finalTitle,
description: htmlToString(descFinal),
htmlDescription: descFinal,
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,
};
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] 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;
}
}
// update placements (CRITICAL)
const placementsPayload = buildPlacementsPayload();
const responseFilePlacements = await updateFilePlacements(
placementsPayload
);
if (responseFilePlacements?.error) {
close();
error(responseFilePlacements?.message);
return false;
}
close();
// 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({
title: "Sukses",
text: "Data berhasil disimpan.",
icon: "success",
confirmButtonColor: "#3085d6",
confirmButtonText: "OK",
}).then(() => {
router.push("/in/contributor/content/image");
});
};
// ========== Upload tus ==========
async function uploadResumableFile(
idx: number,
idMedia: string,
file: any,
duration: string
) {
<<<<<<< HEAD
// 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 resCsrf = await getCsrfToken();
const csrfToken = resCsrf?.data?.token;
const headers = { "X-XSRF-TOKEN": csrfToken };
>>>>>>> 5b6ffd086332104beb9f02b1414b48cda3f030a0
if (!file.secondaryUrl || file.secondaryUrl == "") {
const upload = new Upload(file, {
endpoint: `${process.env.NEXT_PUBLIC_API}/media/file/upload`,
headers,
retryDelays: [0, 3000, 6000, 12000, 24000],
chunkSize: 20000,
metadata: {
mediaid: idMedia,
filename: file.name,
filetype: file.type,
duration,
isWatermark: "true",
},
onBeforeRequest(req) {
const 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 percent = Math.floor((bytesAccepted / bytesTotal) * 100);
progressInfo[idx].percentage = percent;
counterUpdateProgress++;
<<<<<<< HEAD
// console.log(counterUpdateProgress);
=======
>>>>>>> 5b6ffd086332104beb9f02b1414b48cda3f030a0
setProgressList(progressInfo);
setCounterProgress(counterUpdateProgress);
},
onSuccess: async () => {
progressInfo[idx].percentage = 100;
counterUpdateProgress++;
setCounterProgress(counterUpdateProgress);
successTodo();
},
});
// 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",
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 handleDeleteFile = (fid: number | string) => {
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(fid);
}
});
};
async function doDelete(fid: number | string) {
try {
const response = await deleteFile({ id: fid });
if (response?.error) {
error(response.message);
return;
}
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 renderFilePreview = (file: FileWithPreview | any) => {
if (file?.preview || file instanceof File) {
return (
<Image
width={48}
height={48}
alt={file.name}
src={file.preview || URL.createObjectURL(file)}
className="rounded border p-0.5"
/>
);
} else if (file.thumbnailFileUrl) {
return (
<Image
width={48}
height={48}
alt={file.fileName}
src={file.thumbnailFileUrl}
className="rounded border p-0.5"
/>
);
} else {
return <Icon icon="tabler:file-description" />;
}
};
// ========== Render ==========
if (!detail) return null;
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div className="flex flex-col lg:flex-row gap-10">
{/* LEFT */}
<Card className="w-full lg:w-8/12">
<div className="px-6 py-6">
<p className="text-lg font-semibold mb-3">
{t("form-image", { defaultValue: "Form Image" })}
</p>
{/* Title + Translate */}
<div className="py-3 space-y-2">
<div className="flex justify-between items-center">
<Label>{t("title", { defaultValue: "Title" })}</Label>
{roleId === "14" && (
<button
type="button"
onClick={async () => {
try {
loading();
setIsLoadingTranslateTitle(true);
const res = await translateText({
text: getValues("title"),
sourceLang: "ID",
targetLang: "EN",
});
if (!res.error) {
const resultText =
res?.data?.data?.translations?.[0]?.text || "";
setTranslatedTitle(resultText);
}
} catch (err) {
console.error("Translate title gagal:", err);
} finally {
close();
setIsLoadingTranslateTitle(false);
}
}}
className="px-3 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600"
>
{isLoadingTranslateTitle
? "Translating..."
: "Translate to English"}
</button>
)}
</div>
<div className="mt-2">
<Label className="text-sm font-semibold">
Indonesian Title
</Label>
<Controller
control={control}
name="title"
render={({ field }) => (
<Input
size="md"
type="text"
value={field.value}
onChange={field.onChange}
placeholder="Masukkan Judul Bahasa Indonesia"
/>
)}
/>
</div>
{translatedTitle && (
<div className="mt-4">
<Label className="text-sm font-semibold">English Title</Label>
<Input
size="md"
type="text"
value={translatedTitle}
onChange={(e) => setTranslatedTitle(e.target.value)}
placeholder="English version"
/>
<<<<<<< HEAD
{errors.title?.message && (
<p className="text-red-400 text-sm">
{errors.title.message}
</p>
)}
</div> */}
<div className="flex items-center">
<div className="py-3 w-full space-y-2">
<Label>{t("category", { defaultValue: "Category" })}</Label>
<Select
value={selectedTarget}
onValueChange={(id) => {
// console.log("Selected Category ID:", id);
setSelectedTarget(id);
}}
>
<SelectTrigger size="md">
<SelectValue placeholder="Pilih" />
</SelectTrigger>
<SelectContent>
{/* Show the category from details if it doesn't exist in categories list */}
{detail &&
!categories.find(
(cat) =>
String(cat.id) === String(detail.category.id)
) && (
<SelectItem
key={String(detail.category.id)}
value={String(detail.category.id)}
>
{detail.category.name}
</SelectItem>
)}
{categories.map((category) => (
<SelectItem
key={String(category.id)}
value={String(category.id)}
>
{category.name}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
=======
>>>>>>> 5b6ffd086332104beb9f02b1414b48cda3f030a0
</div>
)}
{errors.title?.message && (
<p className="text-red-400 text-sm">{errors.title.message}</p>
)}
</div>
{/* Category */}
<div className="flex items-center">
<div className="py-3 w-full space-y-2">
<Label>{t("category", { defaultValue: "Category" })}</Label>
<Select
value={selectedTarget}
onValueChange={(val) => setSelectedTarget(val)}
>
<SelectTrigger size="md">
<SelectValue placeholder="Pilih" />
</SelectTrigger>
<SelectContent>
{detail &&
!categories.find(
(c) => String(c.id) === String(detail.category.id)
) && (
<SelectItem
key={String(detail.category.id)}
value={String(detail.category.id)}
>
{detail.category.name}
</SelectItem>
)}
{categories.map((c) => (
<SelectItem key={String(c.id)} value={String(c.id)}>
{c.name}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
</div>
{/* Description + Translate */}
<div className="py-3 space-y-2">
<div className="flex justify-between items-center">
<Label>
{t("description", { defaultValue: "Description" })}
</Label>
{roleId === "14" && (
<button
type="button"
onClick={async () => {
try {
loading();
setIsLoadingTranslate(true);
const res = await translateText({
text: getValues("description"),
sourceLang: "ID",
targetLang: "EN",
});
if (!res.error) {
const resultText =
res?.data?.data?.translations?.[0]?.text || "";
setTranslatedContent(resultText);
}
} catch (err) {
console.error("Translate gagal:", err);
} finally {
close();
setIsLoadingTranslate(false);
}
}}
className="px-3 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600"
>
{isLoadingTranslate
? "Translating..."
: "Translate to English"}
</button>
)}
</div>
<div className="mt-3">
<Label className="text-sm font-semibold">
Indonesian Version
</Label>
<Controller
control={control}
name="description"
render={({ field }) => (
<CustomEditor
onChange={field.onChange}
initialData={field.value}
/>
)}
/>
</div>
{translatedContent && (
<div className="mt-5">
<Label className="text-sm font-semibold">
English Version
</Label>
<CustomEditor
onChange={(val: any) => setTranslatedContent(val)}
initialData={translatedContent}
/>
</div>
)}
{errors.description?.message && (
<p className="text-red-400 text-sm">
{errors.description.message}
</p>
)}
</div>
{/* File Selector */}
<div className="py-3 space-y-2">
<Label>{t("select-file", { defaultValue: "Select File" })}</Label>
<Fragment>
<div {...getRootProps({ className: "dropzone" })}>
<input {...getInputProps()} />
<div className="w-full text-center border-dashed border border-default-200 dark:border-default-300 rounded-md py-[52px] flex items-center flex-col">
<CloudUpload className="text-default-300 w-10 h-10" />
<h4 className="text-2xl font-medium mb-1 mt-3 text-card-foreground/80">
{t("drag-file", { defaultValue: "Drag File" })}
</h4>
<div className="text-xs text-muted-foreground">
{t("upload-file-max", {
defaultValue: "Upload File Max",
})}
</div>
</div>
</div>
{/* List Files */}
{files.length > 0 && (
<>
<div className="mt-6">
{files.map((file: any) => (
<div
key={toFileId(file)}
className="flex justify-between border px-3.5 py-3 my-4 rounded-md"
>
<div className="flex gap-3 items-center">
<div className="file-preview">
{renderFilePreview(file)}
</div>
<div>
<div className="text-sm text-card-foreground">
{file.fileName || file.name}
</div>
<div className="text-xs font-light text-muted-foreground">
{Math.round(file.size / 100) / 10 > 1000 ? (
<>
{(
Math.round(file.size / 100) / 10000
).toFixed(1)}
</>
) : (
<>
{(Math.round(file.size / 100) / 10).toFixed(
1
)}
</>
)}
{" kb"}
</div>
</div>
</div>
<Button
type="button"
size="icon"
color="destructive"
variant="outline"
className="border-none rounded-full"
onClick={() => handleDeleteFile(file.id)}
>
<Icon icon="tabler:x" className="h-5 w-5" />
</Button>
</div>
))}
</div>
{/* Placement Per File */}
<div className="mt-4">
<Label className="text-md font-semibold">
{t("file-media", { defaultValue: "File Media" })}
</Label>
<div className="grid gap-4">
{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<number>();
return (
<div
key={fid}
className="flex items-center border p-2 rounded-md"
>
<img
src={file.thumbnailFileUrl}
alt={file.fileName}
className="w-16 h-16 object-cover rounded-md mr-4"
/>
<div className="flex flex-wrap gap-3 items-center">
<div className="flex-grow min-w-[220px]">
<p className="font-medium">
{file.fileName || file.name}
</p>
<a
href={file.url}
target="_blank"
rel="noopener noreferrer"
className="text-blue-500 text-sm"
>
{t("view-file", {
defaultValue: "View File",
})}
</a>
</div>
<div className="bg-white rounded-md p-4 border w-full">
<div className="space-y-4">
{/* Main toggles */}
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
{[
{ key: "semua", label: "Semua" },
{ key: "nasional", label: "Nasional" },
{ key: "wilayah", label: "Wilayah" },
{
key: "international",
label: "Internasional",
},
].map((item) => (
<div
key={item.key}
className="flex items-center gap-2 p-2 border border-gray-200 rounded-md hover:bg-gray-50"
>
<Checkbox
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
);
}
}}
/>
<Label className="text-sm font-medium cursor-pointer">
{item.label}
</Label>
</div>
))}
</div>
{/* Detail Wilayah */}
{unit.wilayah && isDetailOfRegionShowed && (
<div className="border-t border-gray-200 pt-2">
<p className="text-sm font-medium text-gray-700 mb-2">
Detail Wilayah:
</p>
<div className="grid grid-cols-1 md:grid-cols-4 gap-3">
{[
{ key: "polda", label: "POLDA" },
{ key: "satker", label: "SATKER" },
].map((item) => (
<div
key={item.key}
className="flex items-center gap-2 p-3 border border-gray-200 rounded-md hover:bg-gray-50"
>
<Checkbox
checked={Boolean(
unit[
item.key as keyof typeof unit
]
)}
onCheckedChange={(val) =>
setPlacementChecked(
fid,
item.key,
Boolean(val)
)
}
/>
<Label className="text-sm font-medium cursor-pointer">
{item.label}
</Label>
</div>
))}
{/* Kustom */}
<div className="flex items-center justify-center p-3">
<Dialog>
<DialogTrigger asChild>
<Button
variant="outline"
size="sm"
className="gap-2"
>
<Icon
icon="material-symbols:tune"
width={16}
height={16}
/>
{t("custom", {
defaultValue: "Kustom",
})}
</Button>
</DialogTrigger>
<DialogContent className="max-w-[95vw] lg:max-w-[1400px] max-h-[90vh]">
<DialogHeader className="border-b border-gray-200 pb-4">
<DialogTitle className="text-lg font-semibold">
Daftar Wilayah POLDA dan
SATKER
</DialogTitle>
</DialogHeader>
<div className="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-4 max-h-[70vh] overflow-y-auto p-1">
{listDest.map(
(polda: any) => {
const pid = String(
polda.id
);
const isSatker =
polda.name ===
"SATKER POLRI";
const isExpanded =
expandedPolda[pid];
const allSubItemsChecked =
isSatker &&
(
polda.subDestination ||
[]
).every((sub: any) =>
(
fileCheckedLevels[
fid
] ||
new Set<number>()
).has(Number(sub.id))
);
return (
<div
key={pid}
className="border border-gray-200 rounded-lg p-2 bg-white hover:shadow-sm transition-shadow"
>
<div className="flex items-center justify-between">
<Label className="flex items-center gap-3 flex-1 cursor-pointer">
<Checkbox
checked={(
checkedSet ||
new Set<number>()
).has(
Number(pid)
)}
onCheckedChange={() =>
toggleLevelForFile(
fid,
Number(pid)
)
}
/>
<span className="font-semibold text-gray-900 text-sm">
{polda.name}
</span>
</Label>
{isSatker &&
polda.subDestination && (
<button
onClick={(
e
) => {
e.preventDefault();
e.stopPropagation();
toggleExpand(
pid
);
}}
className="p-1 hover:bg-gray-100 rounded-md transition-colors"
>
<Icon
icon={
isExpanded
? "mdi:chevron-up"
: "mdi:chevron-down"
}
width={16}
height={16}
/>
</button>
)}
</div>
{isSatker &&
polda.subDestination &&
isExpanded && (
<div className="max-h-[200px] overflow-y-auto border-t border-gray-100 pt-2">
<div className="mb-2 flex justify-start">
<Button
size="sm"
variant="outline"
className="text-xs h-6 px-2"
onClick={() =>
toggleAllSubItems(
fid,
polda
)
}
>
{allSubItemsChecked ? (
<>
<Icon
icon="material-symbols:check-indeterminate-small"
width={
12
}
height={
12
}
className="mr-1"
/>
Batal
Semua
</>
) : (
<>
<Icon
icon="material-symbols:check-all"
width={
12
}
height={
12
}
className="mr-1"
/>
Pilih
Semua
</>
)}
</Button>
</div>
<div className="space-y-1">
{(
polda.subDestination ||
[]
).map(
(
sub: any
) => (
<Label
key={String(
sub.id
)}
className="flex items-center gap-2 p-2 rounded-md hover:bg-gray-50 transition-colors cursor-pointer text-xs"
>
<Checkbox
checked={(
fileCheckedLevels[
fid
] ||
new Set<number>()
).has(
Number(
sub.id
)
)}
onCheckedChange={() =>
toggleLevelForFile(
fid,
Number(
sub.id
)
)
}
/>
<span className="text-gray-700">
{
sub.name
}
</span>
</Label>
)
)}
</div>
</div>
)}
</div>
);
}
)}
</div>
<div className="flex justify-end gap-3 border-t border-gray-200 pt-4">
<DialogClose asChild>
<Button variant="outline">
{t("cancel", {
defaultValue: "Batal",
})}
</Button>
</DialogClose>
<DialogClose asChild>
<Button>Simpan</Button>
</DialogClose>
</div>
</DialogContent>
</Dialog>
</div>
</div>
</div>
)}
</div>
</div>
</div>
</div>
);
})}
</div>
</div>
</>
)}
</Fragment>
</div>
</div>
</Card>
{/* RIGHT */}
<div className="w-full lg:w-4/12">
<Card className="h-[900px] md:h-[1100px] lg:h-fit">
<div className="px-3 py-3">
<div className="space-y-2">
<Label>{t("creator", { defaultValue: "Creator" })}</Label>
<Controller
control={control}
name="creatorName"
render={({ field }) => (
<Input
size="md"
type="text"
value={field.value}
onChange={field.onChange}
placeholder="Enter Title"
/>
)}
/>
{errors.creatorName?.message && (
<p className="text-red-400 text-sm">
{errors.creatorName.message}
</p>
)}
</div>
</div>
{/* Thumbnail */}
<div className="mt-3 px-3 space-y-2">
<Label>{t("preview", { defaultValue: "Preview" })}</Label>
<Input
type="file"
accept="image/*"
onChange={(e) => {
const f = e.target.files?.[0];
if (f) setThumbnailFile(f);
}}
className="dark:border dark:border-gray-500 dark:rounded-lg"
/>
<Card className="mt-2">
<img
src={
thumbnailFile
? URL.createObjectURL(thumbnailFile)
: detail?.thumbnailLink
? `${detail.thumbnailLink}?v=${Date.now()}`
: ""
}
alt="Thumbnail Preview"
className="w-full h-auto rounded"
/>
</Card>
</div>
{/* Tags */}
<div className="px-3 py-3">
<div className="space-y-2">
<Label>{t("tags", { defaultValue: "Tags" })}</Label>
<Input
type="text"
id="tags"
placeholder="Add a tag and press Enter"
onKeyDown={handleAddTag}
ref={inputRef}
/>
<div className="mt-3 flex flex-wrap gap-2">
{tags.map((tag, index) => (
<span
key={index}
className="flex items-center gap-2 px-2 py-1 rounded-lg bg-black text-white text-sm"
>
<span
className="absolute opacity-0 whitespace-pre"
id={`tag-span-${index}`}
>
{tag || " "}
</span>
<input
type="text"
value={tag}
onChange={(e) => handleEditTag(index, e.target.value)}
style={{ width: `${Math.max(tag.length, 1)}ch` }}
className="bg-black text-white border-none focus:outline-none"
/>
<button
type="button"
onClick={() => handleRemoveTag(index)}
className="remove-tag-button text-white"
>
×
</button>
</span>
))}
</div>
</div>
<<<<<<< HEAD
<div className="px-3 py-3 flex flex-row items-center text-blue-500 gap-2 text-sm">
<MailIcon />
<p className="">
{t("suggestion-box", { defaultValue: "Suggestion Box" })} (0)
</p>
</div>
<div className="px-3 py-3">
<p>{t("information", { defaultValue: "Information" })}:</p>
{/* <p>{detail?.status}</p> */}
</div>
</Card>
<div className="flex flex-row justify-end gap-3">
<div className="mt-4">
<Button type="submit" color="primary">
{t("submit", { defaultValue: "Submit" })}
</Button>
</div>
<div className="mt-4">
<Link href={"/contributor/content/image"}>
<Button type="submit" color="primary" variant="outline">
{t("cancel", { defaultValue: "Cancel" })}
</Button>
</Link>
=======
</div>
{/* Publish Target */}
<div className="px-3 py-3">
<div className="flex flex-col gap-3 space-y-2">
<Label>
{t("publish-target", { defaultValue: "Publish Target" })}
</Label>
{options.map((option: Option) => (
<div key={option.id} className="flex gap-2 items-center">
<Checkbox
id={option.id}
checked={
option.id === "all"
? publishedFor.length ===
options.filter((opt) => opt.id !== "all").length
: publishedFor.includes(option.id)
}
onCheckedChange={() => handleCheckboxChange(option.id)}
/>
<Label htmlFor={option.id}>{option.name}</Label>
</div>
))}
>>>>>>> 5b6ffd086332104beb9f02b1414b48cda3f030a0
</div>
</div>
<div className="px-3 py-3 flex flex-row items-center text-blue-500 gap-2 text-sm">
<MailIcon />
<p>
{t("suggestion-box", { defaultValue: "Suggestion Box" })} (0)
</p>
</div>
<div className="px-3 py-3">
<p>{t("information", { defaultValue: "Information" })}:</p>
</div>
</Card>
<div className="flex flex-row justify-end gap-3">
<div className="mt-4">
<Button type="submit" color="primary">
{t("submit", { defaultValue: "Submit" })}
</Button>
</div>
<div className="mt-4">
<Button
type="button"
color="primary"
variant="outline"
onClick={() => router.back()}
>
{t("cancel", { defaultValue: "Cancel" })}
</Button>
</div>
</div>
</div>
</div>
</form>
);
}
// "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<typeof imageSchema>;
// let progressInfo: any = [];
// let counterUpdateProgress = 0;
// const [progressList, setProgressList] = useState<any>([]);
// 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<File[]>([]);
// const taskId = Cookies.get("taskId");
// const scheduleId = Cookies.get("scheduleId");
// const scheduleType = Cookies.get("scheduleType");
// const [categories, setCategories] = useState<Category[]>([]);
// const [selectedCategory, setSelectedCategory] = useState<any>();
// const [tags, setTags] = useState<any[]>([]);
// const [detail, setDetail] = useState<Detail>();
// const [refresh, setRefresh] = useState(false);
// const [selectedPublishers, setSelectedPublishers] = useState<number[]>([]);
// const [articleBody, setArticleBody] = useState<string>("");
// const [files, setFiles] = useState<FileWithPreview[]>([]);
// const [filesTemp, setFilesTemp] = useState<File[]>([]);
// const [publishedFor, setPublishedFor] = useState<string[]>([]);
// const [thumbnailFile, setThumbnailFile] = useState<File | null>(null);
// const inputRef = useRef<HTMLInputElement>(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<HTMLInputElement>) => {
// 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<Set<number>>(new Set());
// const [listDest, setListDest] = useState<Destination[]>([]);
// const [isLoading, setIsLoading] = useState(false);
// const [expandedPolda, setExpandedPolda] = useState<Record<number, boolean>>(
// {}
// );
// const [fileCheckedLevels, setFileCheckedLevels] = useState<
// Array<Set<number>>
// >([]);
// const [isUpdatingFromMainCheckbox, setIsUpdatingFromMainCheckbox] =
// useState(false);
// const [mainCheckboxChangeType, setMainCheckboxChangeType] =
// useState<string>("");
// 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<number>(
// 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<number>(
// 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<number>(
// 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<number>(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<number>(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<string | undefined>(
// 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<ImageSchema>({
// resolver: zodResolver(imageSchema),
// });
// useEffect(() => {
// async function initState() {
// getCategories();
// }
// initState();
// }, []);
// const handleAddTag = (e: React.KeyboardEvent<HTMLInputElement>) => {
// 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<number>();
// });
// 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<string[][]>([]);
// 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 (
// <Image
// width={48}
// height={48}
// alt={file.name}
// src={file.preview || URL.createObjectURL(file)}
// className="rounded border p-0.5"
// />
// );
// } else if (file.thumbnailFileUrl) {
// return (
// <Image
// width={48}
// height={48}
// alt={file.fileName}
// src={file.thumbnailFileUrl}
// className="rounded border p-0.5"
// />
// );
// } else {
// return <Icon icon="tabler:file-description" />;
// }
// };
// const handleRemoveFile = (file: FileWithPreview) => {
// const uploadedFiles = files;
// const filtered = uploadedFiles.filter((i) => i.name !== file.name);
// setFiles([...filtered]);
// };
// const fileList = files.map((file: any) => (
// <div
// key={file.id || file.name}
// className="flex justify-between border px-3.5 py-3 my-6 rounded-md"
// >
// <div className="flex gap-3 items-center">
// <div className="file-preview">{renderFilePreview(file)}</div>
// <div>
// <div className="text-sm text-card-foreground">
// {file.fileName || file.name}
// </div>
// <div className="text-xs font-light text-muted-foreground">
// {Math.round(file.size / 100) / 10 > 1000 ? (
// <>{(Math.round(file.size / 100) / 10000).toFixed(1)}</>
// ) : (
// <>{(Math.round(file.size / 100) / 10).toFixed(1)}</>
// )}
// {" kb"}
// </div>
// </div>
// </div>
// <Button
// type="button"
// size="icon"
// color="destructive"
// variant="outline"
// className="border-none rounded-full"
// onClick={() => handleDeleteFile(file.id)}
// >
// <Icon icon="tabler:x" className="h-5 w-5" />
// </Button>
// </div>
// ));
// 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<TempFileItem[]>([]);
// 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<number>(
// 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<number>(
// 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<number>(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 (
// <form onSubmit={handleSubmit(onSubmit)}>
// {detail !== undefined ? (
// <div className="flex flex-col lg:flex-row gap-10">
// <Card className="w-full lg:w-8/12">
// <div className="px-6 py-6">
// <p className="text-lg font-semibold mb-3">
// {t("form-image", { defaultValue: "Form Image" })}
// </p>
// <div className="gap-5 mb-5">
// {/* Input Title dengan translate */}
// <div className="py-3 space-y-2">
// <div className="flex justify-between items-center">
// <Label>{t("title", { defaultValue: "Title" })}</Label>
// {roleId === "14" && (
// <button
// type="button"
// onClick={async () => {
// try {
// loading();
// setIsLoadingTranslateTitle(true);
// const res = await translateText({
// text: getValues("title"),
// sourceLang: "ID",
// targetLang: "EN",
// });
// if (!res.error) {
// const resultText =
// res?.data?.data?.translations?.[0]?.text || "";
// setTranslatedTitle(resultText);
// }
// } catch (err) {
// console.error("Translate title gagal:", err);
// } finally {
// close();
// setIsLoadingTranslateTitle(false);
// }
// }}
// className="px-3 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600"
// >
// {isLoadingTranslateTitle
// ? "Translating..."
// : "Translate to English"}
// </button>
// )}
// </div>
// {/* Judul Bahasa Indonesia */}
// <div className="mt-2">
// <Label className="text-sm font-semibold">
// Indonesian Title
// </Label>
// <Controller
// control={control}
// name="title"
// render={({ field }) => (
// <Input
// size="md"
// type="text"
// value={field.value}
// onChange={field.onChange}
// placeholder="Masukkan Judul Bahasa Indonesia"
// />
// )}
// />
// </div>
// {/* Judul Bahasa Inggris (muncul setelah klik translate) */}
// {translatedTitle && (
// <div className="mt-4">
// <Label className="text-sm font-semibold">
// English Title
// </Label>
// <Input
// size="md"
// type="text"
// value={translatedTitle}
// onChange={(e) => setTranslatedTitle(e.target.value)}
// placeholder="English version"
// />
// </div>
// )}
// {errors.title?.message && (
// <p className="text-red-400 text-sm">
// {errors.title.message}
// </p>
// )}
// </div>
// {/* <div className="space-y-2 py-3">
// <Label>{t("title", { defaultValue: "Title" })}</Label>
// <Controller
// control={control}
// name="title"
// render={({ field }) => (
// <Input
// size="md"
// type="text"
// value={field?.value}
// onChange={field.onChange}
// placeholder="Enter Title"
// />
// )}
// />
// {errors.title?.message && (
// <p className="text-red-400 text-sm">
// {errors.title.message}
// </p>
// )}
// </div> */}
// <div className="flex items-center">
// <div className="py-3 w-full space-y-2">
// <Label>{t("category", { defaultValue: "Category" })}</Label>
// <Select
// value={selectedTarget}
// onValueChange={(id) => {
// console.log("Selected Category ID:", id);
// setSelectedTarget(id);
// }}
// >
// <SelectTrigger size="md">
// <SelectValue placeholder="Pilih" />
// </SelectTrigger>
// <SelectContent>
// {/* Show the category from details if it doesn't exist in categories list */}
// {detail &&
// !categories.find(
// (cat) =>
// String(cat.id) === String(detail.category.id)
// ) && (
// <SelectItem
// key={String(detail.category.id)}
// value={String(detail.category.id)}
// >
// {detail.category.name}
// </SelectItem>
// )}
// {categories.map((category) => (
// <SelectItem
// key={String(category.id)}
// value={String(category.id)}
// >
// {category.name}
// </SelectItem>
// ))}
// </SelectContent>
// </Select>
// </div>
// </div>
// <div className="py-3 space-y-2">
// <div className="flex justify-between items-center">
// <Label>
// {t("description", { defaultValue: "Description" })}
// </Label>
// {roleId === "14" && (
// <button
// type="button"
// onClick={async () => {
// try {
// loading();
// setIsLoadingTranslate(true);
// const res = await translateText({
// text: getValues("description"),
// sourceLang: "ID",
// targetLang: "EN",
// });
// console.log("PPP", res);
// if (!res.error) {
// const resultText =
// res?.data?.data?.translations?.[0]?.text || "";
// setTranslatedContent(resultText);
// }
// } catch (err) {
// close();
// console.error("Translate gagal:", err);
// } finally {
// close();
// setIsLoadingTranslate(false);
// }
// }}
// className="px-3 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600"
// >
// {isLoadingTranslate
// ? "Translating..."
// : "Translate to English"}
// </button>
// )}
// </div>
// {/* Editor Bahasa Indonesia */}
// <div className="mt-3">
// <Label className="text-sm font-semibold">
// Indonesian Version
// </Label>
// <Controller
// control={control}
// name="description"
// render={({ field }) => (
// <CustomEditor
// onChange={field.onChange}
// initialData={field.value}
// />
// )}
// />
// </div>
// {/* Editor Bahasa Inggris (muncul setelah klik translate) */}
// {translatedContent && (
// <div className="mt-5">
// <Label className="text-sm font-semibold">
// English Version
// </Label>
// <CustomEditor
// onChange={(val: any) => setTranslatedContent(val)}
// initialData={translatedContent}
// />
// </div>
// )}
// {errors.description?.message && (
// <p className="text-red-400 text-sm">
// {errors.description.message}
// </p>
// )}
// </div>
// {/* <div className="py-3 space-y-2">
// <Label>
// {t("description", { defaultValue: "Description" })}
// </Label>
// <Controller
// control={control}
// name="description"
// render={({ field }) => (
// <CustomEditor
// onChange={field.onChange}
// initialData={field.value}
// />
// )}
// />
// {errors.description?.message && (
// <p className="text-red-400 text-sm">
// {errors.description.message}
// </p>
// )}
// </div> */}
// <div className="py-3 space-y-2">
// <Label>
// {t("select-file", { defaultValue: "Select File" })}
// </Label>
// {/* <Input
// id="fileInput"
// type="file"
// onChange={handleImageChange}
// /> */}
// <Fragment>
// <div {...getRootProps({ className: "dropzone" })}>
// <input {...getInputProps()} />
// <div className=" w-full text-center border-dashed border border-default-200 dark:border-default-300 rounded-md py-[52px] flex items-center flex-col">
// <CloudUpload className="text-default-300 w-10 h-10" />
// <h4 className=" text-2xl font-medium mb-1 mt-3 text-card-foreground/80">
// {/* Drop files here or click to upload. */}
// {t("drag-file", { defaultValue: "Drag File" })}
// </h4>
// <div className=" text-xs text-muted-foreground">
// {t("upload-file-max", {
// defaultValue: "Upload File Max",
// })}
// </div>
// </div>
// </div>
// {files.length ? (
// <Fragment>
// <div>{fileList}</div>
// <div className=" flex justify-between gap-2">
// <div className="flex flex-row items-center gap-3 py-3">
// <Label>
// {t("watermark", { defaultValue: "Watermark" })}
// </Label>
// <div className="flex items-center gap-3">
// <Switch defaultChecked color="primary" id="c2" />
// </div>
// </div>
// {/* <Button
// color="destructive"
// onClick={() => handleDeleteFile(id)}
// >
// Remove file
// </Button> */}
// </div>
// </Fragment>
// ) : null}
// {files.length > 0 && (
// <div className="mt-4">
// <Label className="text-md font-semibold">
// {" "}
// {t("file-media", { defaultValue: "File Media" })}
// </Label>
// <div className="grid gap-4">
// {files.map((file: any, index: any) => (
// <div
// key={file.id}
// className="flex items-center border p-2 rounded-md"
// >
// <img
// src={file.thumbnailFileUrl}
// alt={file.fileName}
// className="w-16 h-16 object-cover rounded-md mr-4"
// />
// <div className="flex flex-wrap gap-3 items-center ">
// <div className="flex-grow">
// <p className="font-medium">{file.fileName}</p>
// <a
// href={file.url}
// target="_blank"
// rel="noopener noreferrer"
// className="text-blue-500 text-sm"
// >
// {t("view-file", {
// defaultValue: "View File",
// })}
// </a>
// </div>
// <div className="bg-white rounded-md p-4 border">
// {/* <h5 className="font-medium text-gray-900 mb-4 flex items-center gap-2">
// <Icon
// icon="material-symbols:settings-outline"
// width={18}
// height={18}
// />
// Pengaturan Distribusi
// </h5> */}
// {/* Checkbox Tingkat Utama */}
// <div className="space-y-4">
// <div className="grid grid-cols-2 md:grid-cols-4 gap-3">
// {[
// { key: "semua", label: "Semua" },
// {
// key: "nasional",
// label: "Nasional",
// },
// { key: "wilayah", label: "Wilayah" },
// {
// key: "international",
// label: "Internasional",
// },
// ].map((item, idx) => (
// <div
// key={item.key}
// className="flex items-center gap-2 p-2 border border-gray-200 rounded-md hover:bg-gray-50"
// >
// <Checkbox
// // id={`${item.key}-${index}`}
// checked={
// fileUnitSelections[index]?.[
// item.key as keyof typeof unitSelection
// ] || false
// }
// onCheckedChange={(value) => {
// handleFileUnitChange(
// index,
// item.key as keyof typeof unitSelection,
// value as boolean
// );
// setupPlacement(
// index,
// item.key,
// Boolean(value)
// );
// }}
// />
// <Label
// htmlFor={`${item.key}-${index}`}
// className="text-sm font-medium cursor-pointer"
// >
// {item.label}
// </Label>
// </div>
// ))}
// </div>
// {/* Detail Wilayah */}
// {fileUnitSelections[index]?.wilayah &&
// isDetailOfRegionShowed && (
// <div className="border-t border-gray-200 pt-2">
// <p className="text-sm font-medium text-gray-700 mb-2">
// Detail Wilayah:
// </p>
// {/* Checkbox Sub-kategori dengan tombol Kustom sejajar */}
// <div className="grid grid-cols-1 md:grid-cols-4 gap-3">
// {[
// { key: "polda", label: "POLDA" },
// {
// key: "satker",
// label: "SATKER",
// },
// ].map((item, idx) => (
// <div
// key={item.key}
// className="flex items-center gap-2 p-3 border border-gray-200 rounded-md hover:bg-gray-50"
// >
// <Checkbox
// id={`${item.key}-${index}`}
// checked={
// fileUnitSelections[index]?.[
// item.key as keyof typeof unitSelection
// ] || false
// }
// onCheckedChange={(value) => {
// handleFileUnitChange(
// index,
// item.key as keyof typeof unitSelection,
// value as boolean
// );
// setupPlacement(
// index,
// item.key,
// Boolean(value)
// );
// }}
// />
// <Label
// htmlFor={`${item.key}-${index}`}
// className="text-sm font-medium cursor-pointer"
// >
// {item.label}
// </Label>
// </div>
// ))}
// {/* Tombol Kustom sejajar dengan checkbox */}
// <div className="flex items-center justify-center p-3">
// <Dialog>
// <DialogTrigger asChild>
// <Button
// variant="outline"
// size="sm"
// className="gap-2"
// >
// <Icon
// icon="material-symbols:tune"
// width={16}
// height={16}
// />
// {t("custom", {
// defaultValue: "Kustom",
// })}
// </Button>
// </DialogTrigger>
// <DialogContent className="max-w-[95vw] lg:max-w-[1400px] max-h-[90vh]">
// <DialogHeader className="border-b border-gray-200 pb-4">
// <DialogTitle className="text-lg font-semibold">
// Daftar Wilayah POLDA dan
// SATKER
// </DialogTitle>
// </DialogHeader>
// <div className="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-4 max-h-[70vh] overflow-y-auto p-1">
// {listDest.map(
// (polda: any) => (
// <div
// key={polda.id}
// className="border border-gray-200 rounded-lg p-2 bg-white hover:shadow-sm transition-shadow"
// >
// {/* Header POLDA */}
// <div className="flex items-center justify-between">
// <Label className="flex items-center gap-3 flex-1 cursor-pointer">
// <Checkbox
// checked={
// fileCheckedLevels[
// index
// ]?.has(
// Number(
// polda.id
// )
// ) || false
// }
// onCheckedChange={() =>
// handleFileCheckboxChangePlacement(
// index,
// Number(
// polda.id
// )
// )
// }
// />
// <span className="font-semibold text-gray-900 text-sm">
// {polda.name}
// </span>
// </Label>
// {/* Tombol expand hanya untuk SATKER POLRI */}
// {polda.name ===
// "SATKER POLRI" &&
// polda.subDestination && (
// <button
// onClick={(
// e
// ) => {
// e.preventDefault();
// e.stopPropagation();
// toggleExpand(
// polda.id
// );
// }}
// className="p-1 hover:bg-gray-100 rounded-md transition-colors"
// >
// <Icon
// icon={
// expandedPolda[
// polda.id
// ]
// ? "mdi:chevron-up"
// : "mdi:chevron-down"
// }
// width={16}
// height={16}
// />
// </button>
// )}
// </div>
// {/* Sub-items hanya untuk SATKER POLRI */}
// {polda.name ===
// "SATKER POLRI" &&
// polda.subDestination &&
// expandedPolda[
// polda.id
// ] && (
// <div className="max-h-[200px] overflow-y-auto border-t border-gray-100 pt-2">
// {/* Tombol Pilih Semua untuk sub-items */}
// <div className="mb-2 flex justify-start">
// {(() => {
// const allSubItemsChecked =
// polda.subDestination?.every(
// (
// sub: any
// ) =>
// fileCheckedLevels[
// index
// ]?.has(
// Number(
// sub.id
// )
// )
// );
// return (
// <Button
// size="sm"
// variant="outline"
// className="text-xs h-6 px-2"
// onClick={() =>
// handleSelectAllSubItems(
// index,
// polda
// )
// }
// >
// {allSubItemsChecked ? (
// <>
// <Icon
// icon="material-symbols:check-indeterminate-small"
// width={
// 12
// }
// height={
// 12
// }
// className="mr-1"
// />
// Batal
// Semua
// </>
// ) : (
// <>
// <Icon
// icon="material-symbols:check-all"
// width={
// 12
// }
// height={
// 12
// }
// className="mr-1"
// />
// Pilih
// Semua
// </>
// )}
// </Button>
// );
// })()}
// </div>
// <div className="space-y-1">
// {polda.subDestination.map(
// (
// sub: any
// ) => (
// <Label
// key={
// sub.id
// }
// className="flex items-center gap-2 p-2 rounded-md hover:bg-gray-50 transition-colors cursor-pointer text-xs"
// >
// <Checkbox
// checked={
// fileCheckedLevels[
// index
// ]?.has(
// Number(
// sub.id
// )
// ) ||
// false
// }
// onCheckedChange={() =>
// handleFileCheckboxChangePlacement(
// index,
// Number(
// sub.id
// )
// )
// }
// />
// <span className="text-gray-700">
// {
// sub.name
// }
// </span>
// </Label>
// )
// )}
// </div>
// </div>
// )}
// </div>
// )
// )}
// </div>
// <div className="flex justify-end gap-3 border-t border-gray-200 pt-4">
// <DialogClose asChild>
// <Button variant="outline">
// {t("cancel", {
// defaultValue: "Batal",
// })}
// </Button>
// </DialogClose>
// <DialogClose asChild>
// <Button>Simpan</Button>
// </DialogClose>
// </div>
// </DialogContent>
// </Dialog>
// </div>
// </div>
// </div>
// )}
// </div>
// </div>
// </div>
// </div>
// ))}
// </div>
// </div>
// )}
// </Fragment>
// </div>
// </div>
// </div>
// </Card>
// <div className="w-full lg:w-4/12">
// <Card className="h-[900px] md:h-[1100px] lg:h-fit">
// <div className="px-3 py-3">
// <div className="space-y-2">
// <Label>{t("creator", { defaultValue: "Creator" })}</Label>
// <Controller
// control={control}
// name="creatorName"
// render={({ field }) => (
// <Input
// size="md"
// type="text"
// value={field?.value}
// onChange={field.onChange}
// placeholder="Enter Title"
// />
// )}
// />
// {errors.creatorName?.message && (
// <p className="text-red-400 text-sm">
// {errors.creatorName.message}
// </p>
// )}
// </div>
// </div>
// {/* <div className="mt-3 px-3 space-y-2">
// <Label>{t("preview", { defaultValue: "Preview" })}</Label>
// <Card className="mt-2">
// <img
// src={detail.thumbnailLink}
// alt="Thumbnail Gambar Utama"
// className="w-full h-auto rounded"
// />
// </Card>
// </div> */}
// <div className="mt-3 px-3 space-y-2">
// <Label>{t("preview", { defaultValue: "Preview" })}</Label>
// <Input
// type="file"
// accept="image/*"
// onChange={(e) => {
// const file = e.target.files?.[0];
// if (file) {
// setThumbnailFile(file);
// }
// }}
// className="dark:border dark:border-gray-500 dark:rounded-lg"
// />
// <Card className="mt-2">
// <img
// src={
// thumbnailFile
// ? URL.createObjectURL(thumbnailFile)
// : detail?.thumbnailLink
// ? `${detail.thumbnailLink}?v=${Date.now()}`
// : ""
// }
// alt="Thumbnail Preview"
// className="w-full h-auto rounded"
// />
// </Card>
// </div>
// <div className="px-3 py-3">
// <div className="space-y-2">
// <Label>{t("tags", { defaultValue: "Tags" })}</Label>
// <Input
// type="text"
// id="tags"
// placeholder="Add a tag and press Enter"
// onKeyDown={handleAddTag}
// ref={inputRef}
// />
// <div className="mt-3 flex flex-wrap gap-2">
// {tags.map((tag, index) => (
// <span
// key={index}
// className="flex items-center gap-2 px-2 py-1 rounded-lg bg-black text-white text-sm"
// >
// {/* Hidden span untuk ukur lebar teks */}
// <span
// className="absolute opacity-0 whitespace-pre"
// id={`tag-span-${index}`}
// >
// {tag || " "}
// </span>
// <input
// type="text"
// value={tag}
// onChange={(e) => handleEditTag(index, e.target.value)}
// style={{
// width: `${Math.max(tag.length, 1)}ch`,
// }}
// className="bg-black text-white border-none focus:outline-none"
// />
// <button
// type="button"
// onClick={() => handleRemoveTag(index)}
// className="remove-tag-button text-white"
// >
// ×
// </button>
// </span>
// ))}
// </div>
// {/* <div className="flex flex-wrap gap-2">
// {detail?.tags?.split(",").map((tag, index) => (
// <Badge
// key={index}
// className="border rounded-md px-2 py-2"
// >
// {tag.trim()}
// </Badge>
// ))}
// </div> */}
// </div>
// </div>
// <div className="px-3 py-3">
// <div className="flex flex-col gap-3 space-y-2">
// <Label>
// {t("publish-target", { defaultValue: "Publish Target" })}
// </Label>
// {options.map((option: Option) => (
// <div key={option.id} className="flex gap-2 items-center">
// <Checkbox
// id={option.id}
// checked={
// option.id === "all"
// ? publishedFor.length ===
// options.filter((opt) => opt.id !== "all").length
// : publishedFor.includes(option.id)
// }
// onCheckedChange={() => handleCheckboxChange(option.id)}
// />
// <Label htmlFor={option.id}>{option.name}</Label>
// </div>
// ))}
// </div>
// </div>
// <div className="px-3 py-3 flex flex-row items-center text-blue-500 gap-2 text-sm">
// <MailIcon />
// <p className="">
// {t("suggestion-box", { defaultValue: "Suggestion Box" })} (0)
// </p>
// </div>
// <div className="px-3 py-3">
// <p>{t("information", { defaultValue: "Information" })}:</p>
// {/* <p>{detail?.status}</p> */}
// </div>
// </Card>
// <div className="flex flex-row justify-end gap-3">
// <div className="mt-4">
// <Button type="submit" color="primary">
// {t("submit", { defaultValue: "Submit" })}
// </Button>
// </div>
// <div className="mt-4">
// <Button type="submit" color="primary" variant="outline">
// {t("cancel", { defaultValue: "Cancel" })}
// </Button>
// </div>
// </div>
// </div>
// </div>
// ) : (
// ""
// )}
// </form>
// );
// }