버튼 기능구현
This commit is contained in:
224
frontend/components/common/ScreenModal.tsx
Normal file
224
frontend/components/common/ScreenModal.tsx
Normal file
@@ -0,0 +1,224 @@
|
||||
"use client";
|
||||
|
||||
import React, { useState, useEffect } from "react";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { InteractiveScreenViewerDynamic } from "@/components/screen/InteractiveScreenViewerDynamic";
|
||||
import { screenApi } from "@/lib/api/screen";
|
||||
import { ComponentData } from "@/types/screen";
|
||||
import { toast } from "sonner";
|
||||
|
||||
interface ScreenModalState {
|
||||
isOpen: boolean;
|
||||
screenId: number | null;
|
||||
title: string;
|
||||
size: "sm" | "md" | "lg" | "xl";
|
||||
}
|
||||
|
||||
interface ScreenModalProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const ScreenModal: React.FC<ScreenModalProps> = ({ className }) => {
|
||||
const [modalState, setModalState] = useState<ScreenModalState>({
|
||||
isOpen: false,
|
||||
screenId: null,
|
||||
title: "",
|
||||
size: "md",
|
||||
});
|
||||
|
||||
const [screenData, setScreenData] = useState<{
|
||||
components: ComponentData[];
|
||||
screenInfo: any;
|
||||
} | null>(null);
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [screenDimensions, setScreenDimensions] = useState<{
|
||||
width: number;
|
||||
height: number;
|
||||
} | null>(null);
|
||||
|
||||
// 화면의 실제 크기 계산 함수
|
||||
const calculateScreenDimensions = (components: ComponentData[]) => {
|
||||
let maxWidth = 800; // 최소 너비
|
||||
let maxHeight = 600; // 최소 높이
|
||||
|
||||
components.forEach((component) => {
|
||||
const x = parseFloat(component.style?.positionX || "0");
|
||||
const y = parseFloat(component.style?.positionY || "0");
|
||||
const width = parseFloat(component.style?.width || "100");
|
||||
const height = parseFloat(component.style?.height || "40");
|
||||
|
||||
// 컴포넌트의 오른쪽 끝과 아래쪽 끝 계산
|
||||
const rightEdge = x + width;
|
||||
const bottomEdge = y + height;
|
||||
|
||||
maxWidth = Math.max(maxWidth, rightEdge + 50); // 여백 추가
|
||||
maxHeight = Math.max(maxHeight, bottomEdge + 50); // 여백 추가
|
||||
});
|
||||
|
||||
return {
|
||||
width: Math.min(maxWidth, window.innerWidth * 0.9), // 화면의 90%를 넘지 않도록
|
||||
height: Math.min(maxHeight, window.innerHeight * 0.8), // 화면의 80%를 넘지 않도록
|
||||
};
|
||||
};
|
||||
|
||||
// 전역 모달 이벤트 리스너
|
||||
useEffect(() => {
|
||||
const handleOpenModal = (event: CustomEvent) => {
|
||||
const { screenId, title, size } = event.detail;
|
||||
setModalState({
|
||||
isOpen: true,
|
||||
screenId,
|
||||
title,
|
||||
size,
|
||||
});
|
||||
};
|
||||
|
||||
window.addEventListener("openScreenModal", handleOpenModal as EventListener);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("openScreenModal", handleOpenModal as EventListener);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// 화면 데이터 로딩
|
||||
useEffect(() => {
|
||||
if (modalState.isOpen && modalState.screenId) {
|
||||
loadScreenData(modalState.screenId);
|
||||
}
|
||||
}, [modalState.isOpen, modalState.screenId]);
|
||||
|
||||
const loadScreenData = async (screenId: number) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
console.log("화면 데이터 로딩 시작:", screenId);
|
||||
|
||||
// 화면 정보와 레이아웃 데이터 로딩
|
||||
const [screenInfo, layoutData] = await Promise.all([
|
||||
screenApi.getScreen(screenId),
|
||||
screenApi.getLayout(screenId),
|
||||
]);
|
||||
|
||||
console.log("API 응답:", { screenInfo, layoutData });
|
||||
|
||||
// screenApi는 직접 데이터를 반환하므로 .success 체크 불필요
|
||||
if (screenInfo && layoutData) {
|
||||
const components = layoutData.components || [];
|
||||
|
||||
// 화면의 실제 크기 계산
|
||||
const dimensions = calculateScreenDimensions(components);
|
||||
setScreenDimensions(dimensions);
|
||||
|
||||
setScreenData({
|
||||
components,
|
||||
screenInfo: screenInfo,
|
||||
});
|
||||
console.log("화면 데이터 설정 완료:", {
|
||||
componentsCount: components.length,
|
||||
dimensions,
|
||||
screenInfo,
|
||||
});
|
||||
} else {
|
||||
throw new Error("화면 데이터가 없습니다");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("화면 데이터 로딩 오류:", error);
|
||||
toast.error("화면을 불러오는 중 오류가 발생했습니다.");
|
||||
handleClose();
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setModalState({
|
||||
isOpen: false,
|
||||
screenId: null,
|
||||
title: "",
|
||||
size: "md",
|
||||
});
|
||||
setScreenData(null);
|
||||
};
|
||||
|
||||
// 모달 크기 설정 - 화면 내용에 맞게 동적 조정
|
||||
const getModalStyle = () => {
|
||||
if (!screenDimensions) {
|
||||
return {
|
||||
className: "w-fit min-w-[400px] max-w-4xl max-h-[80vh] overflow-hidden",
|
||||
style: {}
|
||||
};
|
||||
}
|
||||
|
||||
// 헤더 높이와 패딩을 고려한 전체 높이 계산
|
||||
const headerHeight = 60; // DialogHeader + 패딩
|
||||
const totalHeight = screenDimensions.height + headerHeight;
|
||||
|
||||
return {
|
||||
className: "overflow-hidden p-0",
|
||||
style: {
|
||||
width: `${screenDimensions.width + 48}px`, // 헤더 패딩과 여백 고려
|
||||
height: `${Math.min(totalHeight, window.innerHeight * 0.8)}px`,
|
||||
maxWidth: '90vw',
|
||||
maxHeight: '80vh'
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const modalStyle = getModalStyle();
|
||||
|
||||
return (
|
||||
<Dialog open={modalState.isOpen} onOpenChange={handleClose}>
|
||||
<DialogContent
|
||||
className={`${modalStyle.className} ${className || ""}`}
|
||||
style={modalStyle.style}
|
||||
>
|
||||
<DialogHeader className="px-6 py-4 border-b">
|
||||
<DialogTitle>{modalState.title}</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="flex-1 overflow-hidden p-4">
|
||||
{loading ? (
|
||||
<div className="flex items-center justify-center h-full">
|
||||
<div className="text-center">
|
||||
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600 mx-auto mb-4"></div>
|
||||
<p className="text-gray-600">화면을 불러오는 중...</p>
|
||||
</div>
|
||||
</div>
|
||||
) : screenData ? (
|
||||
<div
|
||||
className="relative bg-white overflow-hidden"
|
||||
style={{
|
||||
width: (screenDimensions?.width || 800),
|
||||
height: (screenDimensions?.height || 600),
|
||||
}}
|
||||
>
|
||||
{screenData.components.map((component) => (
|
||||
<InteractiveScreenViewerDynamic
|
||||
key={component.id}
|
||||
component={component}
|
||||
allComponents={screenData.components}
|
||||
screenInfo={{
|
||||
id: modalState.screenId!,
|
||||
tableName: screenData.screenInfo?.tableName,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center justify-center h-full">
|
||||
<p className="text-gray-600">화면 데이터가 없습니다.</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default ScreenModal;
|
||||
Reference in New Issue
Block a user