472 lines
18 KiB
TypeScript
472 lines
18 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { useRouter } from "next/navigation";
|
|
import { SolutionAdmin } from "@/lib/api";
|
|
import { Loader2, ChevronDown, ChevronUp } from "lucide-react";
|
|
|
|
interface SolutionFormProps {
|
|
initialData?: SolutionAdmin;
|
|
onSubmit: (data: any) => Promise<void>;
|
|
isSubmitting: boolean;
|
|
}
|
|
|
|
const iconOptions = [
|
|
{ value: "", label: "선택하세요" },
|
|
{ value: "Monitor", label: "Monitor (모니터링)" },
|
|
{ value: "Cog", label: "Cog (설정/제어)" },
|
|
{ value: "Database", label: "Database (데이터)" },
|
|
{ value: "Cloud", label: "Cloud (클라우드)" },
|
|
{ value: "Factory", label: "Factory (공장)" },
|
|
{ value: "Cpu", label: "Cpu (프로세싱)" },
|
|
{ value: "BarChart3", label: "BarChart3 (차트)" },
|
|
{ value: "Wifi", label: "Wifi (IoT)" },
|
|
{ value: "Shield", label: "Shield (보안)" },
|
|
{ value: "Zap", label: "Zap (자동화)" },
|
|
];
|
|
|
|
const colorOptions = [
|
|
{ value: "", label: "선택하세요" },
|
|
{ value: "blue", label: "파랑" },
|
|
{ value: "green", label: "초록" },
|
|
{ value: "purple", label: "보라" },
|
|
{ value: "orange", label: "주황" },
|
|
{ value: "red", label: "빨강" },
|
|
{ value: "cyan", label: "청록" },
|
|
{ value: "pink", label: "분홍" },
|
|
];
|
|
|
|
export default function SolutionForm({
|
|
initialData,
|
|
onSubmit,
|
|
isSubmitting,
|
|
}: SolutionFormProps) {
|
|
const router = useRouter();
|
|
const [showEnglish, setShowEnglish] = useState(!!initialData?.title_en);
|
|
const [showJapanese, setShowJapanese] = useState(!!initialData?.title_ja);
|
|
const [showChinese, setShowChinese] = useState(!!initialData?.title_zh);
|
|
|
|
const [formData, setFormData] = useState({
|
|
title_ko: initialData?.title_ko || "",
|
|
subtitle_ko: initialData?.subtitle_ko || "",
|
|
description_ko: initialData?.description_ko || "",
|
|
features_ko: initialData?.features_ko || "",
|
|
title_en: initialData?.title_en || "",
|
|
subtitle_en: initialData?.subtitle_en || "",
|
|
description_en: initialData?.description_en || "",
|
|
features_en: initialData?.features_en || "",
|
|
title_ja: initialData?.title_ja || "",
|
|
subtitle_ja: initialData?.subtitle_ja || "",
|
|
description_ja: initialData?.description_ja || "",
|
|
features_ja: initialData?.features_ja || "",
|
|
title_zh: initialData?.title_zh || "",
|
|
subtitle_zh: initialData?.subtitle_zh || "",
|
|
description_zh: initialData?.description_zh || "",
|
|
features_zh: initialData?.features_zh || "",
|
|
icon: initialData?.icon || "",
|
|
color: initialData?.color || "",
|
|
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="title_ko"
|
|
value={formData.title_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="예: 스마트 모니터링 시스템"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
부제목
|
|
</label>
|
|
<input
|
|
type="text"
|
|
name="subtitle_ko"
|
|
value={formData.subtitle_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={4}
|
|
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="features_ko"
|
|
value={formData.features_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="예: 실시간 모니터링, 데이터 분석, 알림 기능"
|
|
/>
|
|
<p className="text-xs text-gray-500 mt-1">
|
|
기능들을 쉼표(,)로 구분하여 입력하세요
|
|
</p>
|
|
</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">
|
|
Solution Title
|
|
</label>
|
|
<input
|
|
type="text"
|
|
name="title_en"
|
|
value={formData.title_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">
|
|
Subtitle
|
|
</label>
|
|
<input
|
|
type="text"
|
|
name="subtitle_en"
|
|
value={formData.subtitle_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={4}
|
|
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">
|
|
Features (comma separated)
|
|
</label>
|
|
<textarea
|
|
name="features_en"
|
|
value={formData.features_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>
|
|
)}
|
|
</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="title_ja"
|
|
value={formData.title_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="subtitle_ja"
|
|
value={formData.subtitle_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={4}
|
|
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="features_ja"
|
|
value={formData.features_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>
|
|
)}
|
|
</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="title_zh"
|
|
value={formData.title_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="subtitle_zh"
|
|
value={formData.subtitle_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={4}
|
|
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="features_zh"
|
|
value={formData.features_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>
|
|
)}
|
|
</div>
|
|
|
|
{/* Common Fields */}
|
|
<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>
|
|
<select
|
|
name="color"
|
|
value={formData.color}
|
|
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"
|
|
>
|
|
{colorOptions.map((color) => (
|
|
<option key={color.value} value={color.value}>
|
|
{color.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/solutions")}
|
|
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>
|
|
);
|
|
}
|