diff --git a/app/[locale]/(protected)/admin/broadcast/campaign-list/account-list/component/table.tsx b/app/[locale]/(protected)/admin/broadcast/campaign-list/account-list/component/table.tsx index b055ddbe..20b53a64 100644 --- a/app/[locale]/(protected)/admin/broadcast/campaign-list/account-list/component/table.tsx +++ b/app/[locale]/(protected)/admin/broadcast/campaign-list/account-list/component/table.tsx @@ -136,12 +136,12 @@ const AccountListTable = () => { Tambah Akun - + {/* - + */}
diff --git a/app/[locale]/(protected)/admin/broadcast/campaign-list/account-list/create/page.tsx b/app/[locale]/(protected)/admin/broadcast/campaign-list/account-list/create/page.tsx index 02c28100..acd503a6 100644 --- a/app/[locale]/(protected)/admin/broadcast/campaign-list/account-list/create/page.tsx +++ b/app/[locale]/(protected)/admin/broadcast/campaign-list/account-list/create/page.tsx @@ -44,7 +44,7 @@ const FormSchema = z.object({ .refine((value) => value.some((item) => item), { message: "Required", }), - accountCategory: z.enum(["polri", "jurnalis", "umumu", "ksp"], { + accountCategory: z.enum(["polri", "jurnalis", "umum", "ksp"], { required_error: "Required", }), email: z.string({ diff --git a/app/[locale]/(protected)/admin/settings/category/component/column.tsx b/app/[locale]/(protected)/admin/settings/category/component/column.tsx index 71813ee8..ec43df57 100644 --- a/app/[locale]/(protected)/admin/settings/category/component/column.tsx +++ b/app/[locale]/(protected)/admin/settings/category/component/column.tsx @@ -124,7 +124,7 @@ const columns: ColumnDef[] = [ onClick={() => categoryDelete(row.original.id)} className="hover:underline cursor-pointer hover:text-destructive" > - Delete + Delete diff --git a/components/audio-player.tsx b/components/audio-player.tsx new file mode 100644 index 00000000..db85a3d5 --- /dev/null +++ b/components/audio-player.tsx @@ -0,0 +1,62 @@ +import React, { useRef, useState, useEffect } from "react"; + +const AudioPlayer = (props: {urlAudio: string}) => { + const audioRef = useRef(null); + const [currentTime, setCurrentTime] = useState(0); + const {urlAudio} = props + + const playAudio = () => { + audioRef.current?.play(); + }; + + const pauseAudio = () => { + audioRef.current?.pause(); + }; + + const stopAudio = () => { + if (audioRef.current) { + audioRef.current.pause(); + audioRef.current.currentTime = 0; + } + }; + + useEffect(() => { + const audio = audioRef.current; + if (!audio) return; + + const updateTime = () => { + setCurrentTime(audio.currentTime); + }; + + audio.addEventListener("timeupdate", updateTime); + + return () => { + audio.removeEventListener("timeupdate", updateTime); + }; + }, []); + + const formatTime = (time: number) => { + const minutes = Math.floor(time / 60); + const seconds = Math.floor(time % 60) + .toString() + .padStart(2, "0"); + return `${minutes}:${seconds}`; + }; + + return ( +
+

Pemutar Audio

+
+ ); +}; + +export default AudioPlayer; diff --git a/components/form/content/audio-detail-form.tsx b/components/form/content/audio-detail-form.tsx index 0a64334d..bfeab8f4 100644 --- a/components/form/content/audio-detail-form.tsx +++ b/components/form/content/audio-detail-form.tsx @@ -64,6 +64,8 @@ import { useTranslations } from "next-intl"; import SuggestionModal from "@/components/modal/suggestions-modal"; import { formatDateToIndonesian } from "@/utils/globals"; import ApprovalHistoryModal from "@/components/modal/approval-history-modal"; +import { useDropzone } from "react-dropzone"; +import AudioPlayer from "@/components/audio-player"; const imageSchema = z.object({ title: z.string().min(1, { message: "Judul diperlukan" }), @@ -139,32 +141,54 @@ export default function FormAudioDetail() { const [selectedPublishers, setSelectedPublishers] = useState([]); const [description, setDescription] = useState(""); 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 [isUserMabesApprover, setIsUserMabesApprover] = useState(false); const [audioPlaying, setAudioPlaying] = useState(null); const [filePlacements, setFilePlacements] = useState([]); + const [files, setFiles] = useState([]); + const [uploadedFiles, setUploadedFiles] = useState([]); + const [detailThumb, setDetailThumb] = useState([]); const waveSurferRef = useRef(null); + const waveSurfersRef = useRef([]); + const [isPlayingIndex, setIsPlayingIndex] = useState(null); const [wavesurfer, setWavesurfer] = useState(); const [isPlaying, setIsPlaying] = useState(false); const [approval, setApproval] = useState(); - const onReady = (ws: any) => { - setWavesurfer(ws); - setIsPlaying(false); + const onDrop = (acceptedFiles: File[]) => { + setUploadedFiles(acceptedFiles); + const blobUrls = acceptedFiles.map((file) => URL.createObjectURL(file)); + setDetailThumb(blobUrls); }; - const onPlayPause = () => { - wavesurfer && wavesurfer.playPause(); + const onReady = (ws: WaveSurfer, index: number) => { + waveSurfersRef.current[index] = ws; }; + const onPlayPause = (index: number) => { + waveSurfersRef.current.forEach((ws, i) => { + if (i === index) { + ws.isPlaying() ? ws.pause() : ws.play(); + setIsPlayingIndex(ws.isPlaying() ? index : null); + } else { + ws.pause(); + } + }); + }; + + const { getRootProps, getInputProps } = useDropzone({ + onDrop, + accept: { + "audio/*": [], + }, + multiple: true, + }); + let fileTypeId = "4"; const { @@ -261,8 +285,8 @@ export default function FormAudioDetail() { }); setupPlacementCheck(details?.files?.length); - if (details.publishedForObject) { - const publisherIds = details.publishedForObject.map( + if (details?.publishedForObject) { + const publisherIds = details?.publishedForObject.map( (obj: any) => obj.id ); setSelectedPublishers(publisherIds); @@ -276,9 +300,9 @@ export default function FormAudioDetail() { setSelectedTarget(matchingCategory.name); } - setSelectedTarget(details.categoryId); // Untuk dropdown + setSelectedTarget(details?.categoryId); - const filesData = details.files || []; + const filesData = details?.files || []; const audioFiles = filesData.filter( (file: any) => file.contentType && file.contentType.startsWith("video/webm") @@ -439,9 +463,9 @@ export default function FormAudioDetail() { const handleAudioPlayPause = (audioSrc: string) => { if (audioPlaying === audioSrc) { - setAudioPlaying(null); // Pause if the same audio is clicked + setAudioPlaying(null); } else { - setAudioPlaying(audioSrc); // Play the new audio + setAudioPlaying(audioSrc); } }; @@ -463,7 +487,9 @@ export default function FormAudioDetail() {
-

{t("form-audio", { defaultValue: "Form Audio" })}

+

+ {t("form-audio", { defaultValue: "Form Audio" })} +

{/* Input Title */}
@@ -491,7 +517,7 @@ export default function FormAudioDetail() {
{ console.log("Selected Category ID:", id); setSelectedCategory(id); @@ -853,7 +868,9 @@ export default function FormAudio() {
- +
- +
- +
- +