2026-05-07 23:31:33 +02:00
< div >
< div class = "bg-base-100 p-4 rounded shadow" >
< div class = "flex justify-between items-center mb-4" >
2026-06-17 10:56:25 +02:00
< h2 class = "text-xl font-bold" > 📋 {{ __ ( 'Inspection templates' ) }} </ h2 >
2026-06-25 14:18:21 +02:00
< div class = "flex items-center gap-2" >
< button wire : click = "openImportProjectModal" class = "btn btn-outline btn-sm gap-1" title = "{{ __('Import from another project') }}" >
< x - heroicon - o - arrow - down - on - square - stack class = "w-4 h-4" />
{{ __ ( 'Import from project' ) }}
</ button >
< button wire : click = "openImportFileModal" class = "btn btn-outline btn-sm gap-1" title = "{{ __('Import from CSV/Excel') }}" >
< x - heroicon - o - document - arrow - up class = "w-4 h-4" />
{{ __ ( 'Import CSV/Excel' ) }}
</ button >
2026-05-11 15:32:00 +02:00
< button wire : click = "newTemplate" class = "btn btn-primary btn-sm" >
2026-06-17 10:56:25 +02:00
{{ __ ( 'New template' ) }}
2026-05-11 15:32:00 +02:00
</ button >
</ div >
2026-05-07 23:31:33 +02:00
</ div >
@ if ( session () -> has ( 'message' ))
< div class = "alert alert-success mb-4" > {{ session ( 'message' ) }} </ div >
@ endif
{{ -- Formulario de creación / edición con diseño de dos columnas -- }}
@ if ( $showForm )
< form wire : submit . prevent = "saveTemplate" class = "border p-4 rounded mb-6 bg-base-200" >
< table class = "w-full mb-8" >
< tbody >
{{ -- Nombre del template -- }}
< tr >
< td class = "w-1/4 py-3 pr-4 align-top" >
2026-06-17 10:56:25 +02:00
{{ __ ( 'Template name' ) }}
2026-05-07 23:31:33 +02:00
</ td >
< td class = "py-3" >
2026-06-16 18:05:53 +02:00
< input type = "text" wire : model = "form.name"
2026-06-17 10:56:25 +02:00
class = "input w-full"
2026-05-07 23:31:33 +02:00
required >
</ td >
</ tr >
{{ -- Descripción -- }}
< tr >
< td class = "w-1/4 py-3 pr-4 align-top" >
2026-06-17 10:56:25 +02:00
{{ __ ( 'Description' ) }}
2026-05-07 23:31:33 +02:00
</ td >
< td class = "py-3" >
< textarea wire : model = "form.description" class = "textarea textarea-bordered w-full" rows = "2" ></ textarea >
</ td >
</ tr >
2026-05-11 15:28:16 +02:00
{{ -- Fase asociada ( opcional ) -- }}
< tr >
< td class = "w-1/4 py-3 pr-4 align-top" >
2026-06-17 10:56:25 +02:00
{{ __ ( 'Associated phase (optional)' ) }}
2026-05-11 15:28:16 +02:00
</ td >
< td class = "py-3" >
2026-06-25 16:45:21 +02:00
< select wire : model = "form.phase_id" class = "select select-bordered w-full" @ disabled ( $form [ 'is_global' ] ?? false ) >
2026-06-17 10:56:25 +02:00
< option value = "" > {{ __ ( 'Global project' ) }} </ option >
2026-05-11 15:28:16 +02:00
@ foreach ( $phases as $phase )
< option value = "{{ $phase->id }}" {{ old ( 'form.phase_id' ) == $phase -> id ? 'selected' : '' }} >
{{ $phase -> name }}
</ option >
@ endforeach
</ select >
</ td >
</ tr >
2026-06-25 16:45:21 +02:00
{{ -- Plantilla global ( disponible en todos los proyectos ) -- }}
< tr >
< td class = "w-1/4 py-3 pr-4 align-top" > {{ __ ( 'Global template' ) }} </ td >
< td class = "py-3" >
< label class = "flex items-center gap-2 cursor-pointer" >
< input type = "checkbox" wire : model . live = "form.is_global" class = "toggle toggle-primary toggle-sm" />
< span class = "text-sm text-base-content/70" > {{ __ ( 'Available in all projects' ) }} </ span >
</ label >
</ td >
</ tr >
2026-05-07 23:31:33 +02:00
</ tbody >
</ table >
{{ -- Campos dinámicos -- }}
< div class = "border-t pt-4 mt-2" >
2026-06-17 10:56:25 +02:00
< h3 class = "font-bold mb-3" > {{ __ ( 'Form fields' ) }} </ h3 >
2026-05-07 23:31:33 +02:00
@ foreach ( $form [ 'fields' ] as $index => $field )
< div class = "border p-3 rounded mb-3 bg-base-100" >
2026-06-25 16:45:21 +02:00
{{ -- Fila : grupo / sección -- }}
< div class = "grid grid-cols-1 md:grid-cols-2 gap-4 mb-2" >
< div class = "font-medium" > {{ __ ( 'Group / section' ) }} </ div >
< div >< input type = "text" wire : model = "form.fields.{{ $index }}.group" placeholder = "ej: Geometría" class = "input input-sm w-full" ></ div >
</ div >
2026-05-07 23:31:33 +02:00
{{ -- Fila : nombre interno -- }}
< div class = "grid grid-cols-1 md:grid-cols-2 gap-4 mb-2" >
2026-06-17 10:56:25 +02:00
< div class = "font-medium" > {{ __ ( 'Internal name' ) }} </ div >
2026-05-07 23:31:33 +02:00
< div >< input type = "text" wire : model = "form.fields.{{ $index }}.name" placeholder = "ej: altura_medida" class = "input input-sm w-full" ></ div >
</ div >
{{ -- Fila : etiqueta -- }}
< div class = "grid grid-cols-1 md:grid-cols-2 gap-4 mb-2" >
2026-06-17 10:56:25 +02:00
< div class = "font-medium" > {{ __ ( 'Visible label' ) }} </ div >
2026-05-07 23:31:33 +02:00
< div >< input type = "text" wire : model = "form.fields.{{ $index }}.label" placeholder = "ej: Altura medida (m)" class = "input input-sm w-full" ></ div >
</ div >
2026-06-25 16:45:21 +02:00
{{ -- Fila : pregunta / revisar ( texto corto ) -- }}
< div class = "grid grid-cols-1 md:grid-cols-2 gap-4 mb-2" >
< div class = "font-medium" > {{ __ ( 'Question / check' ) }} </ div >
< div >< input type = "text" wire : model = "form.fields.{{ $index }}.question" placeholder = "ej: ¿Cumple la cota prevista?" class = "input input-sm w-full" ></ div >
</ div >
2026-05-07 23:31:33 +02:00
{{ -- Fila : tipo -- }}
< div class = "grid grid-cols-1 md:grid-cols-2 gap-4 mb-2" >
2026-06-17 10:56:25 +02:00
< div class = "font-medium" > {{ __ ( 'Field type' ) }} </ div >
2026-05-07 23:31:33 +02:00
< div >
< select wire : model = "form.fields.{{ $index }}.type" class = "select select-sm w-full" >
@ foreach ( $fieldTypes as $typeValue => $typeLabel )
< option value = "{{ $typeValue }}" > {{ $typeLabel }} </ option >
@ endforeach
</ select >
</ div >
</ div >
{{ -- Fila : requerido y botón eliminar -- }}
< div class = "grid grid-cols-1 md:grid-cols-2 gap-4 mb-2" >
2026-06-17 10:56:25 +02:00
< div class = "font-medium" > {{ __ ( 'Required' ) }} </ div >
2026-05-07 23:31:33 +02:00
< div class = "flex justify-between items-center" >
< input type = "checkbox" wire : model = "form.fields.{{ $index }}.required" class = "checkbox checkbox-sm" >
2026-06-17 10:56:25 +02:00
< button type = "button" wire : click = "removeField({{ $index }})" class = "btn btn-xs btn-error" > {{ __ ( 'Remove field' ) }} </ button >
2026-05-07 23:31:33 +02:00
</ div >
</ div >
{{ -- Campos adicionales según tipo -- }}
@ if ( in_array ( $field [ 'type' ], [ 'integer' , 'decimal' , 'percentage' ]))
< div class = "grid grid-cols-1 md:grid-cols-2 gap-4 mb-2" >
2026-06-17 10:56:25 +02:00
< div class = "font-medium" > {{ __ ( 'Min' ) }} / {{ __ ( 'Max' ) }} / {{ __ ( 'Step' ) }} </ div >
2026-05-07 23:31:33 +02:00
< div class = "flex gap-2" >
2026-06-17 10:56:25 +02:00
< input type = "number" wire : model = "form.fields.{{ $index }}.min" placeholder = "{{ __('Min') }}" class = "input input-xs w-20" >
< input type = "number" wire : model = "form.fields.{{ $index }}.max" placeholder = "{{ __('Max') }}" class = "input input-xs w-20" >
< input type = "number" step = "any" wire : model = "form.fields.{{ $index }}.step" placeholder = "{{ __('Step') }}" class = "input input-xs w-20" >
2026-05-07 23:31:33 +02:00
</ div >
</ div >
@ elseif ( $field [ 'type' ] === 'select' )
< div class = "grid grid-cols-1 md:grid-cols-2 gap-4 mb-2" >
2026-06-17 10:56:25 +02:00
< div class = "font-medium" > {{ __ ( 'Options (comma separated)' ) }} </ div >
2026-05-07 23:31:33 +02:00
< div >< input type = "text" wire : model = "form.fields.{{ $index }}.options" placeholder = "ej: Bueno,Regular,Malo" class = "input input-sm w-full" ></ div >
</ div >
@ endif
2026-06-25 16:45:21 +02:00
{{ -- Fila : comentarios / ayuda ( texto largo ) -- }}
< div class = "grid grid-cols-1 md:grid-cols-2 gap-4 mb-2" >
< div class = "font-medium" > {{ __ ( 'Comments / help' ) }} </ div >
< div >< textarea wire : model = "form.fields.{{ $index }}.help" rows = "2" placeholder = "{{ __('Notes or instructions for this field') }}" class = "textarea textarea-bordered textarea-sm w-full" ></ textarea ></ div >
</ div >
2026-05-07 23:31:33 +02:00
</ div >
@ endforeach
2026-06-17 10:56:25 +02:00
< button type = "button" wire : click = "addField" class = "btn btn-sm btn-secondary mt-2" >+ {{ __ ( 'Add field' ) }} </ button >
2026-05-07 23:31:33 +02:00
</ div >
< div class = "flex gap-2 mt-4" >
2026-06-17 10:56:25 +02:00
< button type = "submit" class = "btn btn-primary" > {{ $editingTemplate ? __ ( 'Update' ) : __ ( 'Save template' ) }} </ button >
2026-06-16 18:05:53 +02:00
< button type = "button" wire : click = "cancelForm" class = "btn" > {{ __ ( 'Cancel' ) }} </ button >
2026-05-07 23:31:33 +02:00
</ div >
</ form >
@ endif
{{ -- Tabla de templates existentes -- }}
< div class = "overflow-x-auto" >
< table class = "table table-zebra" >
< thead >
< tr >
2026-06-17 10:56:25 +02:00
< th > {{ __ ( 'Name' ) }} </ th >
< th > {{ __ ( 'Description' ) }} </ th >
< th > {{ __ ( 'Phase' ) }} </ th >
< th > {{ __ ( 'Fields' ) }} </ th >
< th > {{ __ ( 'Actions' ) }} </ th >
2026-05-07 23:31:33 +02:00
</ tr >
</ thead >
< tbody >
@ forelse ( $templates as $template )
< tr >
2026-06-25 16:45:21 +02:00
< td >
{{ $template -> name }}
@ if ( is_null ( $template -> project_id ))
< span class = "badge badge-info badge-sm ml-1" > {{ __ ( 'Global' ) }} </ span >
@ endif
</ td >
2026-05-07 23:31:33 +02:00
< td > {{ $template -> description ?? '-' }} </ td >
2026-06-17 10:56:25 +02:00
< td > {{ $template -> phase ? $template -> phase -> name : __ ( 'Global project' ) }} </ td >
2026-05-07 23:31:33 +02:00
< td > {{ count ( $template -> fields ) }} </ td >
< td >
< button wire : click = "editTemplate({{ $template->id }})" class = "btn btn-xs btn-warning" >
2026-06-17 10:56:25 +02:00
{{ __ ( 'Edit' ) }}
2026-05-07 23:31:33 +02:00
</ button >
2026-06-17 10:56:25 +02:00
< button wire : click = "deleteTemplate({{ $template->id }})"
wire : confirm = "{{ __('Delete template confirmation') }}"
class = "btn btn-xs btn-error" > {{ __ ( 'Delete' ) }} </ button >
2026-05-07 23:31:33 +02:00
</ td >
</ tr >
@ empty
< tr >
2026-06-17 10:56:25 +02:00
< td colspan = "5" class = "text-center" > {{ __ ( 'No templates yet (table)' ) }} </ td >
2026-05-07 23:31:33 +02:00
</ tr >
@ endforelse
</ tbody >
</ table >
</ div >
</ div >
2026-06-25 14:18:21 +02:00
{{ -- ════════════════════════════════════════════════════════════
MODAL : Importar desde CSV / Excel
════════════════════════════════════════════════════════════ -- }}
@ if ( $showImportFileModal )
< div class = "fixed inset-0 z-40 bg-black/50" wire : click = " $set ('showImportFileModal', false)" ></ div >
< div class = "fixed inset-0 z-50 flex items-center justify-center p-4" >
< div class = "bg-base-100 rounded-box shadow-2xl w-full max-w-2xl max-h-[90vh] overflow-y-auto" >
< div class = "flex items-center justify-between p-4 border-b border-base-300" >
< h3 class = "font-bold" > {{ __ ( 'Import from CSV/Excel' ) }} </ h3 >
< button wire : click = " $set ('showImportFileModal', false)" class = "btn btn-sm btn-ghost btn-circle" >
< x - heroicon - o - x - mark class = "w-4 h-4" />
</ button >
</ div >
< div class = "p-4 space-y-3" >
< p class = "text-xs text-base-content/60" >
{{ __ ( 'Columns: name, label, type, required, options, min, max, step' ) }} .
< button type = "button" wire : click = "downloadExampleCsv" class = "link link-primary" > {{ __ ( 'Download example CSV' ) }} </ button >
</ p >
< div class = "form-control" >
< label class = "label" >< span class = "label-text font-medium" > {{ __ ( 'Template name' ) }} < span class = "text-error" >*</ span ></ span ></ label >
< input type = "text" wire : model = "importTemplateName" class = "input input-bordered w-full"
placeholder = "{{ __('e.g. Concrete reception') }}" />
@ error ( 'importTemplateName' ) < span class = "text-xs text-error" > {{ $message }} </ span >@ enderror
</ div >
< div class = "form-control" >
< label class = "label" >< span class = "label-text font-medium" > {{ __ ( 'File (CSV / Excel)' ) }} < span class = "text-error" >*</ span ></ span ></ label >
< input type = "file" wire : model = "importFile" accept = ".csv,.txt,.xlsx,.xls" class = "file-input file-input-bordered w-full" />
< div wire : loading wire : target = "importFile" class = "text-xs text-base-content/50 mt-1" > {{ __ ( 'Uploading…' ) }} </ div >
@ error ( 'importFile' ) < span class = "text-xs text-error" > {{ $message }} </ span >@ enderror
</ div >
@ if ( $importError )
< div class = "alert alert-error text-sm py-2" > {{ $importError }} </ div >
@ endif
< div class = "flex justify-end" >
< button wire : click = "parseImportFile" class = "btn btn-sm btn-secondary gap-1" wire : loading . attr = "disabled" wire : target = "parseImportFile,importFile" >
< x - heroicon - o - eye class = "w-4 h-4" /> {{ __ ( 'Preview' ) }}
</ button >
</ div >
{{ -- Vista previa de campos detectados -- }}
@ if ( ! empty ( $importPreviewFields ))
< div class = "border border-base-300 rounded-box p-2" >
< p class = "text-sm font-medium mb-2" > {{ count ( $importPreviewFields ) }} {{ __ ( 'fields detected' ) }} :</ p >
< div class = "overflow-x-auto" >
< table class = "table table-xs" >
< thead >< tr >< th > {{ __ ( 'Label' ) }} </ th >< th > {{ __ ( 'Name' ) }} </ th >< th > {{ __ ( 'Type' ) }} </ th >< th > {{ __ ( 'Required' ) }} </ th ></ tr ></ thead >
< tbody >
@ foreach ( $importPreviewFields as $f )
< tr >
< td > {{ $f [ 'label' ] }} </ td >
< td class = "font-mono text-xs" > {{ $f [ 'name' ] }} </ td >
< td >< span class = "badge badge-ghost badge-sm" > {{ $f [ 'type' ] }} </ span ></ td >
< td > {{ ! empty ( $f [ 'required' ]) ? '✓' : '' }} </ td >
</ tr >
@ endforeach
</ tbody >
</ table >
</ div >
</ div >
@ endif
</ div >
< div class = "flex justify-end gap-2 p-4 border-t border-base-300" >
< button wire : click = " $set ('showImportFileModal', false)" class = "btn btn-ghost btn-sm" > {{ __ ( 'Cancel' ) }} </ button >
< button wire : click = "confirmImportFile" class = "btn btn-primary btn-sm" @ disabled ( empty ( $importPreviewFields )) >
{{ __ ( 'Create template' ) }}
</ button >
</ div >
</ div >
</ div >
@ endif
{{ -- ════════════════════════════════════════════════════════════
MODAL : Importar desde otro proyecto
════════════════════════════════════════════════════════════ -- }}
@ if ( $showImportProjectModal )
< div class = "fixed inset-0 z-40 bg-black/50" wire : click = " $set ('showImportProjectModal', false)" ></ div >
< div class = "fixed inset-0 z-50 flex items-center justify-center p-4" >
< div class = "bg-base-100 rounded-box shadow-2xl w-full max-w-lg max-h-[90vh] overflow-y-auto" >
< div class = "flex items-center justify-between p-4 border-b border-base-300" >
< h3 class = "font-bold" > {{ __ ( 'Import from another project' ) }} </ h3 >
< button wire : click = " $set ('showImportProjectModal', false)" class = "btn btn-sm btn-ghost btn-circle" >
< x - heroicon - o - x - mark class = "w-4 h-4" />
</ button >
</ div >
< div class = "p-4 space-y-3" >
< div class = "form-control" >
< label class = "label" >< span class = "label-text font-medium" > {{ __ ( 'Project' ) }} </ span ></ label >
< select wire : model . live = "importProjectId" class = "select select-bordered w-full" >
< option value = "" > {{ __ ( 'Select project...' ) }} </ option >
@ foreach ( $availableProjects as $p )
< option value = "{{ $p->id }}" > {{ $p -> name }} </ option >
@ endforeach
</ select >
</ div >
@ if ( $importProjectId )
@ if ( count ( $importableTemplates ))
< div class = "border border-base-300 rounded-box p-2 space-y-1 max-h-64 overflow-y-auto" >
@ foreach ( $importableTemplates as $t )
< label class = "flex items-center gap-2 p-1 hover:bg-base-200 rounded cursor-pointer" >
< input type = "checkbox" wire : model = "selectedImportTemplateIds" value = "{{ $t->id }}" class = "checkbox checkbox-sm" />
< span class = "text-sm" > {{ $t -> name }} </ span >
< span class = "text-xs text-base-content/50" > ({{ count ( $t -> fields ?? []) }} {{ __ ( 'fields' ) }}) </ span >
</ label >
@ endforeach
</ div >
@ else
< p class = "text-sm text-base-content/40 py-2" > {{ __ ( 'This project has no templates.' ) }} </ p >
@ endif
@ endif
</ div >
< div class = "flex justify-end gap-2 p-4 border-t border-base-300" >
< button wire : click = " $set ('showImportProjectModal', false)" class = "btn btn-ghost btn-sm" > {{ __ ( 'Cancel' ) }} </ button >
< button wire : click = "importFromProject" class = "btn btn-primary btn-sm" @ disabled ( empty ( $selectedImportTemplateIds )) >
{{ __ ( 'Import selected' ) }}
</ button >
</ div >
</ div >
</ div >
@ endif
2026-06-17 10:56:25 +02:00
</ div >