"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 { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Plus, Trash2, List, Link2, ExternalLink } from "lucide-react"; import { WebTypeConfigPanelProps } from "@/lib/registry/types"; import { WidgetComponent, SelectTypeConfig } from "@/types/screen"; import { cascadingRelationApi, CascadingRelation } from "@/lib/api/cascadingRelation"; import Link from "next/link"; interface SelectOption { label: string; value: string; disabled?: boolean; } export const SelectConfigPanel: React.FC = ({ component, onUpdateComponent, onUpdateProperty, }) => { const widget = component as WidgetComponent; const config = (widget.webTypeConfig as SelectTypeConfig) || {}; // 로컬 상태 const [localConfig, setLocalConfig] = useState({ options: config.options || [ { label: "옵션 1", value: "option1" }, { label: "옵션 2", value: "option2" }, ], multiple: config.multiple || false, searchable: config.searchable || false, placeholder: config.placeholder || "선택하세요", defaultValue: config.defaultValue || "", required: config.required || false, readonly: config.readonly || false, emptyMessage: config.emptyMessage || "선택 가능한 옵션이 없습니다", cascadingRelationCode: config.cascadingRelationCode, cascadingParentField: config.cascadingParentField, }); // 연쇄 드롭다운 설정 상태 const [cascadingEnabled, setCascadingEnabled] = useState(!!config.cascadingRelationCode); const [selectedRelationCode, setSelectedRelationCode] = useState(config.cascadingRelationCode || ""); const [selectedParentField, setSelectedParentField] = useState(config.cascadingParentField || ""); // 연쇄 관계 목록 const [relationList, setRelationList] = useState([]); const [loadingRelations, setLoadingRelations] = useState(false); // 새 옵션 추가용 상태 const [newOptionLabel, setNewOptionLabel] = useState(""); const [newOptionValue, setNewOptionValue] = useState(""); const [bulkOptions, setBulkOptions] = useState(""); // 입력 필드용 로컬 상태 const [localInputs, setLocalInputs] = useState({ placeholder: config.placeholder || "", emptyMessage: config.emptyMessage || "", }); // 컴포넌트 변경 시 로컬 상태 동기화 useEffect(() => { const currentConfig = (widget.webTypeConfig as SelectTypeConfig) || {}; setLocalConfig({ options: currentConfig.options || [ { label: "옵션 1", value: "option1" }, { label: "옵션 2", value: "option2" }, ], multiple: currentConfig.multiple || false, searchable: currentConfig.searchable || false, placeholder: currentConfig.placeholder || "선택하세요", defaultValue: currentConfig.defaultValue || "", required: currentConfig.required || false, readonly: currentConfig.readonly || false, emptyMessage: currentConfig.emptyMessage || "선택 가능한 옵션이 없습니다", cascadingRelationCode: currentConfig.cascadingRelationCode, }); // 입력 필드 로컬 상태도 동기화 setLocalInputs({ placeholder: currentConfig.placeholder || "", emptyMessage: currentConfig.emptyMessage || "", }); // 연쇄 드롭다운 설정 동기화 setCascadingEnabled(!!currentConfig.cascadingRelationCode); setSelectedRelationCode(currentConfig.cascadingRelationCode || ""); setSelectedParentField(currentConfig.cascadingParentField || ""); }, [widget.webTypeConfig]); // 연쇄 관계 목록 로드 useEffect(() => { if (cascadingEnabled && relationList.length === 0) { loadRelationList(); } }, [cascadingEnabled]); // 연쇄 관계 목록 로드 함수 const loadRelationList = async () => { setLoadingRelations(true); try { const response = await cascadingRelationApi.getList("Y"); if (response.success && response.data) { setRelationList(response.data); } } catch (error) { console.error("연쇄 관계 목록 로드 실패:", error); } finally { setLoadingRelations(false); } }; // 설정 업데이트 핸들러 const updateConfig = (field: keyof SelectTypeConfig, value: any) => { const newConfig = { ...localConfig, [field]: value }; setLocalConfig(newConfig); onUpdateProperty("webTypeConfig", newConfig); }; // 연쇄 드롭다운 활성화/비활성화 const handleCascadingToggle = (enabled: boolean) => { setCascadingEnabled(enabled); if (!enabled) { // 비활성화 시 관계 코드 제거 setSelectedRelationCode(""); const newConfig = { ...localConfig, cascadingRelationCode: undefined }; setLocalConfig(newConfig); onUpdateProperty("webTypeConfig", newConfig); } else { // 활성화 시 관계 목록 로드 loadRelationList(); } }; // 연쇄 관계 선택 const handleRelationSelect = (code: string) => { setSelectedRelationCode(code); const newConfig = { ...localConfig, cascadingRelationCode: code || undefined }; setLocalConfig(newConfig); onUpdateProperty("webTypeConfig", newConfig); }; // 부모 필드 선택 const handleParentFieldChange = (field: string) => { setSelectedParentField(field); const newConfig = { ...localConfig, cascadingParentField: field || undefined }; setLocalConfig(newConfig); onUpdateProperty("webTypeConfig", newConfig); }; // 옵션 추가 const addOption = () => { if (!newOptionLabel.trim() || !newOptionValue.trim()) return; const newOption: SelectOption = { 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 updateOptionLocal = (index: number, field: keyof SelectOption, value: any) => { const newOptions = [...localConfig.options]; newOptions[index] = { ...newOptions[index], [field]: value }; setLocalConfig({ ...localConfig, options: newOptions }); }; // 옵션 업데이트 완료 (onBlur) const handleOptionBlur = () => { onUpdateProperty("webTypeConfig", localConfig); }; // 벌크 옵션 추가 const addBulkOptions = () => { if (!bulkOptions.trim()) return; const lines = bulkOptions.trim().split("\n"); const newOptions: SelectOption[] = []; 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" }, ], status: [ { label: "활성", value: "active" }, { label: "비활성", value: "inactive" }, { label: "대기", value: "pending" }, ], priority: [ { label: "높음", value: "high" }, { label: "보통", value: "medium" }, { label: "낮음", value: "low" }, ], }; const applyDefaultSet = (setName: keyof typeof defaultOptionSets) => { updateConfig("options", defaultOptionSets[setName]); }; // 선택된 관계 정보 const selectedRelation = relationList.find(r => r.relation_code === selectedRelationCode); return ( 선택박스 설정 드롭다운 선택박스의 옵션과 동작을 설정합니다. {/* 기본 설정 */}

기본 설정

setLocalInputs({ ...localInputs, placeholder: e.target.value })} onBlur={() => updateConfig("placeholder", localInputs.placeholder)} placeholder="선택하세요" className="text-xs" />
setLocalInputs({ ...localInputs, emptyMessage: e.target.value })} onBlur={() => updateConfig("emptyMessage", localInputs.emptyMessage)} placeholder="선택 가능한 옵션이 없습니다" className="text-xs" />

여러 옵션을 선택할 수 있습니다.

updateConfig("multiple", checked)} />

옵션을 검색할 수 있습니다.

updateConfig("searchable", checked)} />
{/* 연쇄 드롭다운 설정 */}

연쇄 드롭다운

다른 필드의 값에 따라 옵션이 동적으로 변경됩니다. (예: 창고 선택 → 해당 창고의 위치만 표시)

{cascadingEnabled && (
{/* 관계 선택 */}

미리 정의된 관계를 선택하세요.

{/* 부모 필드 설정 */} {selectedRelationCode && (
handleParentFieldChange(e.target.value)} placeholder="예: warehouse_code" className="text-xs" />

이 드롭다운의 옵션을 결정할 부모 필드의 컬럼명을 입력하세요.

)} {/* 선택된 관계 정보 표시 */} {selectedRelation && (
부모 테이블:{" "} {selectedRelation.parent_table} ({selectedRelation.parent_value_column})
자식 테이블:{" "} {selectedRelation.child_table} {" "}({selectedRelation.child_filter_column} → {selectedRelation.child_value_column})
{selectedRelation.description && (
{selectedRelation.description}
)}
)} {/* 관계 관리 페이지 링크 */}
)}
{/* 기본 옵션 세트 (연쇄 드롭다운 비활성화 시에만 표시) */} {!cascadingEnabled && (

기본 옵션 세트

)} {/* 옵션 관리 (연쇄 드롭다운 비활성화 시에만 표시) */} {!cascadingEnabled && (

옵션 관리

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