ship-gis/src/components/ship/ShipContextMenu.jsx

83 lines
2.3 KiB
React
Raw Normal View 히스토리

/**
* 선박 우클릭 컨텍스트 메뉴
* - 단일 선박 우클릭: 해당 선박 메뉴
* - Ctrl+Drag 선택 우클릭: 선택된 선박 전체 메뉴
*/
import { useEffect, useRef, useCallback } from 'react';
import useShipStore from '../../stores/shipStore';
import './ShipContextMenu.scss';
const MENU_ITEMS = [
{ key: 'track', label: '항적조회' },
{ key: 'analysis', label: '항적분석' },
{ key: 'detail', label: '상세정보' },
];
export default function ShipContextMenu() {
const contextMenu = useShipStore((s) => s.contextMenu);
const closeContextMenu = useShipStore((s) => s.closeContextMenu);
const menuRef = useRef(null);
// 외부 클릭 시 닫기
useEffect(() => {
if (!contextMenu) return;
const handleClick = (e) => {
if (menuRef.current && !menuRef.current.contains(e.target)) {
closeContextMenu();
}
};
document.addEventListener('mousedown', handleClick);
return () => document.removeEventListener('mousedown', handleClick);
}, [contextMenu, closeContextMenu]);
// 메뉴 항목 클릭
const handleAction = useCallback((key) => {
if (!contextMenu) return;
const { ships } = contextMenu;
// TODO: 향후 API 연결
console.log(`[ContextMenu] action=${key}, ships=`, ships.map((s) => ({
featureId: s.featureId,
shipName: s.shipName,
targetId: s.targetId,
})));
closeContextMenu();
}, [contextMenu, closeContextMenu]);
if (!contextMenu) return null;
const { x, y, ships } = contextMenu;
// 화면 밖 넘침 방지
const menuWidth = 160;
const menuHeight = MENU_ITEMS.length * 36 + 40; // 항목 + 헤더
const adjustedX = x + menuWidth > window.innerWidth ? x - menuWidth : x;
const adjustedY = y + menuHeight > window.innerHeight ? y - menuHeight : y;
const title = ships.length === 1
? (ships[0].shipName || ships[0].featureId)
: `${ships.length}척 선택`;
return (
<div
ref={menuRef}
className="ship-context-menu"
style={{ left: adjustedX, top: adjustedY }}
>
<div className="ship-context-menu__header">{title}</div>
{MENU_ITEMS.map((item) => (
<div
key={item.key}
className="ship-context-menu__item"
onClick={() => handleAction(item.key)}
>
{item.label}
</div>
))}
</div>
);
}