diff --git a/src/nodes/NoteFlow.tsx b/src/nodes/NoteFlow.tsx deleted file mode 100644 index 984c082..0000000 --- a/src/nodes/NoteFlow.tsx +++ /dev/null @@ -1,756 +0,0 @@ -import { useState, useCallback, useEffect } from 'react'; -import { - ReactFlow, - addEdge, - Controls, - Background, - BackgroundVariant, - SelectionMode, - applyNodeChanges, - applyEdgeChanges, - MarkerType -} from '@xyflow/react'; -import '@xyflow/react/dist/style.css'; -import '../assets/css/style.css'; -import Tabbar from './Tabbar.tsx'; -import ShowPopup from './ShowPopup.tsx'; -import { nanoid } from 'nanoid'; -import CustomEdge from './CustomEdge'; -import MenuFlow from './MenuFlow'; - -const initialNodes = [ - { - key: 'customer-sign', - id: '1', - type: 'input', - data: { - label: ( -
-
- -
-
Customer signs up to
-
- ) - }, - position: { x: 250, y: 100 } - }, - { - id: '2', - key: 'add-node', - type: 'output', - data: { - label: ( -
- + Add a journey point -
- ) - }, - position: { x: 250, y: 220 } - } -]; - -// Nội dung cho mỗi node -const nodeContents = { - 'send-email': ` - - - - - `, - 'customer-sign': ` - - - - - `, - ifelse: ` - - - `, - 'contact-exists': ` - - - `, - 'send-survey': ` - - - - - ` -}; - -const connectEdges = [ - { - id: 'e1-2', - source: '1', - target: '2' - } -]; - -const NoteFlow = () => { - const [nodes, setNodes] = useState(initialNodes); - const [edges, setEdges] = useState(connectEdges); - const [showTabBar, setShowTabBar] = useState(false); - const [lastNodeId, setLastNodeId] = useState('1'); - const [nodeToDelete, setNodeToDelete] = useState(null); - const [showPopup, setShowPopup] = useState(false); - const [selectedNodeContent, setSelectedNodeContent] = useState(''); - const [addNodeCallback, setAddNodeCallback] = useState(() => () => {}); - const [isTabbarVisible, setIsTabbarVisible] = useState(false); - - const handleAddNoteClick = () => { - setShowTabBar(true); - setIsTabbarVisible(true); - setAddNodeCallback(() => (selectedNode) => { - addNodeBetween(selectedNode, sourceId, targetId); - }); - }; - const closeTabbar = () => { - setIsTabbarVisible(false); // Ẩn tabbar khi click close - }; - - const onNodeClick = (event, node) => { - console.log(node); - if (node.key === 'add-node') { - console.log(node); - // Check if the clicked node is "Add Node" - setShowTabBar(true); - setIsTabbarVisible(true); - } else { - // Hiển thị popup khi click vào bất kỳ node nào - const content = nodeContents[node.key]; // Lấy nội dung tương ứng của node - setSelectedNodeContent(content); // Cập nhật nội dung cho popup - setShowPopup(true); // Mở popup - } - }; - - const onNodeContextMenu = useCallback((event, node) => { - event.preventDefault(); // Ngăn không cho menu chuột phải mặc định hiện ra - setNodeToDelete(node); - }, []); - - const handleNodeDelete = () => { - if (nodeToDelete) { - setNodes((nds) => nds.filter((node) => node.id !== nodeToDelete.id)); - setEdges((eds) => - eds.filter( - (edge) => - edge.source !== nodeToDelete.id && edge.target !== nodeToDelete.id - ) - ); - setNodeToDelete(null); - } - }; - - // Function to get a unique y position - const getUniqueYPosition = (xPosition, baseY, spacing) => { - const existingYPositions = nodes - .filter((node) => node.position.x === xPosition) - .map((node) => node.position.y); - - let newYPosition = baseY; - - while (existingYPositions.includes(newYPosition)) { - newYPosition += spacing; - } - - return newYPosition; - }; - - const getNextYPosition = (xPosition, spacing) => { - const nodesInColumn = nodes.filter((node) => node.position.x === xPosition); - if (nodesInColumn.length === 0) return 0; // Return 0 if there are no nodes - - const lastNode = nodesInColumn[nodesInColumn.length - 1]; - return lastNode.position.y + spacing; - }; - - const removeEdgesRelatedToNode = (nodeId) => { - setEdges((eds) => - eds.filter((edge) => edge.source !== nodeId && edge.target !== nodeId) - ); - }; - - const addNode = (option) => { - const newNodeId = nanoid(8); // Generate a unique ID for the new node - const addNoteNode = nodes.find((node) => node.key === 'add-node'); - const initialX = addNoteNode?.position.x; - - const nextY = - nodes.length > 2 - ? getNextYPosition(initialX, 120) - : addNoteNode?.position.y; - - // Remove existing edges from addNoteNode - setEdges((eds) => - eds.filter((edge) => edge.source !== '2' && edge.target !== '2') - ); - - if (option.id === '4') { - const repliedNode = { - id: newNodeId, - key: option.key, - data: { label: option.htmlNode }, - position: { x: initialX, y: nextY } - }; - - const yesNode = { - id: nanoid(8), - type: 'output', - key: 'contact-exists', - data: { - label: ( -
-
- -
-
Contact Exists
-
- ) - }, - position: { x: initialX - 150, y: nextY + 150 } - }; - - const noNode = { - id: nanoid(8), - type: '', - key: 'send-survey', - data: { - label: ( -
-
- -
-
Send survey
-
- ) - }, - position: { x: initialX + 150, y: nextY + 150 } - }; - - // Di chuyển node add-note sang nhánh no - setNodes((nds) => - nds.map((node) => - node.id === '2' - ? { - ...node, - position: { - x: noNode.position.x, - y: noNode.position.y + 150 - } - } - : node - ) - ); - - // Thêm các node mới (replied, yes, no) - setNodes((nds) => [...nds, repliedNode, yesNode, noNode]); - - // Kết nối các edges giữa các node - setEdges((eds) => [ - ...eds, - { - id: nanoid(8), - source: repliedNode.id, - target: yesNode.id, - label: 'yes' - }, - { - id: nanoid(8), - source: repliedNode.id, - target: noNode.id, - label: 'no' - }, - { id: nanoid(8), source: lastNodeId, target: repliedNode.id }, - { id: nanoid(8), source: noNode.id, target: addNoteNode.id } - ]); - - setLastNodeId(noNode.id); - } else { - // Add new node logic - if (addNoteNode) { - const initialX = addNoteNode.position.x; - setNodes((nds) => - nds.map((node) => - node.key === 'add-node' - ? { - ...node, - position: { - x: initialX, - y: nextY + 130 - } - } - : node - ) - ); - } - const newNode = { - id: newNodeId, - key: option.key, - data: { label: option.htmlNode }, - position: { - x: initialX, - y: nodes.length > 2 ? nextY : addNoteNode.position.y - } - }; - - const newEdge = { - id: nanoid(8), - source: lastNodeId, - target: newNodeId - // data: { - // label:
+
, - // onClick: handleAddNoteClick - // } - }; - - setNodes((nds) => [...nds, newNode]); - setEdges((eds) => [ - ...eds, - newEdge, - { id: nanoid(8), source: newNodeId, target: addNoteNode.id } - ]); - - // setEdges((eds) => [ - // ...eds, - // { - // id: nanoid(8), - // source: lastNodeId, - // data: { - // label:
Add Note
, // Use HTML or React component - // onClick: handleAddNoteClick - // }, - // target: newNodeId - // }, - // { id: nanoid(8), source: newNodeId, target: addNoteNode.id } - // ]); - - // Cuộn tới node mới thêm - setLastNodeId(newNodeId); - } - - setShowTabBar(false); - }; - - const hidePopup = () => { - setShowPopup(false); - }; - - const addPopup = (node) => { - const content = nodeContents[node.id]; // Lấy nội dung từ nodeContents dựa trên ID node - setSelectedNodeContent(content); // Cập nhật nội dung được chọn - }; - - const onDrop = (event) => { - event.preventDefault(); - - const type = JSON.parse( - event.dataTransfer.getData('application/reactflow') - ); - const reactFlowBounds = event.target.getBoundingClientRect(); - const position = { - x: event.clientX - reactFlowBounds.left - 100, - y: event.clientY - reactFlowBounds.top + 5 - }; - - const newNodeId = nanoid(8); - // Xử lý add-node với id '2' - const addNodeId = '2'; - const addNode = nodes.find((node) => node.id === addNodeId); - - // Tìm các edge nối với node có id '2' - const targetEdge = edges.find( - (edge) => edge?.source === '2' || edge?.target === '2' - ); - const targetNodeId = - targetEdge?.source === '2' ? targetEdge?.target : targetEdge?.source; - - const targetNode = nodes.find((node) => node.id === targetNodeId); - - // Cập nhật vị trí của node mới để cách node đang kết nối 200 đơn vị - const newNodePosition = { - x: targetNode?.position.x, - y: targetNode?.position.y + 110 - }; - - // Tạo node mới - const newNode = { - id: newNodeId, - key: type.key, - type: type.type || 'default', - data: { - label: ( -
-
- -
-
{type.label}
-
- ) - }, - position: newNodePosition - }; - - // Loại bỏ các edge liên quan đến node '2' - setEdges((eds) => - eds.filter((edge) => edge.source !== '2' && edge.target !== '2') - ); - - // Kiểm tra điều kiện node là 'ifelse' - if (type.key === 'ifelse') { - setNodes((nds) => nds.filter((node) => node.id !== addNodeId)); - const yesNodeId = nanoid(8); - const noNodeId = nanoid(8); - - // Tạo node Yes - const yesNode = { - id: yesNodeId, - key: 'add-node', - brand: 'yes', - data: { - label: ( -
- + Add a journey point -
- ) - }, - position: { - x: newNode.position.x - 200, // Điều chỉnh vị trí của nhánh Yes - y: newNode.position.y + 150 // Điều chỉnh vị trí của nhánh Yes - } - }; - - // Tạo node No - const noNode = { - id: noNodeId, - key: 'add-node', - brand: 'no', - data: { - label: ( -
- + Add a journey point -
- ) - }, - position: { - x: newNode?.position.x + 200, // Điều chỉnh vị trí của nhánh No - y: newNode?.position.y + 150 // Điều chỉnh vị trí của nhánh No - } - }; - - // Tạo các edge nối từ node ifelse đến Yes và No - const ifelseEdges = [ - { - id: nanoid(8), - source: targetNodeId, - target: newNodeId - }, - { - id: nanoid(8), - source: newNodeId, - target: yesNodeId, - type: 'custom', - data: { - label: 'Yes' - } - }, - { - id: nanoid(8), - source: newNodeId, - target: noNodeId, - type: 'custom', - data: { - label: 'No' - } - } - ]; - - // Thêm node yes, no và edge vào danh sách node và edges - setNodes((nds) => [...nds, newNode, yesNode, noNode]); - setEdges((eds) => [...eds, ...ifelseEdges]); - } else { - // Nếu không phải 'ifelse', kiểm tra các điều kiện của node bình thường - - if (targetNode) { - setNodes((nds) => [...nds, newNode]); - setEdges((eds) => [ - ...eds, - { - id: nanoid(8), - source: targetNodeId, - target: newNodeId - }, - { - id: nanoid(8), - source: newNodeId, - target: '2' - } - ]); - - if (addNode) { - const addNodePosition = { - x: addNode.position.x, - y: addNode.position.y + 110 - }; - - setNodes((nds) => - nds.map((node) => - node.id === addNodeId - ? { ...node, position: addNodePosition } - : node - ) - ); - - setEdges((eds) => - eds.filter( - (edge) => edge.source !== addNodeId && edge.target !== addNodeId - ) - ); - - // Thêm edge mới nối add-node và node mới - setEdges((eds) => [ - ...eds, - { - id: nanoid(8), - source: newNodeId, - target: addNodeId - } - ]); - - // Kiểm tra nếu node mới là 'contact-exists', ẩn add-node - if (type.key === 'contact-exists') { - setNodes((nds) => nds.filter((node) => node.id !== addNodeId)); - } - } - } else { - const newNodeNew = { - id: newNodeId, - key: type.key, - type: type.type || 'default', - data: { - label: ( -
-
- -
-
{type.label}
-
- ) - }, - position: position - }; - - setNodes((nds) => [...nds, newNodeNew]); - } - } - }; - - const onDragOver = useCallback((event) => { - event.preventDefault(); - event.dataTransfer.dropEffect = 'move'; - }, []); - - const onNodesChange = useCallback( - (changes) => setNodes((nds) => applyNodeChanges(changes, nds)), - [setNodes] - ); - const onEdgesChange = useCallback( - (changes) => setEdges((eds) => applyEdgeChanges(changes, eds)), - [setEdges] - ); - - const defaultEdgeOptions = { - style: { strokeWidth: 1.5, stroke: 'black' }, - type: 'floating', - markerEnd: { - type: MarkerType.ArrowClosed, - color: 'black' - } - }; - - const onConnect = useCallback( - (params) => setEdges((eds) => addEdge(params, eds)), - [setEdges] - ); - - // Hàm tính khoảng cách giữa hai node - const getDistance = (pos1, pos2) => { - return Math.sqrt( - Math.pow(pos1.x - pos2.x, 2) + Math.pow(pos1.y - pos2.y, 2) - ); - }; - - // Hàm xử lý khi dừng kéo node - const onNodeDragStop = useCallback( - (event, node) => { - const threshold = 50; // khoảng cách cho phép để node bị "đè" - let closestNode = null; - let closestDistance = Infinity; - - nodes.forEach((item) => { - if (item.id !== node.id) { - const distance = getDistance(node.position, item.position); - if (distance < closestDistance && distance <= threshold) { - closestNode = item; - closestDistance = distance; - } - } - }); - - if (closestNode) { - // Thay thế node cũ bằng node mới - const updatedEdges = edges.map((edge) => { - if (edge.source === closestNode.id) { - return { ...edge, source: node.id }; // Nối node mới làm source - } - if (edge.target === closestNode.id) { - return { ...edge, target: node.id }; // Nối node mới làm target - } - return edge; - }); - if (node.type != 'output') { - // Tạo một node mới với nội dung "Add a journey point" ngay dưới node thay thế - const newNode = { - id: nanoid(8), - key: 'add-node', - brand: node.brand, - position: { - x: node.position.x, // Giữ nguyên vị trí x - y: node.position.y + 100 // Đặt node mới xuống dưới 150 đơn vị y - }, - data: { - label: ( -
- + Add a journey point -
- ) - } - }; - - // Thay thế node cũ bằng node mới - setNodes((nds) => [ - ...nds.map((n) => - n.id === closestNode.id - ? { ...closestNode, ...node, position: node.position } - : n - ), - newNode // Thêm node mới - ]); - - // Cập nhật edges - setEdges([ - ...updatedEdges, - { - id: nanoid(8), // ID của edge mới - source: node.id, // Nối từ node vừa thay thế - target: newNode.id // Đến node "Add a journey point" - } - ]); - } else { - // Thay thế node cũ bằng node mới - setNodes((nds) => [ - ...nds.map((n) => - n.id === closestNode.id - ? { ...closestNode, ...node, position: node.position } - : n - ) - ]); - - // Cập nhật edges - setEdges(updatedEdges); - } - } else { - // Không có node gần, cập nhật node vào vị trí mới - setNodes((nds) => - nds.map((n) => - n.id === node.id ? { ...n, position: node.position } : n - ) - ); - } - }, - [nodes, edges, setNodes, setEdges] - ); - - return ( -
-
- -
- - - - -
-
- - {isTabbarVisible && ( - - )} - - {nodeToDelete && ( -
- -
- )} - {showPopup && ( - setShowPopup(false)} - /> - )} -
- ); -}; - -export default NoteFlow;