ERP-node/frontend/components/screen/panels/DetailSettingsPanel.tsx

295 lines
10 KiB
TypeScript
Raw Normal View History

2025-09-03 11:32:09 +09:00
"use client";
import React from "react";
import { Settings } from "lucide-react";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
2025-09-09 14:29:04 +09:00
import { useWebTypes } from "@/hooks/admin/useWebTypes";
2025-09-03 11:32:09 +09:00
import {
ComponentData,
WidgetComponent,
2025-09-05 21:52:19 +09:00
FileComponent,
2025-09-03 11:32:09 +09:00
WebTypeConfig,
DateTypeConfig,
NumberTypeConfig,
SelectTypeConfig,
TextTypeConfig,
TextareaTypeConfig,
CheckboxTypeConfig,
RadioTypeConfig,
FileTypeConfig,
CodeTypeConfig,
EntityTypeConfig,
ButtonTypeConfig,
TableInfo,
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";
2025-09-09 14:29:04 +09:00
import { RatingTypeConfigPanel, RatingTypeConfig } from "./webtype-configs/RatingTypeConfigPanel";
2025-09-03 11:32:09 +09:00
import { EntityTypeConfigPanel } from "./webtype-configs/EntityTypeConfigPanel";
import { ButtonConfigPanel } from "./ButtonConfigPanel";
2025-09-05 21:52:19 +09:00
import { FileComponentConfigPanel } from "./FileComponentConfigPanel";
2025-09-03 11:32:09 +09:00
interface DetailSettingsPanelProps {
selectedComponent?: ComponentData;
onUpdateProperty: (componentId: string, path: string, value: any) => void;
currentTable?: TableInfo; // 현재 화면의 테이블 정보
currentTableName?: string; // 현재 화면의 테이블명
2025-09-03 11:32:09 +09:00
}
export const DetailSettingsPanel: React.FC<DetailSettingsPanelProps> = ({
selectedComponent,
onUpdateProperty,
currentTable,
currentTableName,
}) => {
2025-09-09 14:29:04 +09:00
// 데이터베이스에서 입력 가능한 웹타입들을 동적으로 가져오기
const { webTypes } = useWebTypes({ active: "Y" });
const inputableWebTypes = webTypes.map((wt) => wt.web_type);
2025-09-03 11:32:09 +09:00
// 웹타입별 상세 설정 렌더링 함수
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}
/>
);
2025-09-09 14:29:04 +09:00
case "rating":
case "star":
case "score":
return (
<RatingTypeConfigPanel
key={`${widget.id}-rating`}
config={currentConfig as RatingTypeConfig}
onConfigChange={handleConfigChange}
/>
);
2025-09-03 11:32:09 +09:00
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);
});
}}
/>
);
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>
);
}
2025-09-05 21:52:19 +09:00
if (selectedComponent.type !== "widget" && selectedComponent.type !== "file") {
2025-09-03 11:32:09 +09:00
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" />
2025-09-05 21:52:19 +09:00
<h3 className="mb-2 text-lg font-medium text-gray-900"> </h3>
2025-09-03 11:32:09 +09:00
<p className="text-sm text-gray-500">
2025-09-05 21:52:19 +09:00
.
2025-09-03 11:32:09 +09:00
<br />
: {selectedComponent.type}
</p>
</div>
);
}
2025-09-05 21:52:19 +09:00
// 파일 컴포넌트인 경우 FileComponentConfigPanel 렌더링
if (selectedComponent.type === "file") {
const fileComponent = selectedComponent as FileComponent;
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-purple-100 px-2 py-1 text-xs font-medium text-purple-800"> </span>
</div>
<div className="mt-1 text-xs text-gray-500"> : {fileComponent.fileConfig.docTypeName}</div>
</div>
{/* 파일 컴포넌트 설정 영역 */}
<div className="flex-1 overflow-y-auto p-4">
<FileComponentConfigPanel
component={fileComponent}
onUpdateProperty={onUpdateProperty}
currentTable={currentTable}
currentTableName={currentTableName}
/>
2025-09-05 21:52:19 +09:00
</div>
</div>
);
}
2025-09-03 11:32:09 +09:00
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;