'use client' import { memo, useState } from 'react' import { Handle, Position } from '@xyflow/react' import type { NodeProps } from '@xyflow/react' import type { ThresholdNodeData } from '@/lib/types' function ThresholdNode({ data, selected }: NodeProps) { const nodeData = data as ThresholdNodeData const [minThreshold, setMinThreshold] = useState(nodeData.minThreshold) const [maxThreshold, setMaxThreshold] = useState(nodeData.maxThreshold) const currentValue = nodeData.currentValue const maxCapacity = 100000 // Calculate status const isOverflowing = currentValue > maxThreshold const isCritical = currentValue < minThreshold const isHealthy = !isOverflowing && !isCritical // Funnel dimensions const width = 160 const height = 200 const topWidth = 140 const bottomWidth = 30 const padding = 10 // Calculate Y positions for thresholds and fill const maxY = padding + ((maxCapacity - maxThreshold) / maxCapacity) * (height * 0.6) const minY = padding + ((maxCapacity - minThreshold) / maxCapacity) * (height * 0.6) const funnelStartY = minY + 15 const balanceY = Math.max(padding, padding + ((maxCapacity - Math.min(currentValue, maxCapacity * 1.1)) / maxCapacity) * (height * 0.6)) // Funnel shape calculations const leftTop = (width - topWidth) / 2 const rightTop = (width + topWidth) / 2 const leftBottom = (width - bottomWidth) / 2 const rightBottom = (width + bottomWidth) / 2 // Clip path for liquid fill const clipPath = ` M ${leftTop} ${padding} L ${rightTop} ${padding} L ${rightTop} ${funnelStartY} L ${rightBottom} ${height - padding - 15} L ${rightBottom} ${height - padding} L ${leftBottom} ${height - padding} L ${leftBottom} ${height - padding - 15} L ${leftTop} ${funnelStartY} Z ` return (
{/* Top Handle - Inflow */} {/* Header */}
{nodeData.label}
{isOverflowing ? 'OVERFLOW' : isCritical ? 'CRITICAL' : 'HEALTHY'}
{/* Funnel SVG */} {/* Zone backgrounds */} {/* Overflow zone */} {/* Healthy zone */} {/* Critical zone (funnel part) */} {/* Liquid fill */} {/* Funnel outline */} {/* Top line */} {/* MAX line */} MAX {/* MIN line */} MIN {/* Overflow particles */} {isOverflowing && ( <> )} {/* Value display */}
${Math.floor(currentValue).toLocaleString()}
{/* Threshold sliders */}
Min ${minThreshold.toLocaleString()}
setMinThreshold(Number(e.target.value))} className="w-full h-1.5 bg-slate-200 rounded-lg appearance-none cursor-pointer accent-red-500" />
Max ${maxThreshold.toLocaleString()}
setMaxThreshold(Number(e.target.value))} className="w-full h-1.5 bg-slate-200 rounded-lg appearance-none cursor-pointer accent-amber-500" />
{/* Bottom Handle - Outflow */} {/* Side Handles - Overflow */} {isOverflowing && ( <> )}
) } export default memo(ThresholdNode)