import { useEffect } from 'react'; import { Globe2, RefreshCw, Upload, BadgeCheck, Mail, FileDown, PencilLine, Trash2 } from 'lucide-react'; import { useI18n } from '@/lib/i18n'; export type QSOMenuState = { x: number; y: number; ids: number[] } | null; type Props = { menu: QSOMenuState; onClose: () => void; onUpdateFromCty: (ids: number[]) => void; onUpdateFromQRZ: (ids: number[]) => void; onUpdateFromClublog?: (ids: number[]) => void; onSendTo?: (service: string, ids: number[]) => void; onSendRecording?: (ids: number[]) => void; onSendEQSL?: (ids: number[]) => void; onBulkEdit?: (ids: number[]) => void; onExportSelected?: (ids: number[]) => void; onExportFiltered?: () => void; onExportCabrilloSelected?: (ids: number[]) => void; onExportCabrilloFiltered?: () => void; onDelete?: (ids: number[]) => void; }; const UPLOAD_TARGETS: { service: string; name: string }[] = [ { service: 'qrz', name: 'QRZ.com' }, { service: 'clublog', name: 'Club Log' }, { service: 'hrdlog', name: 'HRDLog.net' }, { service: 'eqsl', name: 'eQSL.cc' }, { service: 'lotw', name: 'LoTW' }, ]; // Lightweight right-click menu for the QSO grids. AG Grid's native context // menu is an Enterprise feature, so this is a plain floating menu driven by // onCellContextMenu. Stays open until the user clicks outside, presses Escape, // or picks a command. (We deliberately do NOT close on scroll/resize: the QSO // list auto-refreshes and AG Grid fires internal scroll events on refresh, // which used to dismiss the menu the instant it appeared.) export function QSOContextMenu({ menu, onClose, onUpdateFromCty, onUpdateFromQRZ, onUpdateFromClublog, onSendTo, onSendRecording, onSendEQSL, onBulkEdit, onExportSelected, onExportFiltered, onExportCabrilloSelected, onExportCabrilloFiltered, onDelete }: Props) { const { t } = useI18n(); useEffect(() => { if (!menu) return; const close = () => onClose(); const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); }; window.addEventListener('mousedown', close); window.addEventListener('keydown', onKey); return () => { window.removeEventListener('mousedown', close); window.removeEventListener('keydown', onKey); }; }, [menu, onClose]); if (!menu) return null; const n = menu.ids.length; // Keep the menu on-screen near the cursor. const x = Math.min(menu.x, window.innerWidth - 248); const y = Math.min(menu.y, window.innerHeight - (onSendTo ? 230 : 110)); return (