'use client' import { useState, useEffect } from 'react' import { Monitor, Laptop, Server, Smartphone, Tablet, Router, Network, Shield, Wifi, Printer, HelpCircle, X, Pencil, } from 'lucide-react' import { trpc } from '@/lib/trpc-client' import { cn } from '@/lib/utils' import { mapDeviceToDetail } from '@/mocks/deviceDetailData' import InfoSection from './InfoSection' import SoftwareList from './SoftwareList' import ActionBar from './ActionBar' const DEVICE_TYPE_ICONS: Record = { PC: , LAPTOP: , SERVIDOR: , CELULAR: , TABLET: , ROUTER: , SWITCH: , FIREWALL: , AP: , IMPRESORA: , OTRO: , } const DEVICE_TYPE_OPTIONS: { value: string; label: string }[] = [ { value: 'PC', label: 'PC' }, { value: 'LAPTOP', label: 'Laptop' }, { value: 'SERVIDOR', label: 'Servidor' }, { value: 'CELULAR', label: 'Celular' }, { value: 'TABLET', label: 'Tablet' }, { value: 'ROUTER', label: 'Router' }, { value: 'SWITCH', label: 'Switch' }, { value: 'FIREWALL', label: 'Firewall' }, { value: 'AP', label: 'Access Point' }, { value: 'IMPRESORA', label: 'Impresora' }, { value: 'OTRO', label: 'Otro' }, ] const DEVICE_STATUS_OPTIONS: { value: string; label: string }[] = [ { value: 'DESCONOCIDO', label: 'Desconocido' }, { value: 'ONLINE', label: 'En línea' }, { value: 'OFFLINE', label: 'Fuera de línea' }, { value: 'ALERTA', label: 'Advertencia' }, { value: 'MANTENIMIENTO', label: 'Mantenimiento' }, ] const INPUT_CLASS = 'w-full rounded-lg border border-white/10 bg-dark-300 px-4 py-2.5 text-sm text-gray-200 placeholder-gray-500 focus:border-primary-500/50 focus:outline-none focus:ring-2 focus:ring-primary-500/20' type DeviceTypeValue = | 'PC' | 'LAPTOP' | 'SERVIDOR' | 'CELULAR' | 'TABLET' | 'ROUTER' | 'SWITCH' | 'FIREWALL' | 'AP' | 'IMPRESORA' | 'OTRO' type DeviceStatusValue = 'ONLINE' | 'OFFLINE' | 'ALERTA' | 'MANTENIMIENTO' | 'DESCONOCIDO' interface EditFormState { tipo: string nombre: string descripcion: string ubicacionId: string estado: string ip: string mac: string sistemaOperativo: string versionSO: string fabricante: string modelo: string serial: string } interface DeviceFromApi { tipo: string nombre: string descripcion?: string | null ubicacionId?: string | null estado: string ip?: string | null mac?: string | null sistemaOperativo?: string | null versionSO?: string | null fabricante?: string | null modelo?: string | null serial?: string | null } function buildEditFormFromDevice(device: DeviceFromApi): EditFormState { return { tipo: device.tipo, nombre: device.nombre, descripcion: device.descripcion ?? '', ubicacionId: device.ubicacionId ?? '', estado: device.estado, ip: device.ip ?? '', mac: device.mac ?? '', sistemaOperativo: device.sistemaOperativo ?? '', versionSO: device.versionSO ?? '', fabricante: device.fabricante ?? '', modelo: device.modelo ?? '', serial: device.serial ?? '', } } interface DeviceDetailModalProps { open: boolean onClose: () => void deviceId: string | null deviceName?: string onConnect?: (id: string) => void onTerminal?: (id: string) => void onFiles?: (id: string) => void } export default function DeviceDetailModal({ open, onClose, deviceId, deviceName = 'Dispositivo', onConnect, onTerminal, onFiles, }: DeviceDetailModalProps) { const [isEditing, setIsEditing] = useState(false) const [editForm, setEditForm] = useState(null) const [editError, setEditError] = useState(null) const utils = trpc.useUtils() const deviceQuery = trpc.equipos.byId.useQuery( { id: deviceId! }, { enabled: open && !!deviceId } ) const device = deviceQuery.data const clientId = device?.clienteId const locationsQuery = trpc.clientes.ubicaciones.list.useQuery( { clienteId: clientId! }, { enabled: open && !!clientId && isEditing } ) const updateMutation = trpc.equipos.update.useMutation({ onSuccess: () => { utils.equipos.byId.invalidate({ id: deviceId! }) utils.equipos.list.invalidate() utils.clientes.dashboardStats.invalidate() setIsEditing(false) setEditForm(null) setEditError(null) }, onError: (err) => { setEditError(err.message) }, }) useEffect(() => { if (!open) { setIsEditing(false) setEditForm(null) setEditError(null) } }, [open]) useEffect(() => { if (isEditing && device) { setEditForm(buildEditFormFromDevice(device)) setEditError(null) } }, [isEditing, device]) const detail = device ? mapDeviceToDetail(device) : null const isLoading = deviceQuery.isLoading const hasError = deviceQuery.isError const systemItems = detail ? [ { label: 'Sistema Operativo', value: detail.systemInfo.sistemaOperativo }, { label: 'Procesador', value: detail.systemInfo.procesador }, { label: 'Memoria RAM', value: detail.systemInfo.memoriaRam }, { label: 'Almacenamiento', value: detail.systemInfo.almacenamientoUsoPercent != null ? `${detail.systemInfo.almacenamiento} (${detail.systemInfo.almacenamientoUsoPercent}% uso)` : detail.systemInfo.almacenamiento, }, ] : [] const networkItems = detail ? [ { label: 'Dirección IP', value: detail.networkInfo.direccionIp }, { label: 'Dirección MAC', value: detail.networkInfo.direccionMac }, { label: 'Gateway', value: detail.networkInfo.gateway }, { label: 'DNS', value: detail.networkInfo.dns }, ] : [] const handleSaveEdit = (e: React.FormEvent) => { e.preventDefault() if (!deviceId || !editForm) return setEditError(null) updateMutation.mutate({ id: deviceId, tipo: editForm.tipo as DeviceTypeValue, nombre: editForm.nombre.trim(), descripcion: editForm.descripcion.trim() || null, ubicacionId: editForm.ubicacionId || null, estado: editForm.estado as DeviceStatusValue, ip: editForm.ip.trim() || null, mac: editForm.mac.trim() || null, sistemaOperativo: editForm.sistemaOperativo.trim() || null, versionSO: editForm.versionSO.trim() || null, fabricante: editForm.fabricante.trim() || null, modelo: editForm.modelo.trim() || null, serial: editForm.serial.trim() || null, }) } if (!open) return null return (
{detail ? DEVICE_TYPE_ICONS[detail.tipo] ?? DEVICE_TYPE_ICONS.OTRO : DEVICE_TYPE_ICONS.OTRO}

{detail?.nombre ?? deviceName}

{detail && !isEditing && ( )}
{isLoading && !editForm && (
Cargando información del dispositivo...
)} {hasError && (
No se pudo cargar el dispositivo. Intente de nuevo.
)} {isEditing && editForm && device && (
{editError && (
{editError}
)}
setEditForm((f) => f && { ...f, nombre: e.target.value })} className={INPUT_CLASS} required />