- Add #[On] attributes to 5 Livewire component methods:
- LayerManager::saveManualGeojson
- ProjectForm::setLocation
- ProjectMap::selectFeature (already had #[On])
- TaskForm::closeModal
- TaskKanban::updateTaskStatus
- Replace @this.method() in @push('scripts') with Livewire.emit() calls
- Fix DataTable event payloads from objects {id: X} to scalars X for:
- FeatureTable::map-select-feature
- InspectionTable::map-view-inspection, edit-inspection, delete-inspection
177 lines
12 KiB
PHP
177 lines
12 KiB
PHP
<div x-show="showModal" x-cloak x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0 scale-95" x-transition:enter-end="opacity-100 scale-100" x-transition:leave="transition ease-in duration-150" x-transition:leave-start="opacity-100 scale-100" x-transition:leave-end="opacity-0 scale-95" class="fixed inset-0 z-50 overflow-y-auto" @keydown.escape.window="closeModal">
|
|
<div class="flex min-h-full items-center justify-center p-4">
|
|
<!-- Backdrop -->
|
|
<div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" @click="closeModal" aria-hidden="true"></div>
|
|
|
|
<!-- Modal -->
|
|
<div class="relative w-full max-w-2xl bg-white dark:bg-gray-800 rounded-xl shadow-xl">
|
|
<form wire:submit.prevent="save" class="p-6 space-y-6">
|
|
<!-- Header -->
|
|
<div class="flex items-center justify-between">
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">
|
|
{{ $mode === 'create' ? 'Nueva Tarea' : 'Editar Tarea' }}
|
|
</h3>
|
|
<button type="button" wire:click="closeModal" class="text-gray-400 hover:text-gray-500 dark:hover:text-gray-300">
|
|
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
@if($errors->any())
|
|
<div class="bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg p-4">
|
|
<div class="flex">
|
|
<svg class="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor">
|
|
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"/>
|
|
</svg>
|
|
<ul class="ml-3 text-sm text-red-700 dark:text-red-300">
|
|
@foreach($errors->all() as $error)
|
|
<li>{{ $error }}</li>
|
|
@endforeach
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
<!-- Title -->
|
|
<div>
|
|
<label for="title" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Título <span class="text-red-500">*</span></label>
|
|
<input type="text" id="title" wire:model="title"
|
|
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent dark:bg-gray-700 dark:text-white"
|
|
placeholder="Título de la tarea" required autofocus>
|
|
</div>
|
|
|
|
<!-- Description -->
|
|
<div>
|
|
<label for="description" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Descripción</label>
|
|
<textarea id="description" wire:model="description" rows="3"
|
|
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent dark:bg-gray-700 dark:text-white"
|
|
placeholder="Detalles de la tarea..."></textarea>
|
|
</div>
|
|
|
|
<!-- Row: Project/Phase + Parent Task -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div>
|
|
<label for="phase_id" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Fase</label>
|
|
<select id="phase_id" wire:model="phase_id"
|
|
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent dark:bg-gray-700 dark:text-white">
|
|
<option value="">Sin fase</option>
|
|
@foreach($phases as $id => $name)
|
|
<option value="{{ $id }}">{{ $name }}</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
|
|
<div>
|
|
<label for="parent_task_id" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Tarea Padre (subtarea de)</label>
|
|
<select id="parent_task_id" wire:model="parent_task_id"
|
|
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent dark:bg-gray-700 dark:text-white">
|
|
<option value="">Ninguna (tarea principal)</option>
|
|
@foreach($parentTasks as $pt)
|
|
<option value="{{ $pt->id }}">{{ $pt->title }}</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Row: Status + Priority -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div>
|
|
<label for="status" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Estado <span class="text-red-500">*</span></label>
|
|
<select id="status" wire:model="status"
|
|
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent dark:bg-gray-700 dark:text-white" required>
|
|
@foreach($statusOptions as $value => $label)
|
|
<option value="{{ $value }}">{{ $label }}</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
|
|
<div>
|
|
<label for="priority" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Prioridad <span class="text-red-500">*</span></label>
|
|
<select id="priority" wire:model="priority"
|
|
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent dark:bg-gray-700 dark:text-white" required>
|
|
@foreach($priorityOptions as $value => $label)
|
|
<option value="{{ $value }}">{{ $label }}</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Row: Assignee + Order -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div>
|
|
<label for="assigned_to" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Asignado a</label>
|
|
<select id="assigned_to" wire:model="assigned_to"
|
|
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent dark:bg-gray-700 dark:text-white">
|
|
<option value="">Sin asignar</option>
|
|
@foreach($assignees as $assignee)
|
|
<option value="{{ $assignee->id }}">{{ $assignee->name }}</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
|
|
<div>
|
|
<label for="order" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Orden</label>
|
|
<input type="number" id="order" wire:model="order" min="0"
|
|
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent dark:bg-gray-700 dark:text-white">
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Row: Dates -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div>
|
|
<label for="start_date" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Fecha inicio</label>
|
|
<input type="date" id="start_date" wire:model="start_date"
|
|
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent dark:bg-gray-700 dark:text-white">
|
|
</div>
|
|
|
|
<div>
|
|
<label for="due_date" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Fecha vencimiento</label>
|
|
<input type="date" id="due_date" wire:model="due_date"
|
|
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent dark:bg-gray-700 dark:text-white">
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Row: Hours -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div>
|
|
<label for="estimated_hours" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Horas estimadas</label>
|
|
<input type="number" id="estimated_hours" wire:model="estimated_hours" min="0" max="10000"
|
|
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent dark:bg-gray-700 dark:text-white"
|
|
placeholder="0">
|
|
</div>
|
|
|
|
<div>
|
|
<label for="actual_hours" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Horas reales</label>
|
|
<input type="number" id="actual_hours" wire:model="actual_hours" min="0" max="10000"
|
|
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent dark:bg-gray-700 dark:text-white"
|
|
placeholder="0">
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Actions -->
|
|
<div class="flex justify-end gap-3 pt-4 border-t border-gray-200 dark:border-gray-700">
|
|
<button type="button" wire:click="closeModal"
|
|
class="px-4 py-2 text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-700 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors">
|
|
Cancelar
|
|
</button>
|
|
<button type="submit"
|
|
class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors">
|
|
{{ $mode === 'create' ? 'Crear' : 'Guardar' }}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
@push('scripts')
|
|
<script>
|
|
// Close modal on Escape key
|
|
document.addEventListener('keydown', function(e) {
|
|
if (e.key === 'Escape') {
|
|
Livewire.emit('close-modal');
|
|
}
|
|
});
|
|
</script>
|
|
@endpush |