"use client" import { useState } from "react" import { useAuth } from "@/lib/auth-context" import { useRouter } from "next/navigation" 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 { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Avatar, AvatarFallback } from "@/components/ui/avatar" import { Plus, Pencil, Trash2, Search } from "lucide-react" import { Badge } from "@/components/ui/badge" interface Usuario { id: string name: string email: string role: "admin" | "ingeniero" status: "activo" | "inactivo" } import { apiFetch } from "@/lib/apiutils" import { useEffect } from "react" import { toast } from "sonner" export default function UsuariosPage() { const { user } = useAuth() const router = useRouter() const [usuarios, setUsuarios] = useState([]) const [isLoading, setIsLoading] = useState(true) const fetchData = async () => { setIsLoading(true) try { const res = await apiFetch("/users") if (res.ok) { const data = await res.json() const mappedData = data.map((u: any) => ({ id: u.id.toString(), name: u.name, email: u.email, role: u.role, status: u.status })) setUsuarios(mappedData) } } catch (e) { console.error(e) } finally { setIsLoading(false) } } useEffect(() => { if (user?.role === "admin") { fetchData() } }, [user]) const [searchTerm, setSearchTerm] = useState("") const [isDialogOpen, setIsDialogOpen] = useState(false) const [editingUser, setEditingUser] = useState(null) const [formData, setFormData] = useState({ name: "", email: "", password: "", role: "ingeniero" as "admin" | "ingeniero", status: "activo" as "activo" | "inactivo", }) // Protección de ruta if (user?.role !== "admin") { // Redirect handled in useEffect or handled by layout usually, but here is fine. // However, avoid render loop return null. // Accessing localStorage or similar might be better for sync check but we rely on auth context // If context is loading, maybe show spinner? // For now keeping existing logic but fetch is guarded. } // Note: The existing check below is sync render. // if (user?.role !== "admin") ... // Keeping it as is from previous file content, assuming it works or adapting. // Actually, replace the state init block logic. const filteredUsuarios = usuarios.filter( (usuario) => usuario.name.toLowerCase().includes(searchTerm.toLowerCase()) || usuario.email.toLowerCase().includes(searchTerm.toLowerCase()), ) const handleOpenDialog = (usuario?: Usuario) => { if (usuario) { setEditingUser(usuario) setFormData({ name: usuario.name, email: usuario.email, password: "", role: usuario.role, status: usuario.status, }) } else { setEditingUser(null) setFormData({ name: "", email: "", password: "", role: "ingeniero", status: "activo" }) } setIsDialogOpen(true) } const handleSave = async () => { // Validaciones if (!formData.name || !formData.email) { toast.error("Por favor completa todos los campos obligatorios.") return } if (!editingUser && !formData.password) { toast.error("La contraseña es obligatoria para nuevos usuarios.") return } if (formData.password && formData.password.length < 8) { toast.error("La contraseña debe tener al menos 8 caracteres.") return } try { const payload: any = { name: formData.name, email: formData.email, role: formData.role, status: formData.status } if (formData.password) { payload.password = formData.password } let res; if (editingUser) { res = await apiFetch(`/users/${editingUser.id}`, { method: 'PUT', body: JSON.stringify(payload) }) } else { res = await apiFetch('/users', { method: 'POST', body: JSON.stringify(payload) }) } if (res.ok) { fetchData() setIsDialogOpen(false) } else { toast.error("Error al guardar") } } catch (e) { console.error(e) toast.error("Error de conexión") } } const handleDelete = async (id: string) => { if (confirm("¿Estás seguro de que deseas eliminar este usuario?")) { try { const res = await apiFetch(`/users/${id}`, { method: 'DELETE' }) if (res.ok) { fetchData() } else { const data = await res.json() toast.error(data.message || "Error al eliminar") } } catch (e) { console.error(e) toast.error("Error de conexión") } } } const getInitials = (name: string) => { return name .split(" ") .map((n) => n[0]) .join("") .toUpperCase() .slice(0, 2) } useEffect(() => { if (user && user.role !== "admin") { router.push("/dashboard") } }, [user, router]) if (user?.role !== "admin") { // Return null while redirecting to prevent flash of content or render errors return null } return (

Gestión de Usuarios

Administra los usuarios del sistema

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

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

)}
{ if (e.target.value.length <= 100) { setFormData({ ...formData, email: e.target.value }) } }} maxLength={100} placeholder="juan@agrorecetas.com" autoComplete="off" 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.

)}
{ if (e.target.value.length <= 50) { setFormData({ ...formData, password: e.target.value }) } }} maxLength={50} placeholder={editingUser ? "Dejar en blanco para mantener actual" : "******"} autoComplete="new-password" className={formData.password.length >= 50 ? 'border-red-500 focus-visible:ring-red-500' : ''} /> {formData.password.length >= 50 && (

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

)}
Usuarios Registrados Lista de todos los usuarios del sistema
setSearchTerm(e.target.value)} className="pl-10" autoComplete="off" data-lpignore="true" />
Usuario Email Rol Estado Acciones {isLoading ? ( Cargando usuarios... ) : filteredUsuarios.length === 0 ? ( No se encontraron usuarios ) : ( filteredUsuarios.map((usuario) => (
{getInitials(usuario.name)} {usuario.name}
{usuario.email} {usuario.role} {usuario.status}
)) )}
) }