웹 타입 설정패널 분리

This commit is contained in:
kjs
2025-09-09 15:42:04 +09:00
parent a17602c643
commit 49c8f9a2dd
12 changed files with 357 additions and 243 deletions

View File

@@ -3063,6 +3063,7 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
autoHeight={true}
>
<DetailSettingsPanel
key={`detail-settings-${selectedComponent?.id}-${selectedComponent?.type === "widget" ? (selectedComponent as any).widgetType : "non-widget"}`}
selectedComponent={selectedComponent || undefined}
onUpdateProperty={(componentId: string, path: string, value: any) => {
updateComponentProperty(componentId, path, value);

View File

@@ -4,35 +4,8 @@ import React from "react";
import { Settings } from "lucide-react";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { useWebTypes } from "@/hooks/admin/useWebTypes";
import {
ComponentData,
WidgetComponent,
FileComponent,
WebTypeConfig,
DateTypeConfig,
NumberTypeConfig,
SelectTypeConfig,
TextTypeConfig,
TextareaTypeConfig,
CheckboxTypeConfig,
RadioTypeConfig,
FileTypeConfig,
CodeTypeConfig,
EntityTypeConfig,
ButtonTypeConfig,
TableInfo,
} from "@/types/screen";
import { DateTypeConfigPanel } from "./webtype-configs/DateTypeConfigPanel";
import { NumberTypeConfigPanel } from "./webtype-configs/NumberTypeConfigPanel";
import { SelectTypeConfigPanel } from "./webtype-configs/SelectTypeConfigPanel";
import { TextTypeConfigPanel } from "./webtype-configs/TextTypeConfigPanel";
import { TextareaTypeConfigPanel } from "./webtype-configs/TextareaTypeConfigPanel";
import { CheckboxTypeConfigPanel } from "./webtype-configs/CheckboxTypeConfigPanel";
import { RadioTypeConfigPanel } from "./webtype-configs/RadioTypeConfigPanel";
import { FileTypeConfigPanel } from "./webtype-configs/FileTypeConfigPanel";
import { CodeTypeConfigPanel } from "./webtype-configs/CodeTypeConfigPanel";
import { RatingTypeConfigPanel, RatingTypeConfig } from "./webtype-configs/RatingTypeConfigPanel";
import { EntityTypeConfigPanel } from "./webtype-configs/EntityTypeConfigPanel";
import { getConfigPanelComponent } from "@/lib/utils/getConfigPanelComponent";
import { ComponentData, WidgetComponent, FileComponent, WebTypeConfig, TableInfo } from "@/types/screen";
import { ButtonConfigPanel } from "./ButtonConfigPanel";
import { FileComponentConfigPanel } from "./FileComponentConfigPanel";
@@ -51,166 +24,77 @@ export const DetailSettingsPanel: React.FC<DetailSettingsPanelProps> = ({
}) => {
// 데이터베이스에서 입력 가능한 웹타입들을 동적으로 가져오기
const { webTypes } = useWebTypes({ active: "Y" });
console.log(`🔍 DetailSettingsPanel webTypes 로드됨:`, webTypes?.length, "개");
console.log(`🔍 webTypes:`, webTypes);
console.log(`🔍 DetailSettingsPanel selectedComponent:`, selectedComponent);
console.log(`🔍 DetailSettingsPanel selectedComponent.widgetType:`, selectedComponent?.widgetType);
const inputableWebTypes = webTypes.map((wt) => wt.web_type);
// 웹타입별 상세 설정 렌더링 함수
const renderWebTypeConfig = React.useCallback(
(widget: WidgetComponent) => {
const currentConfig = widget.webTypeConfig || {};
// 웹타입별 상세 설정 렌더링 함수 - useCallback 제거하여 항상 최신 widget 사용
const renderWebTypeConfig = (widget: WidgetComponent) => {
const currentConfig = widget.webTypeConfig || {};
console.log("🎨 DetailSettingsPanel renderWebTypeConfig 호출:", {
componentId: widget.id,
console.log("🎨 DetailSettingsPanel renderWebTypeConfig 호출:", {
componentId: widget.id,
widgetType: widget.widgetType,
currentConfig,
configExists: !!currentConfig,
configKeys: Object.keys(currentConfig),
configStringified: JSON.stringify(currentConfig),
widgetWebTypeConfig: widget.webTypeConfig,
widgetWebTypeConfigExists: !!widget.webTypeConfig,
timestamp: new Date().toISOString(),
});
console.log("🎨 selectedComponent 전체:", selectedComponent);
const handleConfigChange = (newConfig: WebTypeConfig) => {
console.log("🔧 WebTypeConfig 업데이트:", {
widgetType: widget.widgetType,
currentConfig,
configExists: !!currentConfig,
configKeys: Object.keys(currentConfig),
configStringified: JSON.stringify(currentConfig),
widgetWebTypeConfig: widget.webTypeConfig,
widgetWebTypeConfigExists: !!widget.webTypeConfig,
timestamp: new Date().toISOString(),
oldConfig: currentConfig,
newConfig,
componentId: widget.id,
isEqual: JSON.stringify(currentConfig) === JSON.stringify(newConfig),
});
const handleConfigChange = (newConfig: WebTypeConfig) => {
console.log("🔧 WebTypeConfig 업데이트:", {
widgetType: widget.widgetType,
oldConfig: currentConfig,
newConfig,
componentId: widget.id,
isEqual: JSON.stringify(currentConfig) === JSON.stringify(newConfig),
});
// 강제 새 객체 생성으로 React 변경 감지 보장
const freshConfig = { ...newConfig };
onUpdateProperty(widget.id, "webTypeConfig", freshConfig);
};
// 강제 새 객체 생성으로 React 변경 감지 보장
const freshConfig = { ...newConfig };
onUpdateProperty(widget.id, "webTypeConfig", freshConfig);
};
// 1순위: DB에서 지정된 설정 패널 사용
const dbWebType = webTypes.find((wt) => wt.web_type === widget.widgetType);
console.log(`🎨 웹타입 "${widget.widgetType}" DB 조회 결과:`, dbWebType);
switch (widget.widgetType) {
case "date":
case "datetime":
return (
<DateTypeConfigPanel
key={`date-config-${widget.id}`}
config={currentConfig as DateTypeConfig}
onConfigChange={handleConfigChange}
/>
);
if (dbWebType?.config_panel) {
console.log(`🎨 웹타입 "${widget.widgetType}" → DB 지정 설정 패널 "${dbWebType.config_panel}" 사용`);
const ConfigPanelComponent = getConfigPanelComponent(dbWebType.config_panel);
console.log(`🎨 getConfigPanelComponent 결과:`, ConfigPanelComponent);
case "number":
case "decimal":
return (
<NumberTypeConfigPanel
key={`${widget.id}-number`}
config={currentConfig as NumberTypeConfig}
onConfigChange={handleConfigChange}
/>
);
case "select":
case "dropdown":
return (
<SelectTypeConfigPanel
key={`${widget.id}-select`}
config={currentConfig as SelectTypeConfig}
onConfigChange={handleConfigChange}
/>
);
case "text":
case "email":
case "tel":
return (
<TextTypeConfigPanel
key={`${widget.id}-text`}
config={currentConfig as TextTypeConfig}
onConfigChange={handleConfigChange}
/>
);
case "textarea":
return (
<TextareaTypeConfigPanel
key={`${widget.id}-textarea`}
config={currentConfig as TextareaTypeConfig}
onConfigChange={handleConfigChange}
/>
);
case "checkbox":
case "boolean":
return (
<CheckboxTypeConfigPanel
key={`${widget.id}-checkbox`}
config={currentConfig as CheckboxTypeConfig}
onConfigChange={handleConfigChange}
/>
);
case "radio":
return (
<RadioTypeConfigPanel
key={`${widget.id}-radio`}
config={currentConfig as RadioTypeConfig}
onConfigChange={handleConfigChange}
/>
);
case "file":
return (
<FileTypeConfigPanel
key={`${widget.id}-file`}
config={currentConfig as FileTypeConfig}
onConfigChange={handleConfigChange}
/>
);
case "code":
return (
<CodeTypeConfigPanel
key={`${widget.id}-code`}
config={currentConfig as CodeTypeConfig}
onConfigChange={handleConfigChange}
/>
);
case "rating":
case "star":
case "score":
return (
<RatingTypeConfigPanel
key={`${widget.id}-rating`}
config={currentConfig as RatingTypeConfig}
onConfigChange={handleConfigChange}
/>
);
case "entity":
return (
<EntityTypeConfigPanel
key={`${widget.id}-entity`}
config={currentConfig as EntityTypeConfig}
onConfigChange={handleConfigChange}
/>
);
case "button":
return (
<ButtonConfigPanel
key={`${widget.id}-button`}
component={widget}
onUpdateComponent={(updates) => {
Object.entries(updates).forEach(([key, value]) => {
onUpdateProperty(widget.id, key, value);
});
}}
/>
);
default:
return <div className="text-sm text-gray-500 italic"> .</div>;
if (ConfigPanelComponent) {
console.log(`🎨 ✅ ConfigPanelComponent 렌더링 시작`);
return <ConfigPanelComponent config={currentConfig} onConfigChange={handleConfigChange} />;
} else {
console.log(`🎨 ❌ ConfigPanelComponent가 null - 기본 설정 표시`);
return (
<div className="py-8 text-center text-gray-500">
<br />
"{widget.widgetType}" .
</div>
);
}
},
[onUpdateProperty],
);
} else {
console.log(`🎨 config_panel이 없음 - 기본 설정 표시`);
return (
<div className="py-8 text-center text-gray-500">
<br />
"{widget.widgetType}" .
</div>
);
}
};
if (!selectedComponent) {
return (

View File

@@ -1,6 +1,6 @@
"use client";
import React, { useState, useEffect, useRef, useMemo } from "react";
import React, { useState, useEffect, useRef } from "react";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
@@ -20,7 +20,6 @@ import {
TableInfo,
} from "@/types/screen";
import DataTableConfigPanel from "./DataTableConfigPanel";
import { DynamicConfigPanel } from "@/lib/registry";
import { useWebTypes } from "@/hooks/admin/useWebTypes";
// DataTableConfigPanel을 위한 안정화된 래퍼 컴포넌트
@@ -351,39 +350,6 @@ const PropertiesPanelComponent: React.FC<PropertiesPanelProps> = ({
</select>
</div>
{/* 동적 웹타입 설정 패널 */}
{selectedComponent.widgetType && (
<div className="space-y-3">
<Separator />
<div>
<Label className="text-sm font-medium"> </Label>
<div className="mt-2">
<DynamicConfigPanel
webType={selectedComponent.widgetType}
component={selectedComponent}
onUpdateComponent={(updatedComponent) => {
// 컴포넌트 전체 업데이트
Object.keys(updatedComponent).forEach((key) => {
if (key !== "id") {
onUpdateProperty(key, updatedComponent[key]);
}
});
}}
onUpdateProperty={(property, value) => {
// 웹타입 설정 업데이트
if (property === "webTypeConfig") {
onUpdateProperty("webTypeConfig", value);
} else {
onUpdateProperty(property, value);
}
}}
/>
</div>
</div>
<Separator />
</div>
)}
<div>
<Label htmlFor="placeholder" className="text-sm font-medium">