feat: Implementación de gestión manual y panel de administración
Se introduce una refactorización masiva y se añaden nuevas funcionalidades críticas para la gestión del inventario, incluyendo un panel de administración para la limpieza de datos y un sistema completo para la gestión manual de equipos.
### Nuevas Funcionalidades
*   **Panel de Administración:** Se crea una nueva vista de "Administración" para la gestión de datos maestros. Permite unificar valores inconsistentes (ej: "W10" -> "Windows 10 Pro") y eliminar registros maestros no utilizados (ej: Módulos de RAM) para mantener la base de datos limpia.
*   **Gestión de Sectores (CRUD):** Se añade una vista dedicada para crear, editar y eliminar sectores de la organización.
*   **Diferenciación Manual vs. Automático:** Se introduce una columna `origen` en la base de datos para distinguir entre los datos recopilados automáticamente por el script y los introducidos manualmente por el usuario. La UI ahora refleja visualmente este origen.
*   **CRUD de Equipos Manuales:** Se implementa la capacidad de crear, editar y eliminar equipos de origen "manual" a través de la interfaz de usuario. Se protege la eliminación de equipos automáticos.
*   **Gestión de Componentes Manuales:** Se permite añadir y eliminar componentes (Discos, RAM, Usuarios) a los equipos de origen "manual".
### Mejoras de UI/UX
*   **Refactorización de Estilos:** Se migran todos los estilos en línea del componente `SimpleTable` a un archivo CSS Module (`SimpleTable.module.css`), mejorando la mantenibilidad y el rendimiento.
*   **Notificaciones de Usuario:** Se integra `react-hot-toast` para proporcionar feedback visual inmediato (carga, éxito, error) en todas las operaciones asíncronas, reemplazando los `alert`.
*   **Componentización:** Se extraen todos los modales (`ModalDetallesEquipo`, `ModalAnadirEquipo`, etc.) a sus propios componentes, limpiando y simplificando drásticamente el componente `SimpleTable`.
*   **Paginación en Tabla Principal:** Se implementa paginación completa en la tabla de equipos, con controles para navegar, ir a una página específica y cambiar el número de items por página. Se añade un indicador de carga inicial.
*   **Navegación Mejorada:** Se reemplaza la navegación por botones con un componente `Navbar` estilizado y dedicado, mejorando la estructura visual y de código.
*   **Autocompletado de Datos:** Se introduce un componente `AutocompleteInput` reutilizable para guiar al usuario a usar datos consistentes al rellenar campos como OS, CPU y Motherboard. Se implementa búsqueda dinámica para la asociación de usuarios.
*   **Validación de MAC Address:** Se añade validación de formato en tiempo real y auto-formateo para el campo de MAC Address, reduciendo errores humanos.
*   **Consistencia de Iconos:** Se unifica el icono de eliminación a (🗑️) en toda la aplicación para una experiencia de usuario más coherente.
### Mejoras en el Backend / API
*   **Seguridad de Credenciales:** Las credenciales SSH para la función Wake On Lan se mueven del código fuente a `appsettings.json`.
*   **Nuevo `AdminController`:** Se crea un controlador dedicado para las tareas administrativas, con endpoints para obtener valores únicos de componentes y para ejecutar la lógica de unificación y eliminación.
*   **Endpoints de Gestión Manual:** Se añaden rutas específicas (`/manual/...` y `/asociacion/...`) para la manipulación de datos de origen manual, separando la lógica de la gestión automática.
*   **Protección de Datos Automáticos:** Los endpoints `DELETE` y `PUT` ahora validan el campo `origen` para prevenir la modificación o eliminación no deseada de datos generados automáticamente.
*   **Correcciones y Refinamiento:** Se soluciona el mapeo incorrecto de fechas (`created_at`, `updated_at`), se corrigen errores de compilación y se refinan las consultas SQL para incluir los nuevos campos.
											 
										 
										
											2025-10-07 14:44:16 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								import  {  useState ,  useEffect  }  from  'react' ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								import  toast  from  'react-hot-toast' ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								import  styles  from  './SimpleTable.module.css' ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-07 15:18:11 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								const  BASE_URL  =  '/api' ;  
						 
					
						
							
								
									
										
											 
										
											
												feat: Implementación de gestión manual y panel de administración
Se introduce una refactorización masiva y se añaden nuevas funcionalidades críticas para la gestión del inventario, incluyendo un panel de administración para la limpieza de datos y un sistema completo para la gestión manual de equipos.
### Nuevas Funcionalidades
*   **Panel de Administración:** Se crea una nueva vista de "Administración" para la gestión de datos maestros. Permite unificar valores inconsistentes (ej: "W10" -> "Windows 10 Pro") y eliminar registros maestros no utilizados (ej: Módulos de RAM) para mantener la base de datos limpia.
*   **Gestión de Sectores (CRUD):** Se añade una vista dedicada para crear, editar y eliminar sectores de la organización.
*   **Diferenciación Manual vs. Automático:** Se introduce una columna `origen` en la base de datos para distinguir entre los datos recopilados automáticamente por el script y los introducidos manualmente por el usuario. La UI ahora refleja visualmente este origen.
*   **CRUD de Equipos Manuales:** Se implementa la capacidad de crear, editar y eliminar equipos de origen "manual" a través de la interfaz de usuario. Se protege la eliminación de equipos automáticos.
*   **Gestión de Componentes Manuales:** Se permite añadir y eliminar componentes (Discos, RAM, Usuarios) a los equipos de origen "manual".
### Mejoras de UI/UX
*   **Refactorización de Estilos:** Se migran todos los estilos en línea del componente `SimpleTable` a un archivo CSS Module (`SimpleTable.module.css`), mejorando la mantenibilidad y el rendimiento.
*   **Notificaciones de Usuario:** Se integra `react-hot-toast` para proporcionar feedback visual inmediato (carga, éxito, error) en todas las operaciones asíncronas, reemplazando los `alert`.
*   **Componentización:** Se extraen todos los modales (`ModalDetallesEquipo`, `ModalAnadirEquipo`, etc.) a sus propios componentes, limpiando y simplificando drásticamente el componente `SimpleTable`.
*   **Paginación en Tabla Principal:** Se implementa paginación completa en la tabla de equipos, con controles para navegar, ir a una página específica y cambiar el número de items por página. Se añade un indicador de carga inicial.
*   **Navegación Mejorada:** Se reemplaza la navegación por botones con un componente `Navbar` estilizado y dedicado, mejorando la estructura visual y de código.
*   **Autocompletado de Datos:** Se introduce un componente `AutocompleteInput` reutilizable para guiar al usuario a usar datos consistentes al rellenar campos como OS, CPU y Motherboard. Se implementa búsqueda dinámica para la asociación de usuarios.
*   **Validación de MAC Address:** Se añade validación de formato en tiempo real y auto-formateo para el campo de MAC Address, reduciendo errores humanos.
*   **Consistencia de Iconos:** Se unifica el icono de eliminación a (🗑️) en toda la aplicación para una experiencia de usuario más coherente.
### Mejoras en el Backend / API
*   **Seguridad de Credenciales:** Las credenciales SSH para la función Wake On Lan se mueven del código fuente a `appsettings.json`.
*   **Nuevo `AdminController`:** Se crea un controlador dedicado para las tareas administrativas, con endpoints para obtener valores únicos de componentes y para ejecutar la lógica de unificación y eliminación.
*   **Endpoints de Gestión Manual:** Se añaden rutas específicas (`/manual/...` y `/asociacion/...`) para la manipulación de datos de origen manual, separando la lógica de la gestión automática.
*   **Protección de Datos Automáticos:** Los endpoints `DELETE` y `PUT` ahora validan el campo `origen` para prevenir la modificación o eliminación no deseada de datos generados automáticamente.
*   **Correcciones y Refinamiento:** Se soluciona el mapeo incorrecto de fechas (`created_at`, `updated_at`), se corrigen errores de compilación y se refinan las consultas SQL para incluir los nuevos campos.
											 
										 
										
											2025-10-07 14:44:16 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								// Interfaces para los diferentes tipos de datos
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								interface  TextValue  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								  valor : string ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								  conteo : number ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								interface  RamValue  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								  id : number ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								  fabricante? : string ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								  tamano : number ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								  velocidad? : number ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								  partNumber? : string ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								  conteo : number ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								const  GestionComponentes  =  ( )  = >  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								  const  [ componentType ,  setComponentType ]  =  useState ( 'os' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								  const  [ valores ,  setValores ]  =  useState < ( TextValue  |  RamValue ) [ ] > ( [ ] ) ;  // Estado que acepta ambos tipos
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								  const  [ isLoading ,  setIsLoading ]  =  useState ( false ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								  const  [ isModalOpen ,  setIsModalOpen ]  =  useState ( false ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								  const  [ valorAntiguo ,  setValorAntiguo ]  =  useState ( '' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								  const  [ valorNuevo ,  setValorNuevo ]  =  useState ( '' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								  useEffect ( ( )  = >  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    setIsLoading ( true ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    const  endpoint  =  componentType  ===  'ram'  ?  ` ${ BASE_URL } /admin/componentes/ram `  :  ` ${ BASE_URL } /admin/componentes/ ${ componentType } ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    fetch ( endpoint ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								      . then ( res  = >  res . json ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								      . then ( data  = >  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        setValores ( data ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								      } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								      . catch ( _err  = >  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        toast . error ( ` No se pudieron cargar los datos de  ${ componentType } . ` ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								      } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								      . finally ( ( )  = >  setIsLoading ( false ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								  } ,  [ componentType ] ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								  const  handleOpenModal  =  ( valor : string )  = >  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    setValorAntiguo ( valor ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    setValorNuevo ( valor ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    setIsModalOpen ( true ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								  const  handleUnificar  =  async  ( )  = >  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    const  toastId  =  toast . loading ( 'Unificando valores...' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    try  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								      const  response  =  await  fetch ( ` ${ BASE_URL } /admin/componentes/ ${ componentType } /unificar ` ,  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        method :  'PUT' , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        headers :  {  'Content-Type' :  'application/json'  } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        body : JSON.stringify ( {  valorAntiguo ,  valorNuevo  } ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								      } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								      if  ( ! response . ok )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        const  error  =  await  response . json ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        throw  new  Error ( error . message  ||  'La unificación falló.' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								      // Refrescar la lista para ver el resultado
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								      const  refreshedData  =  await  ( await  fetch ( ` ${ BASE_URL } /admin/componentes/ ${ componentType } ` ) ) . json ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								      setValores ( refreshedData ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								      toast . success ( 'Valores unificados correctamente.' ,  {  id : toastId  } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								      setIsModalOpen ( false ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    }  catch  ( error )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								      if  ( error  instanceof  Error )  toast . error ( error . message ,  {  id : toastId  } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								  const  handleDeleteRam  =  async  ( ramId : number )  = >  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( ! window . confirm ( "¿Estás seguro de eliminar este módulo de RAM de la base de datos maestra? Esta acción es irreversible." ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								      return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    const  toastId  =  toast . loading ( 'Eliminando módulo...' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    try  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								      const  response  =  await  fetch ( ` ${ BASE_URL } /admin/componentes/ram/ ${ ramId } ` ,  {  method :  'DELETE'  } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								      if  ( ! response . ok )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        const  error  =  await  response . json ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        throw  new  Error ( error . message  ||  'No se pudo eliminar.' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								      setValores ( prev  = >  prev . filter ( v  = >  ( v  as  RamValue ) . id  !==  ramId ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								      toast . success ( "Módulo de RAM eliminado." ,  {  id : toastId  } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    }  catch  ( error )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								      if  ( error  instanceof  Error )  toast . error ( error . message ,  {  id : toastId  } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								  const  handleDeleteTexto  =  async  ( valor : string )  = >  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( ! window . confirm ( ` Este valor ya no está en uso. ¿Quieres intentar eliminarlo de la base de datos maestra? (Si no existe una tabla maestra, esta acción solo confirmará que no hay usos) ` ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        const  toastId  =  toast . loading ( 'Eliminando valor...' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        try  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            // La API necesita el valor codificado para manejar caracteres especiales como '/'
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            const  encodedValue  =  encodeURIComponent ( valor ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            const  response  =  await  fetch ( ` ${ BASE_URL } /admin/componentes/ ${ componentType } / ${ encodedValue } ` ,  {  method :  'DELETE'  } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( ! response . ok )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                const  error  =  await  response . json ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                throw  new  Error ( error . message  ||  'No se pudo eliminar.' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            setValores ( prev  = >  prev . filter ( v  = >  ( v  as  TextValue ) . valor  !==  valor ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            toast . success ( "Valor eliminado/confirmado como no existente." ,  {  id : toastId  } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        }  catch  ( error )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( error  instanceof  Error )  toast . error ( error . message ,  {  id : toastId  } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								  const  renderValor  =  ( item : TextValue  |  RamValue )  = >  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( componentType  ===  'ram' )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								      const  ram  =  item  as  RamValue ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								      return  ` ${ ram . fabricante  ||  '' }   ${ ram . tamano } GB  ${ ram . velocidad  ?  ram . velocidad  +  'MHz'  :  '' }  ( ${ ram . partNumber  ||  'N/P' } ) ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    return  ( item  as  TextValue ) . valor ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								  return  ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        < div > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            < h2 > Gestión  de  Componentes  Maestros < / h2 > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            < p > Unifica  valores  inconsistentes  y  elimina  registros  no  utilizados . < / p > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            < div  style = { {  marginBottom :  '1.5rem'  } } > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                < label > < strong > Selecciona  un  tipo  de  componente : < / strong > < / label > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                < select  value = { componentType }  onChange = { e  = >  setComponentType ( e . target . value ) }  className = { styles . sectorSelect }  style = { { marginLeft :  '10px' } } > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    < option  value = "os" > Sistema  Operativo < / option > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    < option  value = "cpu" > CPU < / option > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    < option  value = "motherboard" > Motherboard < / option > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    < option  value = "architecture" > Arquitectura < / option > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    < option  value = "ram" > Memorias  RAM < / option > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                < / select > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            < / div > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            { isLoading  ?  ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                < p > Cargando . . . < / p > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            )  :  ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                < table  className = { styles . table } > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    < thead > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                        < tr > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                            < th  className = { styles . th } > Valor  Registrado < / th > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                            < th  className = { styles . th }  style = { { width :  '150px' } } > Nº  de  Equipos < / th > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                            < th  className = { styles . th }  style = { { width :  '200px' } } > Acciones < / th > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                        < / tr > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    < / thead > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    < tbody > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                        { valores . map ( ( item )  = >  ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                            < tr  key = { componentType  ===  'ram'  ?  ( item  as  RamValue ) . id  :  ( item  as  TextValue ) . valor }  className = { styles . tr } > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                < td  className = { styles . td } > { renderValor ( item ) } < / td > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                < td  className = { styles . td } > { item . conteo } < / td > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                < td  className = { styles . td } > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                    < div  style = { { display :  'flex' ,  gap :  '5px' } } > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                        { componentType  ===  'ram'  ?  ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                            // Lógica solo para RAM (no tiene sentido "unificar" un objeto complejo)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                            < button  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                                onClick = { ( )  = >  handleDeleteRam ( ( item  as  RamValue ) . id ) }  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                                className = { styles . deleteUserButton }  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                                style = { { fontSize :  '0.9em' ,  border :  '1px solid' ,  borderRadius :  '4px' ,  padding :  '4px 8px' ,  cursor : item.conteo  >  0  ?  'not-allowed'  :  'pointer' ,  opacity : item.conteo  >  0  ?  0.5  : 1 } } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                                disabled = { item . conteo  >  0 } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                                title = { item . conteo  >  0  ?  ` En uso por  ${ item . conteo }  equipo(s) `  :  'Eliminar este módulo maestro' } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                            > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
										 
							
							
								                                                🗑 ️ Eliminar 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                            < / button > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                        )  :  ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                            // Lógica para todos los demás tipos de componentes (texto)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                            < > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                                < button  onClick = { ( )  = >  handleOpenModal ( ( item  as  TextValue ) . valor ) }  className = { styles . tableButton } > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
										 
							
							
								                                                    ✏ ️ Unificar 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                                < / button > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                                < button  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                                    onClick = { ( )  = >  handleDeleteTexto ( ( item  as  TextValue ) . valor ) }  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                                    className = { styles . deleteUserButton }  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                                    style = { { fontSize :  '0.9em' ,  border :  '1px solid' ,  borderRadius :  '4px' ,  padding :  '4px 8px' ,  cursor : item.conteo  >  0  ?  'not-allowed'  :  'pointer' ,  opacity : item.conteo  >  0  ?  0.5  : 1 } } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                                    disabled = { item . conteo  >  0 } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                                    title = { item . conteo  >  0  ?  ` En uso por  ${ item . conteo }  equipo(s). Unifique primero. `  :  'Eliminar este valor' } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                                > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
										 
							
							
								                                                    🗑 ️ Eliminar 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                                < / button > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                            < / > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                        ) } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                    < / div > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                                < / td > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                            < / tr > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                        ) ) } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    < / tbody > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                < / table > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            ) } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            { isModalOpen  &&  ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                < div  className = { styles . modalOverlay } > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    < div  className = { styles . modal } > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                        < h3 > Unificar  Valor < / h3 > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                        < p > Se  reemplazarán  todas  las  instancias  de : < / p > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                        < strong  style = { {  display :  'block' ,  marginBottom :  '1rem' ,  background :  '#e9ecef' ,  padding :  '8px' ,  borderRadius :  '4px'  } } > { valorAntiguo } < / strong > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                        < label > Por  el  nuevo  valor : < / label > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                        < input  type = "text"  value = { valorNuevo }  onChange = { e  = >  setValorNuevo ( e . target . value ) }  className = { styles . modalInput }  / > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                        < div  className = { styles . modalActions } > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                            < button  onClick = { handleUnificar }  className = { ` ${ styles . btn }   ${ styles . btnPrimary } ` }  disabled = { ! valorNuevo . trim ( )  ||  valorNuevo  ===  valorAntiguo } > Unificar < / button > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                            < button  onClick = { ( )  = >  setIsModalOpen ( false ) }  className = { ` ${ styles . btn }   ${ styles . btnSecondary } ` } > Cancelar < / button > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                        < / div > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    < / div > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                < / div > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            ) } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        < / div > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								} ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								export  default  GestionComponentes ;