fix(mapa): resolvido memory leak e erro infinite loop nas renders
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import React, { useState, useEffect, useRef, useMemo, useCallback } from 'react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Input } from '@/components/ui/input';
|
||||
@@ -18,82 +18,7 @@ import { useUserRole } from '@/hooks/useUserRole';
|
||||
import { UserResourcePermissions } from '@/components/mapa-interativo/UserResourcePermissions';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
export default function MapaInterativo() {
|
||||
const { nodes, connections } = useSystemMapAutoDiscovery();
|
||||
const { isAdmin } = useUserRole();
|
||||
const [activeFilter, setActiveFilter] = useState<string>('all');
|
||||
const [selectedNode, setSelectedNode] = useState<SystemMapNode | null>(null);
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const [draggedNode, setDraggedNode] = useState<string | null>(null);
|
||||
const [highlightedPath, setHighlightedPath] = useState<string[]>([]);
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const [editData, setEditData] = useState<{ title: string; description: string; group: string }>({ title: '', description: '', group: '' });
|
||||
const mapContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const filters = [
|
||||
{ id: 'all', label: 'Ver Tudo', icon: Eye },
|
||||
{ id: 'main-flow', label: 'Fluxo Principal', icon: Workflow },
|
||||
{ id: 'permissions', label: 'Meus Acessos', icon: Shield }
|
||||
];
|
||||
|
||||
const filteredNodes = nodes.filter(node => {
|
||||
switch (activeFilter) {
|
||||
case 'main-flow': return node.isMainFlow;
|
||||
case 'permissions': return node.hasAccess;
|
||||
default: return true;
|
||||
}
|
||||
});
|
||||
|
||||
const filteredConnections = connections.filter(conn => {
|
||||
const sourceExists = filteredNodes.some(n => n.id === conn.from);
|
||||
const targetExists = filteredNodes.some(n => n.id === conn.to);
|
||||
return sourceExists && targetExists;
|
||||
});
|
||||
|
||||
const getMapDimensions = () => {
|
||||
if (filteredNodes.length === 0) return { width: 1200, height: 800 };
|
||||
|
||||
const cardWidth = 240;
|
||||
const cardHeight = 140;
|
||||
const padding = 100; // Padding extra para garantir espaço
|
||||
|
||||
let maxX = 0;
|
||||
let maxY = 0;
|
||||
|
||||
filteredNodes.forEach(node => {
|
||||
const nodeEl = mapContainerRef.current?.querySelector(`[data-node="${node.id}"]`) as HTMLElement;
|
||||
if (nodeEl) {
|
||||
const rect = nodeEl.getBoundingClientRect();
|
||||
const containerRect = mapContainerRef.current!.getBoundingClientRect();
|
||||
maxX = Math.max(maxX, rect.left - containerRect.left + cardWidth);
|
||||
maxY = Math.max(maxY, rect.top - containerRect.top + cardHeight);
|
||||
} else {
|
||||
// Usar posições iniciais se o elemento ainda não foi renderizado
|
||||
maxX = Math.max(maxX, node.left + cardWidth);
|
||||
maxY = Math.max(maxY, node.top + cardHeight);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
width: Math.max(1200, maxX + padding),
|
||||
height: Math.max(800, maxY + padding)
|
||||
};
|
||||
};
|
||||
|
||||
const [mapDimensions, setMapDimensions] = useState(getMapDimensions());
|
||||
|
||||
useEffect(() => {
|
||||
const updateDimensions = () => {
|
||||
setMapDimensions(getMapDimensions());
|
||||
};
|
||||
|
||||
updateDimensions();
|
||||
const interval = setInterval(updateDimensions, 1000); // Atualizar periodicamente
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [filteredNodes]);
|
||||
|
||||
const createCurvedPath = (fromX: number, fromY: number, toX: number, toY: number) => {
|
||||
const createCurvedPath = (fromX: number, fromY: number, toX: number, toY: number) => {
|
||||
const midX = (fromX + toX) / 2;
|
||||
const midY = (fromY + toY) / 2;
|
||||
|
||||
@@ -109,9 +34,9 @@ export default function MapaInterativo() {
|
||||
const controlY = midY + offsetY;
|
||||
|
||||
return `M ${fromX} ${fromY} Q ${controlX} ${controlY} ${toX} ${toY}`;
|
||||
};
|
||||
};
|
||||
|
||||
const getArrowPositions = (fromX: number, fromY: number, toX: number, toY: number) => {
|
||||
const getArrowPositions = (fromX: number, fromY: number, toX: number, toY: number) => {
|
||||
const arrows = [];
|
||||
const steps = 3; // Número de setas ao longo da linha
|
||||
|
||||
@@ -140,9 +65,96 @@ export default function MapaInterativo() {
|
||||
}
|
||||
|
||||
return arrows;
|
||||
};
|
||||
|
||||
export default function MapaInterativo() {
|
||||
const { nodes, connections } = useSystemMapAutoDiscovery();
|
||||
const { isAdmin } = useUserRole();
|
||||
const [activeFilter, setActiveFilter] = useState<string>('all');
|
||||
const [selectedNode, setSelectedNode] = useState<SystemMapNode | null>(null);
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const [draggedNode, setDraggedNode] = useState<string | null>(null);
|
||||
const [highlightedPath, setHighlightedPath] = useState<string[]>([]);
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const [editData, setEditData] = useState<{ title: string; description: string; group: string }>({ title: '', description: '', group: '' });
|
||||
const mapContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const filters = [
|
||||
{ id: 'all', label: 'Ver Tudo', icon: Eye },
|
||||
{ id: 'main-flow', label: 'Fluxo Principal', icon: Workflow },
|
||||
{ id: 'permissions', label: 'Meus Acessos', icon: Shield }
|
||||
];
|
||||
|
||||
const filteredNodes = useMemo(() => {
|
||||
return nodes.filter(node => {
|
||||
switch (activeFilter) {
|
||||
case 'main-flow': return node.isMainFlow;
|
||||
case 'permissions': return node.hasAccess;
|
||||
default: return true;
|
||||
}
|
||||
});
|
||||
}, [nodes, activeFilter]);
|
||||
|
||||
const filteredConnections = useMemo(() => {
|
||||
return connections.filter(conn => {
|
||||
const sourceExists = filteredNodes.some(n => n.id === conn.from);
|
||||
const targetExists = filteredNodes.some(n => n.id === conn.to);
|
||||
return sourceExists && targetExists;
|
||||
});
|
||||
}, [connections, filteredNodes]);
|
||||
|
||||
const getMapDimensions = useCallback(() => {
|
||||
if (filteredNodes.length === 0) return { width: 1200, height: 800 };
|
||||
|
||||
const cardWidth = 240;
|
||||
const cardHeight = 140;
|
||||
const padding = 100; // Padding extra para garantir espaço
|
||||
|
||||
let maxX = 0;
|
||||
let maxY = 0;
|
||||
|
||||
filteredNodes.forEach(node => {
|
||||
const nodeEl = mapContainerRef.current?.querySelector(`[data-node="${node.id}"]`) as HTMLElement;
|
||||
if (nodeEl) {
|
||||
const rect = nodeEl.getBoundingClientRect();
|
||||
const containerRect = mapContainerRef.current!.getBoundingClientRect();
|
||||
maxX = Math.max(maxX, rect.left - containerRect.left + cardWidth);
|
||||
maxY = Math.max(maxY, rect.top - containerRect.top + cardHeight);
|
||||
} else {
|
||||
// Usar posições iniciais se o elemento ainda não foi renderizado
|
||||
maxX = Math.max(maxX, node.left + cardWidth);
|
||||
maxY = Math.max(maxY, node.top + cardHeight);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
width: Math.max(1200, maxX + padding),
|
||||
height: Math.max(800, maxY + padding)
|
||||
};
|
||||
}, [filteredNodes]);
|
||||
|
||||
const [mapDimensions, setMapDimensions] = useState({ width: 1200, height: 800 });
|
||||
|
||||
useEffect(() => {
|
||||
const updateDimensions = () => {
|
||||
setMapDimensions(prev => {
|
||||
const next = getMapDimensions();
|
||||
if (prev.width === next.width && prev.height === next.height) {
|
||||
return prev;
|
||||
}
|
||||
return next;
|
||||
});
|
||||
};
|
||||
|
||||
const updateConnections = () => {
|
||||
updateDimensions();
|
||||
const interval = setInterval(updateDimensions, 1000); // Atualizar periodicamente
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [getMapDimensions]);
|
||||
|
||||
|
||||
|
||||
const updateConnections = useCallback(() => {
|
||||
if (!mapContainerRef.current) return;
|
||||
|
||||
const container = mapContainerRef.current;
|
||||
@@ -179,14 +191,14 @@ export default function MapaInterativo() {
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}, [filteredConnections]);
|
||||
|
||||
useEffect(() => {
|
||||
updateConnections();
|
||||
const handleResize = () => updateConnections();
|
||||
window.addEventListener('resize', handleResize);
|
||||
return () => window.removeEventListener('resize', handleResize);
|
||||
}, [filteredNodes, filteredConnections]);
|
||||
}, [updateConnections]);
|
||||
|
||||
const handleNodeMouseOver = (nodeId: string) => {
|
||||
const relatedNodes = new Set<string>();
|
||||
|
||||
Reference in New Issue
Block a user