import React, { useState, useEffect } from "react"; import { Card, CardHeader, CardTitle, CardContent, CardDescription } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Badge } from "@/components/ui/badge"; import { toast } from "sonner"; import { Users, Search, Trash2, Pencil, Eye, PlusCircle, ClipboardList } from "lucide-react"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; import { api } from "@/services/api"; export default function ClientsPage() { const [activeTab, setActiveTab] = useState("control"); const [clients, setClients] = useState([]); const [orders, setOrders] = useState([]); const [loading, setLoading] = useState(true); const [searchQuery, setSearchQuery] = useState(""); const loadData = async () => { try { setLoading(true); const clientsData = await api.clients.getAll(); const ordersData = await api.orders.getAll(); setClients(clientsData); setOrders(ordersData); } catch (error) { toast.error("Error al cargar datos", { description: error.message || "Por favor, intente nuevamente." }); } finally { setLoading(false); } }; useEffect(() => { loadData(); }, []); // Estados del formulario (Alta / Edición) const [editingId, setEditingId] = useState(null); const [clientName, setClientName] = useState(""); const [clientDni, setClientDni] = useState(""); const [clientPhone, setClientPhone] = useState(""); const [clientEmail, setClientEmail] = useState(""); // Modal de visualización de órdenes const [selectedClientForOrders, setSelectedClientForOrders] = useState(null); const [showOrdersModal, setShowOrdersModal] = useState(false); // Modal de confirmación de borrado const [clientToDelete, setClientToDelete] = useState(null); const [showDeleteAlert, setShowDeleteAlert] = useState(false); // Registrar o editar cliente const handleRegisterClient = async (e) => { e.preventDefault(); try { if (editingId) { // Editar cliente await api.clients.update(editingId, { name: clientName, dni: clientDni, phone: clientPhone, email: clientEmail }); toast.success("¡Ficha de Cliente Actualizada!", { description: `Los datos de ${clientName} fueron actualizados.` }); setEditingId(null); } else { // Alta de cliente // Validar DNI único localmente antes de enviar (opcional, pero ayuda) const exists = clients.some(c => c.dni.replace(/\./g, "").trim() === clientDni.replace(/\./g, "").trim()); if (exists) { toast.error("El DNI ingresado ya pertenece a un cliente registrado."); return; } const data = await api.clients.create({ name: clientName, dni: clientDni, phone: clientPhone, email: clientEmail }); toast.success("¡Cliente Registrado!", { description: `${clientName} fue dado de alta.` }); } // Resetear formulario setClientName(""); setClientDni(""); setClientPhone(""); setClientEmail(""); setActiveTab("control"); loadData(); } catch (error) { toast.error("Error al registrar cliente", { description: error.message || "Por favor, intente nuevamente." }); } }; // Activar modo edición const handleEditClick = (client) => { setEditingId(client._id); setClientName(client.name); setClientDni(client.dni); setClientPhone(client.phone); setClientEmail(client.email); setActiveTab("registro"); }; // Cancelar edición const handleCancelEdit = () => { setEditingId(null); setClientName(""); setClientDni(""); setClientPhone(""); setClientEmail(""); setActiveTab("control"); }; // Solicitar borrado de cliente const handleDeleteRequest = (client) => { setClientToDelete(client); setShowDeleteAlert(true); }; // Confirmar borrado (borra cliente y todas sus órdenes asociadas) const confirmDeleteClient = async () => { if (!clientToDelete) return; try { await api.clients.delete(clientToDelete._id); toast.error("Cliente eliminado", { description: `${clientToDelete.name} y su historial de órdenes asociadas fueron eliminados.` }); setClientToDelete(null); setShowDeleteAlert(false); loadData(); } catch (error) { toast.error("Error al eliminar cliente", { description: error.message || "Por favor, intente nuevamente." }); } }; // Abrir modal con las órdenes de un cliente const handleViewOrders = (client) => { setSelectedClientForOrders(client); setShowOrdersModal(true); }; // Filtrado de clientes const filteredClients = clients.filter(c => { const term = searchQuery.toLowerCase().trim(); const cId = c._id || ""; return ( cId.toLowerCase().includes(term) || c.name.toLowerCase().includes(term) || c.dni.replace(/\./g, "").includes(term.replace(/\./g, "")) || (c.email && c.email.toLowerCase().includes(term)) || (c.phone && c.phone.includes(term)) ); }); return (
{/* Cabecera interna */}

Directorio de Clientes

Gestión de fichas de clientes y acceso a su historial de reparaciones técnico.

{/* Selector de Pestañas (Tabs) */}
{activeTab === "control" ? ( {/* Buscador */}
setSearchQuery(e.target.value)} className="bg-background/80 border-border text-xs w-full pl-9" />
Total: {clients.length} Clientes
{/* Listado de Clientes */} {filteredClients.length > 0 ? (
{filteredClients.map((client) => { const clientOrders = orders.filter(o => { const oClientId = typeof o.clientId === "object" ? o.clientId._id : o.clientId; return oClientId === client._id; }); return ( ); })}
ID Cliente Nombre Identificación (DNI) Contacto Órdenes Acción
{client._id.substring(client._id.length - 6).toUpperCase()} {client.name} {client.dni}
{client.phone} {client.email}
0 ? "default" : "secondary"} className="text-[10px] font-bold"> {clientOrders.length}
) : (
No se encontraron clientes con los filtros actuales.
)}
) : ( /* Formulario de Alta / Edición */
{editingId ? "Editar Ficha de Cliente" : "Alta de Ficha de Cliente"} {editingId ? `Modificá los datos de contacto y facturación de ${clientName}.` : "Registrá un nuevo cliente en la base de datos."}
setClientName(e.target.value)} placeholder="Edgar Ortiz" className="bg-background/85 border-border focus-visible:ring-1 focus-visible:ring-primary text-xs" />
setClientDni(e.target.value)} placeholder="44.375.912" className="bg-background/85 border-border focus-visible:ring-1 focus-visible:ring-primary text-xs font-mono disabled:opacity-60" />
setClientPhone(e.target.value)} placeholder="+54 381 1234567" className="bg-background/85 border-border focus-visible:ring-1 focus-visible:ring-primary text-xs" />
setClientEmail(e.target.value)} placeholder="edgar@repairit.cloud" className="bg-background/85 border-border focus-visible:ring-1 focus-visible:ring-primary text-xs" />
{editingId && ( )}
)}
{/* Modal / Diálogo para visualización de Órdenes del Cliente */} {showOrdersModal && selectedClientForOrders && (
Reparaciones de {selectedClientForOrders.name} Ficha de cliente: {selectedClientForOrders._id.substring(selectedClientForOrders._id.length - 6).toUpperCase()} • DNI: {selectedClientForOrders.dni}
{orders.filter(o => { const oClientId = typeof o.clientId === "object" ? o.clientId._id : o.clientId; return oClientId === selectedClientForOrders._id; }).map(o => { let badgeVariant = "secondary"; if (o.status === "listo") badgeVariant = "success"; if (o.status === "presupuestado") badgeVariant = "warning"; return (
{o.trackingCode} {o.date}
{o.deviceModel} ({o.deviceType})

{o.issue}

{o.status.toUpperCase()}
); })}
)} {/* Diálogo de alerta para confirmación de eliminación */} ¿Confirmás la eliminación del cliente? Al eliminar a {clientToDelete?.name}, también se eliminarán del historial de forma permanente todas las órdenes de servicio asociadas. Esta acción no se puede deshacer. Cancelar Sí, Eliminar Todo
); }