jaecoo-kelapagading/components/form/product/create-product-form.tsx

300 lines
10 KiB
TypeScript
Raw Normal View History

2025-11-18 06:56:39 +00:00
"use client";
import { useState } from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import * as z from "zod";
import { Upload, Plus, UploadCloud } from "lucide-react";
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
import { Label } from "@radix-ui/react-dropdown-menu";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { createProduct } from "@/service/product";
import withReactContent from "sweetalert2-react-content";
import Swal from "sweetalert2";
import { useRouter } from "next/navigation";
const formSchema = z.object({
name: z.string().min(1, "Nama produk wajib diisi"),
variant: z.string().min(1, "Tipe varian wajib diisi"),
price: z.coerce.number().min(1, "Harga produk wajib diisi"), // ⬅️ PRICE NUMBER
banner: z.instanceof(FileList).optional(),
});
export default function AddProductForm() {
const [colors, setColors] = useState([{ id: 1 }]);
const [selectedColor, setSelectedColor] = useState<string | null>(null);
const [specs, setSpecs] = useState([{ id: 1 }]);
const [file, setFile] = useState<File | null>(null);
const router = useRouter();
const MySwal = withReactContent(Swal);
const handleFileChange = (e: any) => {
const selected = e.target.files[0];
if (selected) setFile(selected);
};
const handleAddSpec = () => {
setSpecs((prev) => [...prev, { id: prev.length + 1 }]);
};
const {
register,
handleSubmit,
formState: { errors },
} = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
});
const onSubmit = async (data: z.infer<typeof formSchema>) => {
try {
const formData = new FormData();
formData.append("title", data.name);
formData.append("variant", data.variant);
formData.append("price", data.price.toString());
// if (data.banner && data.banner.length > 0) {
// formData.append("thumbnail_path", data.banner[0]);
// }
if (file) {
formData.append("file", file);
}
const colorsArray = colors.map((c) => selectedColor || "");
formData.append("colors", JSON.stringify(colorsArray));
const res = await createProduct(formData);
console.log("API Success:", res);
successSubmit("/admin/product");
} catch (error) {
console.error("Submit Error:", error);
alert("Gagal mengirim produk");
}
};
function successSubmit(redirect: any) {
MySwal.fire({
title: "Sukses",
icon: "success",
confirmButtonColor: "#3085d6",
confirmButtonText: "OK",
}).then((result) => {
if (result.isConfirmed) {
router.push(redirect);
}
});
}
const handleAddColor = () => {
setColors((prev) => [...prev, { id: prev.length + 1 }]);
};
return (
<Card className="w-full max-w-full mx-auto shadow-md border-none">
<CardHeader>
<CardTitle className="text-xl font-bold text-teal-900">
Form Tambah Produk Baru
</CardTitle>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
{/* 3 Input Field */}
<div className="grid md:grid-cols-3 gap-4">
<div>
<Label>Nama Produk *</Label>
<Input placeholder="Masukkan Nama Produk" {...register("name")} />
{errors.name && (
<p className="text-sm text-red-500 mt-1">
{errors.name.message}
</p>
)}
</div>
<div>
<Label>Tipe Varian *</Label>
<Input
placeholder="Contoh: AWD, SHS, EV"
{...register("variant")}
/>
{errors.variant && (
<p className="text-sm text-red-500 mt-1">
{errors.variant.message}
</p>
)}
</div>
<div>
<Label>Harga Produk *</Label>
<Input
placeholder="Masukkan Harga Produk"
{...register("price")}
/>
{errors.price && (
<p className="text-sm text-red-500 mt-1">
{errors.price.message}
</p>
)}
</div>
</div>
{/* Upload Banner */}
<div>
<Label className="text-gray-700">
Upload Banner <span className="text-red-500">*</span>
</Label>
<label
htmlFor="uploadFile"
className="mt-1 border-2 border-dashed border-gray-300 rounded-xl p-6 flex flex-col items-center justify-center text-gray-500 cursor-pointer hover:border-[#1F6779]/50 transition"
>
<UploadCloud className="w-10 h-10 text-[#1F6779] mb-2" />
<p className="text-sm font-medium">
Klik untuk upload atau drag & drop
</p>
<p className="text-xs text-gray-400 mt-1">PNG, JPG (max 2 MB)</p>
<input
id="uploadFile"
type="file"
accept="image/png, image/jpeg"
className="hidden"
onChange={handleFileChange}
/>
{file && (
<p className="mt-2 text-xs text-[#1F6779] font-medium">
{file.name}
</p>
)}
</label>
</div>
{/* Upload Produk */}
<div>
<Label>Upload Produk *</Label>
{colors.map((color, index) => (
<div
key={color.id}
className="border p-4 rounded-lg mt-4 space-y-4"
>
<Label className="text-sm font-semibold">
Pilih Warna {index + 1}
</Label>
<Input placeholder="Contoh: Silver or #E2E2E2" />
{/* Pilihan Warna */}
<div className="flex flex-wrap gap-2">
{[
"#1E4E52",
"#597E8D",
"#6B6B6B",
"#BEBEBE",
"#E2E2E2",
"#F4F4F4",
"#FFFFFF",
"#F9360A",
"#9A2A00",
"#7A1400",
"#4B0200",
"#B48B84",
"#FFA598",
].map((colorCode) => (
<button
key={colorCode}
type="button"
onClick={() => setSelectedColor(colorCode)}
className={`w-8 h-8 rounded-full border-2 transition ${
selectedColor === colorCode
? "border-teal-700 scale-110"
: "border-gray-200"
}`}
style={{ backgroundColor: colorCode }}
/>
))}
</div>
{/* Upload Foto Warna */}
<div>
<Label>Foto Warna {index + 1}</Label>
<div className="border-2 border-dashed rounded-lg flex flex-col items-center justify-center py-6 cursor-pointer hover:bg-gray-50 transition">
<Upload className="w-6 h-6 text-gray-400 mb-2" />
<p className="text-sm text-gray-500 text-center">
Klik untuk upload foto mobil warna ini
</p>
<p className="text-xs text-gray-400">PNG, JPG (max 5 MB)</p>
<input
type="file"
accept="image/png,image/jpeg"
className="hidden"
/>
</div>
</div>
</div>
))}
{/* Tambah Warna Baru */}
<Button
type="button"
onClick={handleAddColor}
className="w-full bg-teal-800 hover:bg-teal-900 text-white mt-4"
>
<Plus className="w-4 h-4 mr-2" /> Tambah Warna Baru
</Button>
</div>
<div className="mt-8">
<Label className="font-semibold text-lg text-teal-900">
Spesifikasi Produk <span className="text-red-500">*</span>
</Label>
{specs.map((spec, index) => (
<div key={spec.id} className="mt-4">
{/* Judul Spesifikasi */}
<Label className="text-sm font-semibold">
Judul Spesifikasi {index + 1}
</Label>
<Input
placeholder="Contoh: Mesin Turbo 1.6L, Interior Premium, Safety Features"
className="mt-1"
/>
{/* Foto Spesifikasi */}
<Label className="text-sm font-semibold mt-4 block">
Foto Spesifikasi {index + 1}
</Label>
<div className="border-2 border-dashed rounded-lg flex flex-col items-center justify-center py-10 cursor-pointer hover:bg-gray-50 transition mt-1">
<Upload className="w-8 h-8 text-gray-400 mb-2" />
<p className="text-sm text-gray-500 text-center">
Klik untuk upload gambar spesifikasi
</p>
<p className="text-xs text-gray-400">PNG, JPG (max 5 MB)</p>
<input
type="file"
accept="image/png,image/jpeg"
className="hidden"
/>
</div>
</div>
))}
{/* Tambah spesifikasi baru */}
<button
type="button"
onClick={handleAddSpec}
className="w-full bg-teal-800 hover:bg-teal-900 text-white py-3 rounded-lg mt-6 flex items-center justify-center gap-2"
>
<Plus className="w-4 h-4" />
Tambahkan Spesifikasi Baru
</button>
</div>
<Button
type="submit"
className=" bg-teal-800 hover:bg-teal-900 text-white mt-6"
>
Submit
</Button>
</form>
</CardContent>
</Card>
);
}