feat:select color form

This commit is contained in:
Anang Yusman 2026-01-29 16:33:09 +08:00
parent 01df3f41d4
commit 7d3ac22960
5 changed files with 45 additions and 27 deletions

View File

@ -37,7 +37,7 @@ export default function AddProductForm() {
{ id: number; name: string; file: File | null }[] { id: number; name: string; file: File | null }[]
>([{ id: 1, name: "", file: null }]); >([{ id: 1, name: "", file: null }]);
const [selectedColor, setSelectedColor] = useState<string | null>(null); // const [selectedColor, setSelectedColor] = useState<string | null>(null);
const [specs, setSpecs] = useState< const [specs, setSpecs] = useState<
{ id: number; title: string; images: string[]; files: File[] }[] { id: number; title: string; images: string[]; files: File[] }[]
>([{ id: 1, title: "", images: [], files: [] }]); >([{ id: 1, title: "", images: [], files: [] }]);
@ -234,7 +234,9 @@ export default function AddProductForm() {
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6"> <form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
<div className="grid md:grid-cols-3 gap-4"> <div className="grid md:grid-cols-3 gap-4">
<div> <div>
<Label>Nama Produk *</Label> <Label>
Nama Produk <span className="text-red-500">*</span>
</Label>
<Input placeholder="Masukkan Nama Produk" {...register("name")} /> <Input placeholder="Masukkan Nama Produk" {...register("name")} />
{errors.name && ( {errors.name && (
<p className="text-sm text-red-500 mt-1"> <p className="text-sm text-red-500 mt-1">
@ -244,7 +246,9 @@ export default function AddProductForm() {
</div> </div>
<div> <div>
<Label>Tipe Varian *</Label> <Label>
Tipe Varian <span className="text-red-500">*</span>
</Label>
<Input <Input
placeholder="Contoh: AWD, SHS, EV" placeholder="Contoh: AWD, SHS, EV"
{...register("variant")} {...register("variant")}
@ -257,7 +261,9 @@ export default function AddProductForm() {
</div> </div>
<div> <div>
<Label>Harga Produk *</Label> <Label>
Harga Produk <span className="text-red-500">*</span>
</Label>
<Input <Input
placeholder="Masukkan Harga Produk" placeholder="Masukkan Harga Produk"
value={priceDisplay} value={priceDisplay}
@ -302,7 +308,9 @@ export default function AddProductForm() {
{/* Upload Produk */} {/* Upload Produk */}
<div> <div>
<Label>Upload Produk *</Label> <Label>
Upload Produk <span className="text-red-500">*</span>
</Label>
{colors.map((color, index) => ( {colors.map((color, index) => (
<div <div
key={color.id} key={color.id}
@ -342,15 +350,16 @@ export default function AddProductForm() {
type="button" type="button"
onClick={() => { onClick={() => {
const updated = [...colors]; const updated = [...colors];
updated[index].name = colorCode; // 🔥 INI KUNCINYA updated[index].name = colorCode;
setColors(updated); setColors(updated);
setSelectedColor(colorCode);
}} }}
className={`w-8 h-8 rounded-full border-2 transition ${ className={`w-8 h-8 rounded-full border-2 transition
selectedColor === colorCode ${
colors[index].name === colorCode
? "border-teal-700 scale-110" ? "border-teal-700 scale-110"
: "border-gray-200" : "border-gray-200"
}`} }
`}
style={{ backgroundColor: colorCode }} style={{ backgroundColor: colorCode }}
/> />
))} ))}

View File

@ -536,7 +536,7 @@ export default function DetailProductForm(props: { isDetail: boolean }) {
{/* Foto mobil */} {/* Foto mobil */}
<div className="w-full h-[90px] border rounded-lg overflow-hidden"> <div className="w-full h-[90px] border rounded-lg overflow-hidden">
<Image <img
src={item.preview} src={item.preview}
alt={`warna-${index}`} alt={`warna-${index}`}
width={200} width={200}
@ -582,7 +582,7 @@ export default function DetailProductForm(props: { isDetail: boolean }) {
key={i} key={i}
className="border rounded-lg overflow-hidden" className="border rounded-lg overflow-hidden"
> >
<Image <img
src={img} src={img}
alt={`spec-${i}`} alt={`spec-${i}`}
width={200} width={200}

View File

@ -33,6 +33,7 @@ export default function UpdateProductForm() {
name: string; name: string;
preview: string; preview: string;
colorSelected: string | null; colorSelected: string | null;
isImageChanged: boolean;
}; };
const [colors, setColors] = useState<ColorType[]>([]); const [colors, setColors] = useState<ColorType[]>([]);
@ -43,6 +44,7 @@ export default function UpdateProductForm() {
const [price, setPrice] = useState<string>(""); const [price, setPrice] = useState<string>("");
const palette = [ const palette = [
"#000000",
"#1E4E52", "#1E4E52",
"#597E8D", "#597E8D",
"#6B6B6B", "#6B6B6B",
@ -78,6 +80,7 @@ export default function UpdateProductForm() {
name: "", name: "",
preview: "/car-default.png", preview: "/car-default.png",
colorSelected: null, colorSelected: null,
isImageChanged: false, // ✅ WAJIB
}, },
]); ]);
}; };
@ -124,19 +127,19 @@ export default function UpdateProductForm() {
// ===================== COLOR ===================== // ===================== COLOR =====================
if (uploadTarget.type === "color") { if (uploadTarget.type === "color") {
if (uploadTarget.index === undefined) return; if (uploadTarget.index === undefined) return;
const index = uploadTarget.index; const index = uploadTarget.index;
setColors((prev) => { setColors((prev) => {
const updated = [...prev]; const updated = [...prev];
updated[index].preview = previewUrl; updated[index].preview = previewUrl;
updated[index].isImageChanged = true; // 🔥 PENTING
return updated; return updated;
}); });
setColorFiles((prev) => { setColorFiles((prev) => {
const newMap = new Map(prev); const map = new Map(prev);
newMap.set(index, file); map.set(index, file);
return newMap; return map;
}); });
} }
@ -185,8 +188,9 @@ export default function UpdateProductForm() {
data.colors.map((color: any, index: number) => ({ data.colors.map((color: any, index: number) => ({
id: index + 1, id: index + 1,
name: color.name || "", name: color.name || "",
preview: color.image_url || data.thumbnail_url || "", preview: color.image_url || "",
colorSelected: color.name || null, colorSelected: color.name || null,
isImageChanged: false, // 🔥 default
})), })),
); );
} else { } else {
@ -235,12 +239,18 @@ export default function UpdateProductForm() {
})); }));
formData.append("colors", JSON.stringify(colorsPayload)); formData.append("colors", JSON.stringify(colorsPayload));
// Color images (only new files if uploaded) colors.forEach((color, index) => {
// Append files in order of color indices if (color.isImageChanged) {
colors.forEach((_, index) => { // image diganti → kirim file baru
const file = colorFiles.get(index); const file = colorFiles.get(index);
if (file) { if (file) {
formData.append("color_images", file); formData.append("color_images", file);
} else {
formData.append("color_images", new Blob([])); // safety
}
} else {
// image tidak diganti → kirim placeholder
formData.append("color_images", new Blob([]));
} }
}); });
@ -473,7 +483,6 @@ export default function UpdateProductForm() {
className="rounded-lg border object-cover" className="rounded-lg border object-cover"
/> />
{/* 🔴 TOMBOL HAPUS GAMBAR */}
<button <button
type="button" type="button"
onClick={() => { onClick={() => {

View File

@ -0,0 +1 @@
google-site-verification: google162462b69256f396.html

View File

@ -1 +0,0 @@
google-site-verification: googlee3f6c9cb1d4e657b.html