"use client"; import { useState, useCallback, useRef } from "react"; import { ScreenDefinition, ComponentData, LayoutData, Position, ScreenResolution, SCREEN_RESOLUTIONS, } from "@/types/screen"; import { generateComponentId } from "@/lib/utils/generateId"; import { screenApi } from "@/lib/api/screen"; import { toast } from "sonner"; import { RealtimePreview } from "./RealtimePreviewDynamic"; import DesignerToolbar from "./DesignerToolbar"; interface SimpleScreenDesignerProps { selectedScreen: ScreenDefinition | null; onBackToList: () => void; } export default function SimpleScreenDesigner({ selectedScreen, onBackToList }: SimpleScreenDesignerProps) { const [layout, setLayout] = useState({ components: [], }); const [isSaving, setIsSaving] = useState(false); const [screenResolution, setScreenResolution] = useState(SCREEN_RESOLUTIONS[0]); const [selectedComponent, setSelectedComponent] = useState(null); // 드래그 상태 const [dragState, setDragState] = useState({ isDragging: false, draggedComponent: null as ComponentData | null, originalPosition: { x: 0, y: 0, z: 1 }, currentPosition: { x: 0, y: 0, z: 1 }, grabOffset: { x: 0, y: 0 }, }); const canvasRef = useRef(null); // 레이아웃 저장 const handleSave = useCallback(async () => { if (!selectedScreen?.screenId) return; setIsSaving(true); try { const layoutWithResolution = { ...layout, screenResolution: screenResolution, }; await screenApi.saveLayout(selectedScreen.screenId, layoutWithResolution); toast.success("화면이 저장되었습니다."); } catch (error) { // console.error("저장 실패:", error); toast.error("저장 중 오류가 발생했습니다."); } finally { setIsSaving(false); } }, [selectedScreen?.screenId, layout, screenResolution]); // 컴포넌트 추가 const addComponent = useCallback((type: ComponentData["type"], position: Position) => { const newComponent: ComponentData = { id: generateComponentId(), type: type, position: position, size: { width: 200, height: 80 }, title: `새 ${type}`, ...(type === "widget" && { webType: "text" as const, label: "라벨", placeholder: "입력하세요", }), } as ComponentData; setLayout((prev) => ({ ...prev, components: [...prev.components, newComponent], })); }, []); // 드래그 시작 const startDrag = useCallback((component: ComponentData, event: React.MouseEvent) => { event.preventDefault(); const rect = canvasRef.current?.getBoundingClientRect(); if (!rect) return; setDragState({ isDragging: true, draggedComponent: component, originalPosition: component.position, currentPosition: component.position, grabOffset: { x: event.clientX - rect.left - component.position.x, y: event.clientY - rect.top - component.position.y, }, }); }, []); // 드래그 업데이트 const updateDragPosition = useCallback( (event: MouseEvent) => { if (!dragState.isDragging || !dragState.draggedComponent || !canvasRef.current) return; const rect = canvasRef.current.getBoundingClientRect(); const newPosition = { x: Math.max(0, event.clientX - rect.left - dragState.grabOffset.x), y: Math.max(0, event.clientY - rect.top - dragState.grabOffset.y), z: dragState.draggedComponent.position.z || 1, }; setDragState((prev) => ({ ...prev, currentPosition: newPosition, })); }, [dragState], ); // 드래그 종료 const endDrag = useCallback(() => { if (!dragState.isDragging || !dragState.draggedComponent) return; const updatedComponents = layout.components.map((comp) => comp.id === dragState.draggedComponent!.id ? { ...comp, position: dragState.currentPosition } : comp, ); setLayout((prev) => ({ ...prev, components: updatedComponents, })); setDragState({ isDragging: false, draggedComponent: null, originalPosition: { x: 0, y: 0, z: 1 }, currentPosition: { x: 0, y: 0, z: 1 }, grabOffset: { x: 0, y: 0 }, }); }, [dragState, layout.components]); // 마우스 이벤트 리스너 const handleMouseMove = useCallback( (event: MouseEvent) => { updateDragPosition(event); }, [updateDragPosition], ); const handleMouseUp = useCallback(() => { endDrag(); }, [endDrag]); // 이벤트 리스너 등록 React.useEffect(() => { if (dragState.isDragging) { document.addEventListener("mousemove", handleMouseMove); document.addEventListener("mouseup", handleMouseUp); return () => { document.removeEventListener("mousemove", handleMouseMove); document.removeEventListener("mouseup", handleMouseUp); }; } }, [dragState.isDragging, handleMouseMove, handleMouseUp]); // 캔버스 클릭 처리 const handleCanvasClick = useCallback((e: React.MouseEvent) => { if (e.target === e.currentTarget) { setSelectedComponent(null); } }, []); // 툴바 액션들 const handleAddText = () => addComponent("widget", { x: 50, y: 50, z: 1 }); const handleAddContainer = () => addComponent("container", { x: 100, y: 100, z: 1 }); if (!selectedScreen) { return (

화면을 선택해주세요.

); } return (
{/* 상단 툴바 */} {}} onRedo={() => {}} onPreview={() => toast.info("미리보기 기능은 준비 중입니다.")} onTogglePanel={() => {}} panelStates={{}} canUndo={false} canRedo={false} isSaving={isSaving} /> {/* 간단한 컨트롤 버튼들 */}
{/* 메인 캔버스 영역 */}
{/* 해상도 정보 표시 */}
{screenResolution.name} ({screenResolution.width} × {screenResolution.height})
{/* 실제 작업 캔버스 */}
{/* 컴포넌트들 */} {layout.components.map((component) => ( setSelectedComponent(comp)} onStartDrag={(comp, event) => startDrag(comp, event)} onUpdateComponent={(updates) => { setLayout((prev) => ({ ...prev, components: prev.components.map((c) => (c.id === component.id ? { ...c, ...updates } : c)), })); }} dragPosition={ dragState.isDragging && dragState.draggedComponent?.id === component.id ? dragState.currentPosition : undefined } hideLabel={false} /> ))}
); }