From 936a7e6e9407aae86166846d0ada4a98c9b6bc7c Mon Sep 17 00:00:00 2001 From: Anang Yusman Date: Tue, 15 Apr 2025 11:59:21 +0800 Subject: [PATCH] feat:update ui kurator,approver --- .../admin/add-experts/create/page.tsx | 2 +- .../contributor/report/components/columns.tsx | 50 +- .../task-ta/components/columns.tsx | 190 ++ .../task-ta/components/task-ta-table.tsx | 405 ++++ .../contributor/task-ta/create/page.tsx | 16 + .../contributor/task-ta/detail/[id]/page.tsx | 17 + .../contributor/task-ta/layout.tsx | 9 + .../(protected)/contributor/task-ta/page.tsx | 55 + .../contributor/task-ta/update/[id]/page.tsx | 18 + components/form/task-ta/task-detail-form.tsx | 1811 +++++++++++++++++ components/form/task-ta/task-edit-form.tsx | 1160 +++++++++++ components/form/task-ta/task-ta-form.tsx | 929 +++++++++ lib/menus.ts | 16 +- messages/en.json | 15 +- messages/in.json | 19 +- 15 files changed, 4670 insertions(+), 42 deletions(-) create mode 100644 app/[locale]/(protected)/contributor/task-ta/components/columns.tsx create mode 100644 app/[locale]/(protected)/contributor/task-ta/components/task-ta-table.tsx create mode 100644 app/[locale]/(protected)/contributor/task-ta/create/page.tsx create mode 100644 app/[locale]/(protected)/contributor/task-ta/detail/[id]/page.tsx create mode 100644 app/[locale]/(protected)/contributor/task-ta/layout.tsx create mode 100644 app/[locale]/(protected)/contributor/task-ta/page.tsx create mode 100644 app/[locale]/(protected)/contributor/task-ta/update/[id]/page.tsx create mode 100644 components/form/task-ta/task-detail-form.tsx create mode 100644 components/form/task-ta/task-edit-form.tsx create mode 100644 components/form/task-ta/task-ta-form.tsx diff --git a/app/[locale]/(protected)/admin/add-experts/create/page.tsx b/app/[locale]/(protected)/admin/add-experts/create/page.tsx index f0421ff4..8c908a52 100644 --- a/app/[locale]/(protected)/admin/add-experts/create/page.tsx +++ b/app/[locale]/(protected)/admin/add-experts/create/page.tsx @@ -384,7 +384,7 @@ export default function AddExpertForm() { />
- Penempatan + Posisi {placementRows?.map((row: any) => (
setIsSpecificAttention(!isSpecificAttention)} + hidden + /> + + {t("special-attention")} + + + {t("daily-tasks")} + + +
+
+ + +
+
+ + + + + + +
+ +
+
+
+ + + + + + + + 1 - 10 Data + + + 1 - 50 Data + + + 1 - 100 Data + + + 1 - 250 Data + + + + +
+ + + + + +
+

Filter

+
+
+ + setDateFilter(e.target.value)} + className="max-w-sm" + /> +
+ {/*
+ + +
*/} + +
+ handleStatusCheckboxChange(1)} + /> + +
+
+ handleStatusCheckboxChange(2)} + /> + +
+
+
+
+
+ {/*
+ ) => + table.getColumn("status")?.setFilterValue(event.target.value) + } + className="max-w-sm " + /> +
*/} +
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => ( + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext() + )} + + ))} + + ))} + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender(cell.column.columnDef.cell, cell.getContext())} + + ))} + + )) + ) : ( + + + No results. + + + )} + +
+ + + ); +}; + +export default TaskTaTable; diff --git a/app/[locale]/(protected)/contributor/task-ta/create/page.tsx b/app/[locale]/(protected)/contributor/task-ta/create/page.tsx new file mode 100644 index 00000000..36a2c158 --- /dev/null +++ b/app/[locale]/(protected)/contributor/task-ta/create/page.tsx @@ -0,0 +1,16 @@ +import { Card, CardContent } from "@/components/ui/card"; +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import FormTaskTa from "@/components/form/task-ta/task-ta-form"; + +const TaskTaCreatePage = () => { + return ( +
+ +
+ +
+
+ ); +}; + +export default TaskTaCreatePage; diff --git a/app/[locale]/(protected)/contributor/task-ta/detail/[id]/page.tsx b/app/[locale]/(protected)/contributor/task-ta/detail/[id]/page.tsx new file mode 100644 index 00000000..3802aa3c --- /dev/null +++ b/app/[locale]/(protected)/contributor/task-ta/detail/[id]/page.tsx @@ -0,0 +1,17 @@ +import { Card, CardContent } from "@/components/ui/card"; +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import FormTask from "@/components/form/task/task-form"; +import FormTaskDetail from "@/components/form/task/task-detail-form"; + +const TaskTaDetailPage = async () => { + return ( +
+ +
+ +
+
+ ); +}; + +export default TaskTaDetailPage; diff --git a/app/[locale]/(protected)/contributor/task-ta/layout.tsx b/app/[locale]/(protected)/contributor/task-ta/layout.tsx new file mode 100644 index 00000000..56d3004f --- /dev/null +++ b/app/[locale]/(protected)/contributor/task-ta/layout.tsx @@ -0,0 +1,9 @@ +export const metadata = { + title: "Task", +}; + +const Layout = ({ children }: { children: React.ReactNode }) => { + return <>{children}; +}; + +export default Layout; diff --git a/app/[locale]/(protected)/contributor/task-ta/page.tsx b/app/[locale]/(protected)/contributor/task-ta/page.tsx new file mode 100644 index 00000000..7873633d --- /dev/null +++ b/app/[locale]/(protected)/contributor/task-ta/page.tsx @@ -0,0 +1,55 @@ +"use client"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import TaskTable from "./components/task-ta-table"; +import { Button } from "@/components/ui/button"; +import { UploadIcon } from "lucide-react"; +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import { Link } from "@/components/navigation"; +import { checkAuthorization, checkLoginSession } from "@/lib/utils"; +import React, { useEffect } from "react"; +import { useTranslations } from "next-intl"; +import TaskTaTable from "./components/task-ta-table"; + +const TaskTaPage = () => { + const t = useTranslations("AnalyticsDashboard"); + useEffect(() => { + function initState() { + checkAuthorization("admin"); // Specify the page, e.g., "admin" or another value + checkLoginSession(); + } + + initState(); + }, []); + + return ( +
+ +
+ + + +
+
+ {t("tabel")} {t("task-ta")} +
+
+ + + +
+
+
+
+ + + +
+
+
+ ); +}; + +export default TaskTaPage; diff --git a/app/[locale]/(protected)/contributor/task-ta/update/[id]/page.tsx b/app/[locale]/(protected)/contributor/task-ta/update/[id]/page.tsx new file mode 100644 index 00000000..8412bec9 --- /dev/null +++ b/app/[locale]/(protected)/contributor/task-ta/update/[id]/page.tsx @@ -0,0 +1,18 @@ +import { Card, CardContent } from "@/components/ui/card"; +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import FormTask from "@/components/form/task/task-form"; +import FormTaskDetail from "@/components/form/task/task-detail-form"; +import FormTaskEdit from "@/components/form/task/task-edit-form"; + +const TaskTaDetailPage = async () => { + return ( +
+ +
+ +
+
+ ); +}; + +export default TaskTaDetailPage; diff --git a/components/form/task-ta/task-detail-form.tsx b/components/form/task-ta/task-detail-form.tsx new file mode 100644 index 00000000..d2b294c2 --- /dev/null +++ b/components/form/task-ta/task-detail-form.tsx @@ -0,0 +1,1811 @@ +"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 { + acceptAssignment, + createAssignmentResponse, + createTask, + deleteAssignmentResponse, + deleteTask, + finishTask, + getAcceptance, + getAcceptanceAssignmentStatus, + getAssignmentResponseList, + getMediaUpload, + getTask, + getUserLevelForAssignments, +} from "@/service/task"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import { + ChevronDown, + ChevronUp, + Dock, + DotSquare, + ImageIcon, + Music, + Search, + TrashIcon, + VideoIcon, +} 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"; +import { successCallback } from "@/config/swal"; +import FileUploader from "../shared/file-uploader"; +import { AudioRecorder } from "react-audio-voice-recorder"; +import Image from "next/image"; +import { Icon } from "@iconify/react/dist/iconify.js"; +import WavesurferPlayer from "@wavesurfer/react"; +import WaveSurfer from "wavesurfer.js"; +import { InputGroup, InputGroupText } from "@/components/ui/input-group"; +import { useTranslations } from "next-intl"; + +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.", + }), +}); + +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; + }; +} + +interface FileWithPreview extends File { + preview: string; +} + +interface UploadResult { + id: number; + title: string; + description: string; + createdAt: string; + creatorGroupLevelName: string; + category: { name: string }; + fileType: { name: string }; + uploadStatus: { name: string }; + creatorName: string; + creatorGroup: string; +} + +interface FileUploaded { + id: number; + url: string; +} + +export default function FormTaskTaDetail() { + 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"); + const userLevelId = ""; + + // State for various form fields + const [taskOutput, setTaskOutput] = useState({ + all: false, + video: false, + audio: false, + image: false, + text: false, + }); + + const t = useTranslations("Form"); + const [uploadResults, setUploadResults] = useState([]); + const [isTableResult, setIsTableResult] = useState(false); + const [isSentResult] = useState(false); + 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 [urlInputs, setUrlInputs] = useState([]); + const [refresh] = useState(false); + const [listDest, setListDest] = useState([]); // Data Polda dan Polres + const [checkedLevels, setCheckedLevels] = useState(new Set()); + 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 [totalPage, setTotalPage] = React.useState(1); + const [dataTable, setDataTable] = React.useState([]); + const [totalData, setTotalData] = React.useState(1); + const [imageFiles, setImageFiles] = useState([]); + const [videoFiles, setVideoFiles] = useState([]); + const [textFiles, setTextFiles] = useState([]); + const [audioFiles, setAudioFiles] = useState([]); + const [isImageUploadFinish, setIsImageUploadFinish] = useState(false); + const [isVideoUploadFinish, setIsVideoUploadFinish] = useState(false); + const [isTextUploadFinish, setIsTextUploadFinish] = useState(false); + const [isAudioUploadFinish, setIsAudioUploadFinish] = useState(false); + const [voiceNoteLink, setVoiceNoteLink] = 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 [audioFile, setAudioFile] = useState(null); + const [isRecording, setIsRecording] = useState(false); + const [timer, setTimer] = useState(120); + const [search, setSearch] = React.useState(""); + + const [wavesurfer, setWavesurfer] = useState(); + const [isPlaying, setIsPlaying] = useState(false); + + const [imageUploadedFiles, setImageUploadedFiles] = useState( + [] + ); + const [selectedImage, setSelectedImage] = useState( + imageUploadedFiles?.[0]?.url || null + ); + const [videoUploadedFiles, setVideoUploadedFiles] = useState( + [] + ); + const [selectedVideo, setSelectedVideo] = useState( + videoUploadedFiles?.[0]?.url || null + ); + const [textUploadedFiles, setTextUploadedFiles] = useState( + [] + ); + const [selectedText, setSelectedText] = useState( + textUploadedFiles?.[0]?.url || null + ); + const [audioUploadedFiles, setAudioUploadedFiles] = useState( + [] + ); + const [selectedAudio, setSelectedAudio] = useState( + audioUploadedFiles?.[0]?.url || null + ); + + const [platformTypeVisible, setPlatformTypeVisible] = useState(false); + const [unitSelection, setUnitSelection] = useState({ + allUnit: false, + mabes: false, + polda: false, + satker: false, + polres: false, + }); + + const { + control, + 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(); + }, []); + + const fetchAllData = async () => { + try { + const response = await getMediaUpload(id, userLevelId); + setUploadResults(response?.data?.data || []); + } catch (error) { + console.error("Error fetching all data:", error); + } + }; + + const fetchFilteredData = async (selectedLevels: any[]) => { + try { + if (selectedLevels.length === 0) { + fetchAllData(); // Jika tidak ada filter, panggil semua data + return; + } + + const levels = selectedLevels.join(","); + const response = await getMediaUpload(id, levels); + setUploadResults(response?.data?.data || []); + } catch (error) { + console.error("Error fetching filtered data:", error); + } + }; + + useEffect(() => { + async function initState() { + if (id) { + const response = await getTask(id); + const details = response?.data?.data; + + setDetail(details); + + // if (details) { + // setUploadResults(details.uploadResults || []); + // } + + if (details?.urls) { + // Extract attachmentUrl from each object in urls + const urls = details.urls.map( + (urlObj: any) => urlObj.attachmentUrl || "" + ); + setUrlInputs(urls); // Save the URLs to state + } + + if (details?.assignedToLevel) { + const levels = new Set( + details.assignedToLevel.split(",").map(Number) + ); + setCheckedLevels(levels); + } + + const attachment = details?.files; + setImageUploadedFiles( + attachment?.filter((file: any) => file.fileTypeId == 1) + ); + setVideoUploadedFiles( + attachment?.filter((file: any) => file.fileTypeId == 2) + ); + setTextUploadedFiles( + attachment?.filter((file: any) => file.fileTypeId == 3) + ); + setAudioUploadedFiles( + attachment?.filter((file: any) => file.fileTypeId == 4) + ); + } + } + initState(); + // fetchFilteredData(); + }, [id, refresh]); + + const handleUrlChange = (index: number, newUrl: string) => { + setUrlInputs((prev: any) => + prev.map((url: any, idx: any) => (idx === index ? newUrl : url)) + ); + }; + + useEffect(() => { + if (detail?.broadcastType) { + setBroadcastType(detail.broadcastType); + } + }, [detail?.broadcastType]); + + useEffect(() => { + if (detail?.fileTypeOutput) { + const outputSet = new Set(detail.fileTypeOutput.split(",").map(Number)); + setTaskOutput({ + all: outputSet.has(1), + video: outputSet.has(2), + audio: outputSet.has(4), + image: outputSet.has(3), + text: outputSet.has(5), + }); + } + }, [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), + satker: outputSet.has(4), + }); + } + }, [detail?.fileTypeOutput]); + + 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); + if (updatedLevels.has(levelId)) { + updatedLevels.delete(levelId); + } else { + updatedLevels.add(levelId); + } + return updatedLevels; + }); + }; + + const handleCheckboxChangeFilter = async (id: number) => { + setCheckedLevels((prev: any) => { + const updatedLevels = new Set(prev); + + if (updatedLevels.has(id)) { + updatedLevels.delete(id); + } else { + updatedLevels.add(id); + } + + console.log("Checked Levels:", Array.from(updatedLevels)); + + fetchFilteredData(Array.from(updatedLevels)); + + 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 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 getDataAcceptance() { + const response = await getAcceptanceAssignmentStatus(id); + setStatusAcceptance(response?.data?.data?.isAccept); + console.log("Status :", response?.data?.data?.isAccept); + } + + const handleAcceptAcceptance = async () => { + const isAccept = true; + loading(); + console.log("Id user :", userId); + const response = await acceptAssignment(id, !isAccept); + + if (response?.error) { + error(response?.message); + return false; + } + + 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(): 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); + }; + + 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(); + } + }); + } + + const addAudioElement = (blob: Blob) => { + const url = URL.createObjectURL(blob); + const audio = document.createElement("audio"); + audio.src = url; + audio.controls = true; + document.body.appendChild(audio); + + // Convert Blob to File + const file = new File([blob], "voiceNote.webm", { type: "audio/webm" }); + setAudioFile(file); + }; + const handleDeleteAudio = () => { + // Remove the audio file by setting state to null + setAudioFile(null); + const audioElements = document.querySelectorAll("audio"); + audioElements.forEach((audio) => audio.remove()); + }; + + const onRecordingStart = () => { + setIsRecording(true); + + const countdown = setInterval(() => { + setTimer((prevTimer) => { + if (prevTimer <= 1) { + clearInterval(countdown); + return 0; + } + return prevTimer - 1; + }); + }, 1000); + + setTimeout(() => { + if (isRecording) { + handleStopRecording(); + } + }, 120000); + }; + + const handleStopRecording = () => { + setIsRecording(false); + setTimer(120); // Reset the timer to 2 minutes for the next recording + }; + + const renderFilePreview = (url: string) => { + return ( + {"file + ); + }; + + const onReady = (ws: any) => { + setWavesurfer(ws); + setIsPlaying(false); + }; + + const onPlayPause = () => { + wavesurfer && wavesurfer.playPause(); + }; + + const handleRemoveFile = (id: number) => {}; + + const handleSearch = (e: React.ChangeEvent) => { + setSearch(e.target.value); // Perbarui state search + // getColumn("judul")?.setFilterValue(e.target.value); // Set filter tabel + }; + + return ( + + {detail !== undefined ? ( +
+
+

{t("detail-task")}

+
+
+ + + + + + + + + + + + + {t("assignment-status-details")} + + + + {modalType === "terkirim" && getModalContent("terkirim")} + {modalType === "diterima" && getModalContent("diterima")} + + +
+
+
+ +
+
+
+ + ( + + )} + /> +
+
+ + ( + + )} + /> + {errors.title?.message && ( +

{errors.title.message}

+ )} +
+
+
+ + +
+
+ {Object.keys(unitSelection).map((key) => ( +
+ + setUnitSelection({ ...unitSelection, [key]: value }) + } + /> + +
+ ))} +
+
+ + + + + + + + Daftar Wilayah Polda dan Polres + + +
+ {listDest.map((polda: any) => ( +
+ + {expandedPolda[polda.id] && ( +
+ + {polda?.subDestination?.map((polres: any) => ( + + ))} +
+ )} +
+ ))} +
+
+
+
+
+
+ + setMainType(value)} + // value={String(mainType)} + // onValueChange={(value) => setMainType(Number(value))} + className="flex flex-wrap gap-3" + > + + + + + +
+
+ + setTaskType(String(value))} + className="flex flex-wrap gap-3" + > + + + + + +
+ {/* RadioGroup Assignment Category */} +
+ + setType(value)} + className="flex flex-wrap gap-3" + > +
+ + +
+
+ + +
+
+ + +
+
+
+
+ +
+ {Object.keys(taskOutput).map((key) => ( +
+ + setTaskOutput({ ...taskOutput, [key]: value }) + } + /> + +
+ ))} +
+
+ +
+ + ( + + )} + /> + {/* {errors.naration?.message && ( +

+ {errors.naration.message} +

+ )} */} +
+
+ +
+
+ {videoUploadedFiles?.length > 0 && ( + + )} +
+ {selectedVideo && ( + + + )} + + {videoUploadedFiles?.map((file: any, index: number) => ( +
+
setSelectedVideo(file.url)} + > +
+ +
+
+
+ {file.fileName} +
+
+
+ + +
+ ))} +
+
+
+ {imageUploadedFiles?.length > 0 && ( + + )} +
+ {selectedImage && ( + + Thumbnail Gambar Utama + + )} + + {imageUploadedFiles?.map((file: any, index: number) => ( +
+
setSelectedImage(file.url)} + > +
+ +
+
+
+ {file.fileName} +
+
+
+ + +
+ ))} +
+
+
+ {textUploadedFiles?.length > 0 && ( + + )} +
+ {selectedText && ( + +