diff --git a/src/assets/css/style.css b/src/assets/css/style.css index a75a91c..6453f20 100644 --- a/src/assets/css/style.css +++ b/src/assets/css/style.css @@ -105,3 +105,7 @@ font-weight: 700; text-transform: capitalize; } + +.react-flow__panel { + position: fixed; +} diff --git a/src/assets/icons/icon-exits.svg b/src/assets/icons/icon-exits.svg new file mode 100644 index 0000000..92847d3 --- /dev/null +++ b/src/assets/icons/icon-exits.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/main.tsx b/src/main.tsx index 553536f..8a731da 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,5 +1,6 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; +import { ReactFlowProvider } from '@xyflow/react'; import App from './App'; import NoteFlow from './nodes/NoteFlow'; diff --git a/src/nodes/CustomEdge.tsx b/src/nodes/CustomEdge.tsx new file mode 100644 index 0000000..286e9d8 --- /dev/null +++ b/src/nodes/CustomEdge.tsx @@ -0,0 +1,46 @@ +// CustomEdge.js +import React from 'react'; +import { getBezierPath } from '@xyflow/react'; // hoặc một hàm tương tự nếu có + +const CustomEdge = ({ id, sourceX, sourceY, targetX, targetY, data }) => { + const [path] = getBezierPath({ + sourceX, + sourceY, + targetX, + targetY + }); + + return ( + <> + + {data?.label && ( + +
+ {data.label} +
+
+ )} + + ); +}; + +export default CustomEdge; diff --git a/src/nodes/NoteFlow.tsx b/src/nodes/NoteFlow.tsx index 2e04727..2e03a6f 100644 --- a/src/nodes/NoteFlow.tsx +++ b/src/nodes/NoteFlow.tsx @@ -13,7 +13,8 @@ import { FaShuffle } from 'react-icons/fa6'; import '../assets/css/style.css'; import Tabbar from './Tabbar.tsx'; import ShowPopup from './ShowPopup.tsx'; -import { v4 as uuidv4 } from 'uuid'; +import { nanoid } from 'nanoid'; +import CustomEdge from './CustomEdge'; const initialNodes = [ { @@ -87,13 +88,13 @@ const NoteFlow = () => { const [nodeToDelete, setNodeToDelete] = useState(null); const [showPopup, setShowPopup] = useState(false); const [selectedNodeContent, setSelectedNodeContent] = useState(''); + const [addNodeCallback, setAddNodeCallback] = useState(() => () => {}); const handleAddNoteClick = () => { setShowTabBar(true); - const handleNodeSelect = (selectedNode) => { + setAddNodeCallback(() => (selectedNode) => { addNodeBetween(selectedNode, sourceId, targetId); - }; - setAddNodeCallback(() => addNodeBetweenWithIds); + }); }; const onNodeClick = (event, node) => { @@ -149,28 +150,38 @@ const NoteFlow = () => { return lastNode.position.y + spacing; }; + const removeEdgesRelatedToNode = (nodeId) => { + setEdges((eds) => + eds.filter((edge) => edge.source !== nodeId && edge.target !== nodeId) + ); + }; + const addNode = (option) => { - const newNodeId = uuidv4(); // Generate a unique ID for the new node + const newNodeId = nanoid(8); // Generate a unique ID for the new node const addNoteNode = nodes.find((node) => node.id === '2'); const initialX = addNoteNode.position.x; + console.log(initialX); + const nextY = nodes.length > 2 ? getNextYPosition(initialX, 130) : addNoteNode.position.y; - if (option.id === '4') { - // Handle specific option case - setNodes((nds) => nds.filter((node) => node.id !== '2')); + // 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: option.position.x, y: nextY } + position: { x: initialX, y: nextY } }; const yesNode = { - id: uuidv4(), + id: nanoid(8), type: 'output', key: 'contact-exists', data: { @@ -188,12 +199,12 @@ const NoteFlow = () => { ) }, - position: { x: option.position.x - 150, y: nextY + 150 } + position: { x: initialX - 150, y: nextY + 150 } }; const noNode = { - id: uuidv4(), - type: 'output', + id: nanoid(8), + type: '', key: 'send-survey', data: { label: ( @@ -210,30 +221,50 @@ const NoteFlow = () => { ) }, - position: { x: option.position.x + 150, y: nextY + 150 } + 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: uuidv4(), + id: nanoid(8), source: repliedNode.id, target: yesNode.id, - label: 'yes', - animated: false + label: 'yes' }, { - id: uuidv4(), + id: nanoid(8), source: repliedNode.id, target: noNode.id, - label: 'no', - animated: false + label: 'no' }, - { id: uuidv4(), source: lastNodeId, target: repliedNode.id } + { id: nanoid(8), source: lastNodeId, target: repliedNode.id }, + { id: nanoid(8), source: noNode.id, target: addNoteNode.id } ]); + + setLastNodeId(noNode.id); } else { + console.log(option); + // Add new node logic if (addNoteNode) { const initialX = addNoteNode.position.x; @@ -256,24 +287,37 @@ const NoteFlow = () => { key: option.key, data: { label: option.htmlNode }, position: { - x: option.position.x, + x: initialX, y: nodes.length > 2 ? nextY : addNoteNode.position.y } }; - console.log(getNextYPosition(option.position.x, 130)); + const newEdge = { + id: nanoid(8), + source: lastNodeId, + target: newNodeId + }; setNodes((nds) => [...nds, newNode]); - setEdges((eds) => [ ...eds, - { - id: uuidv4(), - source: lastNodeId, - target: newNodeId - } + newEdge, + { id: nanoid(8), source: newNodeId, target: addNoteNode.id } ]); + // setEdges((eds) => [ + // ...eds, + // { + // id: uuidv4(), + // source: lastNodeId, + // data: { + // label:
Add Note
, // Use HTML or React component + // onClick: handleAddNoteClick + // }, + // target: newNodeId + // } + // ]); + // Cuộn tới node mới thêm setLastNodeId(newNodeId); } @@ -294,6 +338,7 @@ const NoteFlow = () => {