diff --git a/.env b/.env index bae8a6f..6160c3f 100644 --- a/.env +++ b/.env @@ -1,4 +1,4 @@ -VITE_DEBUG_MODE=false +DEBUG_MODE=true -VITE_EFC_API_URL=http://192.168.1.195:8000/api/v1 -VITE_EFC_MICROSERVICE_URL=http://192.168.1.195:8001/api/v1 +VITE_EFC_API_URL=https://api.efc-aduanasoft.com/api/v1 +VITE_EFC_MICROSERVICE_URL=https://api.efc-aduanasoft.com/microservice/api/v1 diff --git a/src/pages/Vucem.jsx b/src/pages/Vucem.jsx index 35b4013..bee9261 100644 --- a/src/pages/Vucem.jsx +++ b/src/pages/Vucem.jsx @@ -26,6 +26,74 @@ export default function Vucem() { }; const [form, setForm] = useState(initialForm); + // Estados para controlar visibilidad de contraseñas y copiar + const [showPassword, setShowPassword] = useState({}); + const [showEfirma, setShowEfirma] = useState({}); + const [copySuccess, setCopySuccess] = useState(''); + + // Funciones para alternar visibilidad + const togglePasswordVisibility = (id) => { + setShowPassword(prev => ({ + ...prev, + [id]: !prev[id] + })); + }; + + const toggleEfirmaVisibility = (id) => { + setShowEfirma(prev => ({ + ...prev, + [id]: !prev[id] + })); + }; + + // Función para copiar al portapapeles + const copyToClipboard = async (text, fieldName) => { + try { + // Verificar si el texto existe + if (!text || text.trim() === '') { + setCopySuccess(`${fieldName} está vacío`); + setTimeout(() => setCopySuccess(''), 2000); + return; + } + + // Intentar usar la Clipboard API moderna + if (navigator.clipboard && window.isSecureContext) { + await navigator.clipboard.writeText(text); + setCopySuccess(`${fieldName} copiado`); + setTimeout(() => setCopySuccess(''), 2000); + } else { + // Fallback para navegadores más antiguos o contextos no seguros + const textArea = document.createElement('textarea'); + textArea.value = text; + textArea.style.position = 'fixed'; + textArea.style.opacity = '0'; + textArea.style.pointerEvents = 'none'; + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + + try { + const successful = document.execCommand('copy'); + if (successful) { + setCopySuccess(`${fieldName} copiado`); + } else { + setCopySuccess(`Error al copiar ${fieldName}`); + } + } catch (fallbackErr) { + console.error('Error en fallback:', fallbackErr); + setCopySuccess(`Error al copiar ${fieldName}`); + } finally { + document.body.removeChild(textArea); + setTimeout(() => setCopySuccess(''), 2000); + } + } + } catch (err) { + console.error('Error al copiar:', err); + setCopySuccess(`Error al copiar ${fieldName}`); + setTimeout(() => setCopySuccess(''), 2000); + } + }; + // Handlers básicos para inputs const handleInputChange = e => { const { name, value, type, checked, files } = e.target; @@ -64,6 +132,79 @@ export default function Vucem() { setLoading(false); }; + // Funciones de descarga + const downloadCertificate = async (id, usuario) => { + try { + const token = localStorage.getItem('access'); + const res = await fetch(`${API_URL}/vucem/vucem/${id}/download_cer/`, { + headers: token ? { 'Authorization': `Bearer ${token}` } : {}, + }); + + if (!res.ok) { + if (res.status === 404) { + setCopySuccess('Certificado no encontrado'); + setTimeout(() => setCopySuccess(''), 2000); + return; + } + throw new Error('Error al descargar certificado'); + } + + const blob = await res.blob(); + const url = window.URL.createObjectURL(blob); + const a = document.createElement('a'); + a.style.display = 'none'; + a.href = url; + a.download = `${usuario}_certificado.cer`; + document.body.appendChild(a); + a.click(); + window.URL.revokeObjectURL(url); + document.body.removeChild(a); + + setCopySuccess('Certificado descargado'); + setTimeout(() => setCopySuccess(''), 2000); + } catch (err) { + console.error('Error al descargar certificado:', err); + setCopySuccess('Error al descargar certificado'); + setTimeout(() => setCopySuccess(''), 2000); + } + }; + + const downloadKey = async (id, usuario) => { + try { + const token = localStorage.getItem('access'); + const res = await fetch(`${API_URL}/vucem/vucem/${id}/download_key/`, { + headers: token ? { 'Authorization': `Bearer ${token}` } : {}, + }); + + if (!res.ok) { + if (res.status === 404) { + setCopySuccess('Clave no encontrada'); + setTimeout(() => setCopySuccess(''), 2000); + return; + } + throw new Error('Error al descargar clave'); + } + + const blob = await res.blob(); + const url = window.URL.createObjectURL(blob); + const a = document.createElement('a'); + a.style.display = 'none'; + a.href = url; + a.download = `${usuario}_clave.key`; + document.body.appendChild(a); + a.click(); + window.URL.revokeObjectURL(url); + document.body.removeChild(a); + + setCopySuccess('Clave descargada'); + setTimeout(() => setCopySuccess(''), 2000); + } catch (err) { + console.error('Error al descargar clave:', err); + setCopySuccess('Error al descargar clave'); + setTimeout(() => setCopySuccess(''), 2000); + } + }; + useEffect(() => { fetchVucem(); }, []); @@ -90,9 +231,9 @@ export default function Vucem() { if (editVucem) { setForm({ usuario: editVucem.usuario || '', - password: '', // No se rellena por seguridad + password: editVucem.password || '', // Mostrar el password actual para edición patente: editVucem.patente || '', - efirma: editVucem.efirma || '', + efirma: editVucem.efirma || '', // Ya estaba incluido key: null, // No se rellena, solo se sube si el usuario selecciona cer: null, // No se rellena, solo se sube si el usuario selecciona is_importador: !!editVucem.is_importador, @@ -168,6 +309,17 @@ export default function Vucem() { opacity: 0; } `} + + {/* Mensaje de éxito para copiar */} + {copySuccess && ( +
+ + + + {copySuccess} +
+ )} + {/* Controles de búsqueda y filtros mejorados */}
@@ -239,7 +391,8 @@ export default function Vucem() { Usuario - Patente + Password + e.firma Archivos Estado Acciones @@ -248,7 +401,7 @@ export default function Vucem() { {loading ? ( - +
@@ -259,7 +412,7 @@ export default function Vucem() { ) : error ? ( - +
@@ -285,30 +438,96 @@ export default function Vucem() { >
-
- - - -
{vucem.usuario}
-
ID: {vucem.id}
+
Patente: {vucem.patente}
-
{vucem.patente}
-
e.firma: {vucem.efirma}
+
+ + {showPassword[vucem.id] ? vucem.password || '(vacío)' : '••••••••'} + + + +
+ + +
+ + {showEfirma[vucem.id] ? vucem.efirma || '(vacío)' : '••••••••'} + + + +
{vucem.key ? ( - - - - - Key - +
+ + + + + Key + + +
) : ( @@ -318,12 +537,23 @@ export default function Vucem() { )} {vucem.cer ? ( - - - - - Cer - +
+ + + + + Cer + + +
) : ( @@ -365,21 +595,21 @@ export default function Vucem() {
@@ -388,13 +618,13 @@ export default function Vucem() { {/* Rellenar con filas vacías si hay menos de 8 */} {paginatedList.length < 8 && !loading && !error && Array.from({ length: 8 - paginatedList.length }).map((_, idx) => ( -   +   ))} ) : ( - +
@@ -437,42 +667,98 @@ export default function Vucem() {
-
- - - -

{vucem.usuario}

Patente: {vucem.patente}

-
ID: {vucem.id}
+
+ Password: +
+ + {showPassword[vucem.id] ? vucem.password || '(vacío)' : '••••••••'} + + + +
+
e.firma: -

{vucem.efirma}

+
+ + {showEfirma[vucem.id] ? vucem.efirma || '(vacío)' : '••••••••'} + + + +
Estado: @@ -504,14 +790,25 @@ export default function Vucem() {
Archivos: -
+
{vucem.key ? ( - - - - - Key - +
+ + + + + Key + + +
) : ( @@ -521,12 +818,23 @@ export default function Vucem() { )} {vucem.cer ? ( - - - - - Cer - +
+ + + + + Cer + + +
) : ( @@ -651,7 +959,46 @@ export default function Vucem() {
- +
+ +
+ + +
+
@@ -659,7 +1006,46 @@ export default function Vucem() {
- +
+ +
+ + +
+
@@ -741,8 +1127,46 @@ export default function Vucem() {
- - + +
+ +
+ + +
+
@@ -750,7 +1174,46 @@ export default function Vucem() {
- +
+ +
+ + +
+