Ajuste na coluna de pedidos
This commit is contained in:
@@ -230,6 +230,7 @@ export function OrderDetail({ order, timelineEvents }: OrderDetailProps) {
|
||||
} else if (window.history.length > 2) {
|
||||
goBack();
|
||||
} else {
|
||||
// Usar a função que limpa parâmetros ao navegar para orders/find
|
||||
goToOrdersFind();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -19,6 +19,8 @@ import {
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuCheckboxItem,
|
||||
} from "@/src/components/ui/dropdown-menu";
|
||||
import { useOrderItemTableColumns } from "@/src/hooks/useOrderItemTableColumns";
|
||||
import { NewColumnsNotification } from "@/src/components/ui/NewColumnsNotification";
|
||||
|
||||
interface Item {
|
||||
quantity: number | null | undefined;
|
||||
@@ -58,180 +60,23 @@ export function OrderItemsTable({
|
||||
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<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);
|
||||
|
||||
// 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<HTMLDivElement>, 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<HTMLDivElement>) => {
|
||||
setDraggedColumn(null);
|
||||
e.currentTarget.classList.remove('opacity-50');
|
||||
};
|
||||
|
||||
const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
e.dataTransfer.dropEffect = 'move';
|
||||
};
|
||||
|
||||
const handleDrop = (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);
|
||||
}
|
||||
};
|
||||
|
||||
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 {
|
||||
visibleColumns,
|
||||
columnOrder,
|
||||
getColumnClass,
|
||||
getOrderedVisibleColumns,
|
||||
resetColumnOrder,
|
||||
toggleColumn,
|
||||
selectAllColumns,
|
||||
unselectAllColumns,
|
||||
isColumnVisible,
|
||||
handleDragStart,
|
||||
handleDragEnd,
|
||||
handleDragOver,
|
||||
handleDrop,
|
||||
newColumnsDetected,
|
||||
dismissNewColumnsNotification,
|
||||
} = useOrderItemTableColumns(ALL_COLUMNS);
|
||||
|
||||
const handleEvent = (e: React.SyntheticEvent) => {
|
||||
const element = e.currentTarget;
|
||||
@@ -261,6 +106,10 @@ const handleEvent = (e: React.SyntheticEvent) => {
|
||||
|
||||
return (
|
||||
<div className="rounded-md border-0">
|
||||
<NewColumnsNotification
|
||||
newColumns={newColumnsDetected}
|
||||
onDismiss={dismissNewColumnsNotification}
|
||||
/>
|
||||
<div className="flex justify-end mb-2 gap-2">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
|
||||
@@ -12,6 +12,7 @@ import { SelectedOrderItems } from "./SelectedOrderItems";
|
||||
import { RefreshCw, ChevronLeft, ChevronRight } from "lucide-react";
|
||||
import { useOrderData } from "../../../src/hooks/useOrderData";
|
||||
import { useSort } from "@/src/hooks/useSort";
|
||||
import { NewColumnsNotification } from "@/src/components/ui/NewColumnsNotification";
|
||||
|
||||
export type ColumnKey =
|
||||
| "Data"
|
||||
@@ -28,14 +29,17 @@ export type ColumnKey =
|
||||
| "Valor"
|
||||
| "Peso(kg)"
|
||||
| "Carregamento"
|
||||
| "Dt Carregamento"
|
||||
| "Cobrança"
|
||||
| "Trasportadora"
|
||||
| "Praça"
|
||||
| "Nota fiscal"
|
||||
| "Dt Faturamento"
|
||||
| "Motorista"
|
||||
| "Placa"
|
||||
|
||||
const ALL_COLUMNS: ColumnKey[] = [
|
||||
"Data", "Data previsão de entrega", "Agendamento", "Pedido", "Tipo Pedido", "Cliente", "Vendedor", "Filial", "Situação", "Rota", "Valor", "Peso(kg)", "Carregamento", "Cobrança", "Trasportadora", "Praça", "Nota fiscal", "Dt Faturamento", "TV 7"
|
||||
"Data", "Data previsão de entrega", "Agendamento", "Pedido", "Tipo Pedido", "Cliente", "Vendedor", "Filial", "Situação", "Dt Carregamento", "Rota", "Valor", "Peso(kg)", "Carregamento", "Cobrança", "Trasportadora", "Praça", "Nota fiscal", "Dt Faturamento", "TV 7", "Motorista", "Placa"
|
||||
];
|
||||
|
||||
export interface OrdersTableProps {
|
||||
@@ -103,6 +107,7 @@ export function OrdersTable({
|
||||
"Valor": (order: Order) => parseFloat(String(order.totalValue || "0")),
|
||||
"Peso(kg)": (order: Order) => parseFloat(String(order.totalWeigth || "0")),
|
||||
"Dt Faturamento": (order: Order) => new Date(order.invoiceDate || ""),
|
||||
"Dt Carregamento": (order: Order) => new Date(order.shipmentDate || ""),
|
||||
// Add other column accessors as needed
|
||||
}), []);
|
||||
|
||||
@@ -126,6 +131,8 @@ export function OrdersTable({
|
||||
handleDragEnd,
|
||||
handleDragOver,
|
||||
handleDrop,
|
||||
newColumnsDetected,
|
||||
dismissNewColumnsNotification,
|
||||
} = useOrderTableColumns(ALL_COLUMNS);
|
||||
|
||||
const { tableRef } = useKeyboardNavigation({
|
||||
@@ -248,6 +255,10 @@ export function OrdersTable({
|
||||
|
||||
return (
|
||||
<div className="rounded-md border-0" ref={tableRef} tabIndex={0}>
|
||||
<NewColumnsNotification
|
||||
newColumns={newColumnsDetected}
|
||||
onDismiss={dismissNewColumnsNotification}
|
||||
/>
|
||||
{renderHeaderControls()}
|
||||
{renderOrdersTable()}
|
||||
<SelectedOrderItems
|
||||
|
||||
@@ -43,7 +43,7 @@ const ColumnHeader = memo(({
|
||||
onSort?: (column: string) => void;
|
||||
}) => {
|
||||
// Determinar se esta coluna é ordenável
|
||||
const isSortable = ["Data", "Valor", "Peso(kg)", "Pedido", "Dt Faturamento"].includes(title);
|
||||
const isSortable = ["Data", "Valor", "Peso(kg)", "Pedido", "Dt Faturamento", "Dt Carregamento"].includes(title);
|
||||
|
||||
// Verificar se esta coluna está sendo ordenada
|
||||
const isSorted = sortConfig && sortConfig.key === title;
|
||||
|
||||
@@ -82,6 +82,7 @@ export const orderCellRenderers: Record<OrderColumn, React.FC<CellRenderProps>>
|
||||
[OrderColumn.Value]: ({ order }) => <>{formatCurrency(order.amount || 0)}</>,
|
||||
[OrderColumn.Weight]: ({ order }) => <>{order.totalWeigth}</>,
|
||||
[OrderColumn.Shipment]: ({ order }) => <>{order.shipmentId}</>,
|
||||
[OrderColumn.ShipmentDate]: ({ order }) => <>{formatDateSafe(order.shipmentDate)}</>,
|
||||
[OrderColumn.Billing]: ({ order }) => <>{order.billingName}</>,
|
||||
[OrderColumn.Carrier]: ({ order }) => <>{order.carrier}</>,
|
||||
[OrderColumn.Place]: ({ order }) => <>{order.deliveryLocal}</>,
|
||||
@@ -89,4 +90,6 @@ export const orderCellRenderers: Record<OrderColumn, React.FC<CellRenderProps>>
|
||||
[OrderColumn.InvoiceDate]: ({ order }) => <>{formatDateSafe(order.invoiceDate)}</>,
|
||||
[OrderColumn.DeliveryDate]: ({ order }) => <>{order.deliveryDate ? formatDateSafe(order.deliveryDate) : "-"}</>,
|
||||
[OrderColumn.SchedulerDelivery]: ({ order }) => <>{order.schedulerDelivery || "-"}</>,
|
||||
[OrderColumn.Driver]: ({ order }) => <>{order.driver || "-"}</>,
|
||||
[OrderColumn.CarIdentification]: ({ order }) => <>{order.carIdentification || "-"}</>,
|
||||
};
|
||||
|
||||
@@ -15,10 +15,13 @@ export const columnClasses: Record<OrderColumn, string> = {
|
||||
[OrderColumn.Value]: "p-2 whitespace-nowrap text-right border-r border-gray-200 text-xs",
|
||||
[OrderColumn.Weight]: "p-2 whitespace-nowrap text-right border-r border-gray-200 text-xs",
|
||||
[OrderColumn.Shipment]: "p-2 whitespace-nowrap border-r border-gray-200 text-xs",
|
||||
[OrderColumn.ShipmentDate]: "p-2 whitespace-nowrap border-r border-gray-200 text-xs",
|
||||
[OrderColumn.Billing]: "p-2 whitespace-nowrap border-r border-gray-200 text-xs",
|
||||
[OrderColumn.Carrier]: "p-2 whitespace-nowrap border-r border-gray-200 text-xs",
|
||||
[OrderColumn.Place]: "p-2 whitespace-nowrap border-r border-gray-200 text-xs",
|
||||
[OrderColumn.Invoice]: "p-2 whitespace-nowrap border-r border-gray-200 text-xs",
|
||||
[OrderColumn.InvoiceDate]: "p-2 whitespace-nowrap border-r border-gray-200 text-xs",
|
||||
[OrderColumn.DeliveryDate]: "p-2 whitespace-nowrap border-r border-gray-200 text-xs",
|
||||
[OrderColumn.Driver]: "p-2 whitespace-nowrap border-r border-gray-200 text-xs",
|
||||
[OrderColumn.CarIdentification]: "p-2 whitespace-nowrap border-r border-gray-200 text-xs",
|
||||
};
|
||||
|
||||
@@ -15,10 +15,13 @@ export enum OrderColumn {
|
||||
Value = "Valor",
|
||||
Weight = "Peso(kg)",
|
||||
Shipment = "Carregamento",
|
||||
ShipmentDate = "Dt Carregamento",
|
||||
Billing = "Cobrança",
|
||||
Carrier = "Trasportadora",
|
||||
Place = "Praça",
|
||||
Invoice = "Nota fiscal",
|
||||
InvoiceDate = "Dt Faturamento"
|
||||
InvoiceDate = "Dt Faturamento",
|
||||
Driver = "Motorista",
|
||||
CarIdentification = "Placa"
|
||||
}
|
||||
|
||||
29
src/components/ui/ClearAndNavigateButton.tsx
Normal file
29
src/components/ui/ClearAndNavigateButton.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Button } from "@/src/components/ui/button";
|
||||
import { useOrderSearch } from "@/src/hooks/useOrderSearch";
|
||||
|
||||
interface ClearAndNavigateButtonProps {
|
||||
children: React.ReactNode;
|
||||
variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link";
|
||||
size?: "default" | "sm" | "lg" | "icon";
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function ClearAndNavigateButton({
|
||||
children,
|
||||
variant = "outline",
|
||||
size = "default",
|
||||
className
|
||||
}: ClearAndNavigateButtonProps) {
|
||||
const { clearAndNavigateToOrders } = useOrderSearch(8);
|
||||
|
||||
return (
|
||||
<Button
|
||||
variant={variant}
|
||||
size={size}
|
||||
onClick={clearAndNavigateToOrders}
|
||||
className={className}
|
||||
>
|
||||
{children}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
37
src/components/ui/NewColumnsNotification.tsx
Normal file
37
src/components/ui/NewColumnsNotification.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Alert, AlertDescription } from "@/src/components/ui/alert";
|
||||
import { X, Info } from "lucide-react";
|
||||
import { Button } from "@/src/components/ui/button";
|
||||
|
||||
interface NewColumnsNotificationProps {
|
||||
newColumns: string[];
|
||||
onDismiss: () => void;
|
||||
}
|
||||
|
||||
export function NewColumnsNotification({ newColumns, onDismiss }: NewColumnsNotificationProps) {
|
||||
if (newColumns.length === 0) return null;
|
||||
|
||||
return (
|
||||
<Alert className="mb-4 border-blue-200 bg-blue-50">
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex items-start gap-2">
|
||||
<Info className="h-4 w-4 text-blue-600 mt-0.5" />
|
||||
<AlertDescription className="text-blue-800">
|
||||
<span className="font-medium">Novas colunas detectadas:</span>{" "}
|
||||
{newColumns.join(", ")}.
|
||||
<span className="text-blue-600 text-sm">
|
||||
{" "}Elas foram automaticamente adicionadas à sua visualização.
|
||||
</span>
|
||||
</AlertDescription>
|
||||
</div>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={onDismiss}
|
||||
className="h-6 w-6 p-0 text-blue-600 hover:text-blue-800 hover:bg-blue-100"
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
@@ -27,6 +27,16 @@ export function useNavigation() {
|
||||
router.push("/orders/find");
|
||||
};
|
||||
|
||||
// Função para navegar para orders/find limpando parâmetros da URL
|
||||
const goToOrdersFindClean = () => {
|
||||
router.push("/orders/find");
|
||||
};
|
||||
|
||||
// Função para navegar para outras páginas limpando parâmetros
|
||||
const navigateToClean = (path: string) => {
|
||||
router.push(path);
|
||||
};
|
||||
|
||||
// Helper to build URL with search params
|
||||
const buildUrl = (base: string, params: Record<string, string>) => {
|
||||
const url = new URL(base, window.location.origin);
|
||||
@@ -46,6 +56,8 @@ export function useNavigation() {
|
||||
goBack,
|
||||
goToHome,
|
||||
goToOrdersFind,
|
||||
goToOrdersFindClean,
|
||||
navigateToClean,
|
||||
buildUrl
|
||||
};
|
||||
}
|
||||
52
src/hooks/useOrderItemTableColumns.ts
Normal file
52
src/hooks/useOrderItemTableColumns.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { useCallback } from "react";
|
||||
import { useTableColumns } from "./useTableColumns";
|
||||
|
||||
export function useOrderItemTableColumns(allColumns: string[]) {
|
||||
const tableColumns = useTableColumns({
|
||||
allColumns,
|
||||
storageKey: "OrderItem",
|
||||
defaultVisibleColumns: allColumns,
|
||||
});
|
||||
|
||||
// Memoizar as classes de colunas para evitar recálculos desnecessários
|
||||
const getColumnClass = useCallback((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;
|
||||
}, []);
|
||||
|
||||
return {
|
||||
...tableColumns,
|
||||
getColumnClass,
|
||||
};
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import { extractApiData } from "@/src/utils/api-helpers";
|
||||
import { useSearchParams, useRouter } from "next/navigation";
|
||||
import { clientesApi } from "@/src/lib/api"
|
||||
import { setStorage, getStorage } from "@/src/utils/storage";
|
||||
import { clearUrlAndNavigate } from "@/src/utils/url-helpers";
|
||||
|
||||
/**
|
||||
* Função de utilidade para aplicar debounce em funções
|
||||
@@ -66,6 +67,7 @@ interface UseOrderSearchReturn {
|
||||
handleCustomerFilter: (value: string) => Promise<void>;
|
||||
setInitialOrders: (savedOrders: Order[], savedPage: number, savedHasSearched: boolean) => void;
|
||||
clearStoredParams: () => void;
|
||||
clearAndNavigateToOrders: () => void;
|
||||
handleMultiInputChange: (field: keyof OrderSearchParams, values: string[]) => void;
|
||||
}
|
||||
|
||||
@@ -657,6 +659,16 @@ export function useOrderSearch(ordersPerPage: number = 8): UseOrderSearchReturn
|
||||
setStorage("orderSearchParams", null);
|
||||
}, []);
|
||||
|
||||
// Função para limpar parâmetros e navegar para orders/find
|
||||
const clearAndNavigateToOrders = useCallback(() => {
|
||||
// Limpar parâmetros do localStorage
|
||||
setStorage("orderSearchParams", null);
|
||||
// Limpar parâmetros do estado
|
||||
setSearchParams({});
|
||||
// Limpar URL e navegar
|
||||
clearUrlAndNavigate("/orders/find");
|
||||
}, [setSearchParams]);
|
||||
|
||||
/**
|
||||
* Manipula a seleção de múltiplos valores em filtros de seleção
|
||||
*
|
||||
@@ -701,6 +713,7 @@ export function useOrderSearch(ordersPerPage: number = 8): UseOrderSearchReturn
|
||||
handleCustomerFilter,
|
||||
setInitialOrders,
|
||||
clearStoredParams,
|
||||
clearAndNavigateToOrders,
|
||||
handleMultiInputChange
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,87 +1,12 @@
|
||||
import { useState, useEffect, useMemo, useCallback } from "react";
|
||||
import { ChevronDown, ChevronUp } from "lucide-react";
|
||||
|
||||
|
||||
|
||||
import { useCallback } from "react";
|
||||
import { useTableColumns } from "./useTableColumns";
|
||||
|
||||
export function useOrderTableColumns(allColumns: string[]) {
|
||||
// Carregar as colunas visíveis do localStorage na inicialização
|
||||
const initVisibleColumns = () => {
|
||||
try {
|
||||
const saved = localStorage.getItem('visibleOrderColumns');
|
||||
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 allColumns;
|
||||
};
|
||||
|
||||
// Inicializar a ordem das colunas
|
||||
const initColumnOrder = () => {
|
||||
try {
|
||||
const saved = localStorage.getItem('orderColumnsOrder');
|
||||
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);
|
||||
|
||||
useEffect(() => {
|
||||
try {
|
||||
const savedAllColumns = localStorage.getItem('allOrderColumns');
|
||||
if (savedAllColumns) {
|
||||
const parsedAllColumns = JSON.parse(savedAllColumns);
|
||||
if (JSON.stringify(parsedAllColumns) !== JSON.stringify(allColumns)) {
|
||||
localStorage.removeItem('visibleOrderColumns');
|
||||
localStorage.removeItem('orderColumnsOrder');
|
||||
localStorage.setItem('allOrderColumns', JSON.stringify(allColumns));
|
||||
// Recarregar a página para aplicar as novas colunas
|
||||
window.location.reload();
|
||||
|
||||
}
|
||||
} else {
|
||||
localStorage.setItem('allOrderColumns', JSON.stringify(allColumns));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Erro ao verificar as colunas no localStorage:', error);
|
||||
}
|
||||
}, [allColumns]);
|
||||
|
||||
// Salvar as colunas visíveis no localStorage sempre que elas mudarem
|
||||
useEffect(() => {
|
||||
try {
|
||||
localStorage.setItem('visibleOrderColumns', 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('orderColumnsOrder', JSON.stringify(columnOrder));
|
||||
} catch (error) {
|
||||
console.error('Erro ao salvar ordem das colunas:', error);
|
||||
}
|
||||
}, [columnOrder]);
|
||||
const tableColumns = useTableColumns({
|
||||
allColumns,
|
||||
storageKey: "Order",
|
||||
defaultVisibleColumns: allColumns,
|
||||
});
|
||||
|
||||
// Memoizar as classes de colunas para evitar recálculos desnecessários
|
||||
const getColumnClass = useCallback((title: string) => {
|
||||
@@ -98,12 +23,15 @@ export function useOrderTableColumns(allColumns: string[]) {
|
||||
"Valor": "w-20",
|
||||
"Peso(kg)": "w-20",
|
||||
"Carregamento": "w-28",
|
||||
"Dt Carregamento": "w-28",
|
||||
"Cobrança": "w-28",
|
||||
"Praça": "w-20",
|
||||
"Nota fiscal": "w-20",
|
||||
"Dt Faturamento": "w-28",
|
||||
"Rota": "w-24",
|
||||
"Trasportadora": "w-28",
|
||||
"Motorista": "w-24",
|
||||
"Placa": "w-32",
|
||||
};
|
||||
|
||||
let classes = "whitespace-nowrap ";
|
||||
@@ -121,103 +49,8 @@ export function useOrderTableColumns(allColumns: string[]) {
|
||||
return classes;
|
||||
}, []);
|
||||
|
||||
// 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; // salve a referência antes
|
||||
|
||||
// aplique a classe imediatamente (sem setTimeout)
|
||||
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
|
||||
setVisibleColumns(["Pedido"]);
|
||||
}, []);
|
||||
|
||||
// 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
|
||||
// Memoizando o resultado para evitar recálculos desnecessários
|
||||
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]);
|
||||
|
||||
|
||||
|
||||
return {
|
||||
visibleColumns,
|
||||
columnOrder,
|
||||
...tableColumns,
|
||||
getColumnClass,
|
||||
getOrderedVisibleColumns,
|
||||
resetColumnOrder,
|
||||
toggleColumn,
|
||||
selectAllColumns,
|
||||
unselectAllColumns,
|
||||
isColumnVisible,
|
||||
handleDragStart,
|
||||
handleDragEnd,
|
||||
handleDragOver,
|
||||
handleDrop
|
||||
};
|
||||
}
|
||||
217
src/hooks/useTableColumns.ts
Normal file
217
src/hooks/useTableColumns.ts
Normal file
@@ -0,0 +1,217 @@
|
||||
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,
|
||||
};
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import { leadtime } from "../components/types";
|
||||
import { Cliente } from "../components/types";
|
||||
|
||||
// URL base da API
|
||||
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || "http://10.40.0.2:8888";
|
||||
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || "https://portalapi.jurunense.com";
|
||||
|
||||
/**
|
||||
* Classe de erro personalizada para requisições de API.
|
||||
|
||||
@@ -72,3 +72,32 @@ export function buildUrl(
|
||||
|
||||
return queryString ? `${baseUrl}?${queryString}` : baseUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Limpa os parâmetros da URL atual e navega para uma nova URL
|
||||
*
|
||||
* @param path Caminho para navegar (sem parâmetros)
|
||||
*/
|
||||
export function clearUrlAndNavigate(path: string): void {
|
||||
if (typeof window !== 'undefined') {
|
||||
window.history.replaceState({ path }, "", path);
|
||||
window.location.href = path;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Limpa parâmetros específicos da URL atual
|
||||
*
|
||||
* @param paramsToRemove Array de parâmetros para remover
|
||||
*/
|
||||
export function clearUrlParams(paramsToRemove: string[]): void {
|
||||
if (typeof window !== 'undefined') {
|
||||
const url = new URL(window.location.href);
|
||||
|
||||
paramsToRemove.forEach(param => {
|
||||
url.searchParams.delete(param);
|
||||
});
|
||||
|
||||
window.history.replaceState({ path: url.pathname + url.search }, "", url.pathname + url.search);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user