2024-08-23 14:19:10 +07:00
|
|
|
import { useState } from 'react';
|
|
|
|
|
import { ReactFlow, addEdge, Controls, Background } from '@xyflow/react';
|
2024-08-16 15:08:06 +07:00
|
|
|
import '@xyflow/react/dist/style.css';
|
2024-08-23 14:19:10 +07:00
|
|
|
import { FiUser, FiMail, FiCheckCircle, FiList } from 'react-icons/fi';
|
|
|
|
|
import { FaShuffle } from 'react-icons/fa6';
|
|
|
|
|
|
|
|
|
|
const initialNodes = [
|
|
|
|
|
{
|
|
|
|
|
id: '1',
|
|
|
|
|
type: 'input',
|
|
|
|
|
data: {
|
2024-08-16 15:08:06 +07:00
|
|
|
label: (
|
2024-08-23 14:19:10 +07:00
|
|
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
2024-08-16 15:08:06 +07:00
|
|
|
<FiUser style={{ marginRight: 5 }} />
|
2024-08-23 14:19:10 +07:00
|
|
|
<span>Customer signs up for product updates</span>
|
2024-08-16 15:08:06 +07:00
|
|
|
</div>
|
2024-08-23 14:19:10 +07:00
|
|
|
),
|
2024-08-16 15:08:06 +07:00
|
|
|
},
|
|
|
|
|
position: { x: 250, y: 100 },
|
2024-08-23 14:19:10 +07:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: '2',
|
|
|
|
|
data: { label: 'Add Note' },
|
|
|
|
|
position: { x: 250, y: 250 },
|
|
|
|
|
},
|
|
|
|
|
];
|
2024-08-16 15:08:06 +07:00
|
|
|
|
|
|
|
|
const tabBarOptions = [
|
2024-08-23 14:19:10 +07:00
|
|
|
{
|
|
|
|
|
label: 'Send email',
|
2024-08-16 15:08:06 +07:00
|
|
|
id: '3',
|
|
|
|
|
type: '',
|
|
|
|
|
html: (
|
2024-08-23 14:19:10 +07:00
|
|
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
|
|
|
|
<FiMail style={{ marginRight: 5 }} />
|
|
|
|
|
Send email
|
|
|
|
|
</div>
|
|
|
|
|
),
|
|
|
|
|
position: { x: 250, y: 200 },
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: 'Replied to conversation?',
|
|
|
|
|
id: '4',
|
|
|
|
|
type: '',
|
|
|
|
|
html: (
|
|
|
|
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
|
|
|
|
<FaShuffle style={{ marginRight: 5, transform: `rotate(90deg)` }} />
|
|
|
|
|
<span>Replied to conversation?</span>
|
|
|
|
|
</div>
|
|
|
|
|
),
|
|
|
|
|
position: { x: 250, y: 290 },
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: 'Send survey',
|
|
|
|
|
id: '5',
|
|
|
|
|
type: 'output',
|
|
|
|
|
html: (
|
|
|
|
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
|
|
|
|
<FiCheckCircle style={{ marginRight: 5 }} />
|
|
|
|
|
Send survey
|
|
|
|
|
</div>
|
|
|
|
|
),
|
|
|
|
|
position: { x: 100, y: 400 },
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: 'Contact Exists',
|
|
|
|
|
id: '6',
|
|
|
|
|
type: 'output',
|
|
|
|
|
html: (
|
|
|
|
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
|
|
|
|
<FiList style={{ marginRight: 5 }} />
|
|
|
|
|
Contact Exists
|
|
|
|
|
</div>
|
|
|
|
|
),
|
|
|
|
|
position: { x: 400, y: 400 },
|
|
|
|
|
},
|
2024-08-16 15:08:06 +07:00
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const NoteFlow = () => {
|
2024-08-23 14:19:10 +07:00
|
|
|
const [nodes, setNodes] = useState(initialNodes);
|
|
|
|
|
const [edges, setEdges] = useState([
|
|
|
|
|
{ id: 'e1-2', source: '1', target: '2' }, // Kết nối node "Add Note" với node mặc định ban đầu
|
|
|
|
|
]);
|
2024-08-16 15:08:06 +07:00
|
|
|
const [showTabBar, setShowTabBar] = useState(false);
|
|
|
|
|
const [lastNodeId, setLastNodeId] = useState('1');
|
|
|
|
|
|
|
|
|
|
const handleAddNoteClick = () => {
|
|
|
|
|
setShowTabBar(true);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleTabClick = (option) => {
|
|
|
|
|
setShowTabBar(false);
|
2024-08-23 14:19:10 +07:00
|
|
|
|
2024-08-16 15:08:06 +07:00
|
|
|
const newNode = {
|
|
|
|
|
id: option.id,
|
|
|
|
|
data: { label: option.html },
|
|
|
|
|
position: { x: option.position.x, y: option.position.y },
|
|
|
|
|
};
|
|
|
|
|
|
2024-08-23 14:19:10 +07:00
|
|
|
const addNoteNode = nodes.find((node) => node.id === '2');
|
2024-08-16 15:08:06 +07:00
|
|
|
|
2024-08-23 14:19:10 +07:00
|
|
|
if (option.id === '4') {
|
|
|
|
|
// Xóa node "Add Note"
|
|
|
|
|
setNodes((nds) => nds.filter((node) => node.id !== '2'));
|
2024-08-16 15:08:06 +07:00
|
|
|
|
2024-08-23 14:19:10 +07:00
|
|
|
// Thêm node "Replied to conversation?"
|
|
|
|
|
const repliedNode = {
|
2024-08-16 15:08:06 +07:00
|
|
|
id: '4',
|
2024-08-23 14:19:10 +07:00
|
|
|
data: { label: option.html },
|
|
|
|
|
position: { x: option.position.x, y: option.position.y },
|
2024-08-16 15:08:06 +07:00
|
|
|
};
|
|
|
|
|
|
2024-08-23 14:19:10 +07:00
|
|
|
// Thêm các nhánh "Send survey" và "Contact Exists"
|
|
|
|
|
const yesNode = {
|
2024-08-16 15:08:06 +07:00
|
|
|
id: '5',
|
2024-08-23 14:19:10 +07:00
|
|
|
data: {
|
|
|
|
|
label: (
|
|
|
|
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
|
|
|
|
<FiCheckCircle style={{ marginRight: 5 }} />
|
|
|
|
|
Send survey
|
|
|
|
|
</div>
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
position: { x: option.position.x - 150, y: option.position.y + 150 },
|
2024-08-16 15:08:06 +07:00
|
|
|
};
|
|
|
|
|
|
2024-08-23 14:19:10 +07:00
|
|
|
const noNode = {
|
|
|
|
|
id: '6',
|
|
|
|
|
data: {
|
|
|
|
|
label: (
|
|
|
|
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
|
|
|
|
<FiList style={{ marginRight: 5 }} />
|
|
|
|
|
Contact Exists
|
|
|
|
|
</div>
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
position: { x: option.position.x + 150, y: option.position.y + 150 },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
setNodes((nds) => [...nds, repliedNode, yesNode, noNode]);
|
2024-08-16 15:08:06 +07:00
|
|
|
|
|
|
|
|
setEdges((eds) => [
|
|
|
|
|
...eds,
|
2024-08-23 14:19:10 +07:00
|
|
|
{ id: 'e4-5', source: '4', target: '5', label: 'yes', animated: false },
|
|
|
|
|
{ id: 'e4-6', source: '4', target: '6', label: 'no', animated: false },
|
|
|
|
|
{ id: `e${lastNodeId}-4`, source: lastNodeId, target: '4' } // Kết nối node hiện tại với "Replied to conversation?"
|
2024-08-16 15:08:06 +07:00
|
|
|
]);
|
2024-08-23 14:19:10 +07:00
|
|
|
} else {
|
|
|
|
|
if (addNoteNode) {
|
|
|
|
|
// Di chuyển node "Add Note" xuống dưới node mới
|
|
|
|
|
setNodes((nds) =>
|
|
|
|
|
nds.map((node) =>
|
|
|
|
|
node.id === '2'
|
|
|
|
|
? { ...node, position: { x: option.position.x, y: option.position.y + 150 } }
|
|
|
|
|
: node
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Thêm node mới vào danh sách node
|
|
|
|
|
setNodes((nds) => [...nds, newNode]);
|
|
|
|
|
|
|
|
|
|
// Kết nối node mới với node hiện tại
|
|
|
|
|
setEdges((eds) => addEdge({ id: `e${lastNodeId}-${option.id}`, source: lastNodeId, target: option.id }, eds));
|
|
|
|
|
|
|
|
|
|
// Kết nối node "Add Note" cũ với node mới
|
|
|
|
|
if (addNoteNode) {
|
|
|
|
|
setEdges((eds) => addEdge({ id: `e${option.id}-2`, source: option.id, target: '2' }, eds));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Cập nhật lastNodeId
|
|
|
|
|
setLastNodeId(option.id);
|
2024-08-16 15:08:06 +07:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onNodeClick = (event, node) => {
|
2024-08-23 14:19:10 +07:00
|
|
|
if (node.id === '2') { // Check if the clicked node is "Add Note"
|
|
|
|
|
setShowTabBar(true);
|
2024-08-22 16:56:54 +07:00
|
|
|
}
|
2024-08-22 16:42:25 +07:00
|
|
|
};
|
|
|
|
|
|
2024-08-16 15:08:06 +07:00
|
|
|
return (
|
2024-08-23 14:19:10 +07:00
|
|
|
<div style={{ height: '100vh', width: '100%', position: 'relative' }}>
|
|
|
|
|
<ReactFlow nodes={nodes} edges={edges} onNodeClick={onNodeClick}>
|
2024-08-16 15:08:06 +07:00
|
|
|
<Controls />
|
2024-08-23 14:19:10 +07:00
|
|
|
<Background />
|
2024-08-16 15:08:06 +07:00
|
|
|
</ReactFlow>
|
|
|
|
|
{showTabBar && (
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
|
position: 'absolute',
|
|
|
|
|
top: 50,
|
|
|
|
|
left: 10,
|
|
|
|
|
zIndex: 10,
|
|
|
|
|
background: 'white',
|
|
|
|
|
border: '1px solid #ccc',
|
|
|
|
|
padding: '10px',
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{tabBarOptions.map((option) => (
|
|
|
|
|
<div
|
|
|
|
|
key={option.id}
|
|
|
|
|
onClick={() => handleTabClick(option)}
|
|
|
|
|
style={{
|
|
|
|
|
padding: '10px',
|
|
|
|
|
cursor: 'pointer',
|
|
|
|
|
borderBottom: '1px solid #ddd',
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{option.label}
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
2024-08-23 14:19:10 +07:00
|
|
|
export default NoteFlow;
|