From 16f431cbad7ed34042b544c53d1afcf8889a1f80 Mon Sep 17 00:00:00 2001 From: ronalds Date: Fri, 28 Nov 2025 09:26:35 -0300 Subject: [PATCH] =?UTF-8?q?=E2=9C=85=20Cambios=20Completados=20He=20implem?= =?UTF-8?q?entado=20exitosamente=20la=20funcionalidad=20solicitada.=20Aqu?= =?UTF-8?q?=C3=AD=20est=C3=A1=20el=20resumen:?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🔄 Cambios en el Frontend (App.jsx) Renombrado de "Borrador" a "Incompleta": Actualizado el filtro de estado: draft → incomplete Cambiado el texto del selector: "Borradores" → "Incompletas" Actualizado el badge de estado en la lista de inspecciones Botón "Continuar Inspección": Agregado botón verde "▶️ Continuar Inspección" en InspectionDetailModal Solo aparece cuando inspection.status !== 'completed' Cierra el modal de detalle y abre el modal de inspección para continuar Soporte para continuar inspecciones: Modificado InspectionModal para recibir existingInspection Carga automática de datos del vehículo existentes Carga de respuestas previas desde el backend Si hay respuestas existentes, salta directamente al paso 2 (Preguntas) No crea una nueva inspección si ya existe, solo continúa la actual Actualización de versión: package.json: v1.0.78 → v1.0.79 🔧 Cambios en el Backend (models.py) Renombrado del estado por defecto: status = Column(String(20), default="draft") → default="incomplete" Comentario actualizado: # draft, completed, inactive → # incomplete, completed, inactive --- backend/app/models.py | 2 +- frontend/package.json | 2 +- frontend/src/App.jsx | 115 +++++++++++++++++++++++++++++++++--------- 3 files changed, 93 insertions(+), 26 deletions(-) diff --git a/backend/app/models.py b/backend/app/models.py index d3bde12..c4baf27 100644 --- a/backend/app/models.py +++ b/backend/app/models.py @@ -124,7 +124,7 @@ class Inspection(Base): flagged_items_count = Column(Integer, default=0) # Estado - status = Column(String(20), default="draft") # draft, completed, inactive + status = Column(String(20), default="incomplete") # incomplete, completed, inactive is_active = Column(Boolean, default=True) # Firma diff --git a/frontend/package.json b/frontend/package.json index 899ef12..268d66b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "checklist-frontend", "private": true, - "version": "1.0.78", + "version": "1.0.79", "type": "module", "scripts": { "dev": "vite", diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index ec34ef7..4d17d63 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -348,7 +348,7 @@ function DashboardPage({ user, setUser }) { onStartInspection={setActiveInspection} /> ) : activeTab === 'inspections' ? ( - + ) : activeTab === 'settings' ? ( ) : activeTab === 'api-tokens' ? ( @@ -365,7 +365,8 @@ function DashboardPage({ user, setUser }) { {/* Modal de Inspección Activa */} {activeInspection && ( setActiveInspection(null)} onComplete={() => { @@ -2959,7 +2960,7 @@ function ChecklistsTab({ checklists, user, onChecklistCreated, onStartInspection ) } -function InspectionDetailModal({ inspection, user, onClose, onUpdate }) { +function InspectionDetailModal({ inspection, user, onClose, onUpdate, onContinue }) { const [loading, setLoading] = useState(true) const [inspectionDetail, setInspectionDetail] = useState(null) const [isInactivating, setIsInactivating] = useState(false) @@ -3454,6 +3455,20 @@ function InspectionDetailModal({ inspection, user, onClose, onUpdate }) { {/* Footer */}
+ {/* Botón Continuar Inspección - solo si está incompleta */} + {inspection.status !== 'completed' && onContinue && ( + + )} {user?.role === 'admin' && (
@@ -3787,7 +3802,7 @@ function InspectionsTab({ inspections, user, onUpdate }) { ? 'bg-green-100 text-green-800' : 'bg-yellow-100 text-yellow-800' }`}> - {inspection.status === 'completed' ? 'Completada' : 'Borrador'} + {inspection.status === 'completed' ? 'Completada' : 'Incompleta'}

@@ -3876,26 +3891,27 @@ function InspectionsTab({ inspections, user, onUpdate }) { user={user} onClose={() => setSelectedInspection(null)} onUpdate={onUpdate} + onContinue={onContinue} /> )} ) } -function InspectionModal({ checklist, user, onClose, onComplete }) { +function InspectionModal({ checklist, existingInspection, user, onClose, onComplete }) { const [step, setStep] = useState(1) // 1: Vehicle Info, 2: Questions, 3: Signatures const [loading, setLoading] = useState(false) const [questions, setQuestions] = useState([]) - const [inspectionId, setInspectionId] = useState(null) + const [inspectionId, setInspectionId] = useState(existingInspection?.id || null) // Form data for vehicle and client const [vehicleData, setVehicleData] = useState({ - vehicle_plate: '', - vehicle_brand: '', - vehicle_model: '', - vehicle_km: '', - order_number: '', - or_number: '' + vehicle_plate: existingInspection?.vehicle_plate || '', + vehicle_brand: existingInspection?.vehicle_brand || '', + vehicle_model: existingInspection?.vehicle_model || '', + vehicle_km: existingInspection?.vehicle_km || '', + order_number: existingInspection?.order_number || '', + or_number: existingInspection?.or_number || '' }) // Answers data @@ -3927,15 +3943,54 @@ function InspectionModal({ checklist, user, onClose, onComplete }) { console.log('Questions loaded:', questionsData.length, 'questions') setQuestions(questionsData) - // Initialize answers object - empty values to force user interaction + // Initialize answers object const initialAnswers = {} - questionsData.forEach(q => { - initialAnswers[q.id] = { - value: '', // No default value - user must choose - observations: '', - photos: [] + + // Si hay inspección existente, cargar sus respuestas + if (existingInspection?.id) { + console.log('Loading existing inspection:', existingInspection.id) + const inspResponse = await fetch(`${API_URL}/api/inspections/${existingInspection.id}`, { + headers: { 'Authorization': `Bearer ${token}` } + }) + + if (inspResponse.ok) { + const inspData = await inspResponse.json() + console.log('Existing inspection loaded:', inspData) + + // Cargar respuestas existentes + questionsData.forEach(q => { + const existingAnswer = inspData.answers?.find(a => a.question_id === q.id) + if (existingAnswer) { + initialAnswers[q.id] = { + value: existingAnswer.answer_value || '', + observations: existingAnswer.comment || '', + photos: existingAnswer.media_files?.map(m => m.file_path) || [] + } + } else { + initialAnswers[q.id] = { + value: '', + observations: '', + photos: [] + } + } + }) + + // Si ya tiene respuestas, ir al paso 2 + if (inspData.answers?.length > 0) { + setStep(2) + } } - }) + } else { + // Nueva inspección - inicializar vacío + questionsData.forEach(q => { + initialAnswers[q.id] = { + value: '', // No default value - user must choose + observations: '', + photos: [] + } + }) + } + console.log('Initial answers:', initialAnswers) setAnswers(initialAnswers) } else { @@ -3948,7 +4003,7 @@ function InspectionModal({ checklist, user, onClose, onComplete }) { } loadQuestions() - }, [checklist.id]) + }, [checklist.id, existingInspection]) // Step 1: Create inspection with vehicle data const handleVehicleSubmit = async (e) => { @@ -3959,6 +4014,18 @@ function InspectionModal({ checklist, user, onClose, onComplete }) { const token = localStorage.getItem('token') const API_URL = import.meta.env.VITE_API_URL || '' + // Si ya existe una inspección, solo pasar al siguiente paso + if (existingInspection?.id) { + console.log('Continuing existing inspection:', existingInspection.id) + if (questions.length > 0) { + setStep(2) + } else { + alert('Error: El checklist no tiene preguntas configuradas') + } + setLoading(false) + return + } + console.log('Creating inspection with data:', vehicleData) // Prepare data for API