diff --git a/app/[locale]/(protected)/contributor/agenda-setting/event-modal.tsx b/app/[locale]/(protected)/contributor/agenda-setting/event-modal.tsx index 05846ec0..168b9e3f 100644 --- a/app/[locale]/(protected)/contributor/agenda-setting/event-modal.tsx +++ b/app/[locale]/(protected)/contributor/agenda-setting/event-modal.tsx @@ -21,7 +21,13 @@ import { import { Calendar } from "@/components/ui/calendar"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; -import { Loader2, CalendarIcon, ChevronUp, ChevronDown } from "lucide-react"; +import { + Loader2, + CalendarIcon, + ChevronUp, + ChevronDown, + Music, +} from "lucide-react"; import DeleteConfirmationDialog from "@/components/delete-confirmation-dialog"; import { CalendarCategory } from "./data"; import { @@ -338,11 +344,17 @@ const EventModal = ({ await uploadResumableFile(index, String(id), item, "3", "0"); }); - if (audioFiles?.length === 0) { + if (audioFiles?.length == 0) { setIsAudioUploadFinish(true); } - audioFiles?.map(async (item: any, index: number) => { - await uploadResumableFile(index, String(id), item, "4", "0"); + audioFiles.map(async (item: FileWithPreview, index: number) => { + await uploadResumableFile( + index, + String(id), + item, // Use .file to access the actual File object + "4", + "0" // Optional: Replace with actual duration if available + ); }); }; @@ -429,9 +441,15 @@ const EventModal = ({ audio.controls = true; document.body.appendChild(audio); - // Convert Blob to File - const file = new File([blob], "voiceNote.webm", { type: "audio/webm" }); - setAudioFile(file); + // Convert Blob to File and add preview + const fileWithPreview: FileWithPreview = Object.assign( + new File([blob], "voiceNote.webm", { type: "audio/webm" }), + { preview: url } + ); + + // Add to state + setAudioFile(fileWithPreview); + setAudioFiles((prev) => [...prev, fileWithPreview]); }; const handleDeleteAudio = () => { @@ -993,8 +1011,7 @@ const EventModal = ({ ))}
- - + setAudioFiles(files)} + onDrop={(files) => + setAudioFiles((prev) => [...prev, ...files]) + } className="mt-2" /> {audioUploadedFiles?.map((file: any, index: number) => ( @@ -1054,7 +1073,7 @@ const EventModal = ({ >
- {renderFilePreview(file.url)} +
@@ -1078,7 +1097,10 @@ const EventModal = ({
{audioFile && (
-

Voice note ready to submit: {audioFile.name}

+
+ {" "} +

Voice Note

+
- +
+ + + +
- +
+ + + +
- +
+ + + +
- +
+ + +
diff --git a/components/form/content/spit-convert-form.tsx b/components/form/content/spit-convert-form.tsx index 0d89a2f0..f7898f04 100644 --- a/components/form/content/spit-convert-form.tsx +++ b/components/form/content/spit-convert-form.tsx @@ -96,6 +96,13 @@ interface PlacementData { placements: string; } +type FileType = { + contentId: number; + contentFile: string; + thumbnailFileUrl: string; + fileName: string; +}; + const CustomEditor = dynamic( () => { return import("@/components/editor/custom-editor"); @@ -122,7 +129,7 @@ export default function FormConvertSPIT() { null ); const [tags, setTags] = useState([]); - const [detail, setDetail] = useState(); + const [detail, setDetail] = useState(); const [refresh, setRefresh] = useState(false); const [selectedPublishers, setSelectedPublishers] = useState([]); const [detailThumb, setDetailThumb] = useState([]); @@ -150,7 +157,9 @@ export default function FormConvertSPIT() { polres: false, }); const [publishedFor, setPublishedFor] = useState([]); - const [placementLength, setPlacementLength] = useState([]); + const [filePlacements, setFilePlacements] = useState([]); + const [isUserMabesApprover, setIsUserMabesApprover] = useState(false); + const [files, setFiles] = useState([]); const options: Option[] = [ { id: "all", label: "SEMUA" }, @@ -201,6 +210,17 @@ export default function FormConvertSPIT() { initState(); }, []); + useEffect(() => { + if ( + userLevelId != undefined && + roleId != undefined && + userLevelId == "216" && + roleId == "3" + ) { + setIsUserMabesApprover(true); + } + }, [userLevelId, roleId]); + useEffect(() => { if ( userLevelId != undefined && @@ -237,6 +257,47 @@ export default function FormConvertSPIT() { } }; + const setupPlacement = ( + index: number, + placement: string, + checked: boolean + ) => { + let temp = [...filePlacements]; + if (checked) { + if (placement === "all") { + temp[index] = ["all", "mabes", "polda", "international"]; + } else { + const now = temp[index]; + now.push(placement); + if (now.length === 3 && !now.includes("all")) { + now.push("all"); + } + temp[index] = now; + } + } else { + if (placement === "all") { + 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")) { + const newData = now.filter((b) => b !== "all"); + temp[index] = newData; + } + } + } + setFilePlacements(temp); + }; + + const setupPlacementCheck = (length: number) => { + const temp = []; + for (let i = 0; i < length; i++) { + temp.push([]); + } + setFilePlacements(temp); + }; + useEffect(() => { async function initState() { if (id) { @@ -244,6 +305,8 @@ export default function FormConvertSPIT() { const details = response?.data?.data; setDetail(details); + setFiles(details?.contentList); + setupPlacementCheck(details?.contentList?.length); const filesData = details.contentList || []; const fileUrls = filesData.map((file: { contentFile: string }) => @@ -272,49 +335,6 @@ export default function FormConvertSPIT() { })) ); - 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 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) => { @@ -359,12 +379,32 @@ export default function FormConvertSPIT() { } }; + const getPlacement = () => { + 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].contentId, + placement: now.join(","), + }; + temp.push(data); + } + } + return temp; + }; + const save = async (data: { contentTitle: string; contentDescription: string; contentRewriteDescription: string; contentCreator: string; }): Promise => { + const temp = []; + for (const element of detail.contentList) { + temp.push([]); + } const description = selectedFileType === "original" ? data.contentDescription @@ -376,15 +416,16 @@ export default function FormConvertSPIT() { description, htmlDescription: description, tags: "siap", - categoryId: selectedCategoryId, + categoryId: 1, publishedFor: publishedFor.join(","), creator: data.contentCreator, - files: getPlacement(), // Include placement data + files: isUserMabesApprover ? getPlacement() : [], // Include placement data }; const response = await convertSPIT(requestData); console.log("Form Data Submitted:", response); - + setFilePlacements(temp); + setFiles(detail.files); MySwal.fire({ title: "Sukses", text: "Data berhasil disimpan.", @@ -699,62 +740,96 @@ export default function FormConvertSPIT() {
- {isMabesApprover ? ( -
- - {detailThumb.map((data: any) => ( -
- {`Thumbnail -
- {[ - "all", - "mabes", - "polda", - "satker", - "internasional", - ].map((value) => ( - - ))} + {files?.map((file, index) => ( +
+ +
+ + +
+
+ + setupPlacement(index, "all", Boolean(e)) + } + /> + +
+
+ + setupPlacement(index, "mabes", Boolean(e)) + } + /> + +
+
+ + setupPlacement(index, "polda", Boolean(e)) + } + /> + +
+ +
+ + setupPlacement(index, "international", Boolean(e)) + } + /> +
- ))} +
- ) : ( - "" - )} + ))}
@@ -797,14 +872,16 @@ export default function FormConvertSPIT() {
- {detail?.contentTag?.split(",").map((tag, index) => ( - - {tag.trim()} - - ))} + {detail?.contentTag + ?.split(",") + .map((tag: any, index: any) => ( + + {tag.trim()} + + ))}
diff --git a/components/form/task/task-detail-form.tsx b/components/form/task/task-detail-form.tsx index 768b1c00..8dfab668 100644 --- a/components/form/task/task-detail-form.tsx +++ b/components/form/task/task-detail-form.tsx @@ -40,7 +40,16 @@ import { DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; -import { ChevronDown, ChevronUp, DotSquare, TrashIcon } from "lucide-react"; +import { + ChevronDown, + ChevronUp, + Dock, + DotSquare, + ImageIcon, + Music, + TrashIcon, + VideoIcon, +} from "lucide-react"; import dynamic from "next/dynamic"; import { Link } from "@/components/navigation"; import { Textarea } from "@/components/ui/textarea"; @@ -1064,7 +1073,7 @@ export default function FormTaskDetail() { onClick={() => setSelectedVideo(file.url)} >
- {renderFilePreview(file.url)} +
@@ -1109,7 +1118,7 @@ export default function FormTaskDetail() { onClick={() => setSelectedImage(file.url)} >
- {renderFilePreview(file.url)} +
@@ -1157,7 +1166,7 @@ export default function FormTaskDetail() { onClick={() => setSelectedText(file.url)} >
- {renderFilePreview(file.url)} +
@@ -1228,7 +1237,7 @@ export default function FormTaskDetail() { onClick={() => setSelectedAudio(file.url)} >
- {renderFilePreview(file.url)} +
diff --git a/components/form/task/task-edit-form.tsx b/components/form/task/task-edit-form.tsx index d8eca6ad..a765b190 100644 --- a/components/form/task/task-edit-form.tsx +++ b/components/form/task/task-edit-form.tsx @@ -32,7 +32,14 @@ import { DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; -import { ChevronDown, ChevronUp } from "lucide-react"; +import { + ChevronDown, + ChevronUp, + Dock, + ImageIcon, + Music, + VideoIcon, +} from "lucide-react"; import FileUploader from "../shared/file-uploader"; import { AudioRecorder } from "react-audio-voice-recorder"; import Image from "next/image"; @@ -376,8 +383,14 @@ export default function FormTaskEdit() { if (audioFiles?.length == 0) { setIsAudioUploadFinish(true); } - audioFiles?.map(async (item: any, index: number) => { - await uploadResumableFile(index, String(id), item, "4", "0"); + audioFiles.map(async (item: FileWithPreview, index: number) => { + await uploadResumableFile( + index, + String(id), + item, // Use .file to access the actual File object + "4", + "0" // Optional: Replace with actual duration if available + ); }); // MySwal.fire({ @@ -446,10 +459,17 @@ export default function FormTaskEdit() { audio.controls = true; document.body.appendChild(audio); - // Convert Blob to File - const file = new File([blob], "voiceNote.webm", { type: "audio/webm" }); - setAudioFile(file); + // Convert Blob to File and add preview + const fileWithPreview: FileWithPreview = Object.assign( + new File([blob], "voiceNote.webm", { type: "audio/webm" }), + { preview: url } + ); + + // Add to state + setAudioFile(fileWithPreview); + setAudioFiles((prev) => [...prev, fileWithPreview]); }; + const handleDeleteAudio = () => { // Remove the audio file by setting state to null setAudioFile(null); @@ -835,7 +855,7 @@ export default function FormTaskEdit() {
- {videoUploadedFiles?.length > 0 && } + setImageFiles(files)} + onDrop={(files) => setVideoFiles(files)} /> {videoUploadedFiles?.map((file: any, index: number) => (
@@ -853,7 +873,7 @@ export default function FormTaskEdit() { >
- {renderFilePreview(file.url)} +
@@ -876,7 +896,7 @@ export default function FormTaskEdit() { ))}
- {imageUploadedFiles?.length > 0 && } +
- {renderFilePreview(file.url)} +
@@ -916,7 +936,7 @@ export default function FormTaskEdit() { ))}
- {textUploadedFiles?.length > 0 && } +
- {renderFilePreview(file.url)} +
@@ -956,7 +976,7 @@ export default function FormTaskEdit() { ))}
- {audioUploadedFiles?.length > 0 && } + setAudioFiles(files)} + onDrop={(files) => + setAudioFiles((prev) => [...prev, ...files]) + } className="mt-2" /> {audioUploadedFiles?.map((file: any, index: number) => ( @@ -984,7 +1006,7 @@ export default function FormTaskEdit() { >
- {renderFilePreview(file.url)} +
@@ -1008,7 +1030,7 @@ export default function FormTaskEdit() {
{audioFile && (
-

Voice note ready to submit: {audioFile.name}

+

Voice Note

- + setAudioFiles(files)} + onDrop={(files) => + setAudioFiles((prev) => [...prev, ...files]) + } className="mt-2" />
- {audioFile && ( -
-

Voice note ready to submit: {audioFile.name}

+ {audioFiles?.map((audio: any, idx: any) => ( +
+

Voice Note

- )} + ))} {isRecording &&

Recording... {timer} seconds remaining

}{" "} {/* Display remaining time */}