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

3602 lines
138 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 { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { register } from "module";
import { Switch } from "@/components/ui/switch";
import Cookies from "js-cookie";
import {
createMedia,
deleteFile,
deleteMedia,
getTagsBySubCategoryId,
listEnableCategory,
uploadThumbnail,
} from "@/service/content/content";
import { detailMedia } from "@/service/curated-content/curated-content";
import { Badge } from "@/components/ui/badge";
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";
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;
};
const CustomEditor = dynamic(
() => {
return import("@/components/editor/custom-editor");
},
{ ssr: false }
);
interface FileWithPreview extends File {
preview: string;
}
export default function FormImageUpdate() {
const MySwal = withReactContent(Swal);
const router = useRouter();
const { id } = useParams() as { id: string };
console.log(id);
const editor = useRef(null);
type ImageSchema = z.infer<typeof imageSchema>;
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 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 [selectedOptions, setSelectedOptions] = useState<{
[fileId: number]: string[];
}>({});
const handleThumbnailChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (file) {
setThumbnailFile(file);
}
};
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 {
control,
handleSubmit,
setValue,
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 listEnableCategory(fileTypeId);
const resCategory: Category[] = category?.data?.data?.content;
setCategories(resCategory);
console.log("data category", resCategory);
if (scheduleId && scheduleType === "3") {
const findCategory = resCategory.find((o) =>
o.name.toLowerCase().includes("pers rilis")
);
if (findCategory) {
// setValue("categoryId", findCategory.id);
setSelectedCategory(findCategory.id);
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) {
setFiles(details.files);
const initialOptions: { [key: number]: string[] } = {};
details.files.forEach((file: any) => {
if (file.placements) {
initialOptions[file.id] = mapPlacementsToOptions(file.placements);
}
});
setSelectedOptions(initialOptions);
}
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);
}
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 mapPlacementsToOptions = (placements: string): string[] => {
const mapping: Record<string, string> = {
all: "all",
mabes: "nasional",
polda: "wilayah",
polres: "internasional",
};
if (placements.trim() === "all") {
return ["all", "nasional", "wilayah", "internasional"];
}
const options = placements
.split(",")
.map((p) => mapping[p.trim()])
.filter(Boolean);
const allSelected = ["nasional", "wilayah", "internasional"].every((opt) =>
options.includes(opt)
);
return allSelected ? ["all", ...options] : options;
};
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 save = async (data: ImageSchema) => {
loading();
const finalTags = tags.join(", ");
const requestData = {
...data,
id: detail?.id,
title: data.title,
description: htmlToString(data.description),
htmlDescription: data.description,
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);
console.log("Form Data Submitted:", 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 == true) {
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);
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) => {
// if (file?.type?.startsWith("image")) {
// return (
// <Image
// width={48}
// height={48}
// alt={file.name}
// src={URL.createObjectURL(file)}
// className=" rounded border p-0.5"
// />
// );
// } else {
// return <Icon icon="tabler:file-description" />;
// }
// };
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}
// 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>
// ));
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 [filePlacements, setFilePlacements] = useState<FilePlacement[]>([]);
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);
};
const handleCheckboxChangeImage = (fileId: number, value: string) => {
setSelectedOptions((prev: any) => {
const currentSelections = prev[fileId] || [];
if (value === "all") {
if (currentSelections.includes("all")) {
return { ...prev, [fileId]: [] };
}
return {
...prev,
[fileId]: ["all", "nasional", "wilayah", "internasional"],
};
} else {
const updatedSelections = currentSelections.includes(value)
? currentSelections.filter((option: any) => option !== value)
: [...currentSelections, value];
const isAllSelected = ["nasional", "wilayah", "internasional"].every(
(opt) => updatedSelections.includes(opt)
);
return {
...prev,
[fileId]: isAllSelected
? ["all", ...updatedSelections]
: updatedSelections.filter((opt: any) => opt !== "all"),
};
}
});
};
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 */}
<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">
<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-lg font-semibold">
{" "}
{t("file-media", { defaultValue: "File Media" })}
</Label>
<div className="grid gap-4">
{files.map((file: 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>
<Label className="flex items-center space-x-2">
<input
type="checkbox"
checked={selectedOptions[
file.id
]?.includes("all")}
onChange={(e) =>
setupPlacement(file.id, e.target.value)
}
className="form-checkbox"
/>
<span>
{t("all", { defaultValue: "All" })}
</span>
</Label>
</div>
<div>
<Label className="flex items-center space-x-2">
<input
type="checkbox"
checked={selectedOptions[
file.id
]?.includes("nasional")}
onChange={() =>
handleCheckboxChangeImage(
file.id,
"nasional"
)
}
className="form-checkbox"
/>
<span>Nasional</span>
</Label>
</div>
<div>
<Label className="flex items-center space-x-2">
<input
type="checkbox"
checked={selectedOptions[
file.id
]?.includes("wilayah")}
onChange={() =>
handleCheckboxChangeImage(
file.id,
"wilayah"
)
}
className="form-checkbox"
/>
<span>Wilayah</span>
</Label>
</div>
<div>
<Label className="flex items-center space-x-2">
<input
type="checkbox"
checked={selectedOptions[
file.id
]?.includes("internasional")}
onChange={() =>
handleCheckboxChangeImage(
file.id,
"internasional"
)
}
className="form-checkbox"
/>
<span>Internasional</span>
</Label>
</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"
>
<input
type="text"
value={tag}
onChange={(e) => handleEditTag(index, e.target.value)}
className="bg-black text-white border-none focus:outline-none w-auto"
/>
<button
value={tag}
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-6 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>
);
}
// Yang EROR
// "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 { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
// import { register } from "module";
// import { Switch } from "@/components/ui/switch";
// import Cookies from "js-cookie";
// import {
// createMedia,
// deleteFile,
// deleteMedia,
// getTagsBySubCategoryId,
// listEnableCategory,
// uploadThumbnail,
// } from "@/service/content/content";
// import { detailMedia } from "@/service/curated-content/curated-content";
// import { Badge } from "@/components/ui/badge";
// 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";
// 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;
// };
// const CustomEditor = dynamic(
// () => {
// return import("@/components/editor/custom-editor");
// },
// { ssr: false }
// );
// interface FileWithPreview extends File {
// id: string;
// preview: string;
// }
// interface Destination {
// id: string;
// name: string;
// subDestination?: SubDestination[];
// }
// interface SubDestination {
// id: string;
// name: string;
// }
// export default function FormImageUpdate() {
// const MySwal = withReactContent(Swal);
// const router = useRouter();
// const { id } = useParams() as { id: string };
// console.log(id);
// const editor = useRef(null);
// type ImageSchema = z.infer<typeof imageSchema>;
// 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 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 [selectedOptions, setSelectedOptions] = useState<{
// [fileId: number]: string[];
// }>({});
// 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;
// polres: boolean;
// satker: boolean;
// }>
// >([]);
// // State global untuk kompatibilitas (akan dihapus nanti)
// const [unitSelection, setUnitSelection] = useState({
// semua: false,
// nasional: false,
// wilayah: false,
// international: false,
// polda: false,
// polres: 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 checkedPolresCount = listDest.reduce((total: number, item: any) => {
// if (item.subDestination && item.name !== "SATKER POLRI") {
// // Hanya hitung sub-item dari POLDA (bukan dari SATKER POLRI)
// return (
// total +
// item.subDestination.filter((sub: any) =>
// checkedLevels.has(Number(sub.id))
// ).length
// );
// }
// return total;
// }, 0);
// 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 hasSelectedPolres = checkedPolresCount > 0;
// const hasSelectedSatker = checkedSatkerCount > 0;
// // Update unitSelection berdasarkan yang dipilih di modal
// setUnitSelection((prev) => {
// const newState = { ...prev };
// // Update individual checkboxes
// newState.polda = hasSelectedPolda;
// newState.polres = hasSelectedPolres;
// newState.satker = hasSelectedSatker;
// // Update checkbox "semua" berdasarkan semua checkbox yang aktif
// newState.semua =
// newState.nasional &&
// newState.wilayah &&
// newState.international &&
// hasSelectedPolda &&
// hasSelectedPolres &&
// 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 === "polres_checked") {
// // Checklist semua polres, tapi hanya yang poldanya sudah di-checklist
// // Jangan checklist sub-item SATKER POLRI
// listDest.forEach((item: any) => {
// if (
// item.levelNumber === 2 &&
// item.name !== "SATKER POLRI" &&
// newCheckedLevels.has(Number(item.id))
// ) {
// if (item.subDestination) {
// item.subDestination.forEach((polres: any) => {
// newCheckedLevels.add(Number(polres.id));
// });
// }
// }
// });
// // Tidak perlu menghapus SATKER ketika POLRES di-checklist
// // Biarkan keduanya bisa aktif bersamaan
// // SATKER dan POLRES adalah konsep yang berbeda:
// // - SATKER: unit-unit seperti ITWASUM, BAINTELKAM, dll.
// // - POLRES: unit-unit seperti POLRES METRO JAKARTA PUSAT, dll.
// } 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));
// });
// }
// });
// }
// // Handle unchecklist actions - menghapus item dari modal
// else if (mainCheckboxChangeType === "polres_unchecked") {
// // Clear polres dari checkedLevels, tapi jangan hapus sub-item SATKER POLRI
// listDest.forEach((item: any) => {
// if (item.subDestination && item.name !== "SATKER POLRI") {
// item.subDestination.forEach((polres: any) => {
// newCheckedLevels.delete(Number(polres.id));
// });
// }
// });
// } else if (mainCheckboxChangeType === "polda_unchecked") {
// // Clear polda dan polres dari checkedLevels, tapi jangan hapus SATKER POLRI
// listDest.forEach((item: any) => {
// if (item.levelNumber === 2 && item.name !== "SATKER POLRI") {
// newCheckedLevels.delete(Number(item.id));
// if (item.subDestination) {
// item.subDestination.forEach((polres: any) => {
// newCheckedLevels.delete(Number(polres.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.polres = 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 {
// // Validasi khusus untuk POLRES - harus ada POLDA yang ter-checklist
// if (key === "polres" && value) {
// const currentFileCheckedLevels = fileCheckedLevels[fileIndex];
// const hasSelectedPolda =
// currentFileCheckedLevels &&
// listDest.some(
// (item: any) =>
// item.levelNumber === 2 &&
// item.name !== "SATKER POLRI" &&
// currentFileCheckedLevels.has(Number(item.id))
// );
// if (!hasSelectedPolda) {
// alert(
// "Harap pilih POLDA di Modal terlebih dahulu sebelum mengaktifkan checkbox POLRES."
// );
// return prev; // Batalkan perubahan
// }
// }
// // Update salah satu saja
// currentSelection[key] = value;
// // Cek apakah semua selain "semua" sudah dicentang
// const allChecked = [
// "nasional",
// "wilayah",
// "international",
// "polda",
// "polres",
// "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);
// // Hitung total POLRES yang ada dari POLDA yang ter-checklist
// const totalPolresFromCheckedPolda = listDest.reduce(
// (total: number, item: any) => {
// if (
// item.subDestination &&
// item.name !== "SATKER POLRI" &&
// currentFileLevels.has(Number(item.id))
// ) {
// return total + item.subDestination.length;
// }
// return total;
// },
// 0
// );
// // Hitung berapa banyak POLRES yang ter-checklist
// const checkedPolresCount = listDest.reduce((total: number, item: any) => {
// if (item.subDestination && item.name !== "SATKER POLRI") {
// // Hanya hitung sub-item dari POLDA (bukan dari SATKER POLRI)
// return (
// total +
// item.subDestination.filter((sub: any) =>
// currentFileLevels.has(Number(sub.id))
// ).length
// );
// }
// 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;
// // POLRES aktif jika ada minimal 1 POLRES ter-checklist
// currentSelection.polres = checkedPolresCount > 0;
// currentSelection.satker = Boolean(isSatkerChecked);
// // Update checkbox "semua" berdasarkan semua checkbox yang aktif
// currentSelection.semua =
// currentSelection.nasional &&
// currentSelection.wilayah &&
// currentSelection.international &&
// currentSelection.polda &&
// currentSelection.polres &&
// 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 POLDA
// 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 POLDA 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((prevFiles) => [
// ...prevFiles,
// ...acceptedFiles.map((file) =>
// Object.assign(file, {
// id: uuidv4(), // generate unique id
// preview: URL.createObjectURL(file),
// })
// ),
// ]);
// },
// accept: {
// "image/*": [],
// },
// });
// // 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 {
// control,
// handleSubmit,
// setValue,
// 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 listEnableCategory(fileTypeId);
// const resCategory: Category[] = category?.data?.data?.content;
// setCategories(resCategory);
// console.log("data category", resCategory);
// if (scheduleId && scheduleType === "3") {
// const findCategory = resCategory.find((o) =>
// o.name.toLowerCase().includes("pers rilis")
// );
// if (findCategory) {
// // setValue("categoryId", findCategory.id);
// setSelectedCategory(findCategory.id);
// 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) {
// setFiles(details.files);
// const initialOptions: { [key: number]: string[] } = {};
// details.files.forEach((file: any) => {
// if (file.placements) {
// initialOptions[file.id] = mapPlacementsToOptions(file.placements);
// }
// });
// setSelectedOptions(initialOptions);
// }
// 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);
// }
// 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 mapPlacementsToOptions = (placements: string): string[] => {
// const mapping: Record<string, string> = {
// all: "all",
// mabes: "nasional",
// polda: "wilayah",
// polres: "internasional",
// };
// if (placements.trim() === "all") {
// return ["all", "nasional", "wilayah", "internasional"];
// }
// const options = placements
// .split(",")
// .map((p) => mapping[p.trim()])
// .filter(Boolean);
// const allSelected = ["nasional", "wilayah", "internasional"].every((opt) =>
// options.includes(opt)
// );
// return allSelected ? ["all", ...options] : options;
// };
// 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++) {
// if (filePlacements[i]?.length !== 0) {
// const now = filePlacements[i];
// let nowArr = now?.join(",")?.replaceAll("wilayah", "polda");
// nowArr = nowArr?.replaceAll("nasional", "mabes");
// nowArr = nowArr?.replaceAll("semua", "all");
// // Dapatkan checked levels untuk file ini
// const currentFileCheckedLevels = fileCheckedLevels[i]
// ? Array.from(fileCheckedLevels[i])
// : [];
// const data = {
// mediaFileId: files[i]?.id,
// placements: nowArr,
// customLocationPlacements: currentFileCheckedLevels.join(","),
// };
// temp.push(data);
// }
// }
// return temp;
// };
// const save = async (data: ImageSchema) => {
// loading();
// const finalTags = tags.join(", ");
// const requestData = {
// ...data,
// id: detail?.id,
// title: data.title,
// description: htmlToString(data.description),
// htmlDescription: data.description,
// 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,
// files: getPlacement(),
// };
// console.log("Form Data Submitted:", requestData);
// const response = await createMedia(requestData);
// if (response?.error) {
// error(response?.message);
// return false;
// }
// // Upload thumbnail
// 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;
// }
// // Upload files (progress)
// const progressInfoArr = files.map((item) => ({
// percentage: 0,
// fileName: item.name,
// }));
// setIsStartUpload(true);
// setProgressList(progressInfoArr);
// close();
// 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) => {
// // if (file?.type?.startsWith("image")) {
// // return (
// // <Image
// // width={48}
// // height={48}
// // alt={file.name}
// // src={URL.createObjectURL(file)}
// // className=" rounded border p-0.5"
// // />
// // );
// // } else {
// // return <Icon icon="tabler:file-description" />;
// // }
// // };
// 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}
// // 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>
// // ));
// 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"];
// // Update fileCheckedLevels untuk sinkronisasi dengan modal ketika "all" diklik
// setFileCheckedLevels((prevLevels) => {
// const newArray = [...prevLevels];
// const currentFileLevels = new Set<number>(
// newArray[index] || new Set()
// );
// // 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));
// });
// }
// });
// 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 true
// 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") {
// // Ketika satker di-checklist, HANYA tambahkan satker saja
// // JANGAN otomatis checklist polres
// 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);
// }
// // Hanya auto-checklist "all" jika polda, polres, dan mabes ter-checklist
// // JANGAN include satker dalam perhitungan auto "all"
// 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] = [];
// // Update fileCheckedLevels untuk sinkronisasi dengan modal ketika "all" di-unchecklist
// setFileCheckedLevels((prevLevels) => {
// const newArray = [...prevLevels];
// const currentFileLevels = new Set<number>(
// newArray[index] || new Set()
// );
// // Unchecklist semua item di modal
// 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;
// // 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 === "polres") {
// // Checklist POLRES hanya dari POLDA yang sudah ter-checklist
// listDest.forEach((item: any) => {
// if (item.levelNumber === 2 && item.name !== "SATKER POLRI") {
// // Hanya checklist POLRES jika POLDA-nya sudah ter-checklist
// if (currentFileLevels.has(Number(item.id))) {
// if (item.subDestination) {
// item.subDestination.forEach((polres: any) => {
// currentFileLevels.add(Number(polres.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 dan POLRES di bawahnya
// listDest.forEach((item: any) => {
// if (item.levelNumber === 2 && item.name !== "SATKER POLRI") {
// currentFileLevels.delete(Number(item.id));
// if (item.subDestination) {
// item.subDestination.forEach((polres: any) => {
// currentFileLevels.delete(Number(polres.id));
// });
// }
// }
// });
// } else if (placement === "polres") {
// // Unchecklist semua POLRES
// listDest.forEach((item: any) => {
// if (item.subDestination && item.name !== "SATKER POLRI") {
// item.subDestination.forEach((polres: any) => {
// currentFileLevels.delete(Number(polres.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);
// // };
// const handleCheckboxChangeImage = (fileId: number, value: string) => {
// setSelectedOptions((prev: any) => {
// const currentSelections = prev[fileId] || [];
// if (value === "all") {
// if (currentSelections.includes("all")) {
// return { ...prev, [fileId]: [] };
// }
// return {
// ...prev,
// [fileId]: ["all", "nasional", "wilayah", "internasional"],
// };
// } else {
// const updatedSelections = currentSelections.includes(value)
// ? currentSelections.filter((option: any) => option !== value)
// : [...currentSelections, value];
// const isAllSelected = ["nasional", "wilayah", "internasional"].every(
// (opt) => updatedSelections.includes(opt)
// );
// return {
// ...prev,
// [fileId]: isAllSelected
// ? ["all", ...updatedSelections]
// : updatedSelections.filter((opt: any) => opt !== "all"),
// };
// }
// });
// };
// 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 */}
// <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">
// <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 space-y-2">
// <Label className="text-lg font-semibold">
// {" "}
// {t("file-media", { defaultValue: "File Media" })}
// </Label>
// <div className="grid gap-4">
// {files.map((file: 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>
// <Label className="flex items-center space-x-2">
// <input
// type="checkbox"
// checked={selectedOptions[
// file.id
// ]?.includes("all")}
// onChange={() =>
// handleCheckboxChangeImage(
// file.id,
// "all"
// )
// }
// className="form-checkbox"
// />
// <span>
// {t("all", { defaultValue: "All" })}
// </span>
// </Label>
// </div>
// <div>
// <Label className="flex items-center space-x-2">
// <input
// type="checkbox"
// checked={selectedOptions[
// file.id
// ]?.includes("nasional")}
// onChange={() =>
// handleCheckboxChangeImage(
// file.id,
// "nasional"
// )
// }
// className="form-checkbox"
// />
// <span>Nasional</span>
// </Label>
// </div>
// <div>
// <Label className="flex items-center space-x-2">
// <input
// type="checkbox"
// checked={selectedOptions[
// file.id
// ]?.includes("wilayah")}
// onChange={() =>
// handleCheckboxChangeImage(
// file.id,
// "wilayah"
// )
// }
// className="form-checkbox"
// />
// <span>Wilayah</span>
// </Label>
// </div>
// <div>
// <Label className="flex items-center space-x-2">
// <input
// type="checkbox"
// checked={selectedOptions[
// file.id
// ]?.includes("internasional")}
// onChange={() =>
// handleCheckboxChangeImage(
// file.id,
// "internasional"
// )
// }
// className="form-checkbox"
// />
// <span>Internasional</span>
// </Label>
// </div>
// </div>
// </div>
// ))}
// </div>
// </div>
// )}
// {/* {files.length > 0 && (
// <div className="mt-4">
// <Label className="text-lg 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>
// <div className="space-y-4">
// <div>
// <p className="text-sm font-medium text-gray-700 mb-3">
// Tingkat Distribusi:
// </p>
// <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>
// </div>
// {fileUnitSelections[index]?.wilayah && (
// <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: "polres", label: "POLRES" },
// { 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>
// ))}
// <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
// POLRES
// </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"
// >
// <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>
// {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>
// {polda.subDestination &&
// expandedPolda[
// polda.id
// ] && (
// <div className="max-h-[200px] overflow-y-auto border-t border-gray-100 pt-2">
// <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"
// >
// <input
// type="text"
// value={tag}
// onChange={(e) => handleEditTag(index, e.target.value)}
// className="bg-black text-white border-none focus:outline-none w-auto"
// />
// <button
// value={tag}
// 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-6 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>
// );
// }