'use client'; import React, { useState, useEffect, useRef, useCallback } from 'react'; export interface Ingredient { _id: string; code: string; name: string; category: string; subcategory: string; quantity: number; unit: string; unitPrice: number; vat: number; supplier: string; createdAt: string; updatedAt: string; } interface IngredientTableProps { ingredients: Ingredient[]; onView: (id: string) => void; onEdit: (id: string) => void; onDelete: (id: string, name: string) => void; } export default function IngredientTable({ ingredients, onView, onEdit, onDelete }: IngredientTableProps) { const [selectedIngredients, setSelectedIngredients] = useState>(new Set()); const [openMenuId, setOpenMenuId] = useState(null); const [menuPos, setMenuPos] = useState<{ top: number; right: number } | null>(null); const menuRef = useRef(null); // Close menu on outside click or scroll useEffect(() => { if (!openMenuId) return; const handleClick = (e: MouseEvent) => { if (menuRef.current && !menuRef.current.contains(e.target as Node)) { setOpenMenuId(null); } }; const handleScroll = () => setOpenMenuId(null); document.addEventListener('mousedown', handleClick); window.addEventListener('scroll', handleScroll, true); return () => { document.removeEventListener('mousedown', handleClick); window.removeEventListener('scroll', handleScroll, true); }; }, [openMenuId]); const toggleIngredient = (id: string) => { const newSelected = new Set(selectedIngredients); if (newSelected.has(id)) { newSelected.delete(id); } else { newSelected.add(id); } setSelectedIngredients(newSelected); }; const toggleAll = () => { if (selectedIngredients.size === ingredients.length) { setSelectedIngredients(new Set()); } else { setSelectedIngredients(new Set(ingredients.map(i => i._id))); } }; const calculateNetPrice = (unitPrice: number, vat: number) => { return unitPrice * (1 + vat / 100); }; const handleMenuAction = useCallback((action: 'view' | 'edit' | 'delete', id: string, name: string) => { setOpenMenuId(null); if (action === 'view') onView(id); else if (action === 'edit') onEdit(id); else onDelete(id, name); }, [onView, onEdit, onDelete]); const toggleMenu = (ingredientId: string, e: React.MouseEvent) => { if (openMenuId === ingredientId) { setOpenMenuId(null); setMenuPos(null); } else { const rect = e.currentTarget.getBoundingClientRect(); setMenuPos({ top: rect.bottom + 4, right: window.innerWidth - rect.right }); setOpenMenuId(ingredientId); } }; const renderMenuButton = (ingredient: Ingredient) => ( ); const openIngredient = openMenuId ? ingredients.find(i => i._id === openMenuId) : null; return ( <> {/* Desktop & Tablet Table View */}
{ingredients.map((ingredient) => ( ))}
0} onChange={toggleAll} className="w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500" /> Ingredient Category Subcategory Quantity Unit Price VAT Net Price Supplier Actions
toggleIngredient(ingredient._id)} className="w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500" />

{ingredient.name}

ID: {ingredient.code}

{ingredient.category} • {ingredient.quantity} {ingredient.unit}

{ingredient.category} {ingredient.subcategory} {ingredient.quantity} {ingredient.unit} €{ingredient.unitPrice.toFixed(2)} {ingredient.vat}% €{calculateNetPrice(ingredient.unitPrice, ingredient.vat).toFixed(2)} {ingredient.supplier} {renderMenuButton(ingredient)}
{/* Mobile Card View */}
{ingredients.map((ingredient) => (
toggleIngredient(ingredient._id)} className="w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500 mt-1" />

{ingredient.name}

ID: {ingredient.code}

{renderMenuButton(ingredient)}

Category

{ingredient.category}

Subcategory

{ingredient.subcategory}

Quantity

{ingredient.quantity} {ingredient.unit}

Unit Price

€{ingredient.unitPrice.toFixed(2)}

VAT

{ingredient.vat}%

Net Price

€{calculateNetPrice(ingredient.unitPrice, ingredient.vat).toFixed(2)}

Updated

{new Date(ingredient.updatedAt).toLocaleDateString()}

))}
{/* Fixed-position dropdown menu (renders outside overflow containers) */} {openMenuId && menuPos && openIngredient && (
)} ); }