diff --git a/app/[locale]/(protected)/contributor/agenda-setting/calender-view.tsx b/app/[locale]/(protected)/contributor/agenda-setting/calender-view.tsx index 5c6963d2..d1e19165 100644 --- a/app/[locale]/(protected)/contributor/agenda-setting/calender-view.tsx +++ b/app/[locale]/(protected)/contributor/agenda-setting/calender-view.tsx @@ -115,7 +115,7 @@ const CalendarView = ({ categories }: CalendarViewProps) => { const [selectedCategory, setSelectedCategory] = useState([]); const [selectedEventDate, setSelectedEventDate] = useState(null); const roleId = Number(getCookiesDecrypt("urie")) || 0; - console.log("DUARR", roleId) + const levelNumber = Number(getCookiesDecrypt("ulne")) || 0; const userLevelId = Number(getCookiesDecrypt("ulie")) || 0; const [calendarEvents, setCalendarEvents] = useState([]); const [isLoading, setIsLoading] = useState(false); @@ -415,7 +415,9 @@ const CalendarView = ({ categories }: CalendarViewProps) => {
{events.length === 0 ? (
-

{t("no-data-yet", { defaultValue: "No Data Yet" })}

+

+ {t("no-data-yet", { defaultValue: "No Data Yet" })} +

) : ( <> @@ -527,7 +529,16 @@ const CalendarView = ({ categories }: CalendarViewProps) => { - {[3, 11, 2, 12].includes(roleId) && ( + {/* {[3, 11, 2, 12].includes(roleId) && ( + + )} */} + {[3, 11, 2, 12].includes(roleId) && levelNumber !== 3 && ( - {t("monitoring-results", { defaultValue: "Monitoring Results" })} + + {t("monitoring-results", { + defaultValue: "Monitoring Results", + })} + {getModalContent()} diff --git a/app/[locale]/(protected)/contributor/content/spit/table-spit/table-spit.tsx b/app/[locale]/(protected)/contributor/content/spit/table-spit/table-spit.tsx index 016c9e30..00d73202 100644 --- a/app/[locale]/(protected)/contributor/content/spit/table-spit/table-spit.tsx +++ b/app/[locale]/(protected)/contributor/content/spit/table-spit/table-spit.tsx @@ -179,7 +179,6 @@ const TableSPIT = () => { React.useEffect(() => { fetchData(); getCategories(); - console.log("TRIGGERRRR"); }, [statusFilter, page, showData, search, dateFilter]); async function getCategories() { diff --git a/app/[locale]/(protected)/contributor/content/teks/components/table-teks.tsx b/app/[locale]/(protected)/contributor/content/teks/components/table-teks.tsx index 1c0a57d2..eea434ee 100644 --- a/app/[locale]/(protected)/contributor/content/teks/components/table-teks.tsx +++ b/app/[locale]/(protected)/contributor/content/teks/components/table-teks.tsx @@ -67,7 +67,6 @@ import useTableColumns from "./columns"; const TableTeks = () => { const router = useRouter(); const searchParams = useSearchParams(); - const [dataTable, setDataTable] = React.useState([]); const [totalData, setTotalData] = React.useState(1); const [sorting, setSorting] = React.useState([]); @@ -77,7 +76,7 @@ const TableTeks = () => { const [columnVisibility, setColumnVisibility] = React.useState({}); const [rowSelection, setRowSelection] = React.useState({}); - const [showData, setShowData] = React.useState("50"); + const [showData, setShowData] = React.useState("10"); const [pagination, setPagination] = React.useState({ pageIndex: 0, pageSize: Number(showData), @@ -88,7 +87,6 @@ const TableTeks = () => { const [search, setSearch] = React.useState(""); const userId = getCookiesDecrypt("uie"); const userLevelId = getCookiesDecrypt("ulie"); - const [categories, setCategories] = React.useState([]); const [selectedCategories, setSelectedCategories] = React.useState( [] diff --git a/app/[locale]/(protected)/contributor/report/components/report-table.tsx b/app/[locale]/(protected)/contributor/report/components/report-table.tsx index 976a1e27..1a2ad488 100644 --- a/app/[locale]/(protected)/contributor/report/components/report-table.tsx +++ b/app/[locale]/(protected)/contributor/report/components/report-table.tsx @@ -88,7 +88,7 @@ const ReportTable = () => { const [columnVisibility, setColumnVisibility] = React.useState({}); const [rowSelection, setRowSelection] = React.useState({}); - const [showData, setShowData] = React.useState("50"); + const [showData, setShowData] = React.useState("10"); const [pagination, setPagination] = React.useState({ pageIndex: 0, pageSize: Number(showData), @@ -106,6 +106,8 @@ const ReportTable = () => { const [statusFilter, setStatusFilter] = React.useState([]); const [openPreview, setOpenPreview] = React.useState(false); const [previewData, setPreviewData] = React.useState(null); + const [openDateDialog, setOpenDateDialog] = React.useState(false); + const [reportDate, setReportDate] = React.useState(""); const handlePreview = (id: string) => { const url = `https://new.netidhub.com/api/media/report/view?id=${id}`; @@ -184,8 +186,6 @@ const ReportTable = () => { ? prev.filter((id: any) => id !== categoryId) : [...prev, categoryId] ); - - // Perbarui filter kategori setCategoryFilter((prev) => { const updatedCategories = prev.split(",").filter(Boolean).map(Number); @@ -206,22 +206,65 @@ const ReportTable = () => { } const handleSearch = (e: React.ChangeEvent) => { - setSearch(e.target.value); // Perbarui state search - table.getColumn("judul")?.setFilterValue(e.target.value); // Set filter tabel + setSearch(e.target.value); + table.getColumn("judul")?.setFilterValue(e.target.value); }; - const handleGenerateReport = async () => { - const today = new Date(); - const formattedDate = format(today, "dd-MM-yyyy"); // Hasil: 22-04-2025 - const title = `Report ${formattedDate}`; + // const handleGenerateReport = async () => { + // const today = new Date(); + // const formattedDate = format(today, "dd-MM-yyyy"); + // const title = `Report ${formattedDate}`; + // const requestData = { + // title, + // date: reportDate, + // }; + + // try { + // const response = await saveReport(requestData); + + // if (response?.error) { + // MySwal.fire( + // "Error", + // response?.message || "Gagal menyimpan laporan", + // "error" + // ); + // return; + // } + + // MySwal.fire({ + // title: "Sukses", + // text: "Laporan berhasil dibuat.", + // icon: "success", + // confirmButtonColor: "#3085d6", + // confirmButtonText: "OK", + // }).then(() => { + // fetchData(); + // }); + // } catch (error) { + // console.error("Generate report error:", error); + // MySwal.fire("Error", "Terjadi kesalahan saat membuat laporan", "error"); + // } + // }; + + const handleGenerateReport = async () => { + if (!reportDate) { + MySwal.fire( + "Warning", + "Silakan pilih tanggal laporan terlebih dahulu", + "warning" + ); + return; + } + + const title = `Report ${format(new Date(reportDate), "dd-MM-yyyy")}`; const requestData = { title, + date: reportDate, }; try { const response = await saveReport(requestData); - if (response?.error) { MySwal.fire( "Error", @@ -238,7 +281,8 @@ const ReportTable = () => { confirmButtonColor: "#3085d6", confirmButtonText: "OK", }).then(() => { - fetchData(); // Refresh tabel setelah generate + fetchData(); + setReportDate(""); }); } catch (error) { console.error("Generate report error:", error); @@ -269,10 +313,19 @@ const ReportTable = () => {
- {t("table", { defaultValue: "Table" })} {t("report", { defaultValue: "Report" })} + {t("table", { defaultValue: "Table" })}{" "} + {t("report", { defaultValue: "Report" })}
- */} + @@ -472,6 +525,38 @@ const ReportTable = () => { totalPage={totalPage} />
+ + + + Pilih Tanggal Laporan + +
+ + setReportDate(e.target.value)} + /> +
+ + +
+
+
+
); }; diff --git a/components/form/content/audio-detail-form.tsx b/components/form/content/audio-detail-form.tsx index 8a792d37..e9d5120b 100644 --- a/components/form/content/audio-detail-form.tsx +++ b/components/form/content/audio-detail-form.tsx @@ -19,7 +19,6 @@ import { } 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"; @@ -35,7 +34,7 @@ import { getDataApprovalByMediaUpload, } from "@/service/curated-content/curated-content"; import { Badge } from "@/components/ui/badge"; -import { MailIcon, Music } from "lucide-react"; +import { ChevronDown, ChevronUp, MailIcon, Music } from "lucide-react"; import { Swiper, SwiperSlide } from "swiper/react"; import "swiper/css"; import "swiper/css/free-mode"; @@ -51,6 +50,7 @@ import { Dialog, DialogContent, DialogTitle, + DialogTrigger, } from "@/components/ui/dialog"; import { Textarea } from "@/components/ui/textarea"; import { loading } from "@/config/swal"; @@ -66,6 +66,7 @@ import { formatDateToIndonesian } from "@/utils/globals"; import ApprovalHistoryModal from "@/components/modal/approval-history-modal"; import { useDropzone } from "react-dropzone"; import AudioPlayer from "@/components/audio-player"; +import { getUserLevelForAssignments } from "@/service/task"; const imageSchema = z.object({ title: z.string().min(1, { message: "Judul diperlukan" }), @@ -115,6 +116,17 @@ const ViewEditor = dynamic( { ssr: false } ); +interface Destination { + id: string; + name: string; + subDestination?: SubDestination[]; +} + +interface SubDestination { + id: string; + name: string; +} + export default function FormAudioDetail() { const MySwal = withReactContent(Swal); const router = useRouter(); @@ -155,6 +167,135 @@ export default function FormAudioDetail() { const [wavesurfer, setWavesurfer] = useState(); const [isPlaying, setIsPlaying] = useState(false); const [approval, setApproval] = useState(); + const [expandedPolda, setExpandedPolda] = useState([{}]); + const [unitSelection, setUnitSelection] = useState({ + semua: false, + nasional: false, + wilayah: false, + international: false, + polda: false, + polres: false, + satker: false, + }); + const [isLoading, setIsLoading] = useState(false); + const [listDest, setListDest] = useState([]); + const [checkedLevels, setCheckedLevels] = useState(new Set()); + + const toggleExpand = (id: number) => { + setExpandedPolda((prev) => ({ + ...prev, + [id]: !prev[id], + })); + }; + + useEffect(() => { + if (detail?.assignedToTopLevel) { + const outputSet = new Set( + detail.assignedToTopLevel.split(",").map(Number) + ); + setUnitSelection({ + semua: outputSet.has(0), + nasional: outputSet.has(1), + wilayah: outputSet.has(2), + international: outputSet.has(3), + polda: outputSet.has(4), + polres: outputSet.has(5), + satker: outputSet.has(6), + }); + } + }, [detail?.fileTypeOutput]); + + 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(() => { + const updated = new Set(checkedLevels); + + if (unitSelection.polda) { + listDest.forEach((polda) => { + updated.add(polda.id); + }); + } + + if (unitSelection.polres) { + listDest.forEach((polda) => { + polda?.subDestination?.forEach((polres: any) => { + updated.add(polres.id); + }); + }); + } + + setCheckedLevels(updated); + }, [unitSelection.polda, unitSelection.polres, listDest]); + + const handleUnitChange = ( + key: keyof typeof unitSelection, + value: boolean + ) => { + if (key === "semua") { + const newState = { + semua: value, + nasional: value, + wilayah: value, + international: value, + polda: value, + polres: value, + satker: value, + }; + setUnitSelection(newState); + } else { + const updatedSelection = { + ...unitSelection, + [key]: value, + }; + + const allChecked = [ + "nasional", + "wilayah", + "international", + "polda", + "polres", + "satker", + ].every((k) => updatedSelection[k as keyof typeof unitSelection]); + + updatedSelection.semua = allChecked; + + setUnitSelection(updatedSelection); + } + }; + + const handleCheckboxChangePlacement = (levelId: number) => { + setCheckedLevels((prev: any) => { + const updatedLevels = new Set(prev); + if (updatedLevels.has(levelId)) { + updatedLevels.delete(levelId); + } else { + updatedLevels.add(levelId); + } + return updatedLevels; + }); + }; const onDrop = (acceptedFiles: File[]) => { setUploadedFiles(acceptedFiles); @@ -247,7 +388,7 @@ export default function FormAudioDetail() { if (findCategory) { // setValue("categoryId", findCategory.id); - setSelectedCategory(findCategory.id); + setSelectedCategory(findCategory.id); const response = await getTagsBySubCategoryId(findCategory.id); setTags(response?.data?.data); } @@ -270,10 +411,7 @@ export default function FormAudioDetail() { if (id) { const response = await detailMedia(id); const details = response?.data?.data; - console.log("detail", details); setFiles(details?.files); - console.log("ISI FILES:", details?.files); - setDetail(details); setMain({ type: details?.fileType.name, @@ -283,6 +421,13 @@ export default function FormAudioDetail() { }); setupPlacementCheck(details?.files?.length); + if (details?.assignedToLevel) { + const levels = new Set( + details.assignedToLevel.split(",").map(Number) + ); + setCheckedLevels(levels); + } + if (details?.publishedForObject) { const publisherIds = details?.publishedForObject.map( (obj: any) => obj.id @@ -358,9 +503,9 @@ export default function FormAudioDetail() { console.log("getPlaa", filePlacements); const temp = []; for (let i = 0; i < filePlacements?.length; i++) { - if (filePlacements[i].length !== 0) { - const now = filePlacements[i].filter((a) => a !== "all"); - const data = { mediaFileId: files[i].id, placements: now.join(",") }; + if (filePlacements[i]?.length !== 0) { + const now = filePlacements[i]?.filter((a) => a !== "all"); + const data = { mediaFileId: files[i]?.id, placements: now.join(",") }; temp.push(data); } } @@ -374,6 +519,7 @@ export default function FormAudioDetail() { message: description, // files: [], files: isUserMabesApprover ? getPlacement() : [], + customLocationPlacement: Array.from(checkedLevels).join(","), }; setModalOpen(false); loading(); @@ -420,9 +566,9 @@ export default function FormAudioDetail() { temp[index] = ["all", "mabes", "polda", "international"]; } else { const now = temp[index]; - now.push(placement); - if (now.length === 3 && !now.includes("all")) { - now.push("all"); + now?.push(placement); + if (now?.length === 3 && !now?.includes("all")) { + now?.push("all"); } temp[index] = now; } @@ -431,9 +577,8 @@ export default function FormAudioDetail() { temp[index] = []; } else { const now = temp[index].filter((a) => a !== placement); - console.log("now", now); temp[index] = now; - if (now.length === 3 && now.includes("all")) { + if (now?.length === 3 && now?.includes("all")) { const newData = now.filter((b) => b !== "all"); temp[index] = newData; } @@ -734,7 +879,195 @@ export default function FormAudioDetail() {
- {isUserMabesApprover && ( +
+ {/* --- Checkbox utama --- */} +
+ {[ + "semua", + "nasional", + "wilayah", + "international", + ].map((key, index) => ( +
+ { + handleUnitChange( + key as keyof typeof unitSelection, + value as boolean + ); + setupPlacement( + index, + key, + Boolean(value) + ); + }} + /> + +
+ ))} +
+ + {/* --- Kalau wilayah dicentang baru tampilkan detail --- */} + {unitSelection.wilayah && ( +
+
+ {["polda", "polres", "satker"].map( + (key, index) => ( +
+ { + handleUnitChange( + key as keyof typeof unitSelection, + value as boolean + ); + setupPlacement( + index, + key, + Boolean(value) + ); + }} + /> + +
+ ) + )} +
+ + {/* --- Custom Button + Dialog --- */} + + + + + + + + Daftar Wilayah Polda dan Polres + + +
+ {listDest.map((polda: any) => { + const poldaChecked = + unitSelection.polda; + const polresChecked = + unitSelection.polres; + const isPoldaDisabled = poldaChecked; + const isPolresDisabled = + polresChecked; + + return ( +
+ + + {expandedPolda[polda.id] && ( +
+ {polda?.subDestination?.map( + (polres: any) => ( + + ) + )} +
+ )} +
+ ); + })} +
+
+
+
+ )} +
+ {/* {isUserMabesApprover && (
- )} + )} */} )) diff --git a/components/form/content/image-detail-form.tsx b/components/form/content/image-detail-form.tsx index 86a56f6c..d16491e2 100644 --- a/components/form/content/image-detail-form.tsx +++ b/components/form/content/image-detail-form.tsx @@ -36,7 +36,7 @@ import { getDataApprovalByMediaUpload, } from "@/service/curated-content/curated-content"; import { Badge } from "@/components/ui/badge"; -import { MailIcon } from "lucide-react"; +import { ChevronDown, ChevronUp, MailIcon } from "lucide-react"; import { Swiper, SwiperSlide } from "swiper/react"; import "swiper/css"; import "swiper/css/free-mode"; @@ -67,6 +67,7 @@ import SuggestionModal from "@/components/modal/suggestions-modal"; import { formatDateToIndonesian } from "@/utils/globals"; import ApprovalHistoryModal from "@/components/modal/approval-history-modal"; import Image from "next/image"; +import { getUserLevelForAssignments } from "@/service/task"; const imageSchema = z.object({ title: z.string().min(1, { message: "Judul diperlukan" }), @@ -116,6 +117,17 @@ const ViewEditor = dynamic( { ssr: false } ); +interface Destination { + id: string; + name: string; + subDestination?: SubDestination[]; +} + +interface SubDestination { + id: string; + name: string; +} + export default function FormImageDetail() { const MySwal = withReactContent(Swal); const router = useRouter(); @@ -123,13 +135,13 @@ export default function FormImageDetail() { const userLevelId = getCookiesDecrypt("ulie"); const userLevelName = Cookies.get("state"); const roleId = getCookiesDecrypt("urie"); + const [listDest, setListDest] = useState([]); console.log("LALALALA", userLevelName); const [modalOpen, setModalOpen] = useState(false); const { id } = useParams() as { id: string }; console.log(id); const editor = useRef(null); type ImageSchema = z.infer; - const t = useTranslations("Form"); const [selectedFiles, setSelectedFiles] = useState([]); const taskId = Cookies.get("taskId"); @@ -149,10 +161,21 @@ export default function FormImageDetail() { const [thumbsSwiper, setThumbsSwiper] = useState(null); const [isUserMabesApprover, setIsUserMabesApprover] = useState(false); const [approval, setApproval] = useState(); - + const [unitSelection, setUnitSelection] = useState({ + semua: false, + nasional: false, + wilayah: false, + international: false, + polda: false, + polres: false, + satker: false, + }); + const [isLoading, setIsLoading] = useState(false); + const [checkedLevels, setCheckedLevels] = useState(new Set()); const [selectedTarget, setSelectedTarget] = useState(""); const [files, setFiles] = useState([]); const [rejectedFiles, setRejectedFiles] = useState([]); + const [expandedPolda, setExpandedPolda] = useState([{}]); const [wilayahPublish, setWilayahPublish] = React.useState({ semua: false, nasional: false, @@ -165,6 +188,117 @@ export default function FormImageDetail() { let fileTypeId = "1"; + const toggleExpand = (id: number) => { + setExpandedPolda((prev) => ({ + ...prev, + [id]: !prev[id], + })); + }; + + useEffect(() => { + if (detail?.assignedToTopLevel) { + const outputSet = new Set( + detail.assignedToTopLevel.split(",").map(Number) + ); + setUnitSelection({ + semua: outputSet.has(0), + nasional: outputSet.has(1), + wilayah: outputSet.has(2), + international: outputSet.has(3), + polda: outputSet.has(4), + polres: outputSet.has(5), + satker: outputSet.has(6), + }); + } + }, [detail?.fileTypeOutput]); + + // const handlePoldaPolresChange = () => { + // return Array.from(checkedLevels).join(","); // Mengonversi Set ke 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(() => { + const updated = new Set(checkedLevels); + + if (unitSelection.polda) { + listDest.forEach((polda) => { + updated.add(polda.id); // hanya id polda + }); + } + + if (unitSelection.polres) { + listDest.forEach((polda) => { + polda?.subDestination?.forEach((polres: any) => { + updated.add(polres.id); // hanya id polres + }); + }); + } + + setCheckedLevels(updated); + }, [unitSelection.polda, unitSelection.polres, listDest]); + + const handleUnitChange = ( + key: keyof typeof unitSelection, + value: boolean + ) => { + if (key === "semua") { + // Jika klik Semua, set semua value ke true/false + const newState = { + semua: value, + nasional: value, + wilayah: value, + international: value, + polda: value, + polres: value, + satker: value, + }; + setUnitSelection(newState); + } else { + // Update salah satu saja + const updatedSelection = { + ...unitSelection, + [key]: value, + }; + + // Cek apakah semua selain "semua" sudah dicentang + const allChecked = [ + "nasional", + "wilayah", + "international", + "polda", + "polres", + "satker", + ].every((k) => updatedSelection[k as keyof typeof unitSelection]); + + updatedSelection.semua = allChecked; + + setUnitSelection(updatedSelection); + } + }; + const { control, handleSubmit, @@ -191,6 +325,18 @@ export default function FormImageDetail() { ); }; + const handleCheckboxChangePlacement = (levelId: number) => { + setCheckedLevels((prev: any) => { + const updatedLevels = new Set(prev); + if (updatedLevels.has(levelId)) { + updatedLevels.delete(levelId); + } else { + updatedLevels.add(levelId); + } + return updatedLevels; + }); + }; + useEffect(() => { async function initState() { getCategories(); @@ -214,7 +360,7 @@ export default function FormImageDetail() { if (findCategory) { // setValue("categoryId", findCategory.id); - setSelectedCategory(findCategory.id); // Set the selected category + setSelectedCategory(findCategory.id); const response = await getTagsBySubCategoryId(findCategory.id); setTags(response?.data?.data); } @@ -248,6 +394,13 @@ export default function FormImageDetail() { }); setupPlacementCheck(details?.files?.length); + if (details?.assignedToLevel) { + const levels = new Set( + details.assignedToLevel.split(",").map(Number) + ); + setCheckedLevels(levels); + } + if (details.publishedForObject) { const publisherIds = details.publishedForObject.map( (obj: any) => obj.id @@ -327,8 +480,8 @@ export default function FormImageDetail() { statusId: status, message: description, files: isUserMabesApprover ? getPlacement() : [], + customLocationPlacement: Array.from(checkedLevels).join(","), }; - setModalOpen(false); loading(); const response = await submitApproval(data); @@ -368,7 +521,7 @@ export default function FormImageDetail() { temp[index] = ["all", "mabes", "polda", "international"]; } else { const now = temp[index]; - now.push(placement); + now?.push(placement); if (now.length === 3 && !now.includes("all")) { now.push("all"); } @@ -397,6 +550,7 @@ export default function FormImageDetail() { rejects.push(id); setRejectedFiles(rejects); } + const handleMain = ( type: string, url: string, @@ -454,7 +608,9 @@ export default function FormImageDetail() {
-

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

+

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

{/* Input Title */}
@@ -495,16 +651,23 @@ export default function FormImageDetail() { {/* Show the category from details if it doesn't exist in categories list */} - {detail && !categories.find(cat => String(cat.id) === String(detail.category.id)) && ( - - {detail.category.name} - - )} + {detail && + !categories.find( + (cat) => + String(cat.id) === String(detail.category.id) + ) && ( + + {detail.category.name} + + )} {categories.map((category) => ( - + {category.name} ))} @@ -514,7 +677,9 @@ export default function FormImageDetail() {
- +
- +
- +
- {t("leave-comment", { defaultValue: "Leave Comment" })} + + {t("leave-comment", { defaultValue: "Leave Comment" })} +
{status == "2" @@ -760,7 +931,199 @@ export default function FormImageDetail() {
- {isUserMabesApprover && ( +
+ {/* --- Checkbox utama --- */} +
+ {[ + "semua", + "nasional", + "wilayah", + "international", + ].map((key, index) => ( +
+ { + handleUnitChange( + key as keyof typeof unitSelection, + value as boolean + ); + setupPlacement( + index, + key, + Boolean(value) + ); + }} + /> + +
+ ))} +
+ + {/* --- Kalau wilayah dicentang baru tampilkan detail --- */} + {unitSelection.wilayah && ( +
+
+ {["polda", "polres", "satker"].map( + (key, index) => ( +
+ { + handleUnitChange( + key as keyof typeof unitSelection, + value as boolean + ); + setupPlacement( + index, + key, + Boolean(value) + ); + }} + /> + +
+ ) + )} +
+ + {/* --- Custom Button + Dialog --- */} + + + + + + + + Daftar Wilayah Polda dan Polres + + +
+ {listDest.map((polda: any) => { + const poldaChecked = + unitSelection.polda; + const polresChecked = + unitSelection.polres; + const isPoldaDisabled = + poldaChecked; + const isPolresDisabled = + polresChecked; + + return ( +
+ + + {expandedPolda[polda.id] && ( +
+ {polda?.subDestination?.map( + (polres: any) => ( + + ) + )} +
+ )} +
+ ); + })} +
+
+
+
+ )} +
+ {/* {isUserMabesApprover && (
- )} + )} */}
)) diff --git a/components/form/content/teks-detail-form.tsx b/components/form/content/teks-detail-form.tsx index 19804d13..17868d03 100644 --- a/components/form/content/teks-detail-form.tsx +++ b/components/form/content/teks-detail-form.tsx @@ -35,7 +35,7 @@ import { getDataApprovalByMediaUpload, } from "@/service/curated-content/curated-content"; import { Badge } from "@/components/ui/badge"; -import { MailIcon } from "lucide-react"; +import { ChevronDown, ChevronUp, MailIcon } from "lucide-react"; import { Swiper, SwiperSlide } from "swiper/react"; import "swiper/css"; import "swiper/css/free-mode"; @@ -51,6 +51,7 @@ import { Dialog, DialogContent, DialogTitle, + DialogTrigger, } from "@/components/ui/dialog"; import { Textarea } from "@/components/ui/textarea"; import { loading } from "@/config/swal"; @@ -64,6 +65,7 @@ import { formatDateToIndonesian } from "@/utils/globals"; import ApprovalHistoryModal from "@/components/modal/approval-history-modal"; import FileTextPreview from "./file-preview-text"; import FileTextThumbnail from "./file-text-thumbnail"; +import { getUserLevelForAssignments } from "@/service/task"; const imageSchema = z.object({ title: z.string().min(1, { message: "Judul diperlukan" }), @@ -113,19 +115,28 @@ const ViewEditor = dynamic( { ssr: false } ); +interface Destination { + id: string; + name: string; + subDestination?: SubDestination[]; +} + +interface SubDestination { + id: string; + name: string; +} + export default function FormTeksDetail() { const MySwal = withReactContent(Swal); const router = useRouter(); const userId = getCookiesDecrypt("uie"); const userLevelId = getCookiesDecrypt("ulie"); const roleId = getCookiesDecrypt("urie"); - const [modalOpen, setModalOpen] = useState(false); const { id } = useParams() as { id: string }; console.log(id); const editor = useRef(null); type ImageSchema = z.infer; - const [selectedFiles, setSelectedFiles] = useState([]); const taskId = Cookies.get("taskId"); const scheduleId = Cookies.get("scheduleId"); @@ -141,20 +152,146 @@ export default function FormTeksDetail() { const [main, setMain] = useState([]); const [detailThumb, setDetailThumb] = useState([]); const [thumbsSwiper, setThumbsSwiper] = useState(null); - const t = useTranslations("Form"); const [selectedTarget, setSelectedTarget] = useState(""); const [files, setFiles] = useState([]); const [rejectedFiles, setRejectedFiles] = useState([]); const [isMabesApprover, setIsMabesApprover] = useState(false); - const [filePlacements, setFilePlacements] = useState([]); const [isUserMabesApprover, setIsUserMabesApprover] = useState(false); - const [approval, setApproval] = useState(); + const [expandedPolda, setExpandedPolda] = useState([{}]); + const [unitSelection, setUnitSelection] = useState({ + semua: false, + nasional: false, + wilayah: false, + international: false, + polda: false, + polres: false, + satker: false, + }); + const [isLoading, setIsLoading] = useState(false); + const [listDest, setListDest] = useState([]); + const [checkedLevels, setCheckedLevels] = useState(new Set()); let fileTypeId = "3"; + const toggleExpand = (id: number) => { + setExpandedPolda((prev) => ({ + ...prev, + [id]: !prev[id], + })); + }; + + useEffect(() => { + if (detail?.assignedToTopLevel) { + const outputSet = new Set( + detail.assignedToTopLevel.split(",").map(Number) + ); + setUnitSelection({ + semua: outputSet.has(0), + nasional: outputSet.has(1), + wilayah: outputSet.has(2), + international: outputSet.has(3), + polda: outputSet.has(4), + polres: outputSet.has(5), + satker: outputSet.has(6), + }); + } + }, [detail?.fileTypeOutput]); + + 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(() => { + const updated = new Set(checkedLevels); + + if (unitSelection.polda) { + listDest.forEach((polda) => { + updated.add(polda.id); + }); + } + + if (unitSelection.polres) { + listDest.forEach((polda) => { + polda?.subDestination?.forEach((polres: any) => { + updated.add(polres.id); + }); + }); + } + + setCheckedLevels(updated); + }, [unitSelection.polda, unitSelection.polres, listDest]); + + const handleUnitChange = ( + key: keyof typeof unitSelection, + value: boolean + ) => { + if (key === "semua") { + const newState = { + semua: value, + nasional: value, + wilayah: value, + international: value, + polda: value, + polres: value, + satker: value, + }; + setUnitSelection(newState); + } else { + const updatedSelection = { + ...unitSelection, + [key]: value, + }; + + const allChecked = [ + "nasional", + "wilayah", + "international", + "polda", + "polres", + "satker", + ].every((k) => updatedSelection[k as keyof typeof unitSelection]); + + updatedSelection.semua = allChecked; + + setUnitSelection(updatedSelection); + } + }; + + const handleCheckboxChangePlacement = (levelId: number) => { + setCheckedLevels((prev: any) => { + const updatedLevels = new Set(prev); + if (updatedLevels.has(levelId)) { + updatedLevels.delete(levelId); + } else { + updatedLevels.add(levelId); + } + return updatedLevels; + }); + }; + const { control, handleSubmit, @@ -248,6 +385,13 @@ export default function FormTeksDetail() { format: details?.files[0]?.format, }); + if (details?.assignedToLevel) { + const levels = new Set( + details.assignedToLevel.split(",").map(Number) + ); + setCheckedLevels(levels); + } + if (details.publishedForObject) { const publisherIds = details.publishedForObject.map( (obj: any) => obj.id @@ -313,9 +457,9 @@ export default function FormTeksDetail() { console.log("getPlaa", filePlacements); const temp = []; for (let i = 0; i < filePlacements?.length; i++) { - if (filePlacements[i].length !== 0) { - const now = filePlacements[i].filter((a) => a !== "all"); - const data = { mediaFileId: files[i].id, placements: now.join(",") }; + if (filePlacements[i]?.length !== 0) { + const now = filePlacements[i]?.filter((a) => a !== "all"); + const data = { mediaFileId: files[i]?.id, placements: now?.join(",") }; temp.push(data); } } @@ -328,6 +472,7 @@ export default function FormTeksDetail() { statusId: status, message: description, files: isUserMabesApprover ? getPlacement() : [], + customLocationPlacement: Array.from(checkedLevels).join(","), }; setModalOpen(false); @@ -367,9 +512,9 @@ export default function FormTeksDetail() { temp[index] = ["all", "mabes", "polda", "international"]; } else { const now = temp[index]; - now.push(placement); - if (now.length === 3 && !now.includes("all")) { - now.push("all"); + now?.push(placement); + if (now?.length === 3 && !now?.includes("all")) { + now?.push("all"); } temp[index] = now; } @@ -377,11 +522,10 @@ export default function FormTeksDetail() { if (placement === "all") { temp[index] = []; } else { - const now = temp[index].filter((a) => a !== placement); - console.log("now", now); + const now = temp[index]?.filter((a) => a !== placement); temp[index] = now; - if (now.length === 3 && now.includes("all")) { - const newData = now.filter((b) => b !== "all"); + if (now?.length === 3 && now?.includes("all")) { + const newData = now?.filter((b) => b !== "all"); temp[index] = newData; } } @@ -472,16 +616,23 @@ export default function FormTeksDetail() { {/* Show the category from details if it doesn't exist in categories list */} - {detail && !categories.find(cat => String(cat.id) === String(detail.category.id)) && ( - - {detail.category.name} - - )} + {detail && + !categories.find( + (cat) => + String(cat.id) === String(detail.category.id) + ) && ( + + {detail.category.name} + + )} {categories.map((category) => ( - + {category.name} ))} @@ -696,7 +847,195 @@ export default function FormTeksDetail() {
- {isUserMabesApprover && ( +
+ {/* --- Checkbox utama --- */} +
+ {[ + "semua", + "nasional", + "wilayah", + "international", + ].map((key, index) => ( +
+ { + handleUnitChange( + key as keyof typeof unitSelection, + value as boolean + ); + setupPlacement( + index, + key, + Boolean(value) + ); + }} + /> + +
+ ))} +
+ + {/* --- Kalau wilayah dicentang baru tampilkan detail --- */} + {unitSelection.wilayah && ( +
+
+ {["polda", "polres", "satker"].map( + (key, index) => ( +
+ { + handleUnitChange( + key as keyof typeof unitSelection, + value as boolean + ); + setupPlacement( + index, + key, + Boolean(value) + ); + }} + /> + +
+ ) + )} +
+ + {/* --- Custom Button + Dialog --- */} + + + + + + + + Daftar Wilayah Polda dan Polres + + +
+ {listDest.map((polda: any) => { + const poldaChecked = + unitSelection.polda; + const polresChecked = + unitSelection.polres; + const isPoldaDisabled = poldaChecked; + const isPolresDisabled = + polresChecked; + + return ( +
+ + + {expandedPolda[polda.id] && ( +
+ {polda?.subDestination?.map( + (polres: any) => ( + + ) + )} +
+ )} +
+ ); + })} +
+
+
+
+ )} +
+ {/* {isUserMabesApprover && (
- )} + )} */}
)) diff --git a/components/form/content/video-detail-form.tsx b/components/form/content/video-detail-form.tsx index 698856c4..0e49164d 100644 --- a/components/form/content/video-detail-form.tsx +++ b/components/form/content/video-detail-form.tsx @@ -35,7 +35,7 @@ import { getDataApprovalByMediaUpload, } from "@/service/curated-content/curated-content"; import { Badge } from "@/components/ui/badge"; -import { MailIcon } from "lucide-react"; +import { ChevronDown, ChevronUp, MailIcon } from "lucide-react"; import { Swiper, SwiperSlide } from "swiper/react"; import "swiper/css"; import "swiper/css/free-mode"; @@ -51,6 +51,7 @@ import { Dialog, DialogContent, DialogTitle, + DialogTrigger, } from "@/components/ui/dialog"; import { Textarea } from "@/components/ui/textarea"; import { loading } from "@/config/swal"; @@ -64,6 +65,7 @@ import SuggestionModal from "@/components/modal/suggestions-modal"; import { formatDateToIndonesian } from "@/utils/globals"; import ApprovalHistoryModal from "@/components/modal/approval-history-modal"; import VideoPlayer from "@/utils/video-player"; +import { getUserLevelForAssignments } from "@/service/task"; const imageSchema = z.object({ title: z.string().min(1, { message: "Judul diperlukan" }), @@ -114,19 +116,27 @@ const ViewEditor = dynamic( { ssr: false } ); +interface Destination { + id: string; + name: string; + subDestination?: SubDestination[]; +} + +interface SubDestination { + id: string; + name: string; +} + export default function FormVideoDetail() { const MySwal = withReactContent(Swal); const router = useRouter(); const userId = getCookiesDecrypt("uie"); const userLevelId = getCookiesDecrypt("ulie"); const roleId = getCookiesDecrypt("urie"); - const [modalOpen, setModalOpen] = useState(false); const { id } = useParams() as { id: string }; - console.log(id); const editor = useRef(null); type ImageSchema = z.infer; - const [selectedFiles, setSelectedFiles] = useState([]); const taskId = Cookies.get("taskId"); const scheduleId = Cookies.get("scheduleId"); @@ -142,7 +152,6 @@ export default function FormVideoDetail() { const [main, setMain] = useState([]); const [detailVideo, setDetailVideo] = useState([]); const [thumbsSwiper, setThumbsSwiper] = useState(null); - const t = useTranslations("Form"); const [filePlacements, setFilePlacements] = useState([]); const [selectedTarget, setSelectedTarget] = useState(""); @@ -150,9 +159,138 @@ export default function FormVideoDetail() { const [rejectedFiles, setRejectedFiles] = useState([]); const [isUserMabesApprover, setIsUserMabesApprover] = useState(false); const [approval, setApproval] = useState(); + const [expandedPolda, setExpandedPolda] = useState([{}]); + const [unitSelection, setUnitSelection] = useState({ + semua: false, + nasional: false, + wilayah: false, + international: false, + polda: false, + polres: false, + satker: false, + }); + const [isLoading, setIsLoading] = useState(false); + const [listDest, setListDest] = useState([]); + const [checkedLevels, setCheckedLevels] = useState(new Set()); let fileTypeId = "2"; + const toggleExpand = (id: number) => { + setExpandedPolda((prev) => ({ + ...prev, + [id]: !prev[id], + })); + }; + + useEffect(() => { + if (detail?.assignedToTopLevel) { + const outputSet = new Set( + detail.assignedToTopLevel.split(",").map(Number) + ); + setUnitSelection({ + semua: outputSet.has(0), + nasional: outputSet.has(1), + wilayah: outputSet.has(2), + international: outputSet.has(3), + polda: outputSet.has(4), + polres: outputSet.has(5), + satker: outputSet.has(6), + }); + } + }, [detail?.fileTypeOutput]); + + 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(() => { + const updated = new Set(checkedLevels); + + if (unitSelection.polda) { + listDest.forEach((polda) => { + updated.add(polda.id); + }); + } + + if (unitSelection.polres) { + listDest.forEach((polda) => { + polda?.subDestination?.forEach((polres: any) => { + updated.add(polres.id); + }); + }); + } + + setCheckedLevels(updated); + }, [unitSelection.polda, unitSelection.polres, listDest]); + + const handleUnitChange = ( + key: keyof typeof unitSelection, + value: boolean + ) => { + if (key === "semua") { + const newState = { + semua: value, + nasional: value, + wilayah: value, + international: value, + polda: value, + polres: value, + satker: value, + }; + setUnitSelection(newState); + } else { + const updatedSelection = { + ...unitSelection, + [key]: value, + }; + + const allChecked = [ + "nasional", + "wilayah", + "international", + "polda", + "polres", + "satker", + ].every((k) => updatedSelection[k as keyof typeof unitSelection]); + + updatedSelection.semua = allChecked; + + setUnitSelection(updatedSelection); + } + }; + + const handleCheckboxChangePlacement = (levelId: number) => { + setCheckedLevels((prev: any) => { + const updatedLevels = new Set(prev); + if (updatedLevels.has(levelId)) { + updatedLevels.delete(levelId); + } else { + updatedLevels.add(levelId); + } + return updatedLevels; + }); + }; + const { control, handleSubmit, @@ -238,6 +376,13 @@ export default function FormVideoDetail() { format: details?.files[0]?.format, }); + if (details?.assignedToLevel) { + const levels = new Set( + details.assignedToLevel.split(",").map(Number) + ); + setCheckedLevels(levels); + } + if (details?.publishedForObject) { const publisherIds = details.publishedForObject.map( (obj: any) => obj.id @@ -303,6 +448,7 @@ export default function FormVideoDetail() { statusId: status, message: description, files: isUserMabesApprover ? getPlacement() : [], + customLocationPlacement: Array.from(checkedLevels).join(","), }; setModalOpen(false); loading(); @@ -354,9 +500,9 @@ export default function FormVideoDetail() { temp[index] = ["all", "mabes", "polda", "international"]; } else { const now = temp[index]; - now.push(placement); - if (now.length === 3 && !now.includes("all")) { - now.push("all"); + now?.push(placement); + if (now?.length === 3 && !now.includes("all")) { + now?.push("all"); } temp[index] = now; } @@ -367,7 +513,7 @@ export default function FormVideoDetail() { const now = temp[index].filter((a) => a !== placement); console.log("now", now); temp[index] = now; - if (now.length === 3 && now.includes("all")) { + if (now?.length === 3 && now.includes("all")) { const newData = now.filter((b) => b !== "all"); temp[index] = newData; } @@ -715,7 +861,195 @@ export default function FormVideoDetail() {
- {isUserMabesApprover && ( +
+ {/* --- Checkbox utama --- */} +
+ {[ + "semua", + "nasional", + "wilayah", + "international", + ].map((key, index) => ( +
+ { + handleUnitChange( + key as keyof typeof unitSelection, + value as boolean + ); + setupPlacement( + index, + key, + Boolean(value) + ); + }} + /> + +
+ ))} +
+ + {/* --- Kalau wilayah dicentang baru tampilkan detail --- */} + {unitSelection.wilayah && ( +
+
+ {["polda", "polres", "satker"].map( + (key, index) => ( +
+ { + handleUnitChange( + key as keyof typeof unitSelection, + value as boolean + ); + setupPlacement( + index, + key, + Boolean(value) + ); + }} + /> + +
+ ) + )} +
+ + {/* --- Custom Button + Dialog --- */} + + + + + + + + Daftar Wilayah Polda dan Polres + + +
+ {listDest.map((polda: any) => { + const poldaChecked = + unitSelection.polda; + const polresChecked = + unitSelection.polres; + const isPoldaDisabled = poldaChecked; + const isPolresDisabled = + polresChecked; + + return ( +
+ + + {expandedPolda[polda.id] && ( +
+ {polda?.subDestination?.map( + (polres: any) => ( + + ) + )} +
+ )} +
+ ); + })} +
+
+
+
+ )} +
+ {/* {isUserMabesApprover && (
- )} + )} */}
)) diff --git a/components/form/task/task-edit-form.tsx b/components/form/task/task-edit-form.tsx index d0304471..833ee76f 100644 --- a/components/form/task/task-edit-form.tsx +++ b/components/form/task/task-edit-form.tsx @@ -318,7 +318,7 @@ export default function FormTaskEdit() { }; const handlePoldaPolresChange = () => { - return Array.from(checkedLevels).join(","); // Mengonversi Set ke string + return Array.from(checkedLevels).join(","); }; const handleUnitChange = ( @@ -471,9 +471,9 @@ export default function FormTaskEdit() { await uploadResumableFile( index, String(id), - item, // Use .file to access the actual File object + item, "4", - "0" // Optional: Replace with actual duration if available + "0" ); }); @@ -808,11 +808,11 @@ export default function FormTaskEdit() {
{listDest.map((polda: any) => { - const poldaChecked = unitSelection.polda; // kontrol polda luar - const polresChecked = unitSelection.polres; // kontrol polres luar + const poldaChecked = unitSelection.polda; + const polresChecked = unitSelection.polres; - const isPoldaDisabled = poldaChecked; // lock checkbox polda dialog jika polda luar dicentang - const isPolresDisabled = polresChecked; // lock checkbox polres dialog jika polres luar dicentang + const isPoldaDisabled = poldaChecked; + const isPolresDisabled = polresChecked; return (
@@ -820,7 +820,7 @@ export default function FormTaskEdit() { { if (isPoldaDisabled) return; @@ -852,7 +852,7 @@ export default function FormTaskEdit() { checked={ polresChecked || checkedLevels.has(polres.id) - } // auto-centang jika polres luar dicentang + } disabled={isPolresDisabled} onCheckedChange={() => { if (isPolresDisabled) return; @@ -876,7 +876,7 @@ export default function FormTaskEdit() {
setMainType(value)} // value={String(mainType)} // onValueChange={(value) => setMainType(Number(value))} @@ -893,7 +893,7 @@ export default function FormTaskEdit() { {t("assigment-type", { defaultValue: "Assigment Type" })}{" "} setTaskType(value)} className="flex flex-wrap gap-3" > diff --git a/service/content/content.ts b/service/content/content.ts index 5486f765..14fddef0 100644 --- a/service/content/content.ts +++ b/service/content/content.ts @@ -63,7 +63,7 @@ export async function listDataImage( isInt: boolean = false ) { return await httpGetInterceptor( - `media/list?enablePage=1&size=${size}&sortBy=createdAt&sort=desc&page=${page}&typeId=1&isForSelf=${isForSelf}&isApproval=${isApproval}&categoryId=${categoryFilter}&statusId=${statusFilter}&creatorUserLevelName=${source}&creatorName=${creator}&startDate=${startDate}&endDate=${endDate}&title=${title}&creatorGroupLevelName=${creatorGroup}&needApprovalFromLevel=${needApprovalFromLevel}&isInt=${isInt}` + `media/list?enablePage=1&size=${size}&sortBy=createdAt&sort=desc&page=${page}&typeId=1&isForSelf=${isForSelf}&isApproval=${isApproval}&categoryId=${categoryFilter}&statusId=${statusFilter}&creatorUserLevelName=${source}&creatorName=${creator}&startDate=${startDate}&endDate=${endDate}&title=${title}&creatorGroupLevelName=${creatorGroup}&needApprovalFromLevel=${needApprovalFromLevel}&isInt=${isInt}&isPublish=` ); }