localgreenchain/components/vertical-farm/BatchProgress.tsx
Claude 2f7f22ca22
Add vertical farming UI components and pages
Components:
- FarmCard: Farm summary display with status and metrics
- ZoneGrid: Multi-level zone layout visualization
- ZoneDetailCard: Individual zone details with environment readings
- EnvironmentGauge: Real-time environmental parameter display
- BatchProgress: Crop batch progress tracking with health scores
- RecipeSelector: Growing recipe browser and selector
- AlertPanel: Environment alerts display and management
- GrowthStageIndicator: Visual growth stage progress tracker
- ResourceUsageChart: Energy/water usage analytics visualization

Pages:
- /vertical-farm: Dashboard with farm listing and stats
- /vertical-farm/register: Multi-step farm registration form
- /vertical-farm/[farmId]: Farm detail view with zones and alerts
- /vertical-farm/[farmId]/zones: Zone management with batch starting
- /vertical-farm/[farmId]/batches: Batch management and harvesting
- /vertical-farm/[farmId]/analytics: Farm analytics and performance metrics
2025-11-22 18:35:57 +00:00

105 lines
3.5 KiB
TypeScript

import { CropBatch, GrowingRecipe } from '../../lib/vertical-farming/types';
interface BatchProgressProps {
batch: CropBatch;
recipe?: GrowingRecipe;
showDetails?: boolean;
}
export default function BatchProgress({ batch, recipe, showDetails = true }: BatchProgressProps) {
const progressPercent = recipe
? Math.min(100, (batch.currentDay / recipe.expectedDays) * 100)
: 0;
const statusColors: Record<string, string> = {
germinating: 'bg-yellow-500',
growing: 'bg-green-500',
ready: 'bg-blue-500',
harvesting: 'bg-purple-500',
completed: 'bg-gray-500',
failed: 'bg-red-500',
};
const healthColor =
batch.healthScore >= 80
? 'text-green-600'
: batch.healthScore >= 60
? 'text-yellow-600'
: 'text-red-600';
return (
<div className="bg-white rounded-lg shadow p-4">
<div className="flex justify-between items-start mb-3">
<div>
<h4 className="font-semibold text-gray-900">
{batch.cropType}
{batch.variety && <span className="text-gray-600"> - {batch.variety}</span>}
</h4>
<p className="text-sm text-gray-600">Batch: {batch.id.slice(0, 12)}...</p>
</div>
<div className="text-right">
<span className={`inline-block px-2 py-1 rounded-full text-xs font-semibold text-white ${statusColors[batch.status]}`}>
{batch.status}
</span>
<p className={`text-sm font-bold mt-1 ${healthColor}`}>
Health: {batch.healthScore}%
</p>
</div>
</div>
<div className="mb-3">
<div className="flex justify-between text-sm mb-1">
<span className="text-gray-600">Progress</span>
<span className="font-medium">
Day {batch.currentDay} {recipe && `/ ${recipe.expectedDays}`}
</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-3">
<div
className={`h-3 rounded-full transition-all ${statusColors[batch.status] || 'bg-green-500'}`}
style={{ width: `${progressPercent}%` }}
/>
</div>
</div>
{showDetails && (
<div className="grid grid-cols-2 gap-3 text-sm">
<div>
<p className="text-gray-600">Current Stage</p>
<p className="font-medium">{batch.currentStage}</p>
</div>
<div>
<p className="text-gray-600">Plants</p>
<p className="font-medium">{batch.plantCount.toLocaleString()}</p>
</div>
<div>
<p className="text-gray-600">Expected Yield</p>
<p className="font-medium">{batch.expectedYieldKg.toFixed(1)} kg</p>
</div>
<div>
<p className="text-gray-600">Harvest Date</p>
<p className="font-medium">
{new Date(batch.expectedHarvestDate).toLocaleDateString()}
</p>
</div>
</div>
)}
{batch.issues.length > 0 && (
<div className="mt-3 pt-3 border-t border-gray-200">
<p className="text-sm font-medium text-red-600 mb-1">
{batch.issues.filter(i => !i.resolvedAt).length} Active Issue(s)
</p>
{batch.issues
.filter(i => !i.resolvedAt)
.slice(0, 2)
.map(issue => (
<p key={issue.id} className="text-xs text-gray-600">
- {issue.type}: {issue.description}
</p>
))}
</div>
)}
</div>
);
}