import { useState, useEffect } from 'react'; import { useParams, useNavigate, Link } from 'react-router-dom'; import { ArrowLeft, Calendar, Droplets, Thermometer, Wind, Zap, Bug, Camera, Activity, TrendingUp, Clock, CheckCircle, AlertTriangle, Leaf, Sun, Moon } from 'lucide-react'; import { batchesApi, Batch } from '../lib/batchesApi'; // Mock sensor data generator function generateMockData(days: number, min: number, max: number, variance: number = 5) { return Array.from({ length: days }, (_, i) => ({ day: i + 1, value: min + Math.random() * (max - min) + (Math.random() - 0.5) * variance, timestamp: new Date(Date.now() - (days - i) * 24 * 60 * 60 * 1000).toISOString() })); } // SVG Sparkline Component function Sparkline({ data, color = '#3B82F6', height = 40 }: { data: { value: number }[]; color?: string; height?: number; }) { if (data.length === 0) return null; const values = data.map(d => d.value); const min = Math.min(...values); const max = Math.max(...values); const range = max - min || 1; const width = 120; const padding = 2; const points = data.map((d, i) => { const x = padding + (i / (data.length - 1)) * (width - padding * 2); const y = height - padding - ((d.value - min) / range) * (height - padding * 2); return `${x},${y}`; }).join(' '); return ( {/* Current value dot */} {data.length > 0 && ( )} ); } // Stage Progress Component function StageProgress({ currentStage }: { currentStage: string }) { const stages = [ { id: 'CLONE_IN', label: 'Clone', icon: '🌱', days: 7 }, { id: 'VEGETATIVE', label: 'Veg', icon: '🌿', days: 28 }, { id: 'FLOWERING', label: 'Flower', icon: '🌸', days: 63 }, { id: 'HARVEST', label: 'Harvest', icon: '✂️', days: 1 }, { id: 'DRYING', label: 'Dry', icon: '🍂', days: 14 }, { id: 'CURING', label: 'Cure', icon: '🫙', days: 30 }, ]; const currentIndex = stages.findIndex(s => s.id === currentStage); return (
{stages.map((stage, i) => { const isPast = i < currentIndex; const isCurrent = i === currentIndex; const isFuture = i > currentIndex; return (
{stage.icon} {stage.label}
{i < stages.length - 1 && (
)}
); })}
); } // Metric Card with Sparkline function MetricCard({ icon: Icon, label, value, unit, trend, data, color }: { icon: typeof Thermometer; label: string; value: string; unit: string; trend?: 'up' | 'down' | 'stable'; data: { value: number }[]; color: string; }) { return (
{label}
{trend && ( {trend === 'up' ? '↑' : trend === 'down' ? '↓' : '→'} )}
{value} {unit}
); } // Touch Point Item function TouchPoint({ type, date, user, notes }: { type: string; date: string; user: string; notes?: string; }) { const typeConfig: Record = { WATER: { icon: Droplets, color: 'text-blue-500' }, FEED: { icon: Leaf, color: 'text-green-500' }, INSPECT: { icon: Bug, color: 'text-amber-500' }, PHOTO: { icon: Camera, color: 'text-purple-500' }, DEFOLIATE: { icon: Leaf, color: 'text-orange-500' }, TRANSPLANT: { icon: Activity, color: 'text-teal-500' }, }; const config = typeConfig[type] || { icon: Activity, color: 'text-secondary' }; const Icon = config.icon; return (
{type} {new Date(date).toLocaleDateString()}
{notes &&

{notes}

} {user}
); } export default function BatchDetailPage() { const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); const [batch, setBatch] = useState(null); const [loading, setLoading] = useState(true); // Mock sensor data (will be replaced with real sensor API) const [sensorData] = useState(() => ({ temperature: generateMockData(14, 72, 78), humidity: generateMockData(14, 50, 65), vpd: generateMockData(14, 0.8, 1.2), co2: generateMockData(14, 800, 1200), lightPPFD: generateMockData(14, 600, 900), })); useEffect(() => { if (id) { batchesApi.getById(id) .then(setBatch) .catch((err) => { console.error('Failed to load batch:', err); navigate('/batches'); }) .finally(() => setLoading(false)); } }, [id, navigate]); if (loading) { return (
); } if (!batch) { return (

Batch not found

← Back to batches
); } // Calculate days in stage const startDate = new Date(batch.startDate); const daysInCycle = Math.floor((Date.now() - startDate.getTime()) / (1000 * 60 * 60 * 24)); return (
{/* Header */}

{batch.name}

{batch.stage}
{batch.strain} {batch.plantCount} plants Day {daysInCycle}
{/* Stage Journey */}

Lifecycle

{/* Sensor Grid */}

Environment (14 days)

{/* Two Column Layout */}
{/* Touch Points */}

Recent Activity

{batch.touchPoints?.length || 0} entries
{batch.touchPoints && batch.touchPoints.length > 0 ? ( batch.touchPoints.map((tp) => ( )) ) : (

No activity yet

)}
{/* Stats & IPM */}
{/* Quick Stats */}

Statistics

{daysInCycle}
Days
{batch.touchPoints?.length || 0}
Touch Points
0
Issues
{/* IPM Schedule */} {batch.ipmSchedule ? (

IPM Schedule

{batch.ipmSchedule.product || 'Preventative'}

Next: {new Date(batch.ipmSchedule.nextTreatment).toLocaleDateString()}

) : (

IPM Schedule

No IPM schedule configured

)} {/* Health Score */}

Health Score

92

Excellent

Based on 14 day average

); }