"use client"; import { useState, useEffect } from "react"; import { Upload, Plus, Settings } from "lucide-react"; import Image from "next/image"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Button } from "@/components/ui/button"; import { Card, CardHeader, CardContent, CardTitle } from "@/components/ui/card"; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { useParams } from "next/navigation"; import { getProductDataById, updateProduct } from "@/service/product"; import { useRouter } from "next/navigation"; import { success, error, close, loading } from "@/config/swal"; export default function UpdateProductForm() { const params = useParams(); const id = params?.id; const router = useRouter(); const [specs, setSpecs] = useState< { id: number; title: string; images: string[]; files: File[] }[] >([]); const [specFiles, setSpecFiles] = useState>(new Map()); type ColorType = { id: number; name: string; preview: string; colorSelected: string | null; }; const [colors, setColors] = useState([]); const [colorFiles, setColorFiles] = useState>(new Map()); const [thumbnail, setThumbnail] = useState(""); const [title, setTitle] = useState(""); const [variant, setVariant] = useState(""); const [price, setPrice] = useState(""); const palette = [ "#1E4E52", "#597E8D", "#6B6B6B", "#BEBEBE", "#E2E2E2", "#F4F4F4", "#FFFFFF", "#F9360A", "#9A2A00", "#7A1400", "#4B0200", "#B48B84", "#FFA598", ]; const handleAddSpec = () => { setSpecs((prev) => [ ...prev, { id: prev.length + 1, title: "", images: [], files: [], }, ]); }; const handleAddColor = () => { setColors((p) => [ ...p, { id: p.length + 1, name: "", preview: "/car-default.png", colorSelected: null, }, ]); }; const [isUploadDialogOpen, setIsUploadDialogOpen] = useState(false); const [bannerFile, setBannerFile] = useState(null); const [uploadTarget, setUploadTarget] = useState<{ type: "spec" | "color" | "banner"; index?: number; } | null>(null); const fileInputId = "file-upload-input"; const handleFileSelected = (e: React.ChangeEvent) => { const input = e.target; const file = input.files?.[0]; if (!file || !uploadTarget) return; const previewUrl = URL.createObjectURL(file); // ===================== SPEC ===================== if (uploadTarget.type === "spec") { if (uploadTarget.index === undefined) return; const index = uploadTarget.index; // preview setSpecs((prev) => { const updated = [...prev]; updated[index].images = [...updated[index].images, previewUrl]; return updated; }); // file upload setSpecFiles((prev) => { const newMap = new Map(prev); const files = newMap.get(index) || []; newMap.set(index, [...files, file]); return newMap; }); } // ===================== COLOR ===================== if (uploadTarget.type === "color") { if (uploadTarget.index === undefined) return; const index = uploadTarget.index; setColors((prev) => { const updated = [...prev]; updated[index].preview = previewUrl; return updated; }); setColorFiles((prev) => { const newMap = new Map(prev); newMap.set(index, file); return newMap; }); } // ===================== BANNER ===================== if (uploadTarget.type === "banner") { setThumbnail(previewUrl); setBannerFile(file); } input.value = ""; setIsUploadDialogOpen(false); }; const formatRupiah = (value: string) => "Rp " + Number(value).toLocaleString("id-ID"); useEffect(() => { if (id) { initState(); } }, [id]); async function initState() { if (!id) return; try { loading(); const res = await getProductDataById(id); const data = res?.data?.data; if (!data) { error("Produk tidak ditemukan"); return; } close(); // Set form values setTitle(data.title || ""); setVariant(data.variant || ""); setPrice(formatRupiah(data.price || "0")); setThumbnail(data.thumbnail_url || ""); // Set colors if (data.colors?.length) { setColors( data.colors.map((color: any, index: number) => ({ id: index + 1, name: color.name || "", preview: color.image_url || data.thumbnail_url || "", colorSelected: color.name || null, })), ); } else { setColors([]); } // Set specifications if (data.specifications?.length) { setSpecs( data.specifications.map((spec: any, index: number) => ({ id: index + 1, title: spec.title || "", images: spec.image_urls || [], files: [], })), ); } else { setSpecs([]); } } catch (err) { error("Gagal memuat data produk"); console.error(err); } } const handleSubmit = async () => { if (!id) { error("ID produk tidak ditemukan"); return; } try { loading(); const formData = new FormData(); formData.append("title", title); if (variant) formData.append("variant", variant); if (price) { const priceValue = price.replace(/\D/g, ""); formData.append("price", priceValue); } // Colors JSON const colorsPayload = colors.map((c) => ({ name: c.name, })); formData.append("colors", JSON.stringify(colorsPayload)); // Color images (only new files if uploaded) // Append files in order of color indices colors.forEach((_, index) => { const file = colorFiles.get(index); if (file) { formData.append("color_images", file); } }); if (bannerFile) { formData.append("file", bannerFile); } // Specifications JSON (include image count for new files only) const specificationsPayload = specs.map((s, index) => { const newFiles = specFiles.get(index) || []; return { title: s.title, imageCount: newFiles.length, // Only count new files being uploaded }; }); formData.append("specifications", JSON.stringify(specificationsPayload)); specs.forEach((_, index) => { const files = specFiles.get(index) || []; files.forEach((file) => { formData.append("specification_images", file); }); }); await updateProduct(formData, id); success("Produk berhasil diperbarui"); router.push("/admin/product"); } catch (err) { error("Gagal memperbarui produk"); console.error(err); } }; return ( <> Edit Produk
setTitle(e.target.value)} placeholder="Masukkan nama produk" />
setVariant(e.target.value)} placeholder="Masukkan varian" />
{ const rawValue = e.target.value.replace(/\D/g, ""); setPrice(formatRupiah(rawValue)); }} placeholder="Masukkan harga" />
{thumbnail ? ( Thumbnail ) : (
No Image
)}
{colors.map((item, index) => (
{ setColors((prev) => { const updated = [...prev]; updated[index].name = e.target.value; updated[index].colorSelected = e.target.value; return updated; }); }} />
{palette.map((colorCode) => (
car color
))}
{specs.map((spec, index) => (
{ setSpecs((prev) => { const updated = [...prev]; updated[index].title = e.target.value; return updated; }); }} />
{spec.images.map((img, i) => (
spec {/* 🔴 TOMBOL HAPUS GAMBAR */}
))}
))}
Upload File
document.getElementById(fileInputId)?.click()} >

Klik untuk upload atau drag & drop

PNG, JPG (max 2 MB)

); }