@@ -348,7 +348,7 @@ function DashboardPage({ user, setUser }) {
onStartInspection = { setActiveInspection }
/ >
) : activeTab === 'inspections' ? (
< InspectionsTab inspections = { inspections } user = { user } onUpdate = { loadData } / >
< InspectionsTab inspections = { inspections } user = { user } onUpdate = { loadData } onContinue = { setActiveInspection } / >
) : activeTab === 'settings' ? (
< SettingsTab user = { user } / >
) : activeTab === 'api-tokens' ? (
@@ -365,7 +365,8 @@ function DashboardPage({ user, setUser }) {
{ /* Modal de Inspección Activa */ }
{ activeInspection && (
< InspectionModal
checklist = { activeInspection }
checklist = { activeInspection . checklist _id ? activeInspection . checklist : activeInspection }
existingInspection = { activeInspection . checklist _id ? activeInspection : null }
user = { user }
onClose = { ( ) => 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 */ }
< div className = "border-t p-4 bg-gray-50" >
< div className = "flex gap-3" >
{ /* Botón Continuar Inspección - solo si está incompleta */ }
{ inspection . status !== 'completed' && onContinue && (
< button
onClick = { ( ) => {
// Pasar inspectionDetail que tiene el checklist completo
onContinue ( inspectionDetail || inspection )
onClose ( )
} }
className = "px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition flex items-center gap-2"
>
< span > ▶ ️ < / span >
Continuar Inspección
< / button >
) }
{ user ? . role === 'admin' && (
< button
onClick = { loadAuditLog }
@@ -3679,10 +3694,10 @@ function InspectionDetailModal({ inspection, user, onClose, onUpdate }) {
)
}
function InspectionsTab ( { inspections , user , onUpdate } ) {
function InspectionsTab ( { inspections , user , onUpdate , onContinue } ) {
const [ selectedInspection , setSelectedInspection ] = useState ( null )
const [ searchTerm , setSearchTerm ] = useState ( '' )
const [ statusFilter , setStatusFilter ] = useState ( 'all' ) // all, completed, draft
const [ statusFilter , setStatusFilter ] = useState ( 'all' ) // all, completed, incomplete
const [ currentPage , setCurrentPage ] = useState ( 1 )
const itemsPerPage = 10
@@ -3699,7 +3714,7 @@ function InspectionsTab({ inspections, user, onUpdate }) {
const matchesStatus =
statusFilter === 'all' ||
( statusFilter === 'completed' && inspection . status === 'completed' ) ||
( statusFilter === 'draft ' && inspection . status !== 'completed' )
( statusFilter === 'incomplete ' && inspection . status !== 'completed' )
return matchesSearch && matchesStatus
} )
@@ -3748,7 +3763,7 @@ function InspectionsTab({ inspections, user, onUpdate }) {
>
< option value = "all" > Todos los estados < / option >
< option value = "completed" > Completadas < / option >
< option value = "draft" > Borradore s < / option >
< option value = "incomplete" > Incompleta s < / option >
< / select >
< / div >
@@ -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 ' }
< / span >
< / div >
< p className = "text-sm text-gray-600 mt-1" >
@@ -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