2025-11-27 12:08:32 +09:00
|
|
|
/**
|
|
|
|
|
* 분할 패널 컴포넌트
|
|
|
|
|
* 좌측과 우측에 화면을 임베드합니다.
|
|
|
|
|
*
|
|
|
|
|
* 데이터 전달은 좌측 화면에 배치된 버튼의 transferData 액션으로 처리됩니다.
|
|
|
|
|
* 예: 좌측 화면에 TableListComponent + Button(transferData 액션) 배치
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
"use client";
|
|
|
|
|
|
2026-03-10 23:51:42 +09:00
|
|
|
import React, { useMemo } from "react";
|
2025-11-27 12:08:32 +09:00
|
|
|
import { EmbeddedScreen } from "./EmbeddedScreen";
|
|
|
|
|
import { Columns2 } from "lucide-react";
|
2025-11-28 14:56:11 +09:00
|
|
|
import { SplitPanelProvider } from "@/contexts/SplitPanelContext";
|
2026-03-10 23:51:42 +09:00
|
|
|
import { ResponsiveSplitPanel } from "@/components/common/ResponsiveSplitPanel";
|
2025-11-27 12:08:32 +09:00
|
|
|
|
|
|
|
|
interface ScreenSplitPanelProps {
|
|
|
|
|
screenId?: number;
|
|
|
|
|
config?: any; // 설정 패널에서 오는 config (leftScreenId, rightScreenId, splitRatio, resizable)
|
2025-11-28 18:35:34 +09:00
|
|
|
initialFormData?: Record<string, any>; // 🆕 수정 모드에서 전달되는 초기 데이터
|
2026-01-07 10:24:01 +09:00
|
|
|
groupedData?: Record<string, any>[]; // 🆕 그룹 데이터 (수정 모드에서 원본 데이터 추적용)
|
2025-11-27 12:08:32 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 분할 패널 컴포넌트
|
|
|
|
|
* 순수하게 화면 분할 기능만 제공합니다.
|
|
|
|
|
*/
|
2026-01-07 10:24:01 +09:00
|
|
|
export function ScreenSplitPanel({ screenId, config, initialFormData, groupedData }: ScreenSplitPanelProps) {
|
2025-11-28 14:56:11 +09:00
|
|
|
// config에서 splitRatio 추출 (기본값 50)
|
|
|
|
|
const configSplitRatio = config?.splitRatio ?? 50;
|
2025-11-27 12:08:32 +09:00
|
|
|
|
|
|
|
|
// 설정 패널에서 오는 간단한 config를 임베딩 설정으로 변환
|
2026-03-11 00:12:03 +09:00
|
|
|
const now = new Date().toISOString();
|
|
|
|
|
|
2025-11-27 12:08:32 +09:00
|
|
|
const leftEmbedding = config?.leftScreenId
|
|
|
|
|
? {
|
|
|
|
|
id: 1,
|
|
|
|
|
parentScreenId: screenId || 0,
|
|
|
|
|
childScreenId: config.leftScreenId,
|
|
|
|
|
position: "left" as const,
|
2026-03-11 00:12:03 +09:00
|
|
|
mode: "view" as const,
|
2025-11-27 12:08:32 +09:00
|
|
|
config: {},
|
|
|
|
|
companyCode: "*",
|
2026-03-11 00:12:03 +09:00
|
|
|
createdAt: now,
|
|
|
|
|
updatedAt: now,
|
2025-11-27 12:08:32 +09:00
|
|
|
}
|
|
|
|
|
: null;
|
|
|
|
|
|
|
|
|
|
const rightEmbedding = config?.rightScreenId
|
|
|
|
|
? {
|
|
|
|
|
id: 2,
|
|
|
|
|
parentScreenId: screenId || 0,
|
|
|
|
|
childScreenId: config.rightScreenId,
|
|
|
|
|
position: "right" as const,
|
2026-03-11 00:12:03 +09:00
|
|
|
mode: "view" as const,
|
2025-11-27 12:08:32 +09:00
|
|
|
config: {},
|
|
|
|
|
companyCode: "*",
|
2026-03-11 00:12:03 +09:00
|
|
|
createdAt: now,
|
|
|
|
|
updatedAt: now,
|
2025-11-27 12:08:32 +09:00
|
|
|
}
|
|
|
|
|
: null;
|
|
|
|
|
|
2025-11-28 14:56:11 +09:00
|
|
|
// config가 없는 경우 (디자이너 모드 또는 초기 상태)
|
|
|
|
|
if (!config) {
|
2025-11-27 12:08:32 +09:00
|
|
|
return (
|
|
|
|
|
<div className="border-muted-foreground/25 flex h-full items-center justify-center rounded-lg border-2 border-dashed">
|
|
|
|
|
<div className="space-y-4 p-6 text-center">
|
|
|
|
|
<div className="flex items-center justify-center gap-3">
|
|
|
|
|
<div className="bg-muted flex h-16 w-16 items-center justify-center rounded-lg">
|
|
|
|
|
<Columns2 className="text-muted-foreground h-8 w-8" />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<p className="text-muted-foreground mb-2 text-base font-semibold">화면 분할 패널</p>
|
|
|
|
|
<p className="text-muted-foreground/60 mb-1 text-xs">좌우로 화면을 나눕니다</p>
|
|
|
|
|
<p className="text-muted-foreground/60 text-xs">
|
|
|
|
|
우측 속성 패널 → 상세 설정에서 좌측/우측 화면을 선택하세요
|
|
|
|
|
</p>
|
|
|
|
|
<p className="text-muted-foreground/60 mt-2 text-[10px]">
|
|
|
|
|
💡 데이터 전달: 좌측 화면에 버튼 배치 후 transferData 액션 설정
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-28 14:56:11 +09:00
|
|
|
// 좌측 또는 우측 화면이 설정되지 않은 경우 안내 메시지 표시
|
|
|
|
|
const hasLeftScreen = !!leftEmbedding;
|
|
|
|
|
const hasRightScreen = !!rightEmbedding;
|
|
|
|
|
|
|
|
|
|
// 분할 패널 고유 ID 생성
|
|
|
|
|
const splitPanelId = useMemo(() => `split-panel-${screenId || "unknown"}-${Date.now()}`, [screenId]);
|
2025-11-27 12:08:32 +09:00
|
|
|
|
2025-11-28 14:56:11 +09:00
|
|
|
return (
|
|
|
|
|
<SplitPanelProvider
|
|
|
|
|
splitPanelId={splitPanelId}
|
|
|
|
|
leftScreenId={config?.leftScreenId || null}
|
|
|
|
|
rightScreenId={config?.rightScreenId || null}
|
2025-12-01 18:39:01 +09:00
|
|
|
parentDataMapping={config?.parentDataMapping || []}
|
2025-12-02 18:03:52 +09:00
|
|
|
linkedFilters={config?.linkedFilters || []}
|
2025-12-05 14:08:07 +09:00
|
|
|
disableAutoDataTransfer={config?.disableAutoDataTransfer ?? false}
|
2025-11-28 14:56:11 +09:00
|
|
|
>
|
2026-03-10 23:51:42 +09:00
|
|
|
<ResponsiveSplitPanel
|
|
|
|
|
left={
|
|
|
|
|
hasLeftScreen ? (
|
2026-01-07 10:24:01 +09:00
|
|
|
<EmbeddedScreen embedding={leftEmbedding!} position="left" initialFormData={initialFormData} groupedData={groupedData} />
|
2025-11-28 14:56:11 +09:00
|
|
|
) : (
|
|
|
|
|
<div className="flex h-full items-center justify-center bg-muted/30">
|
|
|
|
|
<p className="text-muted-foreground text-sm">좌측 화면을 선택하세요</p>
|
|
|
|
|
</div>
|
2026-03-10 23:51:42 +09:00
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
right={
|
|
|
|
|
hasRightScreen ? (
|
2026-01-07 10:24:01 +09:00
|
|
|
<EmbeddedScreen embedding={rightEmbedding!} position="right" initialFormData={initialFormData} groupedData={groupedData} />
|
2025-11-28 14:56:11 +09:00
|
|
|
) : (
|
|
|
|
|
<div className="flex h-full items-center justify-center bg-muted/30">
|
|
|
|
|
<p className="text-muted-foreground text-sm">우측 화면을 선택하세요</p>
|
|
|
|
|
</div>
|
2026-03-10 23:51:42 +09:00
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
leftTitle="좌측 패널"
|
|
|
|
|
leftWidth={configSplitRatio}
|
|
|
|
|
minLeftWidth={20}
|
|
|
|
|
maxLeftWidth={80}
|
|
|
|
|
showResizer={config?.resizable !== false}
|
|
|
|
|
collapsedOnMobile={true}
|
|
|
|
|
/>
|
2025-11-28 14:56:11 +09:00
|
|
|
</SplitPanelProvider>
|
2025-11-27 12:08:32 +09:00
|
|
|
);
|
|
|
|
|
}
|