2025-09-03 11:32:09 +09:00
|
|
|
"use client";
|
|
|
|
|
|
|
|
|
|
import React from "react";
|
|
|
|
|
import { Settings } from "lucide-react";
|
|
|
|
|
import {
|
|
|
|
|
ComponentData,
|
|
|
|
|
WidgetComponent,
|
|
|
|
|
WebTypeConfig,
|
|
|
|
|
DateTypeConfig,
|
|
|
|
|
NumberTypeConfig,
|
|
|
|
|
SelectTypeConfig,
|
|
|
|
|
TextTypeConfig,
|
|
|
|
|
TextareaTypeConfig,
|
|
|
|
|
CheckboxTypeConfig,
|
|
|
|
|
RadioTypeConfig,
|
|
|
|
|
FileTypeConfig,
|
|
|
|
|
CodeTypeConfig,
|
|
|
|
|
EntityTypeConfig,
|
2025-09-04 11:33:52 +09:00
|
|
|
ButtonTypeConfig,
|
2025-09-03 11:32:09 +09:00
|
|
|
} 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 { EntityTypeConfigPanel } from "./webtype-configs/EntityTypeConfigPanel";
|
2025-09-04 11:33:52 +09:00
|
|
|
import { ButtonConfigPanel } from "./ButtonConfigPanel";
|
2025-09-03 11:32:09 +09:00
|
|
|
|
|
|
|
|
interface DetailSettingsPanelProps {
|
|
|
|
|
selectedComponent?: ComponentData;
|
|
|
|
|
onUpdateProperty: (componentId: string, path: string, value: any) => void;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const DetailSettingsPanel: React.FC<DetailSettingsPanelProps> = ({ selectedComponent, onUpdateProperty }) => {
|
|
|
|
|
// 웹타입별 상세 설정 렌더링 함수
|
|
|
|
|
const renderWebTypeConfig = React.useCallback(
|
|
|
|
|
(widget: WidgetComponent) => {
|
|
|
|
|
const currentConfig = widget.webTypeConfig || {};
|
|
|
|
|
|
|
|
|
|
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(),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
switch (widget.widgetType) {
|
|
|
|
|
case "date":
|
|
|
|
|
case "datetime":
|
|
|
|
|
return (
|
|
|
|
|
<DateTypeConfigPanel
|
|
|
|
|
key={`date-config-${widget.id}`}
|
|
|
|
|
config={currentConfig as DateTypeConfig}
|
|
|
|
|
onConfigChange={handleConfigChange}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
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 "entity":
|
|
|
|
|
return (
|
|
|
|
|
<EntityTypeConfigPanel
|
|
|
|
|
key={`${widget.id}-entity`}
|
|
|
|
|
config={currentConfig as EntityTypeConfig}
|
|
|
|
|
onConfigChange={handleConfigChange}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
|
2025-09-04 11:33:52 +09:00
|
|
|
case "button":
|
|
|
|
|
return (
|
|
|
|
|
<ButtonConfigPanel
|
|
|
|
|
key={`${widget.id}-button`}
|
|
|
|
|
component={widget}
|
|
|
|
|
onUpdateComponent={(updates) => {
|
|
|
|
|
Object.entries(updates).forEach(([key, value]) => {
|
|
|
|
|
onUpdateProperty(widget.id, key, value);
|
|
|
|
|
});
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
|
2025-09-03 11:32:09 +09:00
|
|
|
default:
|
|
|
|
|
return <div className="text-sm text-gray-500 italic">해당 웹타입의 상세 설정이 지원되지 않습니다.</div>;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
[onUpdateProperty],
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (!selectedComponent) {
|
|
|
|
|
return (
|
|
|
|
|
<div className="flex h-full flex-col items-center justify-center p-6 text-center">
|
|
|
|
|
<Settings className="mb-4 h-12 w-12 text-gray-400" />
|
|
|
|
|
<h3 className="mb-2 text-lg font-medium text-gray-900">컴포넌트를 선택하세요</h3>
|
|
|
|
|
<p className="text-sm text-gray-500">위젯 컴포넌트를 선택하면 상세 설정을 편집할 수 있습니다.</p>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (selectedComponent.type !== "widget") {
|
|
|
|
|
return (
|
|
|
|
|
<div className="flex h-full flex-col items-center justify-center p-6 text-center">
|
|
|
|
|
<Settings className="mb-4 h-12 w-12 text-gray-400" />
|
|
|
|
|
<h3 className="mb-2 text-lg font-medium text-gray-900">위젯 컴포넌트가 아닙니다</h3>
|
|
|
|
|
<p className="text-sm text-gray-500">
|
|
|
|
|
상세 설정은 위젯 컴포넌트에서만 사용할 수 있습니다.
|
|
|
|
|
<br />
|
|
|
|
|
현재 선택된 컴포넌트: {selectedComponent.type}
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const widget = selectedComponent as WidgetComponent;
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="flex h-full flex-col">
|
|
|
|
|
{/* 헤더 */}
|
|
|
|
|
<div className="border-b border-gray-200 p-4">
|
|
|
|
|
<div className="flex items-center space-x-2">
|
|
|
|
|
<Settings className="h-4 w-4 text-gray-600" />
|
|
|
|
|
<h3 className="font-medium text-gray-900">상세 설정</h3>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="mt-2 flex items-center space-x-2">
|
|
|
|
|
<span className="text-sm text-gray-600">웹타입:</span>
|
|
|
|
|
<span className="rounded bg-blue-100 px-2 py-1 text-xs font-medium text-blue-800">{widget.widgetType}</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="mt-1 text-xs text-gray-500">컬럼: {widget.columnName}</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* 상세 설정 영역 */}
|
|
|
|
|
<div className="flex-1 overflow-y-auto p-4">{renderWebTypeConfig(widget)}</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default DetailSettingsPanel;
|