import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/src/components/ui/table"; import { Button } from "@/src/components/ui/button"; import { Eye, GripVertical } from "lucide-react"; import { OrderItem } from "@/src/components/types"; import { cellClass } from "@/src/constants/status-options"; import { formatCurrency } from "@/src/utils/format"; import { useState, useEffect, } from "react"; import { DropdownMenu, DropdownMenuContent, DropdownMenuLabel, DropdownMenuTrigger, DropdownMenuCheckboxItem, } from "@/src/components/ui/dropdown-menu"; interface Item { quantity: number | null | undefined; } const displayQuantity = (item?: Item) => { if (!item?.quantity && item?.quantity !== 0) { return "-"; } return item.quantity >= 0 ? item.quantity.toString() : "0"; }; const ALL_COLUMNS = [ "Código", "Descrição", "Embalagem", "Cor", "F. Estoque", "Tipo Entrega", "Quantidade", "Preço Unitário", "Preço Total", "Departamento", "Marca", ]; interface OrderItemsTableProps { orderItems: OrderItem[]; loadingItems: boolean; itemsError: string | null; onViewDetails?: (item: OrderItem) => void; } export function OrderItemsTable({ orderItems, loadingItems, itemsError, onViewDetails, }: OrderItemsTableProps) { // Carregar as colunas visíveis do localStorage na inicialização const initVisibleColumns = () => { try { const saved = localStorage.getItem('visibleOrderItemColumns'); if (saved) { const parsed = JSON.parse(saved); if (Array.isArray(parsed) && parsed.length > 0) { return parsed; } } } catch (error) { console.error('Erro ao carregar configurações de colunas:', error); } return ALL_COLUMNS; }; // Inicializar a ordem das colunas const initColumnOrder = () => { try { const saved = localStorage.getItem('orderItemColumnsOrder'); if (saved) { const parsed = JSON.parse(saved); if (Array.isArray(parsed) && parsed.length > 0) { return parsed; } } } catch (error) { console.error('Erro ao carregar ordem das colunas:', error); } return ALL_COLUMNS; }; // Estado para controlar quais colunas estão visíveis const [visibleColumns, setVisibleColumns] = useState(initVisibleColumns); // Estado para controlar a ordem das colunas const [columnOrder, setColumnOrder] = useState(initColumnOrder); // Estado para rastrear coluna sendo arrastada const [draggedColumn, setDraggedColumn] = useState(null); // Salvar as colunas visíveis no localStorage sempre que elas mudarem useEffect(() => { try { localStorage.setItem('visibleOrderItemColumns', JSON.stringify(visibleColumns)); } catch (error) { console.error('Erro ao salvar configurações de colunas:', error); } }, [visibleColumns]); // Salvar a ordem das colunas no localStorage useEffect(() => { try { localStorage.setItem('orderItemColumnsOrder', JSON.stringify(columnOrder)); } catch (error) { console.error('Erro ao salvar ordem das colunas:', error); } }, [columnOrder]); // Função para alternar a visibilidade de uma coluna const toggleColumn = (column: string) => { setVisibleColumns((current) => { if (current.includes(column)) { return current.filter((c) => c !== column); } else { return [...current, column]; } }); }; // Função para selecionar todas as colunas const selectAllColumns = () => { setVisibleColumns(ALL_COLUMNS); }; // Função para desmarcar todas as colunas const unselectAllColumns = () => { // Mantém pelo menos uma coluna para garantir que a tabela não fique vazia setVisibleColumns(["Código"]); }; // Função para verificar se uma coluna está visível const isColumnVisible = (column: string) => visibleColumns.includes(column); // Funções para drag & drop const handleDragStart = (e: React.DragEvent, column: string) => { setDraggedColumn(column); e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.setData('text/plain', column); // Adicionar um estilo visual para o elemento sendo arrastado if (e.currentTarget) { setTimeout(() => { if (e.currentTarget) { e.currentTarget.classList.add('opacity-50'); } }, 0); } }; const handleDragEnd = (e: React.DragEvent) => { setDraggedColumn(null); e.currentTarget.classList.remove('opacity-50'); }; const handleDragOver = (e: React.DragEvent) => { e.preventDefault(); e.dataTransfer.dropEffect = 'move'; }; const handleDrop = (e: React.DragEvent, targetColumn: string) => { e.preventDefault(); if (!draggedColumn || draggedColumn === targetColumn) return; // Reordenar as colunas const newColumnOrder = [...columnOrder]; const draggedIndex = newColumnOrder.indexOf(draggedColumn); const targetIndex = newColumnOrder.indexOf(targetColumn); if (draggedIndex !== -1 && targetIndex !== -1) { newColumnOrder.splice(draggedIndex, 1); newColumnOrder.splice(targetIndex, 0, draggedColumn); setColumnOrder(newColumnOrder); } }; const getColumnClass = (title: string) => { const textRight = ["Preço Unitário", "Preço Total", "Quantidade"]; const cellWidth: { [key: string]: string } = { "Código": "w-20", "Descrição": "w-56", "Embalagem": "w-24", "Cor": "w-20", "F. Estoque": "w-24", "Tipo Entrega": "w-28", "Quantidade": "w-24", "Preço Unitário": "w-24", "Preço Total": "w-24", "Departamento": "w-48", "Marca": "w-24", }; let classes = ""; // Não aplicar whitespace-nowrap para Departamento if (title !== "Departamento") { classes += "whitespace-nowrap "; } // Alinhar à direita if (textRight.includes(title)) { classes += "text-right "; } // Aplicar larguras if (cellWidth[title]) { classes += cellWidth[title] + " "; } return classes; }; // Função para ordenar as colunas visíveis na ordem definida pelo usuário const getOrderedVisibleColumns = () => { // Primeiro, filtrar as colunas que são visíveis const visibleColumnSet = new Set(visibleColumns); // Depois, ordenar as colunas de acordo com a ordem definida pelo usuário return columnOrder.filter(column => visibleColumnSet.has(column)); }; // Resetar a ordem das colunas const resetColumnOrder = () => { setColumnOrder(ALL_COLUMNS); }; const handleEvent = (e: React.SyntheticEvent) => { const element = e.currentTarget; if (element instanceof HTMLElement) { const timeoutId = setTimeout(() => { element.classList.add('opacity-50'); }, 0); // Limpeza em caso de desmontagem return () => clearTimeout(timeoutId); } }; if (loadingItems) { return
Carregando itens...
; } if (itemsError) { return
{itemsError}
; } if (orderItems.length === 0) { return
Nenhum item encontrado para este pedido.
; } const orderedVisibleColumns = getOrderedVisibleColumns(); return (
Visibilidade das Colunas
{ALL_COLUMNS.map((column) => ( toggleColumn(column)} className="flex items-center space-x-2 cursor-pointer py-1.5 hover:bg-gray-100 px-2 rounded" >
{isColumnVisible(column) ? ( ) : ( )} {column}
))}
{orderedVisibleColumns.map((title, index, array) => ( handleDragStart(e, title)} onDragEnd={handleDragEnd} onDragOver={handleDragOver} onDrop={(e) => handleDrop(e, title)} >
{title}
))} {onViewDetails && ( Ações )}
{orderItems.map((item, index) => ( {orderedVisibleColumns.map((columnName, colIndex) => { switch (columnName) { case "Código": return ( {item.productId ?? "-"} ); case "Descrição": return ( {item.description ?? "-"} ); case "Embalagem": return ( {item.pacth ?? "-"} ); case "Cor": return ( {item.color ?? "-"} ); case "F. Estoque": return ( {item.stockId ?? "-"} ); case "Tipo Entrega": return ( {item.deliveryType ?? "-"} ); case "Quantidade": return ( {displayQuantity(item)} ); case "Preço Unitário": return ( {formatCurrency(item.salePrice)} ); case "Preço Total": return ( {item.total != null ? formatCurrency(item.total) : "-"} ); case "Departamento": return (
{item.department ?? "-"}
); case "Marca": return ( {item.brand ?? "-"} ); default: return null; } })} {onViewDetails && ( )}
))}
); }