+
Flow Types
+
-
-
Source (Funding Origin)
+
+
Inflow (from source)
-
-
Threshold Gate (Min/Max)
+
+
Outflow (to recipients)
-
-
Recipient (Funded)
+
+
Overflow (excess)
-
-
-
Recipient (Pending)
+
+
+
Funnel Zones
+
+
+
+
Overflow (above MAX)
+
+
+
+
Healthy (MIN to MAX)
+
+
+
+
Critical (below MIN)
+
diff --git a/components/nodes/RecipientNode.tsx b/components/nodes/RecipientNode.tsx
index a258db0..ca0d404 100644
--- a/components/nodes/RecipientNode.tsx
+++ b/components/nodes/RecipientNode.tsx
@@ -13,16 +13,16 @@ function RecipientNode({ data, selected }: NodeProps) {
return (
- {/* Input Handle */}
+ {/* Input Handle - Top for vertical flow */}
{/* Header */}
@@ -49,7 +49,7 @@ function RecipientNode({ data, selected }: NodeProps) {
Received
- ${received.toLocaleString()}
+ ${Math.floor(received).toLocaleString()}
diff --git a/components/nodes/SourceNode.tsx b/components/nodes/SourceNode.tsx
index b5191f6..6cc0c87 100644
--- a/components/nodes/SourceNode.tsx
+++ b/components/nodes/SourceNode.tsx
@@ -33,7 +33,7 @@ function SourceNode({ data, selected }: NodeProps) {
Balance
- ${balance.toLocaleString()}
+ ${Math.floor(balance).toLocaleString()}
@@ -42,13 +42,19 @@ function SourceNode({ data, selected }: NodeProps) {
${flowRate}/hr
+ {/* Flow indicator */}
+
- {/* Output Handle */}
+ {/* Output Handle - Bottom for vertical flow */}
)
diff --git a/components/nodes/ThresholdNode.tsx b/components/nodes/ThresholdNode.tsx
index a64d0b7..b2a6375 100644
--- a/components/nodes/ThresholdNode.tsx
+++ b/components/nodes/ThresholdNode.tsx
@@ -1,6 +1,6 @@
'use client'
-import { memo, useState, useCallback } from 'react'
+import { memo, useState } from 'react'
import { Handle, Position } from '@xyflow/react'
import type { NodeProps } from '@xyflow/react'
import type { ThresholdNodeData } from '@/lib/types'
@@ -10,134 +10,259 @@ function ThresholdNode({ data, selected }: NodeProps) {
const [minThreshold, setMinThreshold] = useState(nodeData.minThreshold)
const [maxThreshold, setMaxThreshold] = useState(nodeData.maxThreshold)
const currentValue = nodeData.currentValue
+ const maxCapacity = 100000
// Calculate status
- const getStatus = () => {
- if (currentValue < minThreshold) return { label: 'Below Min', color: 'red', bg: 'bg-red-500' }
- if (currentValue > maxThreshold) return { label: 'Overflow', color: 'amber', bg: 'bg-amber-500' }
- return { label: 'Active', color: 'green', bg: 'bg-emerald-500' }
- }
+ const isOverflowing = currentValue > maxThreshold
+ const isCritical = currentValue < minThreshold
+ const isHealthy = !isOverflowing && !isCritical
- const status = getStatus()
- const fillPercent = Math.min(100, Math.max(0, ((currentValue - minThreshold) / (maxThreshold - minThreshold)) * 100))
+ // 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 (
- {/* Input Handle */}
+ {/* Top Handle - Inflow */}
{/* Header */}
-
-
-
-
- {status.label}
-
+
+
{nodeData.label}
+
+ {isOverflowing ? 'OVERFLOW' : isCritical ? 'CRITICAL' : 'HEALTHY'}
- {/* Body */}
-
- {/* Current Value Display */}
-
-
- ${currentValue.toLocaleString()}
-
-
Current Value
-
+ {/* Funnel SVG */}
+