fix: Remove car_id property from adminAddVehicle call to fix TypeScript error
This commit is contained in:
475
temp_ProductForm.tsx
Normal file
475
temp_ProductForm.tsx
Normal file
@@ -0,0 +1,475 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { ProductAdmin } from "@/lib/api";
|
||||
import { Loader2, ChevronDown, ChevronUp } from "lucide-react";
|
||||
|
||||
interface ProductFormProps {
|
||||
initialData?: ProductAdmin;
|
||||
onSubmit: (data: any) => Promise<void>;
|
||||
isSubmitting: boolean;
|
||||
}
|
||||
|
||||
const iconOptions = [
|
||||
{ value: "", label: "선택하세요" },
|
||||
{ value: "Cpu", label: "Cpu (프로세서)" },
|
||||
{ value: "HardDrive", label: "HardDrive (하드웨어)" },
|
||||
{ value: "Monitor", label: "Monitor (디스플레이)" },
|
||||
{ value: "Server", label: "Server (서버)" },
|
||||
{ value: "Wifi", label: "Wifi (무선)" },
|
||||
{ value: "Cable", label: "Cable (케이블)" },
|
||||
{ value: "Cog", label: "Cog (설정)" },
|
||||
{ value: "Zap", label: "Zap (전원)" },
|
||||
{ value: "Gauge", label: "Gauge (센서)" },
|
||||
{ value: "Thermometer", label: "Thermometer (온도)" },
|
||||
];
|
||||
|
||||
const categoryOptions = [
|
||||
{ value: "", label: "선택하세요" },
|
||||
{ value: "controller", label: "컨트롤러" },
|
||||
{ value: "sensor", label: "센서" },
|
||||
{ value: "display", label: "디스플레이" },
|
||||
{ value: "communication", label: "통신장비" },
|
||||
{ value: "power", label: "전원장치" },
|
||||
{ value: "software", label: "소프트웨어" },
|
||||
{ value: "accessory", label: "악세서리" },
|
||||
{ value: "other", label: "기타" },
|
||||
];
|
||||
|
||||
export default function ProductForm({
|
||||
initialData,
|
||||
onSubmit,
|
||||
isSubmitting,
|
||||
}: ProductFormProps) {
|
||||
const router = useRouter();
|
||||
const [showEnglish, setShowEnglish] = useState(!!initialData?.name_en);
|
||||
const [showJapanese, setShowJapanese] = useState(!!initialData?.name_ja);
|
||||
const [showChinese, setShowChinese] = useState(!!initialData?.name_zh);
|
||||
|
||||
const [formData, setFormData] = useState({
|
||||
name_ko: initialData?.name_ko || "",
|
||||
category_ko: initialData?.category_ko || "",
|
||||
description_ko: initialData?.description_ko || "",
|
||||
detail_ko: initialData?.detail_ko || "",
|
||||
name_en: initialData?.name_en || "",
|
||||
category_en: initialData?.category_en || "",
|
||||
description_en: initialData?.description_en || "",
|
||||
detail_en: initialData?.detail_en || "",
|
||||
name_ja: initialData?.name_ja || "",
|
||||
category_ja: initialData?.category_ja || "",
|
||||
description_ja: initialData?.description_ja || "",
|
||||
detail_ja: initialData?.detail_ja || "",
|
||||
name_zh: initialData?.name_zh || "",
|
||||
category_zh: initialData?.category_zh || "",
|
||||
description_zh: initialData?.description_zh || "",
|
||||
detail_zh: initialData?.detail_zh || "",
|
||||
specifications: initialData?.specifications || "",
|
||||
icon: initialData?.icon || "",
|
||||
is_active: initialData?.is_active ?? true,
|
||||
display_order: initialData?.display_order || 0,
|
||||
});
|
||||
|
||||
const handleChange = (
|
||||
e: React.ChangeEvent<
|
||||
HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement
|
||||
>
|
||||
) => {
|
||||
const { name, value, type } = e.target;
|
||||
setFormData({
|
||||
...formData,
|
||||
[name]:
|
||||
type === "checkbox"
|
||||
? (e.target as HTMLInputElement).checked
|
||||
: type === "number"
|
||||
? Number(value)
|
||||
: value,
|
||||
});
|
||||
};
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
await onSubmit(formData);
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit} className="space-y-6">
|
||||
{/* Korean (Required) */}
|
||||
<div className="bg-white rounded-xl p-6 shadow-sm">
|
||||
<h3 className="font-semibold text-gray-900 mb-4 flex items-center">
|
||||
<span className="w-6 h-6 bg-[#3B82F6] text-white text-xs rounded flex items-center justify-center mr-2">
|
||||
KO
|
||||
</span>
|
||||
한국어 (필수)
|
||||
</h3>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
제품명 *
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="name_ko"
|
||||
value={formData.name_ko}
|
||||
onChange={handleChange}
|
||||
required
|
||||
className="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-[#3B82F6] focus:border-transparent outline-none"
|
||||
placeholder="예: 스마트 컨트롤러 GT-100"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
카테고리
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="category_ko"
|
||||
value={formData.category_ko}
|
||||
onChange={handleChange}
|
||||
className="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-[#3B82F6] focus:border-transparent outline-none"
|
||||
placeholder="예: 산업용 컨트롤러"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
간단 설명
|
||||
</label>
|
||||
<textarea
|
||||
name="description_ko"
|
||||
value={formData.description_ko}
|
||||
onChange={handleChange}
|
||||
rows={3}
|
||||
className="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-[#3B82F6] focus:border-transparent outline-none resize-none"
|
||||
placeholder="제품에 대한 간단한 설명..."
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
상세 설명
|
||||
</label>
|
||||
<textarea
|
||||
name="detail_ko"
|
||||
value={formData.detail_ko}
|
||||
onChange={handleChange}
|
||||
rows={5}
|
||||
className="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-[#3B82F6] focus:border-transparent outline-none resize-none"
|
||||
placeholder="제품에 대한 상세 설명..."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* English */}
|
||||
<div className="bg-white rounded-xl shadow-sm overflow-hidden">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowEnglish(!showEnglish)}
|
||||
className="w-full px-6 py-4 flex items-center justify-between hover:bg-gray-50"
|
||||
>
|
||||
<span className="font-semibold text-gray-900 flex items-center">
|
||||
<span className="w-6 h-6 bg-gray-300 text-white text-xs rounded flex items-center justify-center mr-2">
|
||||
EN
|
||||
</span>
|
||||
English (선택)
|
||||
</span>
|
||||
{showEnglish ? (
|
||||
<ChevronUp className="w-5 h-5 text-gray-400" />
|
||||
) : (
|
||||
<ChevronDown className="w-5 h-5 text-gray-400" />
|
||||
)}
|
||||
</button>
|
||||
{showEnglish && (
|
||||
<div className="px-6 pb-6 space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Product Name
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="name_en"
|
||||
value={formData.name_en}
|
||||
onChange={handleChange}
|
||||
className="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-[#3B82F6] focus:border-transparent outline-none"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Category
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="category_en"
|
||||
value={formData.category_en}
|
||||
onChange={handleChange}
|
||||
className="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-[#3B82F6] focus:border-transparent outline-none"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Description
|
||||
</label>
|
||||
<textarea
|
||||
name="description_en"
|
||||
value={formData.description_en}
|
||||
onChange={handleChange}
|
||||
rows={3}
|
||||
className="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-[#3B82F6] focus:border-transparent outline-none resize-none"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Detail
|
||||
</label>
|
||||
<textarea
|
||||
name="detail_en"
|
||||
value={formData.detail_en}
|
||||
onChange={handleChange}
|
||||
rows={5}
|
||||
className="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-[#3B82F6] focus:border-transparent outline-none resize-none"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Japanese */}
|
||||
<div className="bg-white rounded-xl shadow-sm overflow-hidden">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowJapanese(!showJapanese)}
|
||||
className="w-full px-6 py-4 flex items-center justify-between hover:bg-gray-50"
|
||||
>
|
||||
<span className="font-semibold text-gray-900 flex items-center">
|
||||
<span className="w-6 h-6 bg-gray-300 text-white text-xs rounded flex items-center justify-center mr-2">
|
||||
JA
|
||||
</span>
|
||||
日本語 (선택)
|
||||
</span>
|
||||
{showJapanese ? (
|
||||
<ChevronUp className="w-5 h-5 text-gray-400" />
|
||||
) : (
|
||||
<ChevronDown className="w-5 h-5 text-gray-400" />
|
||||
)}
|
||||
</button>
|
||||
{showJapanese && (
|
||||
<div className="px-6 pb-6 space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
製品名
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="name_ja"
|
||||
value={formData.name_ja}
|
||||
onChange={handleChange}
|
||||
className="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-[#3B82F6] focus:border-transparent outline-none"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
カテゴリー
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="category_ja"
|
||||
value={formData.category_ja}
|
||||
onChange={handleChange}
|
||||
className="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-[#3B82F6] focus:border-transparent outline-none"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
説明
|
||||
</label>
|
||||
<textarea
|
||||
name="description_ja"
|
||||
value={formData.description_ja}
|
||||
onChange={handleChange}
|
||||
rows={3}
|
||||
className="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-[#3B82F6] focus:border-transparent outline-none resize-none"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
詳細
|
||||
</label>
|
||||
<textarea
|
||||
name="detail_ja"
|
||||
value={formData.detail_ja}
|
||||
onChange={handleChange}
|
||||
rows={5}
|
||||
className="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-[#3B82F6] focus:border-transparent outline-none resize-none"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Chinese */}
|
||||
<div className="bg-white rounded-xl shadow-sm overflow-hidden">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowChinese(!showChinese)}
|
||||
className="w-full px-6 py-4 flex items-center justify-between hover:bg-gray-50"
|
||||
>
|
||||
<span className="font-semibold text-gray-900 flex items-center">
|
||||
<span className="w-6 h-6 bg-gray-300 text-white text-xs rounded flex items-center justify-center mr-2">
|
||||
ZH
|
||||
</span>
|
||||
中文 (선택)
|
||||
</span>
|
||||
{showChinese ? (
|
||||
<ChevronUp className="w-5 h-5 text-gray-400" />
|
||||
) : (
|
||||
<ChevronDown className="w-5 h-5 text-gray-400" />
|
||||
)}
|
||||
</button>
|
||||
{showChinese && (
|
||||
<div className="px-6 pb-6 space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
产品名称
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="name_zh"
|
||||
value={formData.name_zh}
|
||||
onChange={handleChange}
|
||||
className="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-[#3B82F6] focus:border-transparent outline-none"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
类别
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="category_zh"
|
||||
value={formData.category_zh}
|
||||
onChange={handleChange}
|
||||
className="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-[#3B82F6] focus:border-transparent outline-none"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
描述
|
||||
</label>
|
||||
<textarea
|
||||
name="description_zh"
|
||||
value={formData.description_zh}
|
||||
onChange={handleChange}
|
||||
rows={3}
|
||||
className="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-[#3B82F6] focus:border-transparent outline-none resize-none"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
详细信息
|
||||
</label>
|
||||
<textarea
|
||||
name="detail_zh"
|
||||
value={formData.detail_zh}
|
||||
onChange={handleChange}
|
||||
rows={5}
|
||||
className="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-[#3B82F6] focus:border-transparent outline-none resize-none"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Specifications & Common Fields */}
|
||||
<div className="bg-white rounded-xl p-6 shadow-sm">
|
||||
<h3 className="font-semibold text-gray-900 mb-4">제품 사양</h3>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
사양 (JSON 형식)
|
||||
</label>
|
||||
<textarea
|
||||
name="specifications"
|
||||
value={formData.specifications}
|
||||
onChange={handleChange}
|
||||
rows={6}
|
||||
className="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-[#3B82F6] focus:border-transparent outline-none resize-none font-mono text-sm"
|
||||
placeholder='{"전압": "DC 24V", "통신": "RS-485", "크기": "100x80x40mm"}'
|
||||
/>
|
||||
<p className="text-xs text-gray-500 mt-1">
|
||||
JSON 형식으로 입력하세요. 예: {`{"항목": "값", "항목2": "값2"}`}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Display Settings */}
|
||||
<div className="bg-white rounded-xl p-6 shadow-sm">
|
||||
<h3 className="font-semibold text-gray-900 mb-4">표시 설정</h3>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
아이콘
|
||||
</label>
|
||||
<select
|
||||
name="icon"
|
||||
value={formData.icon}
|
||||
onChange={handleChange}
|
||||
className="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-[#3B82F6] focus:border-transparent outline-none"
|
||||
>
|
||||
{iconOptions.map((icon) => (
|
||||
<option key={icon.value} value={icon.value}>
|
||||
{icon.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
표시 순서
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
name="display_order"
|
||||
value={formData.display_order}
|
||||
onChange={handleChange}
|
||||
className="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-[#3B82F6] focus:border-transparent outline-none"
|
||||
/>
|
||||
<p className="text-xs text-gray-500 mt-1">
|
||||
숫자가 작을수록 먼저 표시됩니다
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center pt-6">
|
||||
<label className="flex items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="is_active"
|
||||
checked={formData.is_active}
|
||||
onChange={handleChange}
|
||||
className="w-4 h-4 text-[#3B82F6] rounded border-gray-300 focus:ring-[#3B82F6]"
|
||||
/>
|
||||
<span className="ml-2 text-sm text-gray-700">웹사이트에 표시</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Buttons */}
|
||||
<div className="flex items-center justify-end space-x-4">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => router.push("/admin/products")}
|
||||
className="px-6 py-2 text-gray-700 font-medium rounded-lg hover:bg-gray-100 transition-colors"
|
||||
>
|
||||
취소
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isSubmitting}
|
||||
className="flex items-center px-6 py-2 bg-[#3B82F6] text-white font-medium rounded-lg hover:bg-[#2563EB] transition-colors disabled:opacity-50"
|
||||
>
|
||||
{isSubmitting && <Loader2 className="w-4 h-4 animate-spin mr-2" />}
|
||||
저장
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user