ERP-node/frontend/components/report/designer/modals/ComponentPreviewPanel.tsx

157 lines
4.5 KiB
TypeScript

"use client";
/**
* ComponentPreviewPanel.tsx — 범용 컴포넌트 미리보기 패널
*
* 모든 컴포넌트 타입의 미리보기를 통일된 레이아웃(회색 그리드 + 가운데 배치)으로 제공.
* 카드/테이블 전용 패널을 대체하는 단일 진입점.
*/
import React, { useCallback, useMemo } from "react";
import { Eye } from "lucide-react";
import type { ComponentConfig } from "@/types/report";
import type { QueryResult } from "../renderers/types";
import { TextRenderer } from "../renderers/TextRenderer";
import { ImageRenderer } from "../renderers/ImageRenderer";
import { DividerRenderer } from "../renderers/DividerRenderer";
import { SignatureRenderer, StampRenderer } from "../renderers/SignatureRenderer";
import { PageNumberRenderer } from "../renderers/PageNumberRenderer";
import { CardRenderer } from "../renderers/CardRenderer";
import { CalculationRenderer } from "../renderers/CalculationRenderer";
import { BarcodeCanvasRenderer } from "../renderers/BarcodeCanvasRenderer";
import { CheckboxRenderer } from "../renderers/CheckboxRenderer";
import { TableRenderer } from "../renderers/TableRenderer";
interface ComponentPreviewPanelProps {
component: ComponentConfig;
}
const DUMMY_LAYOUT_CONFIG = {
pages: [{ page_id: "preview_page", page_order: 1 }],
};
export function ComponentPreviewPanel({ component }: ComponentPreviewPanelProps) {
const dummyGetQueryResult = useCallback(
(): QueryResult | null => null,
[],
);
const previewWidth = useMemo(
() => Math.min(component.width || 700, 700),
[component.width],
);
const previewHeight = useMemo(
() => Math.min(component.height || 400, 550),
[component.height],
);
const renderContent = () => {
switch (component.type) {
case "text":
case "label":
return (
<TextRenderer
component={component}
getQueryResult={dummyGetQueryResult}
displayValue={component.content || component.text || "텍스트 미리보기"}
/>
);
case "image":
return <ImageRenderer component={component} />;
case "divider":
return <DividerRenderer component={component} />;
case "signature":
return <SignatureRenderer component={component} />;
case "stamp":
return <StampRenderer component={component} />;
case "pageNumber":
return (
<PageNumberRenderer
component={component}
currentPageId="preview_page"
layoutConfig={DUMMY_LAYOUT_CONFIG}
/>
);
case "card":
return (
<CardRenderer
component={component}
getQueryResult={dummyGetQueryResult}
/>
);
case "table":
return (
<TableRenderer
component={component}
getQueryResult={dummyGetQueryResult}
/>
);
case "calculation":
return (
<CalculationRenderer
component={component}
getQueryResult={dummyGetQueryResult}
/>
);
case "barcode":
return (
<BarcodeCanvasRenderer
component={component}
getQueryResult={dummyGetQueryResult}
/>
);
case "checkbox":
return (
<CheckboxRenderer
component={component}
getQueryResult={dummyGetQueryResult}
/>
);
default:
return (
<div className="flex h-full w-full items-center justify-center text-sm text-gray-400">
.
</div>
);
}
};
return (
<div className="flex shrink-0 flex-col items-center gap-4 p-5">
<div className="w-full">
<div className="mb-1 flex items-center gap-2 text-sm font-semibold text-gray-700">
<Eye className="h-4 w-4 text-blue-600" />
( )
</div>
<p className="text-xs text-muted-foreground">
.
</p>
</div>
<div className="flex min-h-[600px] w-full items-center justify-center overflow-auto rounded-xl border border-gray-200 bg-gray-100 p-8">
<div
className="overflow-hidden rounded-lg border border-gray-300 bg-white shadow-sm"
style={{
width: previewWidth,
minHeight: previewHeight,
}}
>
{renderContent()}
</div>
</div>
</div>
);
}