import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom' import { useState, useEffect, useRef } from 'react' import SignatureCanvas from 'react-signature-canvas' import ReactMarkdown from 'react-markdown' import Sidebar from './Sidebar' import QuestionTypeEditor from './QuestionTypeEditor' import QuestionAnswerInput from './QuestionAnswerInput' function App() { const [user, setUser] = useState(null) const [loading, setLoading] = useState(true) const [updateAvailable, setUpdateAvailable] = useState(false) const [waitingWorker, setWaitingWorker] = useState(null) // Detectar actualizaciones del Service Worker useEffect(() => { if ('serviceWorker' in navigator) { // Registrar service worker navigator.serviceWorker.register('/service-worker.js') .then((registration) => { console.log('✅ Service Worker registrado:', registration); // Verificar si hay actualización esperando if (registration.waiting) { console.log('⚠️ Hay una actualización esperando'); setWaitingWorker(registration.waiting); setUpdateAvailable(true); } // Detectar cuando hay nueva versión instalándose registration.addEventListener('updatefound', () => { const newWorker = registration.installing; console.log('🔄 Nueva versión detectada, instalando...'); newWorker.addEventListener('statechange', () => { if (newWorker.state === 'installed' && navigator.serviceWorker.controller) { // Hay nueva versión disponible - MOSTRAR MODAL, NO ACTIVAR AUTOMÁTICAMENTE console.log('✨ Nueva versión instalada - esperando confirmación del usuario'); setWaitingWorker(newWorker); setUpdateAvailable(true); } }); }); }) .catch((error) => { console.error('❌ Error al registrar Service Worker:', error); }); // Escuchar cambios de controlador (cuando se activa nueva versión) // SOLO se dispara DESPUÉS de que el usuario presione el botón let refreshing = false; navigator.serviceWorker.addEventListener('controllerchange', () => { if (!refreshing) { refreshing = true; console.log('🔄 Controlador cambiado, recargando página...'); window.location.reload(); } }); } }, []); // Función para actualizar la app - SOLO cuando el usuario presiona el botón const handleUpdate = () => { if (waitingWorker) { console.log('👆 Usuario confirmó actualización - activando nueva versión...'); // Enviar mensaje al service worker para que se active waitingWorker.postMessage({ type: 'SKIP_WAITING' }); // El controllerchange listener manejará la recarga } }; useEffect(() => { // Verificar si hay token guardado const token = localStorage.getItem('token') const userData = localStorage.getItem('user') if (token && userData) { setUser(JSON.parse(userData)) } setLoading(false) }, []) if (loading) { return (
Hay una nueva versión disponible con mejoras y correcciones.
Por favor actualiza para continuar.
La página se recargará automáticamente
Sistema Inteligente de Inspecciones
Sistema Inteligente de Inspecciones
Genera tokens para acceder a la API sin necesidad de login
⚠️ Guarda este token ahora. No podrás verlo de nuevo.
{createdToken}
Ejemplo de uso:
curl -H "Authorization: Bearer {createdToken}" http://tu-api.com/api/inspections
No tienes tokens API creados
Genera uno para acceder a la API sin login
¿Cómo usar los tokens API?
Los tokens API te permiten acceder a todos los endpoints sin necesidad de hacer login. Son perfectos para integraciones, scripts automatizados o aplicaciones externas.
Incluye el token en el header Authorization de tus requests:
Authorization: Bearer AYUTEC_tu_token_aqui
{checklist.name}
Total de preguntas: {questions.length} | Puntuación máxima: {questions.reduce((sum, q) => sum + (q.points || 0), 0)}
No hay preguntas en este checklist
Crea la primera pregunta para comenzar
{sectionQuestions.length} preguntas | {sectionQuestions.reduce((sum, q) => sum + (q.points || 0), 0)} puntos
{question.text}
{question.show_if_answer ? `→ Aparece si #${question.parent_question_id} es ${question.show_if_answer}` : `→ Siempre visible debajo de #${question.parent_question_id}` }
)}No hay checklists activos
> ) : ( <>No tienes checklists disponibles
Contacta con el administrador para que te asigne permisos a los checklists que necesites usar.
> )}No se encontraron checklists con los filtros aplicados
{checklist.description}
{selectedChecklist.name}
{selectedChecklist.name}
{/* Logo actual */}💡 Tamaño recomendado: 200x200px o similar. Formatos: JPG, PNG, SVG
{inspection.vehicle_plate} - {inspection.vehicle_brand} {inspection.vehicle_model}
{question.text}
{question.description && ({question.description}
)}{answer.comment}
Mecánico: {inspectionDetail.mechanic?.full_name || 'N/A'}
Inspección #{inspection.id}
No hay cambios registrados en esta inspección
Los cambios realizados por administradores aparecerán aquí
No hay inspecciones registradas
Crea tu primera inspección
No se encontraron inspecciones con los filtros aplicados
{inspection.vehicle_brand} {inspection.vehicle_model} - {inspection.vehicle_km} km
{checklist.ai_mode === 'full' ? 'Modo AUTOCOMPLETADO activado' : 'Modo ASISTIDO activado'}
{checklist.ai_mode === 'full' ? 'El sistema completará automáticamente las respuestas al cargar documentos. Revisa y ajusta si es necesario.' : 'El sistema sugerirá observaciones al cargar documentos.'}
Cargando preguntas...
No hay más preguntas disponibles
✓ Todas las preguntas han sido respondidas. Por favor, agregue su firma para completar la inspección.
{question.text}
¡Hola! Soy tu asistente técnico.
He analizado las fotos anteriores. ¿En qué puedo ayudarte?
⚠️ Has alcanzado el límite de {config.max_messages} mensajes
)}{u.email}
{u.employee_code && (Nro Operario: {u.employee_code}
)}| Posición | Mecánico | Inspecciones | Promedio | % Completado |
|---|---|---|---|---|
| {index === 0 ? '🥇' : index === 1 ? '🥈' : index === 2 ? '🥉' : `#${index + 1}`} | {mechanic.mechanic_name} | {mechanic.total_inspections} | {mechanic.avg_score.toFixed(1)} | {mechanic.completion_rate.toFixed(1)}% |
| Fecha | Checklist | Mecánico | Placa | Score | Estado | Alertas | Acciones |
|---|---|---|---|---|---|---|---|
| {new Date(inspection.started_at).toLocaleDateString()} | {inspection.checklist_name} | {inspection.mechanic_name} | {inspection.vehicle_plate} | {inspection.score} | {inspection.status === 'completed' ? 'Completada' : 'Pendiente'} | {inspection.flagged_items > 0 && ( 🚩 {inspection.flagged_items} )} |