diff --git a/app/[locale]/(protected)/contributor/agenda-setting/event-modal.tsx b/app/[locale]/(protected)/contributor/agenda-setting/event-modal.tsx index 513c743f..00e002c8 100644 --- a/app/[locale]/(protected)/contributor/agenda-setting/event-modal.tsx +++ b/app/[locale]/(protected)/contributor/agenda-setting/event-modal.tsx @@ -1,10 +1,5 @@ // "use client"; -import React, { - useState, - useEffect, - useRef, - Fragment, -} from "react"; +import React, { useState, useEffect, useRef, Fragment } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; @@ -49,6 +44,7 @@ import { getUserLevelForAssignments } from "@/service/task"; import { AudioRecorder } from "react-audio-voice-recorder"; import FileUploader from "@/components/form/shared/file-uploader"; import { Upload } from "tus-js-client"; +import { getCsrfToken } from "@/service/auth"; const schema = z.object({ title: z.string().min(3, { message: "Required" }), @@ -75,9 +71,7 @@ const EventModal = ({ const [startDate, setStartDate] = useState(new Date()); const [endDate, setEndDate] = useState(new Date()); const [isPending, startTransition] = React.useTransition(); - const [agendaType, setAgendaType] = React.useState( - categories[0].value - ); + const [agendaType, setAgendaType] = React.useState(categories[0].value); const [listDest, setListDest] = useState([]); const [deleteModalOpen, setDeleteModalOpen] = useState(false); const [eventIdToDelete, setEventIdToDelete] = useState(null); @@ -97,6 +91,12 @@ const EventModal = ({ const [isVideoUploadFinish, setIsVideoUploadFinish] = useState(false); const [isTextUploadFinish, setIsTextUploadFinish] = useState(false); const [isAudioUploadFinish, setIsAudioUploadFinish] = useState(false); + let progressInfo: any = []; + let counterUpdateProgress = 0; + const [progressList, setProgressList] = useState([]); + let uploadPersen = 0; + const [isStartUpload, setIsStartUpload] = useState(false); + const [counterProgress, setCounterProgress] = useState(0); const { register, @@ -118,11 +118,17 @@ const EventModal = ({ const levelList = response?.data?.data.list; let listFiltered = []; if (agendaType == "polda") { - listFiltered = levelList.filter((level: any) => level.name != 'SATKER POLRI'); + listFiltered = levelList.filter( + (level: any) => level.name != "SATKER POLRI" + ); } else if (agendaType == "polres") { - listFiltered = levelList.filter((level: any) => level.name != 'SATKER POLRI'); + listFiltered = levelList.filter( + (level: any) => level.name != "SATKER POLRI" + ); } else if (agendaType == "satker") { - listFiltered = levelList.filter((level: any) => level.name == 'SATKER POLRI'); + listFiltered = levelList.filter( + (level: any) => level.name == "SATKER POLRI" + ); } setListDest(listFiltered); const initialExpandedState = listFiltered.reduce( @@ -181,52 +187,28 @@ const EventModal = ({ setIsImageUploadFinish(true); } imageFiles?.map(async (item: any, index: number) => { - await uploadResumableFile( - index, - String(id), - item, - "1", - "0" - ); + await uploadResumableFile(index, String(id), item, "1", "0"); }); if (videoFiles?.length == 0) { setIsVideoUploadFinish(true); } videoFiles?.map(async (item: any, index: number) => { - await uploadResumableFile( - index, - String(id), - item, - "2", - "0" - ); + await uploadResumableFile(index, String(id), item, "2", "0"); }); if (textFiles?.length == 0) { setIsTextUploadFinish(true); } textFiles?.map(async (item: any, index: number) => { - await uploadResumableFile( - index, - String(id), - item, - "3", - "0" - ); + await uploadResumableFile(index, String(id), item, "3", "0"); }); if (audioFiles?.length == 0) { setIsAudioUploadFinish(true); } audioFiles?.map(async (item: any, index: number) => { - await uploadResumableFile( - index, - String(id), - item, - "4", - "0" - ); + await uploadResumableFile(index, String(id), item, "4", "0"); }); // Optional: Use Swal for success feedback @@ -325,19 +307,24 @@ const EventModal = ({ }; async function uploadResumableFile( - idx: number, - id: string, - file: any, - fileTypeId: string, - duration: string + idx: number, + id: string, + file: any, + fileTypeId: string, + duration: string ) { console.log(idx, id, file, fileTypeId, duration); - // const placements = getPlacement(file.placements); - // console.log("Placementttt: : ", placements); + const resCsrf = await getCsrfToken(); + const csrfToken = resCsrf?.data?.token; + console.log("CSRF TOKEN : ", csrfToken); + const headers = { + "X-XSRF-TOKEN": csrfToken, + }; const upload = new Upload(file, { endpoint: `${process.env.NEXT_PUBLIC_API}/agenda-settings/file/upload`, + headers: headers, retryDelays: [0, 3000, 6000, 12_000, 24_000], chunkSize: 20_000, metadata: { @@ -345,8 +332,12 @@ const EventModal = ({ filename: file.name, filetype: file.type, fileTypeId: fileTypeId, - duration: "", - isWatermark: "true", // hardcode + duration, + isWatermark: "false", // hardcode + }, + onBeforeRequest: function (req) { + var xhr = req.getUnderlyingObject(); + xhr.withCredentials = true; }, onError: async (e: any) => { console.log("Error upload :", e); @@ -358,27 +349,18 @@ const EventModal = ({ bytesTotal: any ) => { const uploadPersen = Math.floor((bytesAccepted / bytesTotal) * 100); - // progressInfo[idx].percentage = uploadPersen; - // counterUpdateProgress++; - // console.log(counterUpdateProgress); - // setProgressList(progressInfo); - // setCounterProgress(counterUpdateProgress); + progressInfo[idx].percentage = uploadPersen; + counterUpdateProgress++; + console.log(counterUpdateProgress); + setProgressList(progressInfo); + setCounterProgress(counterUpdateProgress); }, onSuccess: async () => { - // uploadPersen = 100; - // progressInfo[idx].percentage = 100; - // counterUpdateProgress++; - // setCounterProgress(counterUpdateProgress); + uploadPersen = 100; + progressInfo[idx].percentage = 100; + counterUpdateProgress++; + setCounterProgress(counterUpdateProgress); successTodo(); - if (fileTypeId == '1'){ - setIsImageUploadFinish(true); - } else if (fileTypeId == '2'){ - setIsVideoUploadFinish(true); - } if (fileTypeId == '3'){ - setIsTextUploadFinish(true); - } if (fileTypeId == '4'){ - setIsAudioUploadFinish(true); - } }, }); @@ -387,14 +369,24 @@ const EventModal = ({ useEffect(() => { successTodo(); - }, [isImageUploadFinish, isVideoUploadFinish, isAudioUploadFinish, isTextUploadFinish]) + }, [ + isImageUploadFinish, + isVideoUploadFinish, + isAudioUploadFinish, + isTextUploadFinish, + ]); function successTodo() { - if (isImageUploadFinish && isVideoUploadFinish && isAudioUploadFinish && isTextUploadFinish) { + if ( + isImageUploadFinish && + isVideoUploadFinish && + isAudioUploadFinish && + isTextUploadFinish + ) { successSubmit("/in/contributor/agenda-setting"); } } - + const successSubmit = (redirect: string) => { MySwal.fire({ title: "Sukses", @@ -422,7 +414,9 @@ const EventModal = ({ > - {event?.length > 1 ? "Edit Agenda Setting" : "Create Agenda Setting"}{" "} + {event?.length > 1 + ? "Edit Agenda Setting" + : "Create Agenda Setting"}{" "} {event?.title} @@ -551,7 +545,9 @@ const EventModal = ({ )} /> - {(agendaType === "polda" || agendaType === "polres" || agendaType === "satker" )&& ( + {(agendaType === "polda" || + agendaType === "polres" || + agendaType === "satker") && (
@@ -588,50 +584,56 @@ const EventModal = ({ )} - {(agendaType == "polres" || agendaType == "satker") && expandedPolda[polda.id] && ( -
- - {polda?.subDestination?.map((polres: any) => ( -
+ )}
))} @@ -665,7 +667,7 @@ const EventModal = ({
-
-
- - - {event?.length > 1 ? "Updating..." : "Adding..."} + {event?.length > 1 ? "Updating..." : "Adding..."} - ) : event?.length > 1 ? ( + ) : event?.length > 1 ? ( "Update Agenda Setting" ) : ( "Simpan Agenda Setting" diff --git a/app/[locale]/(protected)/contributor/content/spit/table-spit/columns.tsx b/app/[locale]/(protected)/contributor/content/spit/table-spit/columns.tsx index ca5cf595..aa706fb3 100644 --- a/app/[locale]/(protected)/contributor/content/spit/table-spit/columns.tsx +++ b/app/[locale]/(protected)/contributor/content/spit/table-spit/columns.tsx @@ -112,12 +112,17 @@ const columns: ColumnDef[] = [ header: "Actions", enableHiding: false, cell: ({ row }) => { + const isDisabled = row.original.isPublish; // Check the isPublish value + return ( - + */} -
- - ); - })} - - - {/*
- - {detailThumb?.map((data: any) => { - return ( - -
- - -
-
- ); - })} -
-
*/} +
+ {detailThumb?.map((url: any, index: number) => ( +
+ +
+ ))} +

{isPlaying ? "Pause" : "Play"}

+
diff --git a/components/form/content/image-detail-form.tsx b/components/form/content/image-detail-form.tsx index 86bd37de..0c2b48a9 100644 --- a/components/form/content/image-detail-form.tsx +++ b/components/form/content/image-detail-form.tsx @@ -334,7 +334,7 @@ export default function FormImageDetail() { return false; } - + const setupPlacement = ( index: number, placement: string, @@ -679,7 +679,7 @@ export default function FormImageDetail() { - {isUserMabesApprover && + {isUserMabesApprover && (
- } + )} )) diff --git a/components/form/content/spit-convert-form.tsx b/components/form/content/spit-convert-form.tsx index 33959df0..0d89a2f0 100644 --- a/components/form/content/spit-convert-form.tsx +++ b/components/form/content/spit-convert-form.tsx @@ -85,6 +85,17 @@ type Option = { label: string; }; +interface FileData { + contentId: number; + placement?: string[]; + [key: string]: any; // Extendable for additional properties +} + +interface PlacementData { + mediaFileId: number; + placements: string; +} + const CustomEditor = dynamic( () => { return import("@/components/editor/custom-editor"); @@ -118,7 +129,6 @@ export default function FormConvertSPIT() { const [thumbsSwiper, setThumbsSwiper] = useState(null); const [selectedAdvConfig, setSelectedAdvConfig] = useState(""); const [title, setTitle] = useState(""); - const roleId = getCookiesDecrypt("urie"); const [articleIds, setArticleIds] = useState([]); const [isGeneratedArticle, setIsGeneratedArticle] = useState(false); const [articleBody, setArticleBody] = useState(""); @@ -128,7 +138,10 @@ export default function FormConvertSPIT() { const [detailData, setDetailData] = useState(null); const [selectedFileType, setSelectedFileType] = useState("original"); const [isLoadingData, setIsLoadingData] = useState(false); - + const userLevelId = getCookiesDecrypt("ulie"); + const userLevelNumber = getCookiesDecrypt("ulne"); + const roleId = getCookiesDecrypt("urie"); + const [isMabesApprover, setIsMabesApprover] = useState(false); const [selectedTarget, setSelectedTarget] = useState(""); const [unitSelection, setUnitSelection] = useState({ allUnit: false, @@ -137,6 +150,7 @@ export default function FormConvertSPIT() { polres: false, }); const [publishedFor, setPublishedFor] = useState([]); + const [placementLength, setPlacementLength] = useState([]); const options: Option[] = [ { id: "all", label: "SEMUA" }, @@ -187,6 +201,17 @@ export default function FormConvertSPIT() { initState(); }, []); + useEffect(() => { + if ( + userLevelId != undefined && + roleId != undefined && + userLevelId == "216" && + roleId == "3" + ) { + setIsMabesApprover(true); + } + }, [userLevelId, roleId]); + const getCategories = async () => { try { const category = await listCategory(fileTypeId); @@ -247,26 +272,64 @@ export default function FormConvertSPIT() { })) ); - const handleCheckboxChangeFile = (mediaFileId: any, value: any) => { - setTempFile((prev: any) => - prev.map((file: any) => - file.contentId === mediaFileId - ? { - ...file, - placement: file.placement.includes(value) - ? file.placement.filter((item: any) => item !== value) // Hapus jika sudah ada - : [...file.placement, value], // Tambah jika belum ada - } - : file - ) - ); + const getPlacement = (): PlacementData[] => { + return tempFile + .filter((file: FileData) => (file.placement || []).length > 0) // Gunakan default array + .map((file: FileData) => ({ + mediaFileId: Number(file.contentId), + placements: (file.placement || []).join(","), // Gunakan default array + })); }; - const getPlacement = () => { - return tempFile.map((file: any) => ({ - mediaFileId: Number(file.contentId), - placements: file.placement.join(","), - })); + const setupPlacement = (value: string, id: number): void => { + const updatedFiles = tempFile.map((file: FileData) => { + if (file.contentId === id) { + const currentPlacement = file.placement || []; + if (currentPlacement.includes(value)) { + // Remove the placement value + file.placement = currentPlacement.filter((val) => val !== value); + } else { + // Add the placement value + file.placement = + value === "all" + ? ["all", "mabes", "polda", "international"] + : [...currentPlacement, value]; + if (file.placement.includes("all") && value !== "all") { + file.placement = file.placement.filter((val) => val !== "all"); + } + } + } + return file; + }); + + const placementLength = updatedFiles.reduce( + (acc: any, file: any) => acc + (file.placement?.length || 0), + 0 + ); + + setTempFile( + updatedFiles.sort((a: any, b: any) => a.contentId - b.contentId) + ); + setPlacementLength(placementLength); + + console.log("Updated Files:", updatedFiles); + }; + + const handleCheckboxChangeFile = (contentId: number, value: string) => { + setTempFile((prevTempFile: any) => { + return prevTempFile.map((file: any) => { + if (file.contentId === contentId) { + const isChecked = file.placement?.includes(value); + return { + ...file, + placement: isChecked + ? file.placement.filter((v: any) => v !== value) // Uncheck + : [...(file.placement || []), value], // Check + }; + } + return file; + }); + }); }; const handleCheckboxChange = (id: string): void => { @@ -296,11 +359,17 @@ export default function FormConvertSPIT() { } }; - const save = async (data: any) => { + const save = async (data: { + contentTitle: string; + contentDescription: string; + contentRewriteDescription: string; + contentCreator: string; + }): Promise => { const description = selectedFileType === "original" ? data.contentDescription : data.contentRewriteDescription; + const requestData = { spitId: id, title: data.contentTitle, @@ -310,7 +379,7 @@ export default function FormConvertSPIT() { categoryId: selectedCategoryId, publishedFor: publishedFor.join(","), creator: data.contentCreator, - files: getPlacement(), + files: getPlacement(), // Include placement data }; const response = await convertSPIT(requestData); @@ -630,18 +699,29 @@ export default function FormConvertSPIT() { -
- - {detailThumb.map((data: any) => ( -
- {`Thumbnail -
- {["all", "mabes", "polda", "internasional"].map( - (value) => ( + {isMabesApprover ? ( +
+ + {detailThumb.map((data: any) => ( +
+ {`Thumbnail +
+ {[ + "all", + "mabes", + "polda", + "satker", + "internasional", + ].map((value) => ( - ) - )} + ))} +
-
- ))} -
+ ))} +
+ ) : ( + "" + )}
diff --git a/components/form/task/task-detail-form.tsx b/components/form/task/task-detail-form.tsx index 04b5a06f..9ab91157 100644 --- a/components/form/task/task-detail-form.tsx +++ b/components/form/task/task-detail-form.tsx @@ -21,10 +21,14 @@ import { Checkbox } from "@/components/ui/checkbox"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import JoditEditor from "jodit-react"; import { + acceptAssignment, createAssignmentResponse, createTask, deleteAssignmentResponse, + deleteTask, + finishTask, getAcceptance, + getAcceptanceAssignmentStatus, getAssignmentResponseList, getTask, getUserLevelForAssignments, @@ -40,9 +44,10 @@ import { ChevronDown, ChevronUp, DotSquare, TrashIcon } from "lucide-react"; import dynamic from "next/dynamic"; import { Link } from "@/components/navigation"; import { Textarea } from "@/components/ui/textarea"; -import { close, loading } from "@/lib/swal"; +import { close, error, loading } from "@/lib/swal"; import { getCookiesDecrypt } from "@/lib/utils"; import { Avatar, AvatarImage } from "@/components/ui/avatar"; +import { successCallback } from "@/config/swal"; const taskSchema = z.object({ uniqueCode: z.string().min(1, { message: "Judul diperlukan" }), @@ -67,6 +72,21 @@ export type taskDetail = { id: number; name: string; }; + createdBy: { + id: number; + fullname: string; + username: string | null; + email: string; + isActive: boolean; + isDefault: boolean; + isInternational: boolean; + userLevel: { + id: number; + name: string; + aliasName: string; + userGroupId: number; + }; + }; taskType: string; broadcastType: string; narration: string; @@ -106,6 +126,25 @@ const formatDate = (dateString: string): string => { return `${day}-${month}-${year} `; }; +interface AcceptanceData { + id: number; + acceptAt: string; + // Tambahkan properti lain sesuai dengan struktur data Anda +} + +interface AcceptanceData { + id: number; + userLevelId: number; + sentAt: string; + isAccept: boolean; + isSent: boolean; + userLevels: { + id: number; + name: string; + aliasName: string; + }; +} + export default function FormTaskDetail() { const MySwal = withReactContent(Swal); const router = useRouter(); @@ -144,9 +183,14 @@ export default function FormTaskDetail() { const [showInput, setShowInput] = useState(false); const [listData, setListData] = useState([]); const [message, setMessage] = useState(""); - const [sentAcceptance, setSentAcceptance] = useState([]); - const [acceptAcceptance, setAcceptAcceptance] = useState([]); - const [refreshAcceptance, setRefreshAcceptance] = useState(false); + const [sentAcceptance, setSentAcceptance] = useState([]); + const [acceptAcceptance, setAcceptAcceptance] = useState( + [] + ); + const [statusAcceptance, setStatusAcceptance] = useState(); + const [modalType, setModalType] = useState<"terkirim" | "diterima" | "">(""); + const [Isloading, setLoading] = useState(false); + const [refreshAcceptance, setRefreshAcceptance] = useState(false); const [replyingTo, setReplyingTo] = useState(null); const [platformTypeVisible, setPlatformTypeVisible] = useState(false); @@ -313,6 +357,19 @@ export default function FormTaskDetail() { }); }; + const successConfirm = () => { + MySwal.fire({ + title: "Sukses", + icon: "success", + confirmButtonColor: "#3085d6", + confirmButtonText: "OK", + }).then((result) => { + if (result.isConfirmed) { + router.push("/en/contributor/task"); + } + }); + }; + const handleCheckboxChange = (levelId: any) => { setCheckedLevels((prev: any) => { const updatedLevels = new Set(prev); @@ -458,35 +515,65 @@ export default function FormTaskDetail() { // } // } - async function getListAcceptance() { + async function getDataAcceptance() { + const response = await getAcceptanceAssignmentStatus(id); + setStatusAcceptance(response?.data?.data?.isAccept); + console.log("Status :", response?.data?.data?.isAccept); + } + + const handleAcceptAcceptance = async () => { const isAccept = true; - const resSent = await getAcceptance(id, !isAccept); - setSentAcceptance(resSent?.data?.data); - const resAccept = await getAcceptance(id, isAccept); + loading(); + console.log("Id user :", userId); + const response = await acceptAssignment(id, !isAccept); - const acceptanceSort = resAccept?.data?.data?.sort((a: any, b: any) => { - const dateA = new Date(a.acceptAt).getTime(); - const dateB = new Date(b.acceptAt).getTime(); - return dateA - dateB; - }); + if (response?.error) { + error(response?.message); + return false; + } - console.log("Data sort :", acceptanceSort); - setAcceptAcceptance(acceptanceSort); + successCallback(); + getDataAcceptance(); + return false; + }; + + async function getListAcceptance(): Promise { + const isAccept = true; + + try { + const resSent = await getAcceptance(id, !isAccept); + setSentAcceptance(resSent?.data?.data); + + const resAccept = await getAcceptance(id, isAccept); + + const acceptanceSort = resAccept?.data?.data?.sort( + (a: AcceptanceData, b: AcceptanceData) => + new Date(a.acceptAt).getTime() - new Date(b.acceptAt).getTime() + ); + + console.log("Data sort:", acceptanceSort); + setAcceptAcceptance(acceptanceSort); + } catch (error) { + console.error("Error fetching acceptance data:", error); + } } useEffect(() => { - async function initState() { - getListAcceptance(); + async function initState(): Promise { + await getListAcceptance(); } initState(); }, [refreshAcceptance]); - const setFinishAcceptance = async (id: any, isFinish: any) => { + const setFinishAcceptance = async ( + id: number, + isFinish: boolean + ): Promise => { if (!isFinish) { loading(); - setRefreshAcceptance(!refreshAcceptance); + setRefreshAcceptance((prev) => !prev); close(); } }; @@ -495,15 +582,145 @@ export default function FormTaskDetail() { setReplyingTo(id); }; + const getModalContent = (type: "terkirim" | "diterima") => ( +
+ {Isloading ? ( +

Loading...

+ ) : ( + + + + + + + + + + {(type === "terkirim" ? sentAcceptance : acceptAcceptance).map( + (item) => ( + + + + + + ) + )} + +
WaktuUnitStatus
+ {new Date(item.sentAt).toLocaleString()} + {item.userLevels.name} + {type === "terkirim" ? "Terkirim" : "Diterima"} +
+ )} +
+ ); + + async function finishAssignment() { + const response = finishTask(id); + + // if (response.error) { + // error(response.message); + // return false; + // } + + successConfirm(); + } + + async function deleteAssignment() { + const response = deleteTask(id); + + // if (response.error) { + // error(response.message); + // return false; + // } + + successConfirm(); + } + + function handleForward() { + router.push(`/en/contributor/task/forward/${id}`); + } + + async function handleDeleteAssignment() { + MySwal.fire({ + title: "Apakah Anda yakin ingin menghapus data?", + text: "", + icon: "warning", + showCancelButton: true, + cancelButtonColor: "#d33", + confirmButtonColor: "#3085d6", + confirmButtonText: "Hapus", + }).then((result) => { + if (result.isConfirmed) { + deleteAssignment(); + } + }); + } + + async function handleAssignmentDone() { + MySwal.fire({ + title: "Apakah tugas sudah selesai?", + text: "", + icon: "warning", + showCancelButton: true, + cancelButtonColor: "#d33", + confirmButtonColor: "#3085d6", + confirmButtonText: "Ya", + cancelButtonText: "Tidak", + }).then((result) => { + if (result.isConfirmed) { + finishAssignment(); + } + }); + } + return ( {detail !== undefined ? (

Detail Penugasan

-
- - +
+
+ + + + + + + + + + + + Detail Status Penugasan + + + {modalType === "terkirim" && getModalContent("terkirim")} + {modalType === "diterima" && getModalContent("diterima")} + + +
@@ -786,7 +1003,17 @@ export default function FormTaskDetail() {
-
@@ -976,10 +1203,41 @@ export default function FormTaskDetail() { ))}
+ {detail?.createdBy?.id == Number(userId) && + detail?.isDone !== true ? ( + <> + + + + ) : ( + "" + )} {detail?.isDone !== true && (Number(userLevelNumber) !== 3 || Number(userLevelNumber) == 2) ? ( - ) : ( diff --git a/components/form/task/task-form.tsx b/components/form/task/task-form.tsx index 7c05330b..88b8d826 100644 --- a/components/form/task/task-form.tsx +++ b/components/form/task/task-form.tsx @@ -427,7 +427,7 @@ export default function FormTask() { isAudioUploadFinish && isTextUploadFinish ) { - successSubmit("/in/contributor/agenda-setting"); + successSubmit("/in/contributor/task"); } } diff --git a/components/form/task/task-forward-form.tsx b/components/form/task/task-forward-form.tsx new file mode 100644 index 00000000..7a41ae1a --- /dev/null +++ b/components/form/task/task-forward-form.tsx @@ -0,0 +1,963 @@ +"use client"; +import React, { 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 JoditEditor from "jodit-react"; +import { + createAssignmentResponse, + createTask, + deleteAssignmentResponse, + deleteTask, + finishTask, + forwardTask, + getAcceptance, + getAssignmentResponseList, + getTask, + getUserLevelForAssignments, +} from "@/service/task"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import { ChevronDown, ChevronUp, DotSquare, TrashIcon } from "lucide-react"; +import dynamic from "next/dynamic"; +import { Link } from "@/components/navigation"; +import { Textarea } from "@/components/ui/textarea"; +import { close, error, loading } from "@/lib/swal"; +import { getCookiesDecrypt } from "@/lib/utils"; +import { Avatar, AvatarImage } from "@/components/ui/avatar"; + +const taskSchema = z.object({ + // uniqueCode: z.string().min(1, { message: "Judul diperlukan" }), + title: z.string().min(1, { message: "Judul diperlukan" }), + naration: z.string().min(2, { + message: "Narasi Penugasan harus lebih dari 2 karakter.", + }), + forwardMessage: z.string().min(2, { + message: "Narasi Penugasan harus lebih dari 2 karakter.", + }), +}); + +export type taskDetail = { + id: number; + uniqueCode: string; + title: string; + fileTypeOutput: string; + assignedToRole: string; + assignedToTopLevel: string; + assignmentType: { + id: number; + name: string; + }; + assignmentMainType: { + id: number; + name: string; + }; + createdBy: { + id: number; + fullname: string; + username: string | null; + email: string; + isActive: boolean; + isDefault: boolean; + isInternational: boolean; + userLevel: { + id: number; + name: string; + aliasName: string; + userGroupId: number; + }; + }; + taskType: string; + broadcastType: string; + narration: string; + is_active: string; + isDone: any; +}; + +interface ListData { + id: number; + name: string; + content: string; + timestamp: string; +} + +const ViewEditor = dynamic( + () => { + return import("@/components/editor/view-editor"); + }, + { ssr: false } +); + +const formatDate = (dateString: string): string => { + const date = new Date(dateString); + + // Pastikan validitas tanggal + if (isNaN(date.getTime())) { + throw new Error("Invalid date format"); + } + + // Format tanggal + const day = date.getDate().toString().padStart(2, "0"); + const month = (date.getMonth() + 1).toString().padStart(2, "0"); + const year = date.getFullYear(); + // const hours = date.getHours().toString().padStart(2, "0"); + + // Gabungkan hasil format + return `${day}-${month}-${year} `; +}; + +interface AcceptanceData { + id: number; + acceptAt: string; + // Tambahkan properti lain sesuai dengan struktur data Anda +} + +interface AcceptanceData { + id: number; + userLevelId: number; + sentAt: string; + isAccept: boolean; + isSent: boolean; + userLevels: { + id: number; + name: string; + aliasName: string; + }; +} + +export default function FormTaskForward() { + const MySwal = withReactContent(Swal); + const router = useRouter(); + const editor = useRef(null); + type TaskSchema = z.infer; + const { id } = useParams() as { id: string }; + console.log(id); + + const userLevelNumber = getCookiesDecrypt("ulne"); + const userId = getCookiesDecrypt("uie"); + + // State for various form fields + const [taskOutput, setTaskOutput] = useState({ + all: false, + video: false, + audio: false, + image: false, + text: false, + }); + + // const [assignmentType, setAssignmentType] = useState("mediahub"); + // const [assignmentCategory, setAssignmentCategory] = useState("publication"); + const [mainType, setMainType] = useState("1"); + const [taskType, setTaskType] = useState("atensi-khusus"); + const [broadcastType, setBroadcastType] = useState(""); // untuk Tipe Penugasan + const [type, setType] = useState("1"); + const [selectedTarget, setSelectedTarget] = useState("all"); + const [detail, setDetail] = useState(); + const [refresh] = useState(false); + const [listDest, setListDest] = useState([]); // Data Polda dan Polres + + const [expandedPolda, setExpandedPolda] = useState([{}]); + const [isLoading, setIsLoading] = useState(false); + const [responses, setResponses] = useState([]); + const [response, setResponse] = useState(""); + const [showInput, setShowInput] = useState(false); + const [listData, setListData] = useState([]); + const [message, setMessage] = useState(""); + const [sentAcceptance, setSentAcceptance] = useState([]); + const [acceptAcceptance, setAcceptAcceptance] = useState( + [] + ); + const [modalType, setModalType] = useState<"terkirim" | "diterima" | "">(""); + const [Isloading, setLoading] = useState(false); + const [refreshAcceptance, setRefreshAcceptance] = useState(false); + const [replyingTo, setReplyingTo] = useState(null); + const [forwardMessage, setForwardMessage] = useState(); + const [narration, setNarration] = useState(null); + const [checkedLevels, setCheckedLevels] = useState(new Set()); + + const [platformTypeVisible, setPlatformTypeVisible] = useState(false); + const [unitSelection, setUnitSelection] = useState({ + allUnit: false, + mabes: false, + polda: false, + polres: false, + }); + + const { + control, + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(taskSchema), + }); + + // const handleRadioChange = (event: React.ChangeEvent) => { + // const selectedValue = Number(event.target.value); + // setMainType(selectedValue); + + // setPlatformTypeVisible(selectedValue === 2); + // }; + + 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(() => { + async function initState() { + if (id) { + const response = await getTask(id); + const details = response?.data?.data; + + setDetail(details); + + if (details?.assignedToLevel) { + const levels = new Set( + details.assignedToLevel.split(",").map(Number) + ); + setCheckedLevels(levels); + } + } + } + initState(); + }, [id, refresh]); + + useEffect(() => { + if (detail?.broadcastType) { + setBroadcastType(detail.broadcastType); // Mengatur nilai broadcastType dari API + } + }, [detail?.broadcastType]); + + useEffect(() => { + if (detail?.fileTypeOutput) { + const outputSet = new Set(detail.fileTypeOutput.split(",").map(Number)); // Membagi string ke dalam array dan mengonversi ke nomor + setTaskOutput({ + all: outputSet.has(0), + video: outputSet.has(2), + audio: outputSet.has(4), + image: outputSet.has(1), + text: outputSet.has(3), + }); + } + }, [detail?.fileTypeOutput]); + + useEffect(() => { + if (detail?.assignedToTopLevel) { + const outputSet = new Set( + detail.assignedToTopLevel.split(",").map(Number) + ); + setUnitSelection({ + allUnit: outputSet.has(0), + mabes: outputSet.has(1), + polda: outputSet.has(2), + polres: outputSet.has(3), + }); + } + }, [detail?.fileTypeOutput]); + + const save = async (data: TaskSchema) => { + const fileTypeMapping = { + all: "1", + video: "2", + audio: "3", + image: "4", + text: "5", + }; + + const selectedOutputs = Object.keys(taskOutput) + .filter((key) => taskOutput[key as keyof typeof taskOutput]) // Ambil hanya yang `true` + .map((key) => fileTypeMapping[key as keyof typeof fileTypeMapping]) // Konversi ke nilai string + .join(","); + + const requestData = { + ...data, + // assignmentType, + // assignmentCategory, + target: selectedTarget, + unitSelection, + assignedToRole: "3", + taskType: taskType, + broadcastType: broadcastType, + assignmentMainTypeId: mainType, + assignmentPurpose: "1", + assignmentTypeId: type, + fileTypeOutput: selectedOutputs, + id: null, + narration: data.naration, + platformType: "", + title: data.title, + }; + + const response = await createTask(requestData); + + console.log("Form Data Submitted:", requestData); + console.log("response", response); + + MySwal.fire({ + title: "Sukses", + text: "Data berhasil disimpan.", + icon: "success", + confirmButtonColor: "#3085d6", + confirmButtonText: "OK", + }).then(() => { + router.push("/en/contributor/task"); + }); + }; + + const onSubmit = (data: TaskSchema) => { + 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 successConfirm = () => { + MySwal.fire({ + title: "Sukses", + icon: "success", + confirmButtonColor: "#3085d6", + confirmButtonText: "OK", + }).then((result) => { + if (result.isConfirmed) { + router.push("/en/contributor/task"); + } + }); + }; + + const handlePoldaPolresChange = () => { + return Array.from(checkedLevels).join(","); // Mengonversi Set ke string + }; + + async function saveForward() { + console.log("Narasi :", narration); + loading(); + const data = { + id, + forwardMessage, + assignedToLevel: handlePoldaPolresChange(), + }; + + const response = await forwardTask(data); + + if (response?.error) { + error(response.message); + return false; + } + + successConfirm(); + return false; + } + + const handleCheckboxChange = (levelId: any) => { + setCheckedLevels((prev: any) => { + const updatedLevels = new Set(prev); + if (updatedLevels.has(levelId)) { + updatedLevels.delete(levelId); + } else { + updatedLevels.add(levelId); + } + return updatedLevels; + }); + }; + + const toggleExpand = (poldaId: any) => { + setExpandedPolda((prev: any) => ({ + ...prev, + [poldaId]: !prev[poldaId], + })); + }; + + useEffect(() => { + async function initState() { + // loading(); + const response = await getAssignmentResponseList(id); + console.log("data", response?.data?.data); + console.log("userLvl", userLevelNumber); + setListData(response?.data?.data); + close(); + } + + initState(); + }, []); + + const handleToggleInput = (): void => { + setShowInput(!showInput); + }; + + const handleInputChange = (e: React.ChangeEvent) => { + setMessage(e.target.value); + }; + + // const handleSubmitResponse = (): void => { + // if (response.trim()) { + // const newResponse: Response = { + // id: Date.now(), // Unique ID for each response + // name: "Mabes Polri - Approver", + // content: response, + // timestamp: new Date().toLocaleString("id-ID"), // Format timestamp for Indonesia locale + // }; + + // setResponses([newResponse, ...responses]); // Add new response to the top + // setResponse(""); // Reset textarea + // setShowInput(false); // Hide input + // } + // }; + + const postData = () => { + sendSuggestionParent(); + }; + + const sendReplyData = async (parentId: number) => { + const inputElement = document.querySelector( + `#input-comment-${parentId}` + ) as HTMLTextAreaElement; + + if (inputElement?.value?.length > 1) { + loading(); + const data = { + assignmentId: id, + message: inputElement.value, + parentId, + }; + + console.log(data); + const response = await createAssignmentResponse(data); + console.log(response); + + const responseGet = await getAssignmentResponseList(id); + console.log(responseGet?.data?.data); + setListData(responseGet?.data?.data); + + inputElement.value = ""; + close(); + setReplyingTo(null); + } + }; + + async function sendSuggestionParent() { + if (message?.length > 1) { + loading(); + const data = { + assignmentId: id, + message, + parentId: null, + }; + + const response = await createAssignmentResponse(data); + + console.log(response); + setMessage(""); + const responseGet = await getAssignmentResponseList(id); + console.log(responseGet?.data?.data); + setListData(responseGet?.data?.data); + + close(); + } + } + + async function deleteDataSuggestion(dataId: any) { + loading(); + const response = await deleteAssignmentResponse(dataId); + console.log(response); + const responseGet = await getAssignmentResponseList(id); + console.log(responseGet?.data?.data); + setListData(responseGet?.data?.data); + close(); + } + + const deleteData = (dataId: any) => { + deleteDataSuggestion(dataId); + console.log(dataId); + }; + + // async function sendSuggestionChild(parentId: any) { + // const msg = document.querySelectorAll(`#input-comment-${parentId}`)[0] + // .value; + + // if (msg?.length > 1) { + // loading(); + // const data = { + // assignmentId: id, + // message: msg, + // parentId, + // }; + + // console.log(data); + // const response = await createAssignmentResponse(data); + // console.log(response); + // const responseGet = await getAssignmentResponseList(id); + // console.log(responseGet?.data?.data); + // setListData(responseGet?.data?.data); + // // $(":input").val(""); + // close(); + // } + // } + + async function getListAcceptance(): Promise { + const isAccept = true; + + try { + const resSent = await getAcceptance(id, !isAccept); + setSentAcceptance(resSent?.data?.data); + + const resAccept = await getAcceptance(id, isAccept); + + const acceptanceSort = resAccept?.data?.data?.sort( + (a: AcceptanceData, b: AcceptanceData) => + new Date(a.acceptAt).getTime() - new Date(b.acceptAt).getTime() + ); + + console.log("Data sort:", acceptanceSort); + setAcceptAcceptance(acceptanceSort); + } catch (error) { + console.error("Error fetching acceptance data:", error); + } + } + + useEffect(() => { + async function initState(): Promise { + await getListAcceptance(); + } + + initState(); + }, [refreshAcceptance]); + + const setFinishAcceptance = async ( + id: number, + isFinish: boolean + ): Promise => { + if (!isFinish) { + loading(); + + setRefreshAcceptance((prev) => !prev); + close(); + } + }; + + const handleReply = (id: any) => { + setReplyingTo(id); + }; + + async function finishAssignment() { + const response = finishTask(id); + + // if (response.error) { + // error(response.message); + // return false; + // } + + successConfirm(); + } + + async function deleteAssignment() { + const response = deleteTask(id); + + // if (response.error) { + // error(response.message); + // return false; + // } + + successConfirm(); + } + + async function handleForward() { + MySwal.fire({ + title: "Forward Penugasan?", + text: "", + icon: "warning", + showCancelButton: true, + cancelButtonColor: "#d33", + confirmButtonColor: "#3085d6", + confirmButtonText: "Ya", + cancelButtonText: "Tidak", + }).then((result) => { + if (result.isConfirmed) { + saveForward(); + } + }); + } + async function handleDeleteAssignment() { + MySwal.fire({ + title: "Apakah Anda yakin ingin menghapus data?", + text: "", + icon: "warning", + showCancelButton: true, + cancelButtonColor: "#d33", + confirmButtonColor: "#3085d6", + confirmButtonText: "Hapus", + }).then((result) => { + if (result.isConfirmed) { + deleteAssignment(); + } + }); + } + + async function handleAssignmentDone() { + MySwal.fire({ + title: "Apakah tugas sudah selesai?", + text: "", + icon: "warning", + showCancelButton: true, + cancelButtonColor: "#d33", + confirmButtonColor: "#3085d6", + confirmButtonText: "Ya", + cancelButtonText: "Tidak", + }).then((result) => { + if (result.isConfirmed) { + finishAssignment(); + } + }); + } + + return ( + + {detail !== undefined ? ( +
+
+

Tujuan Forward

+
+ +
+
+
+ {listDest.map((polda: any) => ( +
+ +
+ ))} +
+
+ +