"use client"; import React, { useEffect, useState } from "react"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Loader2 } from "lucide-react"; import { toast } from "sonner"; import { FieldRenderer } from "../Field/FieldRenderer"; import { DataViewRenderer } from "../DataView/DataViewRenderer"; import { ActionRenderer } from "../Action/ActionRenderer"; import { ReactiveBindingEngine } from "../bindings/ReactiveBindingEngine"; import { getFieldConfig, getTableColumns, saveLayout, getLayout, saveBindings, getBindings, type FieldConfigResponse, type TableColumnsResponse, } from "@/lib/api/metaComponent"; import type { FieldConfig } from "../Field/fieldTypes"; import type { DataViewConfig } from "../DataView/dataViewTypes"; import type { ActionConfig } from "../Action/actionTypes"; import type { ReactiveBinding } from "../bindings/bindingTypes"; /** * 메타 컴포넌트 V3 사용 예시 * * Phase A 구현 범위: * 1. Field 자동 생성 (테이블 컬럼 기반) * 2. DataView 렌더링 (테이블/카드 뷰) * 3. Action 버튼 + 파이프라인 * 4. Reactive Binding 설정 및 실행 */ export function MetaComponentExample() { const [loading, setLoading] = useState(true); const [fieldConfigs, setFieldConfigs] = useState([]); const [dataViewConfig, setDataViewConfig] = useState(null); const [bindingEngine] = useState(() => new ReactiveBindingEngine()); // 예시: user_info 테이블 기반 화면 자동 생성 useEffect(() => { loadMetaComponents(); }, []); /** * 백엔드 API 호출하여 메타 컴포넌트 자동 생성 */ async function loadMetaComponents() { try { setLoading(true); // 1. 테이블 컬럼 목록 조회 (webType + FK 관계 자동 감지) const columnsResponse = await getTableColumns("user_info"); if (!columnsResponse.success || !columnsResponse.data) { throw new Error("테이블 컬럼 조회 실패"); } // 2. 각 컬럼별 Field Config 자동 생성 const configs: FieldConfig[] = []; for (const column of columnsResponse.data.columns) { const configResponse = await getFieldConfig("user_info", column.columnName); if (configResponse.success && configResponse.data) { configs.push({ id: `field_${column.columnName}`, type: "meta-field", webType: configResponse.data.webType, label: configResponse.data.label, binding: column.columnName, placeholder: configResponse.data.placeholder, defaultValue: configResponse.data.defaultValue, required: configResponse.data.required, maxLength: configResponse.data.maxLength, validation: configResponse.data.validation, options: configResponse.data.options, join: configResponse.data.join, }); } } setFieldConfigs(configs); // 3. DataView 설정 (테이블 뷰) setDataViewConfig({ id: "dataview_user_list", type: "meta-dataview", viewMode: "table", tableName: "user_info", columns: columnsResponse.data.columns.map(col => ({ field: col.columnName, header: col.columnComment || col.columnName, webType: col.webType, })), pagination: { enabled: true, pageSize: 20, pageSizeOptions: [10, 20, 50, 100], }, actions: { add: { enabled: true, label: "등록", icon: "plus", }, edit: { enabled: true, label: "수정", icon: "pencil", }, delete: { enabled: true, label: "삭제", icon: "trash", confirmMessage: "정말로 삭제하시겠습니까?", }, }, }); // 4. Reactive Binding 설정 (예시: 부서 선택 → 사용자 목록 필터링) const bindings: ReactiveBinding[] = [ { id: "binding_dept_filter", sourceComponent: "field_dept_code", sourceEvent: "onChange", targetComponent: "dataview_user_list", targetAction: "filter", condition: { type: "expression", expression: "source.value !== ''", }, transform: { config: { filterField: "dept_code", filterOperator: "equals", filterValue: "{{source.value}}", }, }, priority: 10, enabled: true, }, ]; bindingEngine.setBindings(bindings); toast.success("메타 컴포넌트 로드 완료!"); } catch (error: any) { console.error("메타 컴포넌트 로드 실패:", error); toast.error(error.message || "메타 컴포넌트 로드 실패"); } finally { setLoading(false); } } /** * 레이아웃 저장 (screen_layouts_v3 테이블에 version "3.0"로 저장) */ async function handleSaveLayout() { try { const layoutData = { version: "3.0" as const, screenId: 123, // 실제 화면 ID layerId: 1, components: [ ...fieldConfigs, ...(dataViewConfig ? [dataViewConfig] : []), ], layers: [ { id: 1, name: "기본", visible: true, order: 1 }, ], metadata: { lastModified: new Date().toISOString(), description: "사용자 관리 화면 (메타 컴포넌트 V3)", }, }; const response = await saveLayout(layoutData); if (response.success) { toast.success("레이아웃 저장 완료!"); } else { throw new Error(response.error || "저장 실패"); } } catch (error: any) { console.error("레이아웃 저장 실패:", error); toast.error(error.message || "레이아웃 저장 실패"); } } /** * Reactive Binding 저장 */ async function handleSaveBindings() { try { const bindings = bindingEngine.getBindings(); const response = await saveBindings({ screenId: 123, bindings, }); if (response.success) { toast.success("바인딩 저장 완료!"); } else { throw new Error(response.error || "저장 실패"); } } catch (error: any) { console.error("바인딩 저장 실패:", error); toast.error(error.message || "바인딩 저장 실패"); } } if (loading) { return (

메타 컴포넌트 로딩 중...

); } return (
{/* 헤더 */} 메타 컴포넌트 V3 예시 테이블 컬럼 기반 자동 화면 생성 (Phase A) {/* Field 컴포넌트들 (자동 생성) */} 필드 목록 table_type_columns의 webType 기반 자동 생성 {fieldConfigs.map((config) => (
{ console.log(`${config.binding} 변경:`, value); // Reactive Binding 실행 bindingEngine.emitEvent(config.id, "onChange", { value }); }} />
))}
{/* DataView 컴포넌트 (자동 생성) */} {dataViewConfig && ( 데이터 뷰 테이블/카드/리스트 뷰 전환 가능 { console.log("액션 클릭:", action, rowData); toast.info(`${action} 액션 실행`); }} /> )} {/* Action 컴포넌트 예시 */} 액션 버튼 버튼 + steps 파이프라인 (Phase B에서 완전 구현 예정) { console.log("저장 버튼 클릭"); toast.success("저장 완료!"); }} /> { console.log("삭제 버튼 클릭"); toast.error("삭제 완료!"); }} />
); }