update
This commit is contained in:
parent
b623304e9d
commit
475987bcd3
|
|
@ -10,83 +10,170 @@ import {
|
||||||
DialogFooter,
|
DialogFooter,
|
||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
import { X } from "lucide-react";
|
import { X } from "lucide-react";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getGaleryFileData,
|
getGaleryFileData,
|
||||||
updateGalery,
|
updateGalery,
|
||||||
updateUploadGaleryFile,
|
updateUploadGaleryFile,
|
||||||
|
deleteGaleryFile,
|
||||||
} from "@/service/galery";
|
} from "@/service/galery";
|
||||||
|
import { error, success } from "@/config/swal";
|
||||||
|
import withReactContent from "sweetalert2-react-content";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
|
||||||
export function DialogUpdateGaleri({ open, onClose, data, onUpdated }: any) {
|
export function DialogUpdateGaleri({ open, onClose, data, onUpdated }: any) {
|
||||||
const [title, setTitle] = useState(data.title || "");
|
const [title, setTitle] = useState("");
|
||||||
const [description, setDescription] = useState(data.desc || "");
|
const MySwal = withReactContent(Swal);
|
||||||
|
const [description, setDescription] = useState("");
|
||||||
const [oldFiles, setOldFiles] = useState<any[]>([]);
|
const [oldFiles, setOldFiles] = useState<any[]>([]);
|
||||||
const [newFiles, setNewFiles] = useState<File[]>([]);
|
const [newFiles, setNewFiles] = useState<File[]>([]);
|
||||||
|
const [newFilePreviews, setNewFilePreviews] = useState<string[]>([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const fetchOldFiles = async () => {
|
const fetchOldFiles = async (galleryId: any) => {
|
||||||
try {
|
try {
|
||||||
const res = await getGaleryFileData(data.id);
|
const res = await getGaleryFileData(galleryId);
|
||||||
const allImages = res?.data?.data ?? [];
|
const allImages = res?.data?.data ?? [];
|
||||||
|
const filtered = allImages.filter(
|
||||||
const filteredImages = allImages.filter(
|
(img: any) => img.gallery_id === galleryId
|
||||||
(img: any) => img.gallery_id === data.id
|
|
||||||
);
|
);
|
||||||
|
setOldFiles(filtered);
|
||||||
setOldFiles(filteredImages);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Error fetch files:", e);
|
console.error("Error fetching files:", e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (open && data?.id) {
|
if (open && data?.id) {
|
||||||
fetchOldFiles();
|
setTitle(data.title ?? "");
|
||||||
setTitle(data.title || "");
|
|
||||||
setDescription(data.description || "");
|
setDescription(data.description ?? data.desc ?? "");
|
||||||
|
fetchOldFiles(data.id);
|
||||||
|
|
||||||
|
setNewFiles([]);
|
||||||
|
setNewFilePreviews([]);
|
||||||
|
} else if (!open) {
|
||||||
}
|
}
|
||||||
}, [open, data]);
|
}, [open, data]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!newFiles || newFiles.length === 0) {
|
||||||
|
setNewFilePreviews([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const urls = newFiles.map((f) => URL.createObjectURL(f));
|
||||||
|
setNewFilePreviews(urls);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
urls.forEach((u) => URL.revokeObjectURL(u));
|
||||||
|
};
|
||||||
|
}, [newFiles]);
|
||||||
|
|
||||||
const handleUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const uploaded = Array.from(e.target.files || []) as File[];
|
const uploaded = Array.from(e.target.files || []) as File[];
|
||||||
|
if (uploaded.length === 0) return;
|
||||||
setNewFiles((prev) => [...prev, ...uploaded]);
|
setNewFiles((prev) => [...prev, ...uploaded]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeOldFile = (id: number) => {
|
async function doDelete(id: any) {
|
||||||
setOldFiles((prev) => prev.filter((f) => f.id !== id));
|
const resDelete = await deleteGaleryFile(id);
|
||||||
|
if (resDelete?.error) {
|
||||||
|
error(resDelete.message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
success("Berhasil Hapus");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeOldFile = (id: any) => {
|
||||||
|
MySwal.fire({
|
||||||
|
title: "Hapus Data",
|
||||||
|
icon: "warning",
|
||||||
|
showCancelButton: true,
|
||||||
|
cancelButtonColor: "#3085d6",
|
||||||
|
confirmButtonColor: "#d33",
|
||||||
|
confirmButtonText: "Hapus",
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
doDelete(id);
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeNewFile = (index: number) => {
|
const removeNewFile = (index: number) => {
|
||||||
setNewFiles((prev) => prev.filter((_, i) => i !== index));
|
setNewFiles((prev) => prev.filter((_, i) => i !== index));
|
||||||
|
setNewFilePreviews((prev) => prev.filter((_, i) => i !== index));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
try {
|
try {
|
||||||
|
if (!data?.id) {
|
||||||
|
alert("Gallery ID tidak tersedia.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
const formMain = new FormData();
|
const formMain = new FormData();
|
||||||
formMain.append("title", title);
|
formMain.append("title", title);
|
||||||
formMain.append("description", description);
|
formMain.append("description", description);
|
||||||
|
|
||||||
formMain.append("old_files", JSON.stringify(oldFiles.map((f) => f.id)));
|
formMain.append("old_files", JSON.stringify(oldFiles.map((f) => f.id)));
|
||||||
|
|
||||||
await updateGalery(data.id, formMain);
|
const updateRes = await updateGalery(data.id, formMain);
|
||||||
|
console.log("updateGalery response:", updateRes);
|
||||||
|
|
||||||
|
if (updateRes?.error) {
|
||||||
|
alert(updateRes.message || "Gagal update galeri");
|
||||||
|
setLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const galleryId = data.id;
|
||||||
|
const failedUploads: any[] = [];
|
||||||
|
|
||||||
for (const file of newFiles) {
|
for (const file of newFiles) {
|
||||||
const formFile = new FormData();
|
try {
|
||||||
formFile.append("gallery_id", String(data.id));
|
const formFile = new FormData();
|
||||||
formFile.append("title", title);
|
formFile.append("gallery_id", String(galleryId));
|
||||||
formFile.append("file", file);
|
formFile.append("title", title);
|
||||||
|
formFile.append("is_active", "true");
|
||||||
|
formFile.append("file", file);
|
||||||
|
|
||||||
await updateUploadGaleryFile(data.id, formFile);
|
const uploadRes = await updateUploadGaleryFile(data.id, formFile);
|
||||||
|
|
||||||
|
console.log("uploadRes:", uploadRes);
|
||||||
|
|
||||||
|
if (uploadRes?.error) {
|
||||||
|
failedUploads.push({
|
||||||
|
name: file.name,
|
||||||
|
error: uploadRes.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
failedUploads.push({ name: file.name, error: err });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|
||||||
|
if (failedUploads.length > 0) {
|
||||||
|
let msg = failedUploads.map((f) => `${f.name}: ${f.error}`).join("\n");
|
||||||
|
alert("Ada file gagal diupload:\n" + msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
onClose();
|
onClose();
|
||||||
if (onUpdated) onUpdated();
|
onUpdated && onUpdated();
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
console.error("Error update gallery:", err);
|
console.error("Update error:", err);
|
||||||
alert("Gagal menyimpan perubahan galeri");
|
|
||||||
|
if (err?.response?.data) {
|
||||||
|
alert("Server error: " + JSON.stringify(err.response.data));
|
||||||
|
} else {
|
||||||
|
alert("Gagal menyimpan galeri");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -97,8 +184,7 @@ export function DialogUpdateGaleri({ open, onClose, data, onUpdated }: any) {
|
||||||
<DialogTitle>Edit Galeri</DialogTitle>
|
<DialogTitle>Edit Galeri</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
{/* FORM */}
|
<div className="space-y-4 px-4 pb-4">
|
||||||
<div className="space-y-4">
|
|
||||||
{/* TITLE */}
|
{/* TITLE */}
|
||||||
<div>
|
<div>
|
||||||
<label className="font-medium text-sm">Judul Galeri *</label>
|
<label className="font-medium text-sm">Judul Galeri *</label>
|
||||||
|
|
@ -139,14 +225,13 @@ export function DialogUpdateGaleri({ open, onClose, data, onUpdated }: any) {
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
{/* OLD FILES */}
|
|
||||||
{oldFiles.length > 0 && (
|
{oldFiles.length > 0 && (
|
||||||
<div className="flex gap-3 mt-3 flex-wrap">
|
<div className="flex gap-3 mt-3 flex-wrap">
|
||||||
{oldFiles.map((f) => (
|
{oldFiles.map((f) => (
|
||||||
<div key={f.id} className="relative w-20 h-20">
|
<div key={f.id} className="relative w-20 h-20">
|
||||||
<Image
|
<Image
|
||||||
src={f.image_url}
|
src={f.image_url}
|
||||||
alt={f.title}
|
alt={f.title || "image"}
|
||||||
fill
|
fill
|
||||||
className="object-cover rounded-lg"
|
className="object-cover rounded-lg"
|
||||||
/>
|
/>
|
||||||
|
|
@ -161,16 +246,17 @@ export function DialogUpdateGaleri({ open, onClose, data, onUpdated }: any) {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* NEW FILES */}
|
{newFilePreviews.length > 0 && (
|
||||||
{newFiles.length > 0 && (
|
|
||||||
<div className="flex gap-3 mt-3 flex-wrap">
|
<div className="flex gap-3 mt-3 flex-wrap">
|
||||||
{newFiles.map((file, idx) => (
|
{newFilePreviews.map((src, idx) => (
|
||||||
<div key={idx} className="relative w-20 h-20">
|
<div
|
||||||
<Image
|
key={idx}
|
||||||
src={URL.createObjectURL(file)}
|
className="relative w-20 h-20 overflow-hidden rounded-lg border"
|
||||||
alt={file.name}
|
>
|
||||||
fill
|
<img
|
||||||
className="object-cover rounded-lg"
|
src={src}
|
||||||
|
alt={`new-${idx}`}
|
||||||
|
className="object-cover w-full h-full"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
onClick={() => removeNewFile(idx)}
|
onClick={() => removeNewFile(idx)}
|
||||||
|
|
@ -185,8 +271,7 @@ export function DialogUpdateGaleri({ open, onClose, data, onUpdated }: any) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* FOOTER */}
|
<DialogFooter className="mt-6 flex gap-2 px-4 pb-4">
|
||||||
<DialogFooter className="mt-6 flex gap-2">
|
|
||||||
<button
|
<button
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className="px-6 py-2 rounded-lg bg-gray-200 text-gray-700"
|
className="px-6 py-2 rounded-lg bg-gray-200 text-gray-700"
|
||||||
|
|
|
||||||
|
|
@ -63,3 +63,10 @@ export async function deleteGalery(id: string) {
|
||||||
};
|
};
|
||||||
return await httpDeleteInterceptor(`galleries/${id}`, headers);
|
return await httpDeleteInterceptor(`galleries/${id}`, headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function deleteGaleryFile(id: any) {
|
||||||
|
const headers = {
|
||||||
|
"content-type": "application/json",
|
||||||
|
};
|
||||||
|
return await httpDeleteInterceptor(`gallery-files/${id}`, headers);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue