fixing
This commit is contained in:
parent
978c8b364f
commit
968f2642cc
|
|
@ -2,34 +2,19 @@ import React, { useRef, useState, useEffect } from "react";
|
||||||
|
|
||||||
interface AudioPlayerProps {
|
interface AudioPlayerProps {
|
||||||
urlAudio: string;
|
urlAudio: string;
|
||||||
fileName: string; // ✅ Tambahkan props ini
|
fileName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const AudioPlayer: React.FC<AudioPlayerProps> = ({ urlAudio, fileName }) => {
|
const AudioPlayer: React.FC<AudioPlayerProps> = ({ urlAudio, fileName }) => {
|
||||||
const audioRef = useRef<HTMLAudioElement>(null);
|
const audioRef = useRef<HTMLAudioElement>(null);
|
||||||
const [currentTime, setCurrentTime] = useState(0);
|
const [currentTime, setCurrentTime] = useState(0);
|
||||||
|
|
||||||
const playAudio = () => {
|
|
||||||
audioRef.current?.play();
|
|
||||||
};
|
|
||||||
|
|
||||||
const pauseAudio = () => {
|
|
||||||
audioRef.current?.pause();
|
|
||||||
};
|
|
||||||
|
|
||||||
const stopAudio = () => {
|
|
||||||
if (audioRef.current) {
|
|
||||||
audioRef.current.pause();
|
|
||||||
audioRef.current.currentTime = 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const audio = audioRef.current;
|
const audio = audioRef.current;
|
||||||
if (!audio) return;
|
if (!audio) return;
|
||||||
|
|
||||||
const updateTime = () => {
|
const updateTime = () => {
|
||||||
setCurrentTime(audio.currentTime);
|
setCurrentTime(audio?.currentTime);
|
||||||
};
|
};
|
||||||
|
|
||||||
audio.addEventListener("timeupdate", updateTime);
|
audio.addEventListener("timeupdate", updateTime);
|
||||||
|
|
@ -38,22 +23,17 @@ const AudioPlayer: React.FC<AudioPlayerProps> = ({ urlAudio, fileName }) => {
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const formatTime = (time: number) => {
|
|
||||||
const minutes = Math.floor(time / 60);
|
|
||||||
const seconds = Math.floor(time % 60).toString().padStart(2, "0");
|
|
||||||
return `${minutes}:${seconds}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mt-2">
|
<div className="mt-2">
|
||||||
<h2 className="text-lg font-semibold">{fileName}</h2>
|
<h2 className="text-lg font-semibold">{fileName}</h2>
|
||||||
|
{/* <a href={urlAudio} target="_blank">{urlAudio}</a> */}
|
||||||
<audio ref={audioRef} src={urlAudio} controls className="mt-1 w-full" />
|
<audio ref={audioRef} src={urlAudio} controls className="mt-1 w-full" />
|
||||||
<div className="mt-2 space-x-2">
|
{/* <div className="mt-2 space-x-2">
|
||||||
<button onClick={playAudio}>▶️ Play</button>
|
<button onClick={playAudio}>▶️ Play</button>
|
||||||
<button onClick={pauseAudio}>⏸️ Pause</button>
|
<button onClick={pauseAudio}>⏸️ Pause</button>
|
||||||
<button onClick={stopAudio}>⏹️ Stop</button>
|
<button onClick={stopAudio}>⏹️ Stop</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-1 text-sm text-gray-500">{formatTime(currentTime)}</div>
|
<div className="mt-1 text-sm text-gray-500">{formatTime(currentTime)}</div> */}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ type Category = {
|
||||||
|
|
||||||
type FileType = {
|
type FileType = {
|
||||||
id: number;
|
id: number;
|
||||||
url: string;
|
secondaryUrl: string;
|
||||||
thumbnailFileUrl: string;
|
thumbnailFileUrl: string;
|
||||||
fileName: string;
|
fileName: string;
|
||||||
};
|
};
|
||||||
|
|
@ -121,13 +121,11 @@ export default function FormAudioDetail() {
|
||||||
const userId = getCookiesDecrypt("uie");
|
const userId = getCookiesDecrypt("uie");
|
||||||
const userLevelId = getCookiesDecrypt("ulie");
|
const userLevelId = getCookiesDecrypt("ulie");
|
||||||
const roleId = getCookiesDecrypt("urie");
|
const roleId = getCookiesDecrypt("urie");
|
||||||
|
|
||||||
const [modalOpen, setModalOpen] = useState(false);
|
const [modalOpen, setModalOpen] = useState(false);
|
||||||
const { id } = useParams() as { id: string };
|
const { id } = useParams() as { id: string };
|
||||||
console.log(id);
|
console.log(id);
|
||||||
const editor = useRef(null);
|
const editor = useRef(null);
|
||||||
type ImageSchema = z.infer<typeof imageSchema>;
|
type ImageSchema = z.infer<typeof imageSchema>;
|
||||||
|
|
||||||
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
|
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
|
||||||
const taskId = Cookies.get("taskId");
|
const taskId = Cookies.get("taskId");
|
||||||
const scheduleId = Cookies.get("scheduleId");
|
const scheduleId = Cookies.get("scheduleId");
|
||||||
|
|
@ -249,7 +247,7 @@ export default function FormAudioDetail() {
|
||||||
|
|
||||||
if (findCategory) {
|
if (findCategory) {
|
||||||
// setValue("categoryId", findCategory.id);
|
// setValue("categoryId", findCategory.id);
|
||||||
setSelectedCategory(findCategory.id); // Set the selected category
|
setSelectedCategory(findCategory.id);
|
||||||
const response = await getTagsBySubCategoryId(findCategory.id);
|
const response = await getTagsBySubCategoryId(findCategory.id);
|
||||||
setTags(response?.data?.data);
|
setTags(response?.data?.data);
|
||||||
}
|
}
|
||||||
|
|
@ -274,6 +272,8 @@ export default function FormAudioDetail() {
|
||||||
const details = response?.data?.data;
|
const details = response?.data?.data;
|
||||||
console.log("detail", details);
|
console.log("detail", details);
|
||||||
setFiles(details?.files);
|
setFiles(details?.files);
|
||||||
|
console.log("ISI FILES:", details?.files);
|
||||||
|
|
||||||
setDetail(details);
|
setDetail(details);
|
||||||
setMain({
|
setMain({
|
||||||
type: details?.fileType.name,
|
type: details?.fileType.name,
|
||||||
|
|
@ -293,19 +293,23 @@ export default function FormAudioDetail() {
|
||||||
setSelectedTarget(String(details.category.id));
|
setSelectedTarget(String(details.category.id));
|
||||||
|
|
||||||
const filesData = details?.files || [];
|
const filesData = details?.files || [];
|
||||||
const audioFiles = filesData.filter(
|
// const audioFiles = filesData.filter(
|
||||||
(file: any) =>
|
// (file: any) =>
|
||||||
file.contentType &&
|
// file.contentType &&
|
||||||
(file.contentType.startsWith("audio/") ||
|
// (file.contentType.startsWith("audio/") ||
|
||||||
file.contentType.includes("mpeg"))
|
// file.contentType.includes("mpeg"))
|
||||||
);
|
// );
|
||||||
|
// const audioFiles = filesData.filter(
|
||||||
|
// (file: any) =>
|
||||||
|
// file.contentType && /^audio\/(mpeg|mp3|wav)$/.test(file.contentType)
|
||||||
|
// );
|
||||||
|
|
||||||
const fileUrls = audioFiles.map((file: { url: string }) =>
|
// const fileUrls = audioFiles.map((file: { secondaryUrl: string }) =>
|
||||||
file.url ? file.url : ""
|
// file.secondaryUrl ? file.secondaryUrl : ""
|
||||||
);
|
// );
|
||||||
console.log("Audio file URLs:", fileUrls);
|
// console.log("Audio file URLs:", fileUrls);
|
||||||
|
|
||||||
setDetailThumb(fileUrls);
|
// setDetailThumb(fileUrls);
|
||||||
|
|
||||||
const approvals = await getDataApprovalByMediaUpload(details?.id);
|
const approvals = await getDataApprovalByMediaUpload(details?.id);
|
||||||
setApproval(approvals?.data?.data);
|
setApproval(approvals?.data?.data);
|
||||||
|
|
@ -570,17 +574,19 @@ export default function FormAudioDetail() {
|
||||||
{t("file-media", { defaultValue: "File Media" })}
|
{t("file-media", { defaultValue: "File Media" })}
|
||||||
</Label>
|
</Label>
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
{detailThumb.map((url, index) => (
|
{files.length === 0 ? (
|
||||||
<div key={index}>
|
<p className="text-center text-gray-500">
|
||||||
{files.map((file, index) => (
|
Tidak ada file media
|
||||||
<AudioPlayer
|
</p>
|
||||||
key={index}
|
) : (
|
||||||
urlAudio={file.url}
|
files.map((file, index) => (
|
||||||
fileName={file.fileName}
|
<AudioPlayer
|
||||||
/>
|
key={index}
|
||||||
))}
|
urlAudio={file?.secondaryUrl}
|
||||||
</div>
|
fileName={file?.fileName}
|
||||||
))}
|
/>
|
||||||
|
))
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -211,9 +211,6 @@ export default function FormAudio() {
|
||||||
tags: z
|
tags: z
|
||||||
.array(z.string().min(1))
|
.array(z.string().min(1))
|
||||||
.min(1, { message: "Wajib isi minimal 1 tag" }),
|
.min(1, { message: "Wajib isi minimal 1 tag" }),
|
||||||
publishedFor: z
|
|
||||||
.array(z.string())
|
|
||||||
.min(1, { message: "Minimal 1 target publish harus dipilih." }),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
|
@ -230,7 +227,6 @@ export default function FormAudio() {
|
||||||
rewriteDescription: "",
|
rewriteDescription: "",
|
||||||
category: "",
|
category: "",
|
||||||
tags: [],
|
tags: [],
|
||||||
publishedFor: [],
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -483,8 +479,10 @@ export default function FormAudio() {
|
||||||
const handleCheckboxChange = (id: string): void => {
|
const handleCheckboxChange = (id: string): void => {
|
||||||
if (id === "all") {
|
if (id === "all") {
|
||||||
if (publishedFor.includes("all")) {
|
if (publishedFor.includes("all")) {
|
||||||
|
// Uncheck all checkboxes
|
||||||
setPublishedFor([]);
|
setPublishedFor([]);
|
||||||
} else {
|
} else {
|
||||||
|
// Select all checkboxes
|
||||||
setPublishedFor(
|
setPublishedFor(
|
||||||
options
|
options
|
||||||
.filter((opt: any) => opt.id !== "all")
|
.filter((opt: any) => opt.id !== "all")
|
||||||
|
|
@ -495,6 +493,8 @@ export default function FormAudio() {
|
||||||
const updatedPublishedFor = publishedFor.includes(id)
|
const updatedPublishedFor = publishedFor.includes(id)
|
||||||
? publishedFor.filter((item) => item !== id)
|
? publishedFor.filter((item) => item !== id)
|
||||||
: [...publishedFor, id];
|
: [...publishedFor, id];
|
||||||
|
|
||||||
|
// Remove "all" if any checkbox is unchecked
|
||||||
if (publishedFor.includes("all") && id !== "all") {
|
if (publishedFor.includes("all") && id !== "all") {
|
||||||
setPublishedFor(updatedPublishedFor.filter((item) => item !== "all"));
|
setPublishedFor(updatedPublishedFor.filter((item) => item !== "all"));
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -505,6 +505,7 @@ export default function FormAudio() {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (articleBody) {
|
if (articleBody) {
|
||||||
|
// Set ke dua field jika rewrite juga aktif
|
||||||
setValue("description", articleBody);
|
setValue("description", articleBody);
|
||||||
setValue("rewriteDescription", articleBody);
|
setValue("rewriteDescription", articleBody);
|
||||||
}
|
}
|
||||||
|
|
@ -512,21 +513,13 @@ export default function FormAudio() {
|
||||||
|
|
||||||
const save = async (data: AudioSchema) => {
|
const save = async (data: AudioSchema) => {
|
||||||
loading();
|
loading();
|
||||||
|
|
||||||
if (files.length === 0) {
|
|
||||||
MySwal.fire("Error", "Minimal 1 file harus diunggah.", "error");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const finalTags = tags.join(", ");
|
const finalTags = tags.join(", ");
|
||||||
const finalTitle = isSwitchOn ? title : data.title;
|
const finalTitle = isSwitchOn ? title : data.title;
|
||||||
// const finalDescription = articleBody || data.description;
|
|
||||||
const finalDescription = isSwitchOn
|
const finalDescription = isSwitchOn
|
||||||
? data.description
|
? data.description
|
||||||
: selectedFileType === "rewrite"
|
: selectedFileType === "rewrite"
|
||||||
? data.rewriteDescription
|
? data.rewriteDescription
|
||||||
: data.descriptionOri;
|
: data.descriptionOri;
|
||||||
|
|
||||||
if (!finalDescription?.trim()) {
|
if (!finalDescription?.trim()) {
|
||||||
MySwal.fire("Error", "Deskripsi tidak boleh kosong.", "error");
|
MySwal.fire("Error", "Deskripsi tidak boleh kosong.", "error");
|
||||||
return;
|
return;
|
||||||
|
|
@ -574,36 +567,40 @@ export default function FormAudio() {
|
||||||
const response = await createMedia(requestData);
|
const response = await createMedia(requestData);
|
||||||
console.log("Form Data Submitted:", requestData);
|
console.log("Form Data Submitted:", requestData);
|
||||||
|
|
||||||
|
if (response?.error) {
|
||||||
|
MySwal.fire("Error", response?.message, "error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
Cookies.set("idCreate", response?.data?.data, { expires: 1 });
|
Cookies.set("idCreate", response?.data?.data, { expires: 1 });
|
||||||
id = response?.data?.data;
|
id = response?.data?.data;
|
||||||
|
|
||||||
const formMedia = new FormData();
|
const formMedia = new FormData();
|
||||||
const thumbnail = files[0];
|
console.log("Thumbnail : ", files[0]);
|
||||||
formMedia.append("file", thumbnail);
|
formMedia.append("file", files[0]);
|
||||||
const responseThumbnail = await uploadThumbnail(id, formMedia);
|
const responseThumbnail = await uploadThumbnail(id, formMedia);
|
||||||
if (responseThumbnail?.error == true) {
|
if (responseThumbnail?.error == true) {
|
||||||
error(responseThumbnail?.message);
|
error(responseThumbnail?.message);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const progressInfoArr = files.map((item) => ({
|
|
||||||
percentage: 0,
|
const progressInfoArr = [];
|
||||||
fileName: item.name,
|
for (const item of files) {
|
||||||
}));
|
progressInfoArr.push({ percentage: 0, fileName: item.name });
|
||||||
|
}
|
||||||
progressInfo = progressInfoArr;
|
progressInfo = progressInfoArr;
|
||||||
setIsStartUpload(true);
|
setIsStartUpload(true);
|
||||||
setProgressList(progressInfoArr);
|
setProgressList(progressInfoArr);
|
||||||
|
|
||||||
close();
|
close();
|
||||||
|
// showProgress();
|
||||||
files.map(async (item: any, index: number) => {
|
files.map(async (item: any, index: number) => {
|
||||||
await uploadResumableFile(
|
await uploadResumableFile(index, String(id), item, "0");
|
||||||
index,
|
|
||||||
String(id),
|
|
||||||
item,
|
|
||||||
fileTypeId == "2" || fileTypeId == "4" ? item.duration : "0"
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Cookies.remove("idCreate");
|
Cookies.remove("idCreate");
|
||||||
|
|
||||||
|
// MySwal.fire("Sukses", "Data berhasil disimpan.", "success");
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSubmit = (data: AudioSchema) => {
|
const onSubmit = (data: AudioSchema) => {
|
||||||
|
|
@ -1416,73 +1413,29 @@ export default function FormAudio() {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Controller
|
<div className="px-3 py-3">
|
||||||
control={control}
|
<div className="flex flex-col gap-3 space-y-2">
|
||||||
name="publishedFor"
|
<Label>
|
||||||
render={({ field }) => (
|
{t("publish-target", { defaultValue: "Publish Target" })}
|
||||||
<div className="px-3 py-3">
|
</Label>
|
||||||
<div className="flex flex-col gap-3 space-y-2">
|
{options.map((option) => (
|
||||||
<Label>
|
<div key={option.id} className="flex gap-2 items-center">
|
||||||
{t("publish-target", { defaultValue: "Publish Target" })}
|
<Checkbox
|
||||||
</Label>
|
id={option.id}
|
||||||
|
checked={
|
||||||
{options.map((option) => {
|
|
||||||
const isAllChecked =
|
|
||||||
field.value.length ===
|
|
||||||
options.filter((opt: any) => opt.id !== "all").length;
|
|
||||||
|
|
||||||
const isChecked =
|
|
||||||
option.id === "all"
|
option.id === "all"
|
||||||
? isAllChecked
|
? publishedFor.length ===
|
||||||
: field.value.includes(option.id);
|
options.filter((opt: any) => opt.id !== "all")
|
||||||
|
.length
|
||||||
const handleChange = () => {
|
: publishedFor.includes(option.id)
|
||||||
let updated: string[] = [];
|
}
|
||||||
|
onCheckedChange={() => handleCheckboxChange(option.id)}
|
||||||
if (option.id === "all") {
|
/>
|
||||||
updated = isAllChecked
|
<Label htmlFor={option.id}>{option.label}</Label>
|
||||||
? []
|
|
||||||
: options
|
|
||||||
.filter((opt: any) => opt.id !== "all")
|
|
||||||
.map((opt: any) => opt.id);
|
|
||||||
} else {
|
|
||||||
updated = isChecked
|
|
||||||
? field.value.filter((val) => val !== option.id)
|
|
||||||
: [...field.value, option.id];
|
|
||||||
|
|
||||||
if (isAllChecked && option.id !== "all") {
|
|
||||||
updated = updated.filter((val) => val !== "all");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
field.onChange(updated);
|
|
||||||
setPublishedFor(updated);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={option.id}
|
|
||||||
className="flex gap-2 items-center"
|
|
||||||
>
|
|
||||||
<Checkbox
|
|
||||||
id={option.id}
|
|
||||||
checked={isChecked}
|
|
||||||
onCheckedChange={handleChange}
|
|
||||||
/>
|
|
||||||
<Label htmlFor={option.id}>{option.label}</Label>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
|
|
||||||
{errors.publishedFor && (
|
|
||||||
<p className="text-red-500 text-sm">
|
|
||||||
{errors.publishedFor.message}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
))}
|
||||||
)}
|
</div>
|
||||||
/>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
<div className="flex flex-row justify-end gap-3">
|
<div className="flex flex-row justify-end gap-3">
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
|
|
|
||||||
|
|
@ -99,9 +99,7 @@ const DetailAudio = () => {
|
||||||
|
|
||||||
const initFetch = async () => {
|
const initFetch = async () => {
|
||||||
const response = await getDetail(String(slug));
|
const response = await getDetail(String(slug));
|
||||||
console.log("detailAudio", response);
|
|
||||||
const responseGet = await getPublicSuggestionList(slug?.split("-")?.[0]);
|
const responseGet = await getPublicSuggestionList(slug?.split("-")?.[0]);
|
||||||
|
|
||||||
setIsFromSPIT(response?.data?.data?.isFromSPIT);
|
setIsFromSPIT(response?.data?.data?.isFromSPIT);
|
||||||
setWidth(window.innerWidth);
|
setWidth(window.innerWidth);
|
||||||
setContent(response?.data?.data);
|
setContent(response?.data?.data);
|
||||||
|
|
@ -405,7 +403,7 @@ const DetailAudio = () => {
|
||||||
const { default: WaveSurfer } = await import("wavesurfer.js");
|
const { default: WaveSurfer } = await import("wavesurfer.js");
|
||||||
|
|
||||||
if (wavesurfer.current) {
|
if (wavesurfer.current) {
|
||||||
wavesurfer.current.destroy(); // 🔥 Hapus instance lama sebelum membuat yang baru
|
wavesurfer.current.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
setPlaying(false);
|
setPlaying(false);
|
||||||
|
|
@ -414,7 +412,7 @@ const DetailAudio = () => {
|
||||||
return [
|
return [
|
||||||
Math.floor((time % 3600) / 60),
|
Math.floor((time % 3600) / 60),
|
||||||
// minutes
|
// minutes
|
||||||
`00${Math.floor(time % 60)}`.slice(-2), // seconds
|
`00${Math.floor(time % 60)}`.slice(-2),
|
||||||
].join(":");
|
].join(":");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -445,7 +443,7 @@ const DetailAudio = () => {
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (wavesurfer.current) {
|
if (wavesurfer.current) {
|
||||||
wavesurfer.current.destroy(); // 🔥 Hapus saat unmount
|
wavesurfer.current.destroy();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue