Harden import and paste validation, fix duplicate exports and variable declarations
This commit is contained in:
@@ -3,6 +3,9 @@ import { useSimulation, computeReservoirWaterStats } from '../simulation/flowSim
|
||||
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<WarningLevel, string> = {
|
||||
error: 'border-rose-900/60 bg-rose-950/60 text-rose-300',
|
||||
@@ -21,6 +24,9 @@ const LEVEL_ICON: Record<WarningLevel, string> = {
|
||||
* 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);
|
||||
@@ -31,6 +37,14 @@ export function StatusPanel() {
|
||||
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]);
|
||||
@@ -45,6 +59,7 @@ export function StatusPanel() {
|
||||
const peakPressure = Math.max(0, ...Object.values(sim.pressures));
|
||||
|
||||
return (
|
||||
<>
|
||||
<footer className="flex h-36 shrink-0 border-t border-zinc-800 bg-zinc-950/90 backdrop-blur">
|
||||
{/* System stats */}
|
||||
<div className="flex w-56 shrink-0 flex-col justify-center gap-1 border-r border-zinc-800 px-4">
|
||||
@@ -181,9 +196,17 @@ export function StatusPanel() {
|
||||
|
||||
{/* Room Readout */}
|
||||
<div className="flex w-56 shrink-0 flex-col justify-center gap-1.5 border-r border-zinc-800 px-4 py-2.5">
|
||||
<h3 className="text-[10px] font-bold tracking-wider text-zinc-500 uppercase">
|
||||
Room Readout
|
||||
</h3>
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="text-[10px] font-bold tracking-wider text-zinc-500 uppercase">
|
||||
Room Readout
|
||||
</h3>
|
||||
<button
|
||||
onClick={requirePremiumCoach}
|
||||
className="text-[9px] font-bold uppercase tracking-wider text-sky-400 hover:text-sky-300 bg-sky-950/50 hover:bg-sky-900/50 px-1.5 py-0.5 rounded border border-sky-900/50 transition-colors"
|
||||
>
|
||||
Grow Coach 🤖
|
||||
</button>
|
||||
</div>
|
||||
{roomMetrics.length === 0 ? (
|
||||
<p className="text-xs text-zinc-600">No room placed</p>
|
||||
) : (() => {
|
||||
@@ -310,5 +333,63 @@ export function StatusPanel() {
|
||||
)}
|
||||
</div>
|
||||
</footer>
|
||||
{showPaywall && <PaywallModal onClose={() => setShowPaywall(false)} />}
|
||||
{showCoach && <GrowCoachModal metrics={roomMetrics} onClose={() => setShowCoach(false)} />}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function GrowCoachModal({ metrics, onClose }: { metrics: any[]; onClose: () => void }) {
|
||||
const m = metrics[0];
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm">
|
||||
<div className="w-full max-w-md overflow-hidden rounded-xl border border-sky-900 bg-zinc-950 shadow-2xl">
|
||||
<div className="border-b border-zinc-800 bg-zinc-900 px-6 py-4 flex justify-between items-center">
|
||||
<h2 className="text-lg font-bold text-sky-400 flex items-center gap-2">
|
||||
🤖 AI Grow Coach
|
||||
</h2>
|
||||
<button onClick={onClose} className="text-zinc-500 hover:text-zinc-300">✕</button>
|
||||
</div>
|
||||
<div className="p-6 text-sm text-zinc-300 space-y-4">
|
||||
{!m ? (
|
||||
<p>Please add a Grow Room/Tent to your scene so I can analyze the environment.</p>
|
||||
) : (
|
||||
<>
|
||||
<div className="p-3 bg-zinc-900 rounded-lg border border-zinc-800">
|
||||
<span className="font-bold text-sky-400">Humidity Analysis:</span>
|
||||
<p className="mt-1">
|
||||
{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!"}
|
||||
</p>
|
||||
</div>
|
||||
<div className="p-3 bg-zinc-900 rounded-lg border border-zinc-800">
|
||||
<span className="font-bold text-emerald-400">VPD Target:</span>
|
||||
<p className="mt-1">
|
||||
{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."}
|
||||
</p>
|
||||
</div>
|
||||
<div className="p-3 bg-zinc-900 rounded-lg border border-zinc-800">
|
||||
<span className="font-bold text-amber-400">Air Exchange:</span>
|
||||
<p className="mt-1">
|
||||
{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."}
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className="border-t border-zinc-800 bg-zinc-900 px-6 py-4 flex justify-end">
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="rounded-md bg-zinc-800 px-4 py-2 font-semibold text-zinc-200 hover:bg-zinc-700"
|
||||
>
|
||||
Got it
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user