"use client"; import React, { useState, useEffect } from "react"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Switch } from "@/components/ui/switch"; import { Button } from "@/components/ui/button"; import { Textarea } from "@/components/ui/textarea"; import { Radio, Plus, Trash2 } from "lucide-react"; import { WebTypeConfigPanelProps } from "@/lib/registry/types"; import { WidgetComponent, RadioTypeConfig } from "@/types/screen"; interface RadioOption { label: string; value: string; disabled?: boolean; } export const RadioConfigPanel: React.FC = ({ component, onUpdateComponent, onUpdateProperty, }) => { const widget = component as WidgetComponent; const config = (widget.webTypeConfig as RadioTypeConfig) || {}; // 로컬 상태 const [localConfig, setLocalConfig] = useState({ options: config.options || [ { label: "옵션 1", value: "option1" }, { label: "옵션 2", value: "option2" }, ], groupName: config.groupName || "", defaultValue: config.defaultValue || "", required: config.required || false, readonly: config.readonly || false, inline: config.inline !== false, // 기본값 true groupLabel: config.groupLabel || "", }); // 새 옵션 추가용 상태 const [newOptionLabel, setNewOptionLabel] = useState(""); const [newOptionValue, setNewOptionValue] = useState(""); const [bulkOptions, setBulkOptions] = useState(""); // 입력 필드용 로컬 상태 const [localInputs, setLocalInputs] = useState({ groupLabel: config.groupLabel || "", groupName: config.groupName || "", }); // 컴포넌트 변경 시 로컬 상태 동기화 useEffect(() => { const currentConfig = (widget.webTypeConfig as RadioTypeConfig) || {}; setLocalConfig({ options: currentConfig.options || [ { label: "옵션 1", value: "option1" }, { label: "옵션 2", value: "option2" }, ], groupName: currentConfig.groupName || "", defaultValue: currentConfig.defaultValue || "", required: currentConfig.required || false, readonly: currentConfig.readonly || false, inline: currentConfig.inline !== false, groupLabel: currentConfig.groupLabel || "", }); // 입력 필드 로컬 상태도 동기화 setLocalInputs({ groupLabel: currentConfig.groupLabel || "", groupName: currentConfig.groupName || "", }); }, [widget.webTypeConfig]); // 설정 업데이트 핸들러 const updateConfig = (field: keyof RadioTypeConfig, value: any) => { const newConfig = { ...localConfig, [field]: value }; setLocalConfig(newConfig); onUpdateProperty("webTypeConfig", newConfig); }; // 옵션 추가 const addOption = () => { if (!newOptionLabel.trim() || !newOptionValue.trim()) return; const newOption: RadioOption = { label: newOptionLabel.trim(), value: newOptionValue.trim(), }; const newOptions = [...localConfig.options, newOption]; updateConfig("options", newOptions); setNewOptionLabel(""); setNewOptionValue(""); }; // 옵션 제거 const removeOption = (index: number) => { const newOptions = localConfig.options.filter((_, i) => i !== index); updateConfig("options", newOptions); // 삭제된 옵션이 기본값이었다면 기본값 초기화 const removedOption = localConfig.options[index]; if (removedOption && localConfig.defaultValue === removedOption.value) { updateConfig("defaultValue", ""); } }; // 옵션 업데이트 (입력 필드용 - 로컬 상태만) const updateOptionLocal = (index: number, field: keyof RadioOption, value: any) => { const newOptions = [...localConfig.options]; const oldValue = newOptions[index].value; newOptions[index] = { ...newOptions[index], [field]: value }; // 값이 변경되고 해당 값이 기본값이었다면 기본값도 업데이트 const newConfig = { ...localConfig, options: newOptions }; if (field === "value" && localConfig.defaultValue === oldValue) { newConfig.defaultValue = value; } setLocalConfig(newConfig); }; // 옵션 업데이트 완료 (onBlur) const handleOptionBlur = () => { onUpdateProperty("webTypeConfig", localConfig); }; // 벌크 옵션 추가 const addBulkOptions = () => { if (!bulkOptions.trim()) return; const lines = bulkOptions.trim().split("\n"); const newOptions: RadioOption[] = []; lines.forEach((line) => { const trimmed = line.trim(); if (!trimmed) return; if (trimmed.includes("|")) { // "라벨|값" 형식 const [label, value] = trimmed.split("|").map((s) => s.trim()); if (label && value) { newOptions.push({ label, value }); } } else { // 라벨과 값이 같은 경우 newOptions.push({ label: trimmed, value: trimmed }); } }); if (newOptions.length > 0) { const combinedOptions = [...localConfig.options, ...newOptions]; updateConfig("options", combinedOptions); setBulkOptions(""); } }; // 기본 옵션 세트 const defaultOptionSets = { yesno: [ { label: "예", value: "Y" }, { label: "아니오", value: "N" }, ], gender: [ { label: "남성", value: "M" }, { label: "여성", value: "F" }, ], agreement: [ { label: "동의", value: "agree" }, { label: "비동의", value: "disagree" }, ], rating: [ { label: "매우 좋음", value: "5" }, { label: "좋음", value: "4" }, { label: "보통", value: "3" }, { label: "나쁨", value: "2" }, { label: "매우 나쁨", value: "1" }, ], }; const applyDefaultSet = (setName: keyof typeof defaultOptionSets) => { updateConfig("options", defaultOptionSets[setName]); }; return ( 라디오버튼 설정 라디오버튼 그룹의 옵션과 동작을 설정합니다. {/* 기본 설정 */}

기본 설정

setLocalInputs({ ...localInputs, groupLabel: e.target.value })} onBlur={() => updateConfig("groupLabel", localInputs.groupLabel)} placeholder="라디오버튼 그룹 제목" className="text-xs" />
setLocalInputs({ ...localInputs, groupName: e.target.value })} onBlur={() => updateConfig("groupName", localInputs.groupName)} placeholder="자동 생성 (필드명 기반)" className="text-xs" />

비워두면 필드명을 기반으로 자동 생성됩니다.

라디오버튼들을 가로로 배열합니다.

updateConfig("inline", checked)} />
{/* 기본 옵션 세트 */}

기본 옵션 세트

{/* 옵션 관리 */}

옵션 관리

{/* 개별 옵션 추가 */}
setNewOptionLabel(e.target.value)} placeholder="라벨" className="flex-1 text-xs" /> setNewOptionValue(e.target.value)} placeholder="값" className="flex-1 text-xs" />
{/* 벌크 옵션 추가 */}