import { useMemo } from 'react'; import { useSimulation, computeReservoirWaterStats } from '../simulation/flowSimulator'; import { useBuilder } from '../store/builderStore'; import { computeRoomMetrics } from '../environment/roomMetrics'; import type { WarningLevel } from '../types'; import { useAuth } from '../auth/AuthContext'; import { PaywallModal } from '../payments/PaywallModal'; import { useState } from 'react'; const LEVEL_STYLE: Record = { error: 'border-rose-900/60 bg-rose-950/60 text-rose-300', warning: 'border-amber-900/60 bg-amber-950/50 text-amber-300', info: 'border-sky-900/60 bg-sky-950/50 text-sky-300', }; const LEVEL_ICON: Record = { error: '⛔', warning: '⚠️', info: 'ℹ️', }; /** * StatusPanel — bottom bar showing live simulation results: * per-pump delivered flow, system totals, and diagnostics. */ export function StatusPanel() { const { user } = useAuth(); const [showPaywall, setShowPaywall] = useState(false); const [showCoach, setShowCoach] = useState(false); const sim = useSimulation(); const partCount = useBuilder((s) => Object.keys(s.parts).length); const parts = useBuilder((s) => s.parts); const setSelected = useBuilder((s) => s.setSelected); const simRunning = useBuilder((s) => s.simRunning); const toggleSimRunning = useBuilder((s) => s.toggleSimRunning); const heatmapMode = useBuilder((s) => s.heatmapMode); const toggleHeatmapMode = useBuilder((s) => s.toggleHeatmapMode); const roomMetrics = useMemo(() => computeRoomMetrics(parts), [parts]); const requirePremiumCoach = () => { if (!user || user.purchased_slots === 0) { setShowPaywall(true); } else { setShowCoach(true); } }; const reservoirs = useMemo(() => { return Object.values(parts).filter((p) => p.type === 'reservoir'); }, [parts]); const reservoirStats = useMemo(() => { return reservoirs.map((res) => computeReservoirWaterStats(res, parts)); }, [reservoirs, parts]); const lph = sim.totalGph * 3.785; const flowing = sim.pumps.some((p) => p.running); const peakVelocity = Math.max(0, ...Object.values(sim.velocities)); const peakPressure = Math.max(0, ...Object.values(sim.pressures)); return ( <>
{/* System stats */}

Simulation

{sim.totalGph.toFixed(0)} GPH
≈ {lph.toFixed(0)} L/h · {partCount} parts · {sim.connectionCount} connections
peak {peakVelocity.toFixed(1)} ft/s · {peakPressure.toFixed(1)} psi
{/* Pumps */}

Pumps

{sim.pumps.length === 0 && (

No pumps in the system.

)} {sim.pumps.map((p) => ( ))}
{/* Diagnostics */}

Environment

{roomMetrics.length === 0 ? (

Add a grow tent/room to track air exchange.

) : ( roomMetrics.map((room) => ( )) )}
{/* Room Readout */}

Room Readout

{roomMetrics.length === 0 ? (

No room placed

) : (() => { const m = roomMetrics[0]; return (
🌡️ {m.roomTempF.toFixed(0)}°F 💧 {m.roomRH.toFixed(0)}% VPD {m.roomVPD.toFixed(2)} CO₂ {m.roomCo2} ☀️ {m.roomPPFD.toFixed(0)} ACH {m.airChangesPerHour.toFixed(1)}
); })()}
{/* Aeration & Water */}

Aeration & Water

{reservoirStats.length === 0 && (

No reservoirs in the system.

)} {reservoirStats.map((stats) => ( ))}

Diagnostics

{sim.warnings.length === 0 ? (

✓ System healthy — no issues detected.

) : ( sim.warnings.map((w, i) => ( )) )}
{showPaywall && setShowPaywall(false)} />} {showCoach && setShowCoach(false)} />} ); } function GrowCoachModal({ metrics, onClose }: { metrics: any[]; onClose: () => void }) { const m = metrics[0]; return (

🤖 drjonesbot

{!m ? (

Please add a Grow Room/Tent to your scene so I can analyze the environment.

) : ( <>
Humidity Analysis:

{m.roomRH > 65 ? "Your relative humidity is dangerously high for late-stage growth. Consider adding a dehumidifier or increasing exhaust CFM to prevent bud rot." : m.roomRH < 40 ? "Your humidity is too low. Seedlings and vegetative plants will struggle to transpire. Consider adding a humidifier." : "Your humidity is right in the sweet spot for vegetative growth!"}

VPD Target:

{m.roomVPD < 0.8 ? "VPD is low. Plants are not transpiring enough water, which can stunt nutrient uptake. Increase temperature or decrease humidity." : m.roomVPD > 1.2 ? "VPD is high. Plants may experience water stress and close their stomata. Decrease temperature or increase humidity." : "Perfect! A VPD of around 1.0 kPa is optimal for most stages of growth."}

Air Exchange:

{m.airChangesPerMinute < 1.0 ? "Your Air Changes Per Minute (ACH) is quite low. Stagnant air invites pests and mold. Add more inline exhaust fans." : "Your air exchange rate is solid, ensuring fresh CO2 is continuously supplied to the canopy."}

)}
); }