feat:upload content, video,teks,audio, fix tags, fix responsif ckeditor spit

This commit is contained in:
Anang Yusman 2025-01-08 03:21:19 +08:00
parent 73fc0ef934
commit d76b224a72
7 changed files with 125 additions and 92 deletions

View File

@ -243,8 +243,8 @@ export default function FormAudioDetail() {
setSelectedTarget(details.categoryId); // Untuk dropdown setSelectedTarget(details.categoryId); // Untuk dropdown
const filesData = details.files || []; const filesData = details.files || [];
const fileUrls = filesData.map((file: { thumbnailFileUrl: string }) => const fileUrls = filesData.map((file: { secondaryUrl: string }) =>
file.thumbnailFileUrl ? file.thumbnailFileUrl : "default-image.jpg" file.secondaryUrl ? file.secondaryUrl : "default-image.jpg"
); );
setDetailThumb(fileUrls); setDetailThumb(fileUrls);
} }
@ -354,7 +354,7 @@ export default function FormAudioDetail() {
<div className="flex lg:flex-row gap-10"> <div className="flex lg:flex-row gap-10">
<Card className="w-full lg:w-8/12"> <Card className="w-full lg:w-8/12">
<div className="px-6 py-6"> <div className="px-6 py-6">
<p className="text-lg font-semibold mb-3">Form Konten Foto</p> <p className="text-lg font-semibold mb-3">Form Konten Audio</p>
<div className="gap-5 mb-5"> <div className="gap-5 mb-5">
{/* Input Title */} {/* Input Title */}
<div className="space-y-2 py-3"> <div className="space-y-2 py-3">
@ -418,25 +418,39 @@ export default function FormAudioDetail() {
)} )}
</div> </div>
<Label className="text-xl text-black">File Media</Label> <Label className="text-xl text-black">File Mediaaa</Label>
<div className="w-full "> <div className="w-full">
<Swiper <Swiper
thumbs={{ swiper: thumbsSwiper }} thumbs={{ swiper: thumbsSwiper }}
modules={[FreeMode, Navigation, Thumbs]} modules={[FreeMode, Navigation, Thumbs]}
navigation={false} navigation={false}
className="w-full" className="w-full"
> >
{detailThumb?.map((data: any) => ( {detailThumb?.map((data: any) => {
<SwiperSlide key={data.id}> const isAudio =
<img data.endsWith(".webm") ||
className="object-fill h-full w-full rounded-md" data.endsWith(".mp3") ||
src={data} data.endsWith(".ogg");
alt={` ${data.id}`} return (
/> <SwiperSlide key={data.id}>
</SwiperSlide> {isAudio ? (
))} <audio
className="object-fill h-full w-full rounded-md"
src={data.secondaryUrl}
controls
/>
) : (
<img
className="object-fill h-full w-full rounded-md"
src={data.secondaryUrl}
alt={` ${data.id}`}
/>
)}
</SwiperSlide>
);
})}
</Swiper> </Swiper>
<div className=" mt-2 "> <div className="mt-2">
<Swiper <Swiper
onSwiper={setThumbsSwiper} onSwiper={setThumbsSwiper}
slidesPerView={6} slidesPerView={6}
@ -445,17 +459,30 @@ export default function FormAudioDetail() {
clickable: true, clickable: true,
}} }}
modules={[Pagination, Thumbs]} modules={[Pagination, Thumbs]}
// className="mySwiper2"
> >
{detailThumb?.map((data: any) => ( {detailThumb?.map((data: any) => {
<SwiperSlide key={data.id}> const isAudio =
<img data.endsWith(".webm") ||
className="object-cover h-[60px] w-[80px]" data.endsWith(".mp3") ||
src={data} data.endsWith(".ogg");
alt={` ${data.id}`} return (
/> <SwiperSlide key={data.id}>
</SwiperSlide> {isAudio ? (
))} <audio
className="object-cover h-[60px] w-[80px]"
src={data.secondaryUrl}
controls
/>
) : (
<img
className="object-cover h-[60px] w-[80px]"
src={data.secondaryUrl}
alt={` ${data.id}`}
/>
)}
</SwiperSlide>
);
})}
</Swiper> </Swiper>
</div> </div>
</div> </div>

View File

@ -121,7 +121,7 @@ export default function FormAudio() {
const [detailData, setDetailData] = useState<any>(null); const [detailData, setDetailData] = useState<any>(null);
const [articleImages, setArticleImages] = useState<string[]>([]); const [articleImages, setArticleImages] = useState<string[]>([]);
const [isSwitchOn, setIsSwitchOn] = useState<boolean>(false); const [isSwitchOn, setIsSwitchOn] = useState<boolean>(false);
const inputRef = useRef<HTMLInputElement>(null);
const [selectedTarget, setSelectedTarget] = useState(""); const [selectedTarget, setSelectedTarget] = useState("");
const [unitSelection, setUnitSelection] = useState({ const [unitSelection, setUnitSelection] = useState({
allUnit: false, allUnit: false,
@ -347,7 +347,9 @@ export default function FormAudio() {
const newTag = e.currentTarget.value.trim(); const newTag = e.currentTarget.value.trim();
if (!tags.includes(newTag)) { if (!tags.includes(newTag)) {
setTags((prevTags) => [...prevTags, newTag]); // Add new tag setTags((prevTags) => [...prevTags, newTag]); // Add new tag
// setValue("tags", ""); // Clear input field if (inputRef.current) {
inputRef.current.value = ""; // Clear input field
}
} }
} }
}; };
@ -479,12 +481,7 @@ export default function FormAudio() {
close(); close();
// showProgress(); // 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");
@ -528,7 +525,7 @@ export default function FormAudio() {
filename: file.name, filename: file.name,
filetype: file.type, filetype: file.type,
duration, duration,
isWatermark: "true", // hardcode isWatermark: "false", // hardcode
}, },
onError: async (e: any) => { onError: async (e: any) => {
console.log("Error upload :", e); console.log("Error upload :", e);
@ -1033,6 +1030,7 @@ export default function FormAudio() {
id="tags" id="tags"
placeholder="Add a tag and press Enter" placeholder="Add a tag and press Enter"
onKeyDown={handleAddTag} onKeyDown={handleAddTag}
ref={inputRef}
/> />
<div className="mt-3 "> <div className="mt-3 ">
{tags.map((tag, index) => ( {tags.map((tag, index) => (

View File

@ -123,6 +123,7 @@ export default function FormImage() {
const [detailData, setDetailData] = useState<any>(null); const [detailData, setDetailData] = useState<any>(null);
const [articleImages, setArticleImages] = useState<string[]>([]); const [articleImages, setArticleImages] = useState<string[]>([]);
const [isSwitchOn, setIsSwitchOn] = useState<boolean>(false); const [isSwitchOn, setIsSwitchOn] = useState<boolean>(false);
const inputRef = useRef<HTMLInputElement>(null);
const [content, setContent] = useState(""); const [content, setContent] = useState("");
@ -352,7 +353,9 @@ export default function FormImage() {
const newTag = e.currentTarget.value.trim(); const newTag = e.currentTarget.value.trim();
if (!tags.includes(newTag)) { if (!tags.includes(newTag)) {
setTags((prevTags) => [...prevTags, newTag]); // Add new tag setTags((prevTags) => [...prevTags, newTag]); // Add new tag
// setValue("tags", ""); // Clear input field if (inputRef.current) {
inputRef.current.value = ""; // Clear input field
}
} }
} }
}; };
@ -1038,6 +1041,7 @@ export default function FormImage() {
id="tags" id="tags"
placeholder="Add a tag and press Enter" placeholder="Add a tag and press Enter"
onKeyDown={handleAddTag} onKeyDown={handleAddTag}
ref={inputRef}
/> />
<div className="mt-3 "> <div className="mt-3 ">
{tags.map((tag, index) => ( {tags.map((tag, index) => (

View File

@ -487,19 +487,19 @@ export default function FormConvertSPIT() {
</Select> </Select>
</div> </div>
</div> </div>
<div> <div className="">
<RadioGroup <RadioGroup
onValueChange={(value) => setSelectedFileType(value)} onValueChange={(value) => setSelectedFileType(value)}
value={selectedFileType} value={selectedFileType}
className=" grid-cols-1"
> >
<div className="flex items-center space-x-2"> <div className="">
<RadioGroupItem value="original" id="original-file" /> <RadioGroupItem value="original" id="original-file" />
<Label htmlFor="original-file"> <Label htmlFor="original-file">
Select Original File Select Original File
</Label> </Label>
</div> </div>
<div className="py-3 ">
<div className="py-3">
<Label>Deskripsi</Label> <Label>Deskripsi</Label>
<Controller <Controller
control={control} control={control}
@ -557,7 +557,7 @@ export default function FormConvertSPIT() {
Select File Hasil Rewrite Select File Hasil Rewrite
</Label> </Label>
</div> </div>
<div className="py-3"> <div className="py-3 ">
<Label>File hasil Rewrite</Label> <Label>File hasil Rewrite</Label>
<Controller <Controller
control={control} control={control}

View File

@ -243,8 +243,8 @@ export default function FormTeksDetail() {
setSelectedTarget(details.categoryId); // Untuk dropdown setSelectedTarget(details.categoryId); // Untuk dropdown
const filesData = details.files || []; const filesData = details.files || [];
const fileUrls = filesData.map((file: { thumbnailFileUrl: string }) => const fileUrls = filesData.map((file: { url: string }) =>
file.thumbnailFileUrl ? file.thumbnailFileUrl : "default-image.jpg" file.url ? file.url : "default-image.jpg"
); );
setDetailThumb(fileUrls); setDetailThumb(fileUrls);
} }
@ -419,9 +419,8 @@ export default function FormTeksDetail() {
</p> </p>
)} )}
</div> </div>
<Label className="text-xl text-black">File Media</Label> <Label className="text-xl text-black">File Media</Label>
<div className="w-full "> <div className="w-full">
<Swiper <Swiper
thumbs={{ swiper: thumbsSwiper }} thumbs={{ swiper: thumbsSwiper }}
modules={[FreeMode, Navigation, Thumbs]} modules={[FreeMode, Navigation, Thumbs]}
@ -430,32 +429,56 @@ export default function FormTeksDetail() {
> >
{detailThumb?.map((data: any) => ( {detailThumb?.map((data: any) => (
<SwiperSlide key={data.id}> <SwiperSlide key={data.id}>
<img {[".jpg", ".jpeg", ".png", ".webp"].includes(
className="object-fill h-full w-full rounded-md" data.format
src={data} ) ? (
alt={` ${data.id}`} <img
/> className="object-fill h-full w-full rounded-md"
src={data.url}
alt={data.fileName}
/>
) : [".pdf", ".docx", ".txt"].includes(data.format) ? (
<iframe
className="w-full h-96 rounded-md"
src={data.url}
title={data.fileName}
/>
) : (
<a
href={data}
target="_blank"
rel="noopener noreferrer"
className="block text-blue-500 underline"
>
View {data.fileName}
</a>
)}
</SwiperSlide> </SwiperSlide>
))} ))}
</Swiper> </Swiper>
<div className=" mt-2 "> <div className="mt-2">
<Swiper <Swiper
onSwiper={setThumbsSwiper} onSwiper={setThumbsSwiper}
slidesPerView={6} slidesPerView={6}
spaceBetween={8} spaceBetween={8}
pagination={{ pagination={{ clickable: true }}
clickable: true,
}}
modules={[Pagination, Thumbs]} modules={[Pagination, Thumbs]}
// className="mySwiper2"
> >
{detailThumb?.map((data: any) => ( {detailThumb?.map((data: any) => (
<SwiperSlide key={data.id}> <SwiperSlide key={data.id}>
<img {[".jpg", ".jpeg", ".png", ".webp"].includes(
className="object-cover h-[60px] w-[80px]" data.format
src={data} ) ? (
alt={` ${data.id}`} <img
/> className="object-cover h-[60px] w-[80px]"
src={data.url}
alt={data.fileName}
/>
) : (
<div className="h-[60px] w-[80px] flex items-center justify-center bg-gray-200 text-sm text-center text-gray-700 rounded-md">
{data?.format?.replace(".", "").toUpperCase()}
</div>
)}
</SwiperSlide> </SwiperSlide>
))} ))}
</Swiper> </Swiper>

View File

@ -121,6 +121,7 @@ export default function FormTeks() {
const [detailData, setDetailData] = useState<any>(null); const [detailData, setDetailData] = useState<any>(null);
const [articleImages, setArticleImages] = useState<string[]>([]); const [articleImages, setArticleImages] = useState<string[]>([]);
const [isSwitchOn, setIsSwitchOn] = useState<boolean>(false); const [isSwitchOn, setIsSwitchOn] = useState<boolean>(false);
const inputRef = useRef<HTMLInputElement>(null);
const [selectedTarget, setSelectedTarget] = useState(""); const [selectedTarget, setSelectedTarget] = useState("");
const [unitSelection, setUnitSelection] = useState({ const [unitSelection, setUnitSelection] = useState({
@ -346,7 +347,9 @@ export default function FormTeks() {
const newTag = e.currentTarget.value.trim(); const newTag = e.currentTarget.value.trim();
if (!tags.includes(newTag)) { if (!tags.includes(newTag)) {
setTags((prevTags) => [...prevTags, newTag]); // Add new tag setTags((prevTags) => [...prevTags, newTag]); // Add new tag
// setValue("tags", ""); // Clear input field if (inputRef.current) {
inputRef.current.value = ""; // Clear input field
}
} }
} }
}; };
@ -478,12 +481,7 @@ export default function FormTeks() {
close(); close();
// showProgress(); // 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");
@ -527,7 +525,7 @@ export default function FormTeks() {
filename: file.name, filename: file.name,
filetype: file.type, filetype: file.type,
duration, duration,
isWatermark: "true", // hardcode isWatermark: "false", // hardcode
}, },
onError: async (e: any) => { onError: async (e: any) => {
console.log("Error upload :", e); console.log("Error upload :", e);
@ -1032,6 +1030,7 @@ export default function FormTeks() {
id="tags" id="tags"
placeholder="Add a tag and press Enter" placeholder="Add a tag and press Enter"
onKeyDown={handleAddTag} onKeyDown={handleAddTag}
ref={inputRef}
/> />
<div className="mt-3 "> <div className="mt-3 ">
{tags.map((tag, index) => ( {tags.map((tag, index) => (

View File

@ -121,6 +121,7 @@ export default function FormVideo() {
const [detailData, setDetailData] = useState<any>(null); const [detailData, setDetailData] = useState<any>(null);
const [articleImages, setArticleImages] = useState<string[]>([]); const [articleImages, setArticleImages] = useState<string[]>([]);
const [isSwitchOn, setIsSwitchOn] = useState<boolean>(false); const [isSwitchOn, setIsSwitchOn] = useState<boolean>(false);
const inputRef = useRef<HTMLInputElement>(null);
const [selectedTarget, setSelectedTarget] = useState(""); const [selectedTarget, setSelectedTarget] = useState("");
const [unitSelection, setUnitSelection] = useState({ const [unitSelection, setUnitSelection] = useState({
@ -150,24 +151,7 @@ export default function FormVideo() {
const { getRootProps, getInputProps } = useDropzone({ const { getRootProps, getInputProps } = useDropzone({
onDrop: (acceptedFiles) => { onDrop: (acceptedFiles) => {
const validFiles = acceptedFiles.filter((file) => { setFiles(acceptedFiles.map((file) => Object.assign(file)));
const isValidType = ["video/mp4", "video/mov"].includes(file.type);
const isValidSize = file.size <= 100 * 1024 * 1024; // 100MB
return isValidType && isValidSize;
});
if (!validFiles.length) {
alert("Format file harus mp4/mov dan ukuran maksimal 100MB");
return;
}
setFiles(
validFiles.map((file) =>
Object.assign(file, {
preview: URL.createObjectURL(file),
})
)
);
}, },
}); });
@ -363,7 +347,9 @@ export default function FormVideo() {
const newTag = e.currentTarget.value.trim(); const newTag = e.currentTarget.value.trim();
if (!tags.includes(newTag)) { if (!tags.includes(newTag)) {
setTags((prevTags) => [...prevTags, newTag]); // Add new tag setTags((prevTags) => [...prevTags, newTag]); // Add new tag
// setValue("tags", ""); // Clear input field if (inputRef.current) {
inputRef.current.value = ""; // Clear input field
}
} }
} }
}; };
@ -495,12 +481,7 @@ export default function FormVideo() {
close(); close();
// showProgress(); // 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,
"0"
);
}); });
Cookies.remove("idCreate"); Cookies.remove("idCreate");
@ -1062,6 +1043,7 @@ export default function FormVideo() {
id="tags" id="tags"
placeholder="Add a tag and press Enter" placeholder="Add a tag and press Enter"
onKeyDown={handleAddTag} onKeyDown={handleAddTag}
ref={inputRef}
/> />
<div className="mt-3 "> <div className="mt-3 ">
{tags.map((tag, index) => ( {tags.map((tag, index) => (