2025-11-18 06:56:39 +00:00
|
|
|
"use client";
|
|
|
|
|
|
2025-11-20 06:57:16 +00:00
|
|
|
import { useEffect, useState } from "react";
|
2025-11-18 06:56:39 +00:00
|
|
|
import Image from "next/image";
|
|
|
|
|
import {
|
|
|
|
|
Dialog,
|
|
|
|
|
DialogContent,
|
|
|
|
|
DialogHeader,
|
|
|
|
|
DialogTitle,
|
|
|
|
|
DialogFooter,
|
|
|
|
|
} from "@/components/ui/dialog";
|
|
|
|
|
import { X } from "lucide-react";
|
2025-11-20 06:57:16 +00:00
|
|
|
import {
|
|
|
|
|
getGaleryFileData,
|
|
|
|
|
updateGalery,
|
|
|
|
|
updateUploadGaleryFile,
|
|
|
|
|
} from "@/service/galery";
|
2025-11-18 06:56:39 +00:00
|
|
|
|
|
|
|
|
export function DialogUpdateGaleri({ open, onClose, data, onUpdated }: any) {
|
2025-11-20 06:57:16 +00:00
|
|
|
const [title, setTitle] = useState(data.title || "");
|
|
|
|
|
const [description, setDescription] = useState(data.desc || "");
|
|
|
|
|
const [oldFiles, setOldFiles] = useState<any[]>([]);
|
2025-11-18 06:56:39 +00:00
|
|
|
const [newFiles, setNewFiles] = useState<File[]>([]);
|
|
|
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
|
|
2025-11-20 06:57:16 +00:00
|
|
|
const fetchOldFiles = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const res = await getGaleryFileData(data.id);
|
|
|
|
|
const allImages = res?.data?.data ?? [];
|
|
|
|
|
|
|
|
|
|
const filteredImages = allImages.filter(
|
|
|
|
|
(img: any) => img.gallery_id === data.id
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
setOldFiles(filteredImages);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error("Error fetch files:", e);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (open && data?.id) {
|
|
|
|
|
fetchOldFiles();
|
|
|
|
|
setTitle(data.title || "");
|
|
|
|
|
setDescription(data.description || "");
|
|
|
|
|
}
|
|
|
|
|
}, [open, data]);
|
|
|
|
|
|
2025-11-18 06:56:39 +00:00
|
|
|
const handleUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
|
|
|
const uploaded = Array.from(e.target.files || []) as File[];
|
|
|
|
|
setNewFiles((prev) => [...prev, ...uploaded]);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const removeOldFile = (id: number) => {
|
2025-11-20 06:57:16 +00:00
|
|
|
setOldFiles((prev) => prev.filter((f) => f.id !== id));
|
2025-11-18 06:56:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const removeNewFile = (index: number) => {
|
2025-11-20 06:57:16 +00:00
|
|
|
setNewFiles((prev) => prev.filter((_, i) => i !== index));
|
2025-11-18 06:56:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleSubmit = async () => {
|
|
|
|
|
try {
|
|
|
|
|
setLoading(true);
|
|
|
|
|
|
2025-11-20 06:57:16 +00:00
|
|
|
const formMain = new FormData();
|
|
|
|
|
formMain.append("title", title);
|
|
|
|
|
formMain.append("description", description);
|
2025-11-18 06:56:39 +00:00
|
|
|
|
2025-11-20 06:57:16 +00:00
|
|
|
formMain.append("old_files", JSON.stringify(oldFiles.map((f) => f.id)));
|
2025-11-18 06:56:39 +00:00
|
|
|
|
2025-11-20 06:57:16 +00:00
|
|
|
await updateGalery(data.id, formMain);
|
2025-11-18 06:56:39 +00:00
|
|
|
|
2025-11-20 06:57:16 +00:00
|
|
|
for (const file of newFiles) {
|
|
|
|
|
const formFile = new FormData();
|
|
|
|
|
formFile.append("gallery_id", String(data.id));
|
|
|
|
|
formFile.append("title", title);
|
|
|
|
|
formFile.append("file", file);
|
|
|
|
|
|
|
|
|
|
await updateUploadGaleryFile(data.id, formFile);
|
|
|
|
|
}
|
2025-11-18 06:56:39 +00:00
|
|
|
|
|
|
|
|
setLoading(false);
|
|
|
|
|
onClose();
|
2025-11-20 06:57:16 +00:00
|
|
|
if (onUpdated) onUpdated();
|
|
|
|
|
} catch (err) {
|
2025-11-18 06:56:39 +00:00
|
|
|
setLoading(false);
|
2025-11-20 06:57:16 +00:00
|
|
|
console.error("Error update gallery:", err);
|
|
|
|
|
alert("Gagal menyimpan perubahan galeri");
|
2025-11-18 06:56:39 +00:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Dialog open={open} onOpenChange={onClose}>
|
|
|
|
|
<DialogContent className="max-w-xl rounded-2xl">
|
2025-11-20 06:57:16 +00:00
|
|
|
<DialogHeader>
|
|
|
|
|
<DialogTitle>Edit Galeri</DialogTitle>
|
2025-11-18 06:56:39 +00:00
|
|
|
</DialogHeader>
|
|
|
|
|
|
2025-11-20 06:57:16 +00:00
|
|
|
{/* FORM */}
|
2025-11-18 06:56:39 +00:00
|
|
|
<div className="space-y-4">
|
2025-11-20 06:57:16 +00:00
|
|
|
{/* TITLE */}
|
2025-11-18 06:56:39 +00:00
|
|
|
<div>
|
|
|
|
|
<label className="font-medium text-sm">Judul Galeri *</label>
|
|
|
|
|
<input
|
|
|
|
|
className="w-full border rounded-lg px-3 py-2 mt-1"
|
|
|
|
|
value={title}
|
|
|
|
|
onChange={(e) => setTitle(e.target.value)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
2025-11-20 06:57:16 +00:00
|
|
|
{/* DESCRIPTION */}
|
2025-11-18 06:56:39 +00:00
|
|
|
<div>
|
|
|
|
|
<label className="font-medium text-sm">Deskripsi Galeri *</label>
|
|
|
|
|
<textarea
|
|
|
|
|
className="w-full border rounded-lg px-3 py-2 mt-1"
|
|
|
|
|
rows={3}
|
2025-11-20 06:57:16 +00:00
|
|
|
value={description}
|
|
|
|
|
onChange={(e) => setDescription(e.target.value)}
|
2025-11-18 06:56:39 +00:00
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
2025-11-20 06:57:16 +00:00
|
|
|
{/* UPLOAD FILE */}
|
2025-11-18 06:56:39 +00:00
|
|
|
<div>
|
2025-11-20 06:57:16 +00:00
|
|
|
<label className="font-medium text-sm">Upload File</label>
|
2025-11-18 06:56:39 +00:00
|
|
|
<label className="mt-2 flex flex-col items-center justify-center border border-dashed rounded-xl py-6 cursor-pointer">
|
|
|
|
|
<input
|
|
|
|
|
type="file"
|
|
|
|
|
className="hidden"
|
|
|
|
|
multiple
|
|
|
|
|
onChange={handleUpload}
|
|
|
|
|
/>
|
|
|
|
|
<div className="flex flex-col items-center text-gray-500">
|
|
|
|
|
<svg width="32" height="32" fill="#1F6779">
|
|
|
|
|
<path d="M5 20h14v-2H5v2zm7-16l-5 5h3v4h4v-4h3l-5-5z" />
|
|
|
|
|
</svg>
|
|
|
|
|
<p>Klik untuk upload atau drag & drop</p>
|
|
|
|
|
<p className="text-xs">PNG, JPG (max 2MB)</p>
|
|
|
|
|
</div>
|
|
|
|
|
</label>
|
|
|
|
|
|
2025-11-20 06:57:16 +00:00
|
|
|
{/* OLD FILES */}
|
|
|
|
|
{oldFiles.length > 0 && (
|
|
|
|
|
<div className="flex gap-3 mt-3 flex-wrap">
|
|
|
|
|
{oldFiles.map((f) => (
|
|
|
|
|
<div key={f.id} className="relative w-20 h-20">
|
|
|
|
|
<Image
|
|
|
|
|
src={f.image_url}
|
|
|
|
|
alt={f.title}
|
|
|
|
|
fill
|
|
|
|
|
className="object-cover rounded-lg"
|
|
|
|
|
/>
|
|
|
|
|
<button
|
|
|
|
|
onClick={() => removeOldFile(f.id)}
|
|
|
|
|
className="absolute -top-2 -right-2 bg-red-600 text-white rounded-full p-1"
|
|
|
|
|
>
|
|
|
|
|
<X size={12} />
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
2025-11-18 06:56:39 +00:00
|
|
|
</div>
|
2025-11-20 06:57:16 +00:00
|
|
|
)}
|
2025-11-18 06:56:39 +00:00
|
|
|
|
|
|
|
|
{/* NEW FILES */}
|
2025-11-20 06:57:16 +00:00
|
|
|
{newFiles.length > 0 && (
|
|
|
|
|
<div className="flex gap-3 mt-3 flex-wrap">
|
|
|
|
|
{newFiles.map((file, idx) => (
|
|
|
|
|
<div key={idx} className="relative w-20 h-20">
|
|
|
|
|
<Image
|
|
|
|
|
src={URL.createObjectURL(file)}
|
|
|
|
|
alt={file.name}
|
|
|
|
|
fill
|
|
|
|
|
className="object-cover rounded-lg"
|
|
|
|
|
/>
|
|
|
|
|
<button
|
|
|
|
|
onClick={() => removeNewFile(idx)}
|
|
|
|
|
className="absolute -top-2 -right-2 bg-red-600 text-white rounded-full p-1"
|
|
|
|
|
>
|
|
|
|
|
<X size={12} />
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2025-11-18 06:56:39 +00:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
2025-11-20 06:57:16 +00:00
|
|
|
{/* FOOTER */}
|
|
|
|
|
<DialogFooter className="mt-6 flex gap-2">
|
2025-11-18 06:56:39 +00:00
|
|
|
<button
|
|
|
|
|
onClick={onClose}
|
|
|
|
|
className="px-6 py-2 rounded-lg bg-gray-200 text-gray-700"
|
|
|
|
|
>
|
|
|
|
|
Batal
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
<button
|
|
|
|
|
disabled={loading}
|
|
|
|
|
onClick={handleSubmit}
|
|
|
|
|
className="px-6 py-2 rounded-lg bg-[#1F6779] text-white"
|
|
|
|
|
>
|
|
|
|
|
{loading ? "Menyimpan..." : "Simpan"}
|
|
|
|
|
</button>
|
|
|
|
|
</DialogFooter>
|
|
|
|
|
</DialogContent>
|
|
|
|
|
</Dialog>
|
|
|
|
|
);
|
|
|
|
|
}
|