55 lines
2.1 KiB
TypeScript
55 lines
2.1 KiB
TypeScript
|
|
import { memo } from 'react';
|
||
|
|
import { Handle, Position, type NodeProps } from '@xyflow/react';
|
||
|
|
import { AlertTriangle, CheckCircle2, XCircle, Shield } from 'lucide-react';
|
||
|
|
|
||
|
|
type TransactionNodeData = {
|
||
|
|
label: string;
|
||
|
|
category: string;
|
||
|
|
icon: string;
|
||
|
|
color: string;
|
||
|
|
status?: 'valid' | 'warning' | 'error';
|
||
|
|
};
|
||
|
|
|
||
|
|
const complianceCategories = ['compliance'];
|
||
|
|
const routingCategories = ['routing'];
|
||
|
|
|
||
|
|
function TransactionNodeComponent({ data, selected }: NodeProps) {
|
||
|
|
const nodeData = data as unknown as TransactionNodeData;
|
||
|
|
const statusIcon = nodeData.status === 'valid' ? <CheckCircle2 size={10} color="#22c55e" /> :
|
||
|
|
nodeData.status === 'warning' ? <AlertTriangle size={10} color="#eab308" /> :
|
||
|
|
nodeData.status === 'error' ? <XCircle size={10} color="#ef4444" /> : null;
|
||
|
|
|
||
|
|
const isCompliance = complianceCategories.includes(nodeData.category);
|
||
|
|
const isRouting = routingCategories.includes(nodeData.category);
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className={`transaction-node ${selected ? 'selected' : ''} ${nodeData.status ? `status-${nodeData.status}` : ''}`}
|
||
|
|
style={{ borderColor: selected ? '#3b82f6' : nodeData.color + '60' }}>
|
||
|
|
<Handle type="target" position={Position.Left} className="node-handle" />
|
||
|
|
<div className="node-header" style={{ borderBottomColor: nodeData.color + '30' }}>
|
||
|
|
<span className="node-icon">{nodeData.icon}</span>
|
||
|
|
<span className="node-label">{nodeData.label}</span>
|
||
|
|
<div className="node-badges">
|
||
|
|
{isCompliance && (
|
||
|
|
<span className="node-badge compliance" title="Compliance node">
|
||
|
|
<Shield size={8} />
|
||
|
|
</span>
|
||
|
|
)}
|
||
|
|
{isRouting && (
|
||
|
|
<span className="node-badge routing" title="Routing node">
|
||
|
|
🔀
|
||
|
|
</span>
|
||
|
|
)}
|
||
|
|
{statusIcon && <span className="node-status">{statusIcon}</span>}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<div className="node-body">
|
||
|
|
<span className="node-category" style={{ color: nodeData.color }}>{nodeData.category}</span>
|
||
|
|
</div>
|
||
|
|
<Handle type="source" position={Position.Right} className="node-handle" />
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
export default memo(TransactionNodeComponent);
|