import React, { useMemo, useState, useRef, useEffect } from 'react'; import { Operation } from '../types'; import { format } from 'date-fns'; import ConfirmationModal from './ConfirmationModal'; interface OperationsTableProps { title: 'Income' | 'Expenses'; operations: Operation[]; onEdit: (operation: Operation) => void; onDelete: (operationId: string) => void; } const OperationsTable: React.FC = ({ title, operations, onEdit, onDelete }) => { const [openMenuId, setOpenMenuId] = useState(null); const menuRef = useRef(null); const [menuPosition, setMenuPosition] = useState<{ top: number; left: number } | null>(null); const [operationToDelete, setOperationToDelete] = useState(null); const [collapsedGroups, setCollapsedGroups] = useState>({}); const toggleGroup = (group: string) => { setCollapsedGroups(prev => ({ ...prev, [group]: !prev[group] })); }; useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if (menuRef.current && !menuRef.current.contains(event.target as Node)) { setOpenMenuId(null); setMenuPosition(null); } }; const handleScroll = () => { if (openMenuId) { setOpenMenuId(null); setMenuPosition(null); } }; document.addEventListener('mousedown', handleClickOutside); window.addEventListener('scroll', handleScroll, true); return () => { document.removeEventListener('mousedown', handleClickOutside); window.removeEventListener('scroll', handleScroll, true); }; }, [openMenuId]); const toggleMenu = (id: string, e: React.MouseEvent) => { e.stopPropagation(); if (openMenuId === id) { setOpenMenuId(null); setMenuPosition(null); } else { const rect = e.currentTarget.getBoundingClientRect(); const spaceBelow = window.innerHeight - rect.bottom; const menuHeight = 100; let top = rect.bottom; if (spaceBelow < menuHeight) { top = rect.top - menuHeight; } setMenuPosition({ top: top, left: rect.right - 128, }); setOpenMenuId(id); } }; const handleDeleteClick = (op: Operation) => { setOperationToDelete(op); setOpenMenuId(null); setMenuPosition(null); }; const confirmDelete = () => { if (operationToDelete) { onDelete(operationToDelete.id); setOperationToDelete(null); } }; const groupedOperations = useMemo(() => { return operations.reduce((acc, op) => { (acc[op.group] = acc[op.group] || []).push(op); return acc; }, {} as Record); }, [operations]); const formatCurrency = (amount: number) => { return new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR' }).format(amount); }; const titleColor = title === 'Income' ? 'text-green-600' : 'text-red-600'; return (

{title}

{Object.keys(groupedOperations).length > 0 ? ( Object.keys(groupedOperations).map((group) => { const ops = groupedOperations[group]; return (
toggleGroup(group)} >
{group}
{!collapsedGroups[group] && (
{ops.map(op => (

{op.name}

{format(new Date(op.date), 'MMM dd, yyyy')}

{op.description}

{formatCurrency(op.amount)}
))}
)}
); }) ) : (

No {title.toLowerCase()} for this period.

)}
{/* Fixed Menu Portal */} {openMenuId && menuPosition && (
)} setOperationToDelete(null)} onConfirm={confirmDelete} title="Delete Operation" message={`Are you sure you want to delete the operation "${operationToDelete?.name}"? This action cannot be undone.`} confirmText="Delete" isDanger={true} />
); }; export default OperationsTable;