up 10/9
This commit is contained in:
@@ -105,3 +105,7 @@
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
text-transform: capitalize;
|
text-transform: capitalize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.react-flow__panel {
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
|||||||
1
src/assets/icons/icon-exits.svg
Normal file
1
src/assets/icons/icon-exits.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" focusable="false" aria-hidden="true" class="wink-icon exitIndicatorIcon-1gdYp"><path d="M7 2a2 2 0 00-2 2v5h2V4h12v16H7v-5H5v5a2 2 0 002 2h12a2 2 0 002-2V4a2 2 0 00-2-2H7z"></path><path d="M11.743 6.331l-1.486 1.338 3.181 3.535L2 11v2l11.438-.204-3.181 3.535 1.486 1.338L16.845 12l-5.102-5.669z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 369 B |
@@ -1,5 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom/client';
|
import ReactDOM from 'react-dom/client';
|
||||||
|
import { ReactFlowProvider } from '@xyflow/react';
|
||||||
|
|
||||||
import App from './App';
|
import App from './App';
|
||||||
import NoteFlow from './nodes/NoteFlow';
|
import NoteFlow from './nodes/NoteFlow';
|
||||||
|
|||||||
46
src/nodes/CustomEdge.tsx
Normal file
46
src/nodes/CustomEdge.tsx
Normal file
@@ -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 (
|
||||||
|
<>
|
||||||
|
<path
|
||||||
|
id={id}
|
||||||
|
d={path}
|
||||||
|
style={{ stroke: '#ccc', strokeWidth: .8, fill: 'transparent' }}
|
||||||
|
/>
|
||||||
|
{data?.label && (
|
||||||
|
<foreignObject
|
||||||
|
width={90}
|
||||||
|
height={30}
|
||||||
|
x={(sourceX + targetX) / 2 - 38}
|
||||||
|
y={(sourceY + targetY) / 2 - 15}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
xmlns='http://www.w3.org/1999/xhtml'
|
||||||
|
style={{
|
||||||
|
background: 'white',
|
||||||
|
padding: '5px',
|
||||||
|
borderRadius: '0.8px',
|
||||||
|
cursor: 'pointer',
|
||||||
|
fontSize: '13px'
|
||||||
|
}}
|
||||||
|
onClick={data.onClick}
|
||||||
|
>
|
||||||
|
{data.label}
|
||||||
|
</div>
|
||||||
|
</foreignObject>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CustomEdge;
|
||||||
@@ -13,7 +13,8 @@ import { FaShuffle } from 'react-icons/fa6';
|
|||||||
import '../assets/css/style.css';
|
import '../assets/css/style.css';
|
||||||
import Tabbar from './Tabbar.tsx';
|
import Tabbar from './Tabbar.tsx';
|
||||||
import ShowPopup from './ShowPopup.tsx';
|
import ShowPopup from './ShowPopup.tsx';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { nanoid } from 'nanoid';
|
||||||
|
import CustomEdge from './CustomEdge';
|
||||||
|
|
||||||
const initialNodes = [
|
const initialNodes = [
|
||||||
{
|
{
|
||||||
@@ -87,13 +88,13 @@ const NoteFlow = () => {
|
|||||||
const [nodeToDelete, setNodeToDelete] = useState(null);
|
const [nodeToDelete, setNodeToDelete] = useState(null);
|
||||||
const [showPopup, setShowPopup] = useState(false);
|
const [showPopup, setShowPopup] = useState(false);
|
||||||
const [selectedNodeContent, setSelectedNodeContent] = useState('');
|
const [selectedNodeContent, setSelectedNodeContent] = useState('');
|
||||||
|
const [addNodeCallback, setAddNodeCallback] = useState(() => () => {});
|
||||||
|
|
||||||
const handleAddNoteClick = () => {
|
const handleAddNoteClick = () => {
|
||||||
setShowTabBar(true);
|
setShowTabBar(true);
|
||||||
const handleNodeSelect = (selectedNode) => {
|
setAddNodeCallback(() => (selectedNode) => {
|
||||||
addNodeBetween(selectedNode, sourceId, targetId);
|
addNodeBetween(selectedNode, sourceId, targetId);
|
||||||
};
|
});
|
||||||
setAddNodeCallback(() => addNodeBetweenWithIds);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onNodeClick = (event, node) => {
|
const onNodeClick = (event, node) => {
|
||||||
@@ -149,28 +150,38 @@ const NoteFlow = () => {
|
|||||||
return lastNode.position.y + spacing;
|
return lastNode.position.y + spacing;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const removeEdgesRelatedToNode = (nodeId) => {
|
||||||
|
setEdges((eds) =>
|
||||||
|
eds.filter((edge) => edge.source !== nodeId && edge.target !== nodeId)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const addNode = (option) => {
|
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 addNoteNode = nodes.find((node) => node.id === '2');
|
||||||
const initialX = addNoteNode.position.x;
|
const initialX = addNoteNode.position.x;
|
||||||
|
console.log(initialX);
|
||||||
|
|
||||||
const nextY =
|
const nextY =
|
||||||
nodes.length > 2
|
nodes.length > 2
|
||||||
? getNextYPosition(initialX, 130)
|
? getNextYPosition(initialX, 130)
|
||||||
: addNoteNode.position.y;
|
: addNoteNode.position.y;
|
||||||
|
|
||||||
if (option.id === '4') {
|
// Remove existing edges from addNoteNode
|
||||||
// Handle specific option case
|
setEdges((eds) =>
|
||||||
setNodes((nds) => nds.filter((node) => node.id !== '2'));
|
eds.filter((edge) => edge.source !== '2' && edge.target !== '2')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (option.id === '4') {
|
||||||
const repliedNode = {
|
const repliedNode = {
|
||||||
id: newNodeId,
|
id: newNodeId,
|
||||||
key: option.key,
|
key: option.key,
|
||||||
data: { label: option.htmlNode },
|
data: { label: option.htmlNode },
|
||||||
position: { x: option.position.x, y: nextY }
|
position: { x: initialX, y: nextY }
|
||||||
};
|
};
|
||||||
|
|
||||||
const yesNode = {
|
const yesNode = {
|
||||||
id: uuidv4(),
|
id: nanoid(8),
|
||||||
type: 'output',
|
type: 'output',
|
||||||
key: 'contact-exists',
|
key: 'contact-exists',
|
||||||
data: {
|
data: {
|
||||||
@@ -188,12 +199,12 @@ const NoteFlow = () => {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
position: { x: option.position.x - 150, y: nextY + 150 }
|
position: { x: initialX - 150, y: nextY + 150 }
|
||||||
};
|
};
|
||||||
|
|
||||||
const noNode = {
|
const noNode = {
|
||||||
id: uuidv4(),
|
id: nanoid(8),
|
||||||
type: 'output',
|
type: '',
|
||||||
key: 'send-survey',
|
key: 'send-survey',
|
||||||
data: {
|
data: {
|
||||||
label: (
|
label: (
|
||||||
@@ -210,30 +221,50 @@ const NoteFlow = () => {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
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]);
|
setNodes((nds) => [...nds, repliedNode, yesNode, noNode]);
|
||||||
|
|
||||||
|
// Kết nối các edges giữa các node
|
||||||
setEdges((eds) => [
|
setEdges((eds) => [
|
||||||
...eds,
|
...eds,
|
||||||
{
|
{
|
||||||
id: uuidv4(),
|
id: nanoid(8),
|
||||||
source: repliedNode.id,
|
source: repliedNode.id,
|
||||||
target: yesNode.id,
|
target: yesNode.id,
|
||||||
label: 'yes',
|
label: 'yes'
|
||||||
animated: false
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: uuidv4(),
|
id: nanoid(8),
|
||||||
source: repliedNode.id,
|
source: repliedNode.id,
|
||||||
target: noNode.id,
|
target: noNode.id,
|
||||||
label: 'no',
|
label: 'no'
|
||||||
animated: false
|
|
||||||
},
|
},
|
||||||
{ 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 {
|
} else {
|
||||||
|
console.log(option);
|
||||||
|
|
||||||
// Add new node logic
|
// Add new node logic
|
||||||
if (addNoteNode) {
|
if (addNoteNode) {
|
||||||
const initialX = addNoteNode.position.x;
|
const initialX = addNoteNode.position.x;
|
||||||
@@ -256,24 +287,37 @@ const NoteFlow = () => {
|
|||||||
key: option.key,
|
key: option.key,
|
||||||
data: { label: option.htmlNode },
|
data: { label: option.htmlNode },
|
||||||
position: {
|
position: {
|
||||||
x: option.position.x,
|
x: initialX,
|
||||||
y: nodes.length > 2 ? nextY : addNoteNode.position.y
|
y: nodes.length > 2 ? nextY : addNoteNode.position.y
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(getNextYPosition(option.position.x, 130));
|
const newEdge = {
|
||||||
|
id: nanoid(8),
|
||||||
setNodes((nds) => [...nds, newNode]);
|
|
||||||
|
|
||||||
setEdges((eds) => [
|
|
||||||
...eds,
|
|
||||||
{
|
|
||||||
id: uuidv4(),
|
|
||||||
source: lastNodeId,
|
source: lastNodeId,
|
||||||
target: newNodeId
|
target: newNodeId
|
||||||
}
|
};
|
||||||
|
|
||||||
|
setNodes((nds) => [...nds, newNode]);
|
||||||
|
setEdges((eds) => [
|
||||||
|
...eds,
|
||||||
|
newEdge,
|
||||||
|
{ id: nanoid(8), source: newNodeId, target: addNoteNode.id }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// setEdges((eds) => [
|
||||||
|
// ...eds,
|
||||||
|
// {
|
||||||
|
// id: uuidv4(),
|
||||||
|
// source: lastNodeId,
|
||||||
|
// data: {
|
||||||
|
// label: <div onClick={handleAddNoteClick}>Add Note</div>, // Use HTML or React component
|
||||||
|
// onClick: handleAddNoteClick
|
||||||
|
// },
|
||||||
|
// target: newNodeId
|
||||||
|
// }
|
||||||
|
// ]);
|
||||||
|
// Cuộn tới node mới thêm
|
||||||
setLastNodeId(newNodeId);
|
setLastNodeId(newNodeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,6 +338,7 @@ const NoteFlow = () => {
|
|||||||
<ReactFlow
|
<ReactFlow
|
||||||
nodes={nodes}
|
nodes={nodes}
|
||||||
edges={edges}
|
edges={edges}
|
||||||
|
edgeTypes={{ custom: CustomEdge }}
|
||||||
onNodeClick={onNodeClick}
|
onNodeClick={onNodeClick}
|
||||||
onNodeContextMenu={onNodeContextMenu}
|
onNodeContextMenu={onNodeContextMenu}
|
||||||
panOnScroll
|
panOnScroll
|
||||||
|
|||||||
Reference in New Issue
Block a user