"use client" import { useState } from "react" import { DashboardLayout } from "@/components/dashboard-layout" 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, DialogTrigger, } from "@/components/ui/dialog" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Plus, Pencil, Search, Phone, User, Power, Trash2 } from "lucide-react" import { Badge } from "@/components/ui/badge" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" interface Productor { id: string nombre: string razonSocial?: string cuit?: string email?: string tipoProduccion?: string telefono?: string establecimientos_count: number lotes_count: number status: "activo" | "inactivo" } import { apiFetch, getErrorMessage } from "@/lib/apiutils" import { useEffect } from "react" // ... imports // ... imports (will check if useApi needs to be added, yes) import { useApi } from "@/lib/use-api" import { PaginationControl } from "@/components/ui/pagination-control" import { useTableSort } from "@/lib/use-table-sort" import { toast } from "sonner" export default function ProductoresPage() { /* State */ const { sortBy, sortDir, handleSort, appendSortParams, SortIcon } = useTableSort("created_at", "desc") const [statusFilter, setStatusFilter] = useState<"activo" | "inactivo" | "all">("activo") const [searchTerm, setSearchTerm] = useState("") const [currentPage, setCurrentPage] = useState(1) /* Reset page when filter or search changes */ useEffect(() => { setCurrentPage(1) }, [statusFilter, searchTerm]) /* Fetch Data */ const queryParams = new URLSearchParams() queryParams.append("page", currentPage.toString()) if (statusFilter !== "all") { queryParams.append("status", statusFilter) } if (searchTerm.trim() !== "") { queryParams.append("search", searchTerm) } appendSortParams(queryParams) const { data: rawData, isLoading, mutate } = useApi(`/productores?${queryParams.toString()}`) const dataList = rawData?.data || [] const lastPage = rawData?.last_page || 1 const total = rawData?.total || 0 const productores: Productor[] = dataList.map((p: any) => ({ ...p, id: p.id.toString(), razonSocial: p.razon_social, tipoProduccion: p.tipo_produccion, // Counts come directly from API now })) const [isDialogOpen, setIsDialogOpen] = useState(false) const [editingProductor, setEditingProductor] = useState(null) const [formData, setFormData] = useState>({ nombre: "", razonSocial: "", cuit: "", email: "", tipoProduccion: "Mixto", telefono: "", status: "activo", }) const filteredProductores = productores const handleOpenDialog = (productor?: Productor) => { if (productor) { setEditingProductor(productor) const { id, establecimientos_count, lotes_count, razon_social, tipo_produccion, ...productorData } = productor as any // Handle extended props setFormData({ nombre: productorData.nombre || "", razonSocial: productor.razonSocial || "", cuit: productorData.cuit || "", email: productorData.email || "", tipoProduccion: productor.tipoProduccion || "Mixto", telefono: productorData.telefono || "", status: productorData.status || "activo", }) } else { setEditingProductor(null) setFormData({ nombre: "", razonSocial: "", cuit: "", email: "", tipoProduccion: "Mixto", telefono: "", status: "activo", }) } setIsDialogOpen(true) } const handleSave = async () => { try { const payload = { ...formData, razon_social: formData.razonSocial, tipo_produccion: formData.tipoProduccion, status: formData.status // Explicitly ensuring status is sent } let res; if (editingProductor) { res = await apiFetch(`/productores/${editingProductor.id}`, { method: 'PUT', body: JSON.stringify(payload) }) } else { res = await apiFetch('/productores', { method: 'POST', body: JSON.stringify(payload) }) } if (res.ok) { mutate() setIsDialogOpen(false) } else { const msg = await getErrorMessage(res) toast.error(msg) } } catch (e) { console.error(e) toast.error("Error de conexión") } } const handleToggleStatus = async (productor: Productor) => { const newStatus = productor.status === "activo" ? "inactivo" : "activo" const action = newStatus === "activo" ? "activar" : "desactivar" if (confirm(`¿Estás seguro de que deseas ${action} este productor?`)) { try { const res = await apiFetch(`/productores/${productor.id}`, { method: 'PUT', // Uses update endpoint body: JSON.stringify({ status: newStatus }) }) if (res.ok) { mutate() // SWR Revalidation } else { toast.error("Error al actualizar estado") } } catch (e) { console.error(e) toast.error("Error de conexión") } } } const handleDelete = async (productor: Productor) => { if (confirm(`¿Estás seguro de que deseas ELIMINAR PERMANENTEMENTE a ${productor.nombre}? Esta acción no se puede deshacer.`)) { try { const res = await apiFetch(`/productores/${productor.id}`, { method: 'DELETE' }) if (res.ok) { toast.success("Productor eliminado permanentemente") mutate() } else if (res.status === 409) { const data = await res.json() toast.error(data.message || "No se puede eliminar porque tiene registros asociados.") } else { const msg = await getErrorMessage(res) toast.error(msg || "Error al eliminar productor") } } catch (e) { console.error(e) toast.error("Error de conexión") } } } return (

Gestión de Productores

Administra los productores agrícolas

{editingProductor ? "Editar Productor" : "Nuevo Productor"} {editingProductor ? "Modifica la información del productor" : "Completa los datos para registrar un nuevo productor"}
{ if (e.target.value.length <= 100) { setFormData({ ...formData, nombre: e.target.value }) } }} maxLength={100} placeholder="Juan Carlos Pérez" className={formData.nombre.length >= 100 ? 'border-red-500 focus-visible:ring-red-500' : ''} /> {formData.nombre.length >= 100 && (

Has alcanzado el límite máximo de 100 caracteres.

)}
{ if (e.target.value.length <= 100) { setFormData({ ...formData, razonSocial: e.target.value }) } }} maxLength={100} placeholder="Pérez Cereales S.A." className={(formData.razonSocial || "").length >= 100 ? 'border-red-500 focus-visible:ring-red-500' : ''} /> {(formData.razonSocial || "").length >= 100 && (

Has alcanzado el límite máximo de 100 caracteres.

)}
{ let val = e.target.value.replace(/\D/g, '') if (val.length > 11) val = val.slice(0, 11) let formatted = val if (val.length > 2) { formatted = `${val.slice(0, 2)}-${val.slice(2)}` } if (val.length > 10) { formatted = `${val.slice(0, 2)}-${val.slice(2, 10)}-${val.slice(10)}` } setFormData({ ...formData, cuit: formatted }) }} placeholder="20-12345678-9" maxLength={13} />
{ if (e.target.value.length <= 100) { setFormData({ ...formData, email: e.target.value }) } }} maxLength={100} placeholder="contacto@ejemplo.com" className={ ((formData.email || "").length >= 100 || (formData.email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email))) ? 'border-red-500 focus-visible:ring-red-500' : '' } /> {(formData.email || "").length >= 100 && (

Has alcanzado el límite máximo de 100 caracteres.

)} {formData.email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email) && (

Formato de correo inválido.

)}
{ const val = e.target.value.replace(/[^\d\s\+\(\)\-]/g, '') if (val.length <= 20) { setFormData({ ...formData, telefono: val }) } }} maxLength={20} placeholder="+54 11 1234-5678" className={(formData.telefono || "").length >= 20 ? 'border-red-500 focus-visible:ring-red-500' : ''} /> {(formData.telefono || "").length >= 20 && (

Has alcanzado el límite máximo de 20 caracteres.

)}
Total Productores {isLoading ? (
) : (
{rawData?.stats?.total || 0}
)}

{rawData?.stats?.activos || 0} activos

Total Establecimientos
{rawData?.stats?.total_establecimientos || 0}

Vinculados

Listado de Productores Todos los productores registrados
setSearchTerm(e.target.value)} className="pl-10" />
handleSort("nombre")}>
Productor
handleSort("tipo_produccion")}>
Tipo
handleSort("establecimientos_count")}>
Establecimientos
handleSort("lotes_count")}>
Lotes
handleSort("status")}>
Estado
Acciones
{isLoading && productores.length === 0 ? ( Cargando productores... ) : filteredProductores.length === 0 ? ( No se encontraron productores ) : ( filteredProductores.map((productor) => (
{productor.nombre} {productor.razonSocial && ( {productor.razonSocial} )}
{productor.tipoProduccion || "Mixto"} {productor.establecimientos_count} campos {productor.lotes_count} lotes {productor.status}
{productor.status === "inactivo" && ( )}
)) )}
) }