This commit is contained in:
2024-09-25 17:20:34 +07:00
parent 3762dbe776
commit f89d9e3658
3 changed files with 249 additions and 25 deletions

View File

@@ -10,6 +10,7 @@ import {
ReactFlowProvider,
useNodesState,
useEdgesState,
useStoreApi,
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';
import '../assets/css/style.css';
@@ -18,6 +19,7 @@ import ShowPopup from './ShowPopup.tsx';
import { nanoid } from 'nanoid';
import CustomEdge from './CustomEdge';
import MenuFlow from './MenuFlow';
import DeleteNodeModal from './popup/DeleteNodeModal.tsx';
// Nội dung cho mỗi node
const nodeContents = {
@@ -53,8 +55,8 @@ const nodeContents = {
};
const NodeFlow = ({ initialNodes, initialEdges }) => {
const [nodes, setNodes] = useState(initialNodes);
const [edges, setEdges] = useState(initialEdges);
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
const [showTabBar, setShowTabBar] = useState(false);
const [lastNodeId, setLastNodeId] = useState(nodes[0].id);
const [showPopup, setShowPopup] = useState(false);
@@ -64,6 +66,9 @@ const NodeFlow = ({ initialNodes, initialEdges }) => {
const { screenToFlowPosition } = useReactFlow();
const [showActions, setShowActions] = useState(null);
const [showPopupSuccess, setShowPopupSuccess] = useState(false);
const store = useStoreApi();
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [deleteNodeId, setDeleteNodeId] = useState(null);
const handleAddNoteClick = () => {
setShowTabBar(true);
@@ -337,7 +342,7 @@ const NodeFlow = ({ initialNodes, initialEdges }) => {
Sửa
</button>
<button
onClick={() => handleDeleteNode(newNodeId)}
onClick={() => handleDeleteNode(newNodeId, type.key)}
className="btn-remove"
>
Xóa
@@ -505,8 +510,6 @@ const NodeFlow = ({ initialNodes, initialEdges }) => {
}
}
}
console.log('Updated nodes:', nodes);
};
const onDragOver = useCallback((event) => {
@@ -546,32 +549,62 @@ const NodeFlow = ({ initialNodes, initialEdges }) => {
// Hàm xóa node
const handleDeleteNode = useCallback(
(nodeId) => {
(nodeId, nodeKey) => {
// Tìm tất cả các edges có nodeId là source hoặc target
const connectedEdges = edges.filter(
(edge) => edge.source === nodeId || edge.target === nodeId
);
const allNode = store.getState();
const edgeNode = allNode.edges;
const Node = allNode.nodes;
console.log(connectedEdges);
if (nodeKey === 'ifelse') {
setDeleteNodeId(nodeId); // Lưu lại ID của node muốn xóa
// Hiển thị modal để người dùng chọn nhánh xóa
setIsDeleteModalOpen(true);
document
.querySelector('.actions-' + nodeId)
?.classList.remove('staticNode');
} else {
const isConfirmed = window.confirm(
'Bạn có chắc chắn muốn xóa node này không?'
);
// Lấy các nodes đang nối với node bị xóa
const sourceNode = connectedEdges.find(
(edge) => edge.target === nodeId
)?.source;
const targetNode = connectedEdges.find(
(edge) => edge.source === nodeId
)?.target;
if (!isConfirmed) return;
// Cập nhật nodes: xóa node bị xóa
setNodes((nds) => nds.filter((node) => node.id !== nodeId));
// Tìm tất cả các edges có nodeId là source hoặc target
const connectedEdges = edgeNode.filter(
(edge) => edge.source === nodeId || edge.target === nodeId
);
// Cập nhật edges: xóa các cạnh kết nối với node bị xóa
setEdges((eds) =>
eds.filter((edge) => edge.source !== nodeId && edge.target !== nodeId)
);
console.log('connectedEdges', connectedEdges);
const sourceNode = connectedEdges.find(
(edge) => edge.target === nodeId
)?.source;
const targetNode = connectedEdges.find(
(edge) => edge.source === nodeId
)?.target;
// Xóa node và các node con
setNodes((nds) => {
const updatedNodes = nds.filter((node) => node.id !== nodeId);
// Cập nhật vị trí cho các node còn lại
const sortedNodes = updatedNodes.sort(
(a, b) => a.position.y - b.position.y
);
return sortedNodes.map((node, index) => ({
...node,
position: {
...node.position,
y: index * 110, // Khoảng cách giữa các node
},
}));
});
// Xóa các cạnh kết nối với node bị xóa và các node con
setEdges((eds) =>
eds.filter((edge) => edge.source !== nodeId && edge.target !== nodeId)
);
// Nếu có cả sourceNode và targetNode, tạo một edge mới nối 2 node này
if (sourceNode && targetNode) {
setEdges((eds) => [
...eds,
{
@@ -585,6 +618,111 @@ const NodeFlow = ({ initialNodes, initialEdges }) => {
[edges, setNodes, setEdges]
);
// Hàm xác định và xóa nhánh dựa trên node đã chọn
const handleConfirmDeleteBranchNode = (branch) => {
const allNode = store.getState();
const Node = allNode.nodes;
const edgeNode = allNode.edges;
// Tìm node ifelse
const ifelseNode = allNode.nodes.find((node) => node.id === deleteNodeId);
// Tìm edges của nhánh được chọn (Yes hoặc No)
const branchEdges = edgeNode.filter((edge) => edge.data?.label === branch);
// Lấy ID của tất cả các node trong nhánh dựa trên các edges
const branchNodeIds = branchEdges.map((edge) => edge.target);
// Lấy danh sách các node trong nhánh dựa trên cùng tọa độ x với node được chọn
const selectedNode = allNode.nodes.find(
(node) => node.id === branchNodeIds[0]
);
const nodesToDelete = allNode.nodes
.filter((node) => node.position.x === selectedNode.position.x) // Lọc các node có cùng tọa độ x với node được chọn
.map((node) => node.id); // Lấy ID của các node trong nhánh
// Bao gồm cả node ifelse trong danh sách node cần xóa
nodesToDelete.push(ifelseNode.id);
// Tìm edges nối đến nhánh còn lại
const remainingEdges = edgeNode.filter(
(edge) => edge.source === ifelseNode.id && edge.data?.label !== branch
);
const TargetIfelse = edgeNode.filter(
(edge) => edge.target === ifelseNode.id
);
const NodeRemaining = allNode.nodes.find(
(node) => node.id === remainingEdges[0].target
);
// Xóa tất cả các node trong nhánh
setNodes((nds) => {
const updatedNodes = nds.filter(
(node) => !nodesToDelete.includes(node.id)
);
// Nếu còn node sau khi xóa
if (updatedNodes.length > 0) {
// Lấy tất cả các node của nhánh còn lại
const nodesToRemaining = allNode.nodes
.filter((node) => node.position.x === NodeRemaining.position.x) // Lọc các node có cùng tọa độ x với node được chọn
.map((node) => node); // Lấy các node trong nhánh
// Đặt lại vị trí của tất cả các node còn lại theo thứ tự và khoảng cách đều
const updatedRemainingNodes = nodesToRemaining.map((node, index) => ({
...node,
position: {
x: ifelseNode.position.x,
y: ifelseNode.position.y + index * 110,
},
}));
// Kết hợp lại với các node khác (nếu có)
return updatedNodes.map((node) => {
const updatedNode = updatedRemainingNodes.find(
(n) => n.id === node.id
);
return updatedNode ? updatedNode : node;
});
}
return updatedNodes; // Trả về danh sách nodes đã được cập nhật
});
// Xóa các edges liên quan đến nhánh được chọn
setEdges((eds) => {
const updatedEdges = [
...eds.filter(
(edge) =>
!nodesToDelete.includes(edge.source) &&
!nodesToDelete.includes(edge.target)
),
{
id: `edge-${NodeRemaining.id}-${TargetIfelse[0].source}`,
source: NodeRemaining.id,
target: TargetIfelse[0].source,
},
];
return updatedEdges;
});
setIsDeleteModalOpen(false); // Đóng modal
};
// Hàm xử lý xác nhận xóa
const handleConfirmDelete = (choice) => {
if (choice === 'yes') {
handleConfirmDeleteBranchNode('Yes');
} else if (choice === 'no') {
handleConfirmDeleteBranchNode('No');
} else if (choice === 'both') {
handleConfirmDeleteBranchNode('Yes');
handleConfirmDeleteBranchNode('No');
}
};
// Hàm sửa node
const handleEditNode = (nodeId: string) => {
// Logic chỉnh sửa node
@@ -614,6 +752,8 @@ const NodeFlow = ({ initialNodes, initialEdges }) => {
panOnScroll
defaultEdgeOptions={defaultEdgeOptions}
onConnect={onConnect}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
>
<Controls position="right-bottom" />
<Background variant={BackgroundVariant.Lines} color="#ccccc" />
@@ -652,6 +792,13 @@ const NodeFlow = ({ initialNodes, initialEdges }) => {
</div>
</div>
)}
{isDeleteModalOpen && (
<DeleteNodeModal
onConfirm={handleConfirmDelete}
onClose={() => setIsDeleteModalOpen(false)}
/>
)}
</div>
);
};