"use client" import { useState, useEffect } from "react" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table" import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog" import { Plus, Trash2 } from "lucide-react" import { apiFetch } from "@/lib/apiutils" import { useApi } from "@/lib/use-api" import { toast } from "sonner" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" interface Lote { id: string nombre: string superficie: number establecimientoId: string cultivoId?: string cultivoNombre?: string } interface LotesDialogProps { open: boolean onOpenChange: (open: boolean) => void establecimientoId: string | null establecimientoNombre: string | null maxHectareas: number } export function LotesDialog({ open, onOpenChange, establecimientoId, establecimientoNombre, maxHectareas }: LotesDialogProps) { const [lotes, setLotes] = useState([]) const [lotesLoading, setLotesLoading] = useState(false) const [newLote, setNewLote] = useState<{ nombre: string; superficie: string; cultivoId: string }>({ nombre: "", superficie: "", cultivoId: "" }) const [editingLoteId, setEditingLoteId] = useState(null) const { data: cultData } = useApi("/cultivos") const cultivos = Array.isArray(cultData) ? cultData : (cultData?.data || []) const fetchLotes = async () => { if (!establecimientoId) return setLotesLoading(true) try { const res = await apiFetch(`/lotes?establecimiento_id=${establecimientoId}`) if (res.ok) { const data = await res.json() if (Array.isArray(data)) { setLotes(data.map((l: any) => ({ id: String(l.id), nombre: l.nombre, superficie: Number(l.superficie), establecimientoId: String(l.establecimiento_id), cultivoId: l.cultivo_id ? String(l.cultivo_id) : "", cultivoNombre: l.cultivo?.nombre || "-" }))) } else { setLotes([]) } } } catch (e) { console.error(e) } finally { setLotesLoading(false) } } useEffect(() => { if (open && establecimientoId) { fetchLotes() setNewLote({ nombre: "", superficie: "", cultivoId: "" }) setEditingLoteId(null) } }, [open, establecimientoId]) const handleCreateLote = async () => { if (!establecimientoId || !newLote.nombre || !newLote.superficie || !newLote.cultivoId) { toast.error("Por favor complete todos los campos requeridos, incluyendo el cultivo.") return } try { const res = await apiFetch("/lotes", { method: "POST", body: JSON.stringify({ establecimiento_id: establecimientoId, nombre: newLote.nombre, superficie: Number(newLote.superficie), cultivo_id: newLote.cultivoId }) }) if (res.ok) { fetchLotes() setNewLote({ nombre: "", superficie: "", cultivoId: "" }) } else { const error = await res.json() toast.error("Error al crear lote: " + (error.message || "Desconocido")) } } catch (e) { console.error(e) } } const handleEditLote = (lote: Lote) => { setNewLote({ nombre: lote.nombre, superficie: String(lote.superficie), cultivoId: lote.cultivoId || "" }) setEditingLoteId(lote.id) } const handleUpdateLote = async () => { if (!editingLoteId || !newLote.nombre || !newLote.superficie || !newLote.cultivoId) { toast.error("Por favor complete todos los campos requeridos, incluyendo el cultivo.") return } try { const res = await apiFetch(`/lotes/${editingLoteId}`, { method: "PUT", body: JSON.stringify({ nombre: newLote.nombre, superficie: Number(newLote.superficie), cultivo_id: newLote.cultivoId }) }) if (res.ok) { fetchLotes() setNewLote({ nombre: "", superficie: "", cultivoId: "" }) setEditingLoteId(null) } else { const error = await res.json() toast.error("Error al actualizar lote: " + (error.message || "Desconocido")) } } catch (e) { console.error(e) } } const handleCancelEdit = () => { setNewLote({ nombre: "", superficie: "", cultivoId: "" }) setEditingLoteId(null) } const handleCultivoChange = async (loteId: string, cultivoId: string) => { const cultivo_id = cultivoId === "ninguno" ? null : cultivoId try { const res = await apiFetch(`/lotes/${loteId}`, { method: "PUT", body: JSON.stringify({ cultivo_id }) }) if (res.ok) { fetchLotes() toast.success("Cultivo actualizado") } else { const err = await res.json() toast.error("Error: " + (err.message || "No se pudo guardar")) } } catch (e) { console.error(e) } } const handleDeleteLote = async (id: string) => { if (!confirm("¿Eliminar lote?")) return try { const res = await apiFetch(`/lotes/${id}`, { method: "DELETE" }) if (res.ok) { fetchLotes() if (editingLoteId === id) { handleCancelEdit() } toast.success("Lote eliminado") } else { const err = await res.json() toast.error("Error: " + (err.message || "No se pudo eliminar el lote")) } } catch (e) { console.error(e) toast.error("Error de conexión al intentar eliminar") } } // Calculate available surface // If editing, we should temporarily add back the current lote's original surface to available? // Actually, available is (Total - Sum(All)). // Check constraint: // If Creating: New <= Available // If Updating: New <= Available + Old_Size_of_Updating_Lote // But simplified check in disabled Logic: // New validation allows sum > total, but we still want to show "Available" correctly. // And disables if *individual* lote > total (which is handled by backend too, but good for UI). const currentTotalUsed = lotes.reduce((acc, l) => acc + l.superficie, 0) const available = maxHectareas - currentTotalUsed const availableFormatted = Number(available.toFixed(2)) // For disabling button: // Backend rule: Un lote individual <= Max Hectareas. // Cumulative rule: Permitted (Available can be negative). // However, UX wise, maybe we want to show red if negative? return ( Gestión de Lotes - {establecimientoNombre} Administra los lotes asociados a este establecimiento.
{/* Formulario Nuevo Lote */}
Superficie Total: {maxHectareas} ha Disponible: {availableFormatted.toFixed(2)} ha
setNewLote({ ...newLote, nombre: e.target.value })} className="bg-background" />
{ const val = e.target.value.replace(',', '.'); if (val === '' || /^\d*\.?\d*$/.test(val)) { setNewLote({ ...newLote, superficie: val as any }); } }} onKeyDown={(e) => { if (e.ctrlKey || e.metaKey || e.key.length > 1) return; if (!/[0-9.,]/.test(e.key)) { e.preventDefault(); } }} className="bg-background" />
{editingLoteId ? (
) : ( )}
{/* Listado de Lotes */}
Nombre Cultivo Superficie Acciones {lotesLoading ? ( Cargando... ) : lotes.length === 0 ? ( No hay lotes registrados ) : ( lotes.map((lote) => ( {lote.nombre} {lote.superficie} ha
)) )}
) }