Se agregaron cambios en vucem y settings
This commit is contained in:
135
docs/documentation-guide.md
Normal file
135
docs/documentation-guide.md
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
# Guía para Documentar la Aplicación EFC
|
||||||
|
|
||||||
|
## Metodología Recomendada
|
||||||
|
|
||||||
|
### 1. CAPTURA DE PANTALLAS SISTEMÁTICA
|
||||||
|
|
||||||
|
#### Preparación:
|
||||||
|
- Usar datos de prueba consistentes
|
||||||
|
- Configurar resoluciones estándar (1920x1080, 1366x768)
|
||||||
|
- Usar navegadores principales (Chrome, Firefox, Safari)
|
||||||
|
- Preparar diferentes roles de usuario
|
||||||
|
|
||||||
|
#### Herramientas recomendadas:
|
||||||
|
- **Snagit** - Para capturas profesionales con anotaciones
|
||||||
|
- **Loom** - Para videos explicativos
|
||||||
|
- **Figma** - Para crear diagramas de flujo
|
||||||
|
- **Draw.io** - Para diagramas técnicos
|
||||||
|
|
||||||
|
### 2. ESTRUCTURA DE CADA SECCIÓN
|
||||||
|
|
||||||
|
Para cada funcionalidad documentar:
|
||||||
|
|
||||||
|
1. **Objetivo** - ¿Para qué sirve?
|
||||||
|
2. **Prerrequisitos** - ¿Qué se necesita antes?
|
||||||
|
3. **Paso a paso** - Procedimiento detallado
|
||||||
|
4. **Screenshots** - Pantallas relevantes
|
||||||
|
5. **Consejos** - Mejores prácticas
|
||||||
|
6. **Troubleshooting** - Problemas comunes
|
||||||
|
|
||||||
|
### 3. PLAN DE DOCUMENTACIÓN
|
||||||
|
|
||||||
|
#### Semana 1: Funcionalidades Básicas
|
||||||
|
- [ ] Acceso al sistema
|
||||||
|
- [ ] Navegación general
|
||||||
|
- [ ] Panel principal
|
||||||
|
|
||||||
|
#### Semana 2: Gestión de Contenido
|
||||||
|
- [ ] Expedientes
|
||||||
|
- [ ] Documentos
|
||||||
|
- [ ] Búsquedas y filtros
|
||||||
|
|
||||||
|
#### Semana 3: Funcionalidades Avanzadas
|
||||||
|
- [ ] Procesos
|
||||||
|
- [ ] Administración
|
||||||
|
- [ ] Reportes
|
||||||
|
|
||||||
|
#### Semana 4: Integración y Finalización
|
||||||
|
- [ ] VUCEM
|
||||||
|
- [ ] Notificaciones
|
||||||
|
- [ ] Revisión y ajustes
|
||||||
|
|
||||||
|
### 4. CONSIDERACIONES TÉCNICAS
|
||||||
|
|
||||||
|
#### Responsive Design:
|
||||||
|
- Documentar vista desktop
|
||||||
|
- Documentar vista móvil/tablet
|
||||||
|
- Mostrar cómo cambia la interfaz
|
||||||
|
|
||||||
|
#### Roles de Usuario:
|
||||||
|
- Importador
|
||||||
|
- Administrador
|
||||||
|
- Grupos específicos (3,5)
|
||||||
|
|
||||||
|
#### Estados del Sistema:
|
||||||
|
- Con datos
|
||||||
|
- Sin datos
|
||||||
|
- Estados de carga
|
||||||
|
- Estados de error
|
||||||
|
|
||||||
|
### 5. FORMATO DE DOCUMENTACIÓN
|
||||||
|
|
||||||
|
#### Para cada pantalla incluir:
|
||||||
|
```markdown
|
||||||
|
## [Nombre de la Funcionalidad]
|
||||||
|
|
||||||
|
### Descripción
|
||||||
|
Breve explicación de qué hace esta funcionalidad.
|
||||||
|
|
||||||
|
### Acceso
|
||||||
|
Cómo llegar a esta pantalla.
|
||||||
|
|
||||||
|
### Elementos de la Interfaz
|
||||||
|
1. **Header/Encabezado**: [descripción]
|
||||||
|
2. **Barra lateral**: [descripción]
|
||||||
|
3. **Área principal**: [descripción]
|
||||||
|
4. **Controles**: [descripción]
|
||||||
|
|
||||||
|
### Procedimientos
|
||||||
|
#### Para [acción específica]:
|
||||||
|
1. [Paso 1 con screenshot]
|
||||||
|
2. [Paso 2 con screenshot]
|
||||||
|
3. [Resultado esperado]
|
||||||
|
|
||||||
|
### Consejos y Buenas Prácticas
|
||||||
|
- [Consejo 1]
|
||||||
|
- [Consejo 2]
|
||||||
|
|
||||||
|
### Problemas Comunes
|
||||||
|
- **Problema**: [descripción]
|
||||||
|
**Solución**: [pasos para resolver]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. CONTROL DE CALIDAD
|
||||||
|
|
||||||
|
#### Checklist por sección:
|
||||||
|
- [ ] Screenshots actualizados
|
||||||
|
- [ ] Pasos verificados
|
||||||
|
- [ ] Texto claro y conciso
|
||||||
|
- [ ] Formato consistente
|
||||||
|
- [ ] Links funcionando
|
||||||
|
- [ ] Información de roles correcta
|
||||||
|
|
||||||
|
### 7. HERRAMIENTAS DE COLABORACIÓN
|
||||||
|
|
||||||
|
#### Para equipos:
|
||||||
|
- **Slack/Teams** - Comunicación
|
||||||
|
- **Trello/Jira** - Seguimiento de tareas
|
||||||
|
- **Google Drive/SharePoint** - Almacenamiento colaborativo
|
||||||
|
- **GitHub** - Versionado si usas Markdown
|
||||||
|
|
||||||
|
### 8. MANTENIMIENTO
|
||||||
|
|
||||||
|
#### Plan de actualización:
|
||||||
|
- Revisar cada release
|
||||||
|
- Actualizar screenshots con cambios de UI
|
||||||
|
- Verificar procedimientos
|
||||||
|
- Actualizar enlaces y referencias
|
||||||
|
|
||||||
|
## Próximos Pasos
|
||||||
|
|
||||||
|
1. **Configurar entorno de documentación**
|
||||||
|
2. **Definir estilo y formato**
|
||||||
|
3. **Crear plantillas**
|
||||||
|
4. **Comenzar con funcionalidades básicas**
|
||||||
|
5. **Establecer proceso de revisión**
|
||||||
183
docs/manual-outline.md
Normal file
183
docs/manual-outline.md
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
# Manual de Usuario - Sistema EFC
|
||||||
|
## Guía Completa para la Gestión de Expedientes y Documentos Aduaneros
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 📋 TABLA DE CONTENIDOS
|
||||||
|
|
||||||
|
## PARTE I: PRIMEROS PASOS
|
||||||
|
### 1. Bienvenida al Sistema EFC
|
||||||
|
- ¿Qué es EFC?
|
||||||
|
- Beneficios del sistema
|
||||||
|
- Requisitos mínimos del sistema
|
||||||
|
|
||||||
|
### 2. Acceso y Autenticación
|
||||||
|
- Registro en el sistema
|
||||||
|
- Inicio de sesión
|
||||||
|
- Recuperación de contraseña
|
||||||
|
- Gestión de sesiones
|
||||||
|
|
||||||
|
## PARTE II: INTERFAZ Y NAVEGACIÓN
|
||||||
|
### 3. Conociendo la Interfaz
|
||||||
|
- Panel principal (Dashboard)
|
||||||
|
- Barra de navegación lateral
|
||||||
|
- Sistema de notificaciones
|
||||||
|
- Interfaz responsiva (móvil/tablet)
|
||||||
|
|
||||||
|
### 4. Roles y Permisos
|
||||||
|
- Usuario Importador
|
||||||
|
- Administrador de Organización
|
||||||
|
- Grupos especiales
|
||||||
|
- Permisos por funcionalidad
|
||||||
|
|
||||||
|
## PARTE III: GESTIÓN DE EXPEDIENTES
|
||||||
|
### 5. Expedientes
|
||||||
|
- ¿Qué es un expediente?
|
||||||
|
- Crear nuevo expediente
|
||||||
|
- Buscar y filtrar expedientes
|
||||||
|
- Estados de expedientes
|
||||||
|
- Acciones disponibles
|
||||||
|
|
||||||
|
### 6. Detalles de Pedimento
|
||||||
|
- Visualizar información del pedimento
|
||||||
|
- Datos asociados
|
||||||
|
- Documentos vinculados
|
||||||
|
- Historial de cambios
|
||||||
|
|
||||||
|
## PARTE IV: GESTIÓN DOCUMENTAL
|
||||||
|
### 7. Documentos
|
||||||
|
- Tipos de documentos soportados
|
||||||
|
- Subir documentos individuales
|
||||||
|
- Carga masiva de documentos
|
||||||
|
- Organización por categorías
|
||||||
|
- Búsqueda avanzada de documentos
|
||||||
|
|
||||||
|
### 8. Descargas y Exportación
|
||||||
|
- Descarga individual
|
||||||
|
- Descarga masiva
|
||||||
|
- Formatos de exportación
|
||||||
|
- Limitaciones y consideraciones
|
||||||
|
|
||||||
|
## PARTE V: PROCESOS AUTOMATIZADOS
|
||||||
|
### 9. Gestión de Procesos
|
||||||
|
- Tipos de procesos disponibles
|
||||||
|
- Configurar procesamiento automático
|
||||||
|
- Monitorear estado de ejecución
|
||||||
|
- Historial de procesos
|
||||||
|
- Manejo de errores
|
||||||
|
|
||||||
|
## PARTE VI: ADMINISTRACIÓN
|
||||||
|
### 10. Gestión de Usuarios
|
||||||
|
- Crear usuarios
|
||||||
|
- Asignar roles y permisos
|
||||||
|
- Gestión de grupos
|
||||||
|
- Desactivar usuarios
|
||||||
|
|
||||||
|
### 11. Configuración de Organización
|
||||||
|
- Datos de la empresa
|
||||||
|
- Configuraciones del sistema
|
||||||
|
- Preferencias de usuario
|
||||||
|
- Integraciones externas
|
||||||
|
|
||||||
|
## PARTE VII: REPORTES Y ANALÍTICA
|
||||||
|
### 12. Reportes
|
||||||
|
- Reportes predefinidos
|
||||||
|
- Filtros y parámetros
|
||||||
|
- Exportación de reportes
|
||||||
|
- Programación de reportes
|
||||||
|
|
||||||
|
### 13. Tableros de Control
|
||||||
|
- Tablero de almacenamiento
|
||||||
|
- Métricas de uso
|
||||||
|
- Estadísticas de documentos
|
||||||
|
- Indicadores de rendimiento
|
||||||
|
|
||||||
|
## PARTE VIII: INTEGRACIONES
|
||||||
|
### 14. Ventanilla Única (VUCEM)
|
||||||
|
- Configuración de conexión
|
||||||
|
- Sincronización de datos
|
||||||
|
- Procedimientos específicos
|
||||||
|
- Resolución de conflictos
|
||||||
|
|
||||||
|
### 15. Notificaciones
|
||||||
|
- Tipos de notificaciones
|
||||||
|
- Configuración de alertas
|
||||||
|
- Notificaciones en tiempo real
|
||||||
|
- Historial de notificaciones
|
||||||
|
|
||||||
|
## PARTE IX: SOLUCIÓN DE PROBLEMAS
|
||||||
|
### 16. Problemas Comunes y Soluciones
|
||||||
|
- Errores de conexión
|
||||||
|
- Problemas de carga de documentos
|
||||||
|
- Errores de sincronización
|
||||||
|
- Problemas de rendimiento
|
||||||
|
|
||||||
|
### 17. Preguntas Frecuentes (FAQ)
|
||||||
|
- Preguntas sobre expedientes
|
||||||
|
- Preguntas sobre documentos
|
||||||
|
- Preguntas sobre procesos
|
||||||
|
- Preguntas sobre administración
|
||||||
|
|
||||||
|
## ANEXOS
|
||||||
|
### A. Formatos de Archivo Soportados
|
||||||
|
### B. Límites del Sistema
|
||||||
|
### C. Glosario de Términos Aduaneros
|
||||||
|
### D. Referencias Legales
|
||||||
|
### E. Contacto y Soporte Técnico
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 PRÓXIMOS PASOS PARA CREAR EL MANUAL
|
||||||
|
|
||||||
|
### Fase 1: Configuración (1 semana)
|
||||||
|
1. **Elegir plataforma de documentación**
|
||||||
|
- GitBook (recomendado)
|
||||||
|
- Notion
|
||||||
|
- Confluence
|
||||||
|
- MkDocs
|
||||||
|
|
||||||
|
2. **Configurar entorno**
|
||||||
|
- Crear estructura de carpetas
|
||||||
|
- Definir plantillas
|
||||||
|
- Configurar herramientas de captura
|
||||||
|
|
||||||
|
### Fase 2: Contenido Base (2-3 semanas)
|
||||||
|
1. **Documentar funcionalidades principales**
|
||||||
|
- Login y navegación
|
||||||
|
- Expedientes y documentos
|
||||||
|
- Procesos básicos
|
||||||
|
|
||||||
|
2. **Capturar screenshots sistemáticamente**
|
||||||
|
- Diferentes roles de usuario
|
||||||
|
- Estados con/sin datos
|
||||||
|
- Vista desktop y móvil
|
||||||
|
|
||||||
|
### Fase 3: Contenido Avanzado (2 semanas)
|
||||||
|
1. **Administración y configuración**
|
||||||
|
2. **Integraciones y reportes**
|
||||||
|
3. **Troubleshooting**
|
||||||
|
|
||||||
|
### Fase 4: Revisión y Publicación (1 semana)
|
||||||
|
1. **Control de calidad**
|
||||||
|
2. **Pruebas con usuarios**
|
||||||
|
3. **Ajustes finales**
|
||||||
|
4. **Publicación**
|
||||||
|
|
||||||
|
## 💡 RECOMENDACIONES ESPECÍFICAS
|
||||||
|
|
||||||
|
### Para Screenshots:
|
||||||
|
- Usar datos de ejemplo consistentes
|
||||||
|
- Resolución estándar: 1920x1080
|
||||||
|
- Herramientas: Snagit o CloudApp
|
||||||
|
- Anotar elementos importantes
|
||||||
|
|
||||||
|
### Para Videos (opcional):
|
||||||
|
- Loom para procesos complejos
|
||||||
|
- Máximo 3-5 minutos por video
|
||||||
|
- Audio claro y pausado
|
||||||
|
|
||||||
|
### Para Mantenimiento:
|
||||||
|
- Revisar con cada release
|
||||||
|
- Versionado del manual
|
||||||
|
- Feedback de usuarios
|
||||||
|
- Métricas de uso del manual
|
||||||
79
docs/manual-structure.md
Normal file
79
docs/manual-structure.md
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
# Estructura del Manual de Usuario - Sistema EFC
|
||||||
|
|
||||||
|
## 1. INTRODUCCIÓN Y CONCEPTOS BÁSICOS
|
||||||
|
- ¿Qué es EFC?
|
||||||
|
- Objetivos del sistema
|
||||||
|
- Glosario de términos aduaneros
|
||||||
|
- Roles de usuario (Importador, Administrador, etc.)
|
||||||
|
|
||||||
|
## 2. ACCESO AL SISTEMA
|
||||||
|
- Requisitos del sistema
|
||||||
|
- Proceso de registro
|
||||||
|
- Inicio de sesión
|
||||||
|
- Recuperación de contraseña
|
||||||
|
- Gestión de sesiones
|
||||||
|
|
||||||
|
## 3. PANEL PRINCIPAL (DASHBOARD)
|
||||||
|
- Navegación general
|
||||||
|
- Sidebar responsivo
|
||||||
|
- Notificaciones
|
||||||
|
- Vista general de métricas
|
||||||
|
|
||||||
|
## 4. GESTIÓN DE EXPEDIENTES
|
||||||
|
- Crear nuevo expediente
|
||||||
|
- Buscar y filtrar expedientes
|
||||||
|
- Visualizar detalles de expediente
|
||||||
|
- Estados de expedientes
|
||||||
|
- Acciones disponibles
|
||||||
|
|
||||||
|
## 5. GESTIÓN DE DOCUMENTOS
|
||||||
|
- Tipos de documentos soportados
|
||||||
|
- Subir documentos
|
||||||
|
- Descargar documentos (individual y masiva)
|
||||||
|
- Organización por pedimento
|
||||||
|
- Filtros y búsqueda avanzada
|
||||||
|
|
||||||
|
## 6. PROCESOS AUTOMATIZADOS
|
||||||
|
- Tipos de procesos disponibles
|
||||||
|
- Configurar procesamiento
|
||||||
|
- Monitorear estado de procesos
|
||||||
|
- Historial de ejecuciones
|
||||||
|
|
||||||
|
## 7. ADMINISTRACIÓN DE USUARIOS
|
||||||
|
- Crear usuarios
|
||||||
|
- Asignar roles y permisos
|
||||||
|
- Gestionar grupos de usuarios
|
||||||
|
- Configuración de accesos
|
||||||
|
|
||||||
|
## 8. CONFIGURACIÓN DE ORGANIZACIÓN
|
||||||
|
- Datos de la organización
|
||||||
|
- Configuraciones específicas
|
||||||
|
- Preferencias del sistema
|
||||||
|
|
||||||
|
## 9. REPORTES Y TABLEROS
|
||||||
|
- Reportes disponibles
|
||||||
|
- Tablero de almacenamiento
|
||||||
|
- Métricas y estadísticas
|
||||||
|
- Exportación de datos
|
||||||
|
|
||||||
|
## 10. INTEGRACIÓN CON VUCEM
|
||||||
|
- Conexión con Ventanilla Única
|
||||||
|
- Sincronización de datos
|
||||||
|
- Procedimientos específicos
|
||||||
|
|
||||||
|
## 11. NOTIFICACIONES
|
||||||
|
- Tipos de notificaciones
|
||||||
|
- Configuración de alertas
|
||||||
|
- Historial de notificaciones
|
||||||
|
|
||||||
|
## 12. SOLUCIÓN DE PROBLEMAS
|
||||||
|
- Problemas comunes
|
||||||
|
- Códigos de error
|
||||||
|
- Contacto con soporte
|
||||||
|
- FAQ
|
||||||
|
|
||||||
|
## 13. ANEXOS Y REFERENCIAS
|
||||||
|
- Formatos de archivo soportados
|
||||||
|
- Límites del sistema
|
||||||
|
- Actualizaciones y changelog
|
||||||
|
- Referencias legales
|
||||||
@@ -243,13 +243,13 @@ const Settings = () => {
|
|||||||
|
|
||||||
setSaving(true);
|
setSaving(true);
|
||||||
try {
|
try {
|
||||||
// Preparar datos para enviar - NO incluir grupos para preservarlos
|
// Preparar datos para enviar - NO incluir grupos ni RFC para preservarlos
|
||||||
const updateData = {
|
const updateData = {
|
||||||
first_name: formData.first_name.trim(),
|
first_name: formData.first_name.trim(),
|
||||||
last_name: formData.last_name.trim(),
|
last_name: formData.last_name.trim(),
|
||||||
email: formData.email.trim(),
|
email: formData.email.trim(),
|
||||||
// Username NO se incluye - no se puede modificar
|
// Username NO se incluye - no se puede modificar
|
||||||
...(formData.rfc.trim() && { rfc: formData.rfc.trim() }), // Solo incluir RFC si existe
|
// RFC NO se incluye - no se puede modificar
|
||||||
is_importador: currentUser.is_importador, // Preservar estado actual
|
is_importador: currentUser.is_importador, // Preservar estado actual
|
||||||
is_active: currentUser.is_active // Preservar estado actual
|
is_active: currentUser.is_active // Preservar estado actual
|
||||||
};
|
};
|
||||||
@@ -336,9 +336,8 @@ const Settings = () => {
|
|||||||
return (
|
return (
|
||||||
formData.first_name !== (currentUser.first_name || '') ||
|
formData.first_name !== (currentUser.first_name || '') ||
|
||||||
formData.last_name !== (currentUser.last_name || '') ||
|
formData.last_name !== (currentUser.last_name || '') ||
|
||||||
formData.email !== (currentUser.email || '') ||
|
formData.email !== (currentUser.email || '')
|
||||||
// Username excluded from change detection - field is read-only
|
// RFC excluded from change detection - field is read-only
|
||||||
formData.rfc !== (currentUser.rfc || '')
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -543,10 +542,13 @@ const Settings = () => {
|
|||||||
type="text"
|
type="text"
|
||||||
name="rfc"
|
name="rfc"
|
||||||
value={formData.rfc}
|
value={formData.rfc}
|
||||||
onChange={handleInputChange}
|
disabled
|
||||||
className="w-full px-4 py-3 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm transition-all duration-200 hover:border-gray-400"
|
className="w-full px-4 py-3 border border-gray-300 rounded-lg shadow-sm bg-gray-50 text-gray-500 cursor-not-allowed text-sm"
|
||||||
placeholder="XXXX000000XXX"
|
placeholder="XXXX000000XXX"
|
||||||
/>
|
/>
|
||||||
|
<p className="text-xs text-gray-500">
|
||||||
|
El RFC no puede ser modificado por razones de seguridad
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -576,13 +578,13 @@ const Settings = () => {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
// Resetear formulario a los valores originales (username no se resetea porque no se puede cambiar)
|
// Resetear formulario a los valores originales (username y RFC no se resetean porque no se pueden cambiar)
|
||||||
setFormData({
|
setFormData({
|
||||||
first_name: currentUser?.first_name || '',
|
first_name: currentUser?.first_name || '',
|
||||||
last_name: currentUser?.last_name || '',
|
last_name: currentUser?.last_name || '',
|
||||||
email: currentUser?.email || '',
|
email: currentUser?.email || '',
|
||||||
username: currentUser?.username || '', // Mantener valor original
|
username: currentUser?.username || '', // Mantener valor original
|
||||||
rfc: currentUser?.rfc || ''
|
rfc: currentUser?.rfc || '' // Mantener valor original
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
disabled={saving}
|
disabled={saving}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { fetchWithAuth, postWithAuth, putWithAuth, deleteWithAuth, putFormDataWithAuth, postFormDataWithAuth } from '../fetchWithAuth';
|
import { fetchWithAuth, postWithAuth, putWithAuth, deleteWithAuth, putFormDataWithAuth, postFormDataWithAuth, patchWithAuth } from '../fetchWithAuth';
|
||||||
|
|
||||||
const API_URL = import.meta.env.VITE_EFC_API_URL;
|
const API_URL = import.meta.env.VITE_EFC_API_URL;
|
||||||
export default function Vucem() {
|
export default function Vucem() {
|
||||||
@@ -32,6 +32,10 @@ export default function Vucem() {
|
|||||||
const [showEfirma, setShowEfirma] = useState({});
|
const [showEfirma, setShowEfirma] = useState({});
|
||||||
const [copySuccess, setCopySuccess] = useState('');
|
const [copySuccess, setCopySuccess] = useState('');
|
||||||
|
|
||||||
|
// Estados específicos para modal de edición (siempre ocultos por defecto)
|
||||||
|
const [showEditPassword, setShowEditPassword] = useState(false);
|
||||||
|
const [showEditEfirma, setShowEditEfirma] = useState(false);
|
||||||
|
|
||||||
// Funciones para alternar visibilidad
|
// Funciones para alternar visibilidad
|
||||||
const togglePasswordVisibility = (id) => {
|
const togglePasswordVisibility = (id) => {
|
||||||
setShowPassword(prev => ({
|
setShowPassword(prev => ({
|
||||||
@@ -47,6 +51,23 @@ export default function Vucem() {
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Funciones para alternar visibilidad en modal de edición
|
||||||
|
const toggleEditPasswordVisibility = () => {
|
||||||
|
setShowEditPassword(!showEditPassword);
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleEditEfirmaVisibility = () => {
|
||||||
|
setShowEditEfirma(!showEditEfirma);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Función helper para truncar texto largo en la tabla
|
||||||
|
const truncateForTable = (text, maxLength = 20) => {
|
||||||
|
if (!text || text.length <= maxLength) return text;
|
||||||
|
const start = text.substring(0, 6);
|
||||||
|
const end = text.substring(text.length - 6);
|
||||||
|
return `${start}...${end}`;
|
||||||
|
};
|
||||||
|
|
||||||
// Función para copiar al portapapeles
|
// Función para copiar al portapapeles
|
||||||
const copyToClipboard = async (text, fieldName) => {
|
const copyToClipboard = async (text, fieldName) => {
|
||||||
try {
|
try {
|
||||||
@@ -113,6 +134,9 @@ export default function Vucem() {
|
|||||||
setForm(initialForm);
|
setForm(initialForm);
|
||||||
setEditVucem(null);
|
setEditVucem(null);
|
||||||
setDeleteVucem(null);
|
setDeleteVucem(null);
|
||||||
|
// Resetear estados de visibilidad del modal de edición
|
||||||
|
setShowEditPassword(false);
|
||||||
|
setShowEditEfirma(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fetch list
|
// Fetch list
|
||||||
@@ -197,6 +221,25 @@ export default function Vucem() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Función para activar/desactivar credencial
|
||||||
|
const toggleVucemStatus = async (id, currentStatus) => {
|
||||||
|
try {
|
||||||
|
const response = await patchWithAuth(`${API_URL}/vucem/vucem/${id}/`, {
|
||||||
|
is_active: !currentStatus
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Error al cambiar el estado');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recargar la lista para reflejar los cambios
|
||||||
|
await fetchVucem();
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
alert('Error al cambiar el estado de la credencial');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchVucem();
|
fetchVucem();
|
||||||
}, []);
|
}, []);
|
||||||
@@ -233,6 +276,9 @@ export default function Vucem() {
|
|||||||
acuseedocument: !!editVucem.acuseedocument,
|
acuseedocument: !!editVucem.acuseedocument,
|
||||||
is_active: !!editVucem.is_active,
|
is_active: !!editVucem.is_active,
|
||||||
});
|
});
|
||||||
|
// Resetear visibilidad de campos sensibles cuando se abre el modal de edición
|
||||||
|
setShowEditPassword(false);
|
||||||
|
setShowEditEfirma(false);
|
||||||
}
|
}
|
||||||
}, [editVucem]);
|
}, [editVucem]);
|
||||||
|
|
||||||
@@ -439,7 +485,7 @@ export default function Vucem() {
|
|||||||
<td className="px-6 py-4 whitespace-nowrap">
|
<td className="px-6 py-4 whitespace-nowrap">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<span className="text-sm text-gray-600 font-mono">
|
<span className="text-sm text-gray-600 font-mono">
|
||||||
{showPassword[vucem.id] ? vucem.password || '(vacío)' : '••••••••'}
|
{showPassword[vucem.id] ? truncateForTable(vucem.password) || '(vacío)' : '••••••••'}
|
||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
onClick={() => togglePasswordVisibility(vucem.id)}
|
onClick={() => togglePasswordVisibility(vucem.id)}
|
||||||
@@ -471,7 +517,7 @@ export default function Vucem() {
|
|||||||
<td className="px-6 py-4 whitespace-nowrap">
|
<td className="px-6 py-4 whitespace-nowrap">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<span className="text-sm text-gray-600 font-mono">
|
<span className="text-sm text-gray-600 font-mono">
|
||||||
{showEfirma[vucem.id] ? vucem.efirma || '(vacío)' : '••••••••'}
|
{showEfirma[vucem.id] ? truncateForTable(vucem.efirma) || '(vacío)' : '••••••••'}
|
||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
onClick={() => toggleEfirmaVisibility(vucem.id)}
|
onClick={() => toggleEfirmaVisibility(vucem.id)}
|
||||||
@@ -594,6 +640,25 @@ export default function Vucem() {
|
|||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => toggleVucemStatus(vucem.id, vucem.is_active)}
|
||||||
|
className={`inline-flex items-center p-2 border shadow-sm font-medium rounded-lg bg-white focus:outline-none focus:ring-2 focus:ring-offset-2 transition-all duration-200 transform hover:scale-105 ${
|
||||||
|
vucem.is_active
|
||||||
|
? 'border-orange-300 text-orange-700 hover:bg-orange-50 focus:ring-orange-500'
|
||||||
|
: 'border-green-300 text-green-700 hover:bg-green-50 focus:ring-green-500'
|
||||||
|
}`}
|
||||||
|
title={vucem.is_active ? "Desactivar" : "Activar"}
|
||||||
|
>
|
||||||
|
{vucem.is_active ? (
|
||||||
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728L5.636 5.636m12.728 12.728L5.636 5.636" />
|
||||||
|
</svg>
|
||||||
|
) : (
|
||||||
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => { setDeleteVucem(vucem); setShowDeleteModal(true); }}
|
onClick={() => { setDeleteVucem(vucem); setShowDeleteModal(true); }}
|
||||||
className="inline-flex items-center p-2 border border-red-300 shadow-sm font-medium rounded-lg text-red-700 bg-white hover:bg-red-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 transition-all duration-200 transform hover:scale-105"
|
className="inline-flex items-center p-2 border border-red-300 shadow-sm font-medium rounded-lg text-red-700 bg-white hover:bg-red-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 transition-all duration-200 transform hover:scale-105"
|
||||||
@@ -674,6 +739,25 @@ export default function Vucem() {
|
|||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => toggleVucemStatus(vucem.id, vucem.is_active)}
|
||||||
|
className={`inline-flex items-center justify-center p-2 border shadow-sm font-medium rounded-lg bg-white focus:outline-none focus:ring-2 focus:ring-offset-2 transition-all duration-200 ${
|
||||||
|
vucem.is_active
|
||||||
|
? 'border-orange-300 text-orange-700 hover:bg-orange-50 focus:ring-orange-500'
|
||||||
|
: 'border-green-300 text-green-700 hover:bg-green-50 focus:ring-green-500'
|
||||||
|
}`}
|
||||||
|
title={vucem.is_active ? "Desactivar" : "Activar"}
|
||||||
|
>
|
||||||
|
{vucem.is_active ? (
|
||||||
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728L5.636 5.636m12.728 12.728L5.636 5.636" />
|
||||||
|
</svg>
|
||||||
|
) : (
|
||||||
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => { setDeleteVucem(vucem); setShowDeleteModal(true); }}
|
onClick={() => { setDeleteVucem(vucem); setShowDeleteModal(true); }}
|
||||||
className="inline-flex items-center justify-center p-2 border border-red-300 shadow-sm font-medium rounded-lg text-red-700 bg-white hover:bg-red-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 transition-all duration-200"
|
className="inline-flex items-center justify-center p-2 border border-red-300 shadow-sm font-medium rounded-lg text-red-700 bg-white hover:bg-red-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 transition-all duration-200"
|
||||||
@@ -690,7 +774,7 @@ export default function Vucem() {
|
|||||||
<span className="font-medium text-gray-500">Password:</span>
|
<span className="font-medium text-gray-500">Password:</span>
|
||||||
<div className="mt-1 flex items-center space-x-2">
|
<div className="mt-1 flex items-center space-x-2">
|
||||||
<span className="text-gray-600 font-mono">
|
<span className="text-gray-600 font-mono">
|
||||||
{showPassword[vucem.id] ? vucem.password || '(vacío)' : '••••••••'}
|
{showPassword[vucem.id] ? truncateForTable(vucem.password) || '(vacío)' : '••••••••'}
|
||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
onClick={() => togglePasswordVisibility(vucem.id)}
|
onClick={() => togglePasswordVisibility(vucem.id)}
|
||||||
@@ -723,7 +807,7 @@ export default function Vucem() {
|
|||||||
<span className="font-medium text-gray-500">e.firma:</span>
|
<span className="font-medium text-gray-500">e.firma:</span>
|
||||||
<div className="mt-1 flex items-center space-x-2">
|
<div className="mt-1 flex items-center space-x-2">
|
||||||
<span className="text-gray-600 font-mono">
|
<span className="text-gray-600 font-mono">
|
||||||
{showEfirma[vucem.id] ? vucem.efirma || '(vacío)' : '••••••••'}
|
{showEfirma[vucem.id] ? truncateForTable(vucem.efirma) || '(vacío)' : '••••••••'}
|
||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
onClick={() => toggleEfirmaVisibility(vucem.id)}
|
onClick={() => toggleEfirmaVisibility(vucem.id)}
|
||||||
@@ -1113,7 +1197,7 @@ export default function Vucem() {
|
|||||||
<div className="relative">
|
<div className="relative">
|
||||||
<input
|
<input
|
||||||
name="password"
|
name="password"
|
||||||
type={showPassword ? "text" : "password"}
|
type={showEditPassword ? "text" : "password"}
|
||||||
value={form.password}
|
value={form.password}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="w-full px-3 py-2 pr-20 border border-gray-300 rounded-md shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm"
|
className="w-full px-3 py-2 pr-20 border border-gray-300 rounded-md shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm"
|
||||||
@@ -1122,11 +1206,11 @@ export default function Vucem() {
|
|||||||
<div className="absolute inset-y-0 right-0 flex items-center">
|
<div className="absolute inset-y-0 right-0 flex items-center">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setShowPassword(!showPassword)}
|
onClick={toggleEditPasswordVisibility}
|
||||||
className="px-2 py-1 text-gray-400 hover:text-gray-600 focus:outline-none"
|
className="px-2 py-1 text-gray-400 hover:text-gray-600 focus:outline-none"
|
||||||
title={showPassword ? "Ocultar password" : "Mostrar password"}
|
title={showEditPassword ? "Ocultar password" : "Mostrar password"}
|
||||||
>
|
>
|
||||||
{showPassword ? (
|
{showEditPassword ? (
|
||||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.878 9.878L8.464 8.464m1.414 1.414L21.536 21.536" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.878 9.878L8.464 8.464m1.414 1.414L21.536 21.536" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
Reference in New Issue
Block a user