217 lines
7.2 KiB
TypeScript
217 lines
7.2 KiB
TypeScript
import { useState, useEffect, useCallback } from "react";
|
|
|
|
interface UseTableColumnsOptions {
|
|
allColumns: string[];
|
|
storageKey: string;
|
|
defaultVisibleColumns?: string[];
|
|
}
|
|
|
|
export function useTableColumns({
|
|
allColumns,
|
|
storageKey,
|
|
defaultVisibleColumns
|
|
}: UseTableColumnsOptions) {
|
|
// Carregar as colunas visíveis do localStorage na inicialização
|
|
const initVisibleColumns = () => {
|
|
try {
|
|
const saved = localStorage.getItem(`visible${storageKey}Columns`);
|
|
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 defaultVisibleColumns || allColumns;
|
|
};
|
|
|
|
// Inicializar a ordem das colunas
|
|
const initColumnOrder = () => {
|
|
try {
|
|
const saved = localStorage.getItem(`${storageKey}ColumnsOrder`);
|
|
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 allColumns;
|
|
};
|
|
|
|
// Estado para controlar quais colunas estão visíveis
|
|
const [visibleColumns, setVisibleColumns] = useState<string[]>(initVisibleColumns);
|
|
// Estado para controlar a ordem das colunas
|
|
const [columnOrder, setColumnOrder] = useState<string[]>(initColumnOrder);
|
|
// Estado para rastrear coluna sendo arrastada
|
|
const [draggedColumn, setDraggedColumn] = useState<string | null>(null);
|
|
// Estado para notificar sobre novas colunas
|
|
const [newColumnsDetected, setNewColumnsDetected] = useState<string[]>([]);
|
|
|
|
useEffect(() => {
|
|
try {
|
|
const savedAllColumns = localStorage.getItem(`all${storageKey}Columns`);
|
|
if (savedAllColumns) {
|
|
const parsedAllColumns = JSON.parse(savedAllColumns);
|
|
if (JSON.stringify(parsedAllColumns) !== JSON.stringify(allColumns)) {
|
|
// Detectar novas colunas
|
|
const newColumns = allColumns.filter(col => !parsedAllColumns.includes(col));
|
|
|
|
if (newColumns.length > 0) {
|
|
// Adicionar novas colunas às colunas visíveis
|
|
setVisibleColumns(prev => {
|
|
const updated = [...prev, ...newColumns];
|
|
// Remover duplicatas
|
|
return [...new Set(updated)];
|
|
});
|
|
|
|
// Atualizar a ordem das colunas incluindo as novas
|
|
setColumnOrder(prev => {
|
|
const updated = [...prev, ...newColumns];
|
|
// Remover duplicatas
|
|
return [...new Set(updated)];
|
|
});
|
|
|
|
// Notificar sobre as novas colunas
|
|
setNewColumnsDetected(newColumns);
|
|
|
|
// Limpar a notificação após 5 segundos
|
|
setTimeout(() => {
|
|
setNewColumnsDetected([]);
|
|
}, 5000);
|
|
}
|
|
|
|
// Salvar as novas colunas no localStorage
|
|
localStorage.setItem(`all${storageKey}Columns`, JSON.stringify(allColumns));
|
|
}
|
|
} else {
|
|
localStorage.setItem(`all${storageKey}Columns`, JSON.stringify(allColumns));
|
|
}
|
|
} catch (error) {
|
|
console.error('Erro ao verificar as colunas no localStorage:', error);
|
|
}
|
|
}, [allColumns, storageKey]);
|
|
|
|
// Salvar as colunas visíveis no localStorage sempre que elas mudarem
|
|
useEffect(() => {
|
|
try {
|
|
localStorage.setItem(`visible${storageKey}Columns`, JSON.stringify(visibleColumns));
|
|
} catch (error) {
|
|
console.error('Erro ao salvar configurações de colunas:', error);
|
|
}
|
|
}, [visibleColumns, storageKey]);
|
|
|
|
// Salvar a ordem das colunas no localStorage
|
|
useEffect(() => {
|
|
try {
|
|
localStorage.setItem(`${storageKey}ColumnsOrder`, JSON.stringify(columnOrder));
|
|
} catch (error) {
|
|
console.error('Erro ao salvar ordem das colunas:', error);
|
|
}
|
|
}, [columnOrder, storageKey]);
|
|
|
|
// Funções para drag & drop
|
|
const handleDragStart = useCallback((e: React.DragEvent<HTMLDivElement>, column: string) => {
|
|
setDraggedColumn(column);
|
|
e.dataTransfer.effectAllowed = 'move';
|
|
e.dataTransfer.setData('text/plain', column);
|
|
|
|
const target = e.currentTarget as HTMLDivElement;
|
|
target.classList.add('opacity-50');
|
|
}, []);
|
|
|
|
const handleDragEnd = useCallback((e: React.DragEvent<HTMLDivElement>) => {
|
|
setDraggedColumn(null);
|
|
e.currentTarget.classList.remove('opacity-50');
|
|
}, []);
|
|
|
|
const handleDragOver = useCallback((e: React.DragEvent<HTMLDivElement>) => {
|
|
e.preventDefault();
|
|
e.dataTransfer.dropEffect = 'move';
|
|
}, []);
|
|
|
|
const handleDrop = useCallback((e: React.DragEvent<HTMLDivElement>, 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);
|
|
}
|
|
}, [draggedColumn, columnOrder]);
|
|
|
|
// Função para alternar a visibilidade de uma coluna
|
|
const toggleColumn = useCallback((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 = useCallback(() => {
|
|
setVisibleColumns(allColumns);
|
|
}, [allColumns]);
|
|
|
|
// Função para desmarcar todas as colunas
|
|
const unselectAllColumns = useCallback(() => {
|
|
// Mantém pelo menos uma coluna para garantir que a tabela não fique vazia
|
|
const firstColumn = allColumns[0] || "Código";
|
|
setVisibleColumns([firstColumn]);
|
|
}, [allColumns]);
|
|
|
|
// Função para verificar se uma coluna está visível
|
|
const isColumnVisible = useCallback((column: string) => {
|
|
return visibleColumns.includes(column);
|
|
}, [visibleColumns]);
|
|
|
|
// Função para ordenar as colunas visíveis na ordem definida pelo usuário
|
|
const getOrderedVisibleColumns = useCallback(() => {
|
|
// 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));
|
|
}, [visibleColumns, columnOrder]);
|
|
|
|
// Resetar a ordem das colunas
|
|
const resetColumnOrder = useCallback(() => {
|
|
setColumnOrder(allColumns);
|
|
}, [allColumns]);
|
|
|
|
// Função para limpar a notificação de novas colunas
|
|
const dismissNewColumnsNotification = useCallback(() => {
|
|
setNewColumnsDetected([]);
|
|
}, []);
|
|
|
|
return {
|
|
visibleColumns,
|
|
columnOrder,
|
|
getOrderedVisibleColumns,
|
|
resetColumnOrder,
|
|
toggleColumn,
|
|
selectAllColumns,
|
|
unselectAllColumns,
|
|
isColumnVisible,
|
|
handleDragStart,
|
|
handleDragEnd,
|
|
handleDragOver,
|
|
handleDrop,
|
|
newColumnsDetected,
|
|
dismissNewColumnsNotification,
|
|
};
|
|
}
|