up 10/9
This commit is contained in:
@@ -105,3 +105,7 @@
|
||||
font-weight: 700;
|
||||
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 ReactDOM from 'react-dom/client';
|
||||
import { ReactFlowProvider } from '@xyflow/react';
|
||||
|
||||
import App from './App';
|
||||
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 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 = () => {
|
||||
</div>
|
||||
)
|
||||
},
|
||||
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 = () => {
|
||||
</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]);
|
||||
|
||||
// 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));
|
||||
|
||||
setNodes((nds) => [...nds, newNode]);
|
||||
|
||||
setEdges((eds) => [
|
||||
...eds,
|
||||
{
|
||||
id: uuidv4(),
|
||||
const newEdge = {
|
||||
id: nanoid(8),
|
||||
source: lastNodeId,
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -294,6 +338,7 @@ const NoteFlow = () => {
|
||||
<ReactFlow
|
||||
nodes={nodes}
|
||||
edges={edges}
|
||||
edgeTypes={{ custom: CustomEdge }}
|
||||
onNodeClick={onNodeClick}
|
||||
onNodeContextMenu={onNodeContextMenu}
|
||||
panOnScroll
|
||||
|
||||
Reference in New Issue
Block a user