feat(phases): modal crear/editar fase + tabla Rappasoft
- PhaseList pasa a contenedor: botón "Agregar fase" + modal crear/editar con todos los parámetros (nombre, descripción, orden, color, progreso, fechas previstas y reales) y validación. Antes "Agregar fase" creaba directamente 'Nueva fase'. - PhaseTable (Rappasoft): orden, nombre+descripción, barra de progreso, fechas, color y acciones (editar abre el modal vía evento, actualizar progreso, eliminar); búsqueda y ordenación. Gateado por 'manage phases' + acceso al proyecto. Tests: PhaseManagementTest (4). Suite 65 passing (solo 2 pre-existentes sqlite). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,29 +1,115 @@
|
||||
<div>
|
||||
@if(session()->has('message'))
|
||||
<div class="alert alert-success mb-2">{{ session('message') }}</div>
|
||||
@endif
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr><th>{{ __('Name') }}</th><th>{{ __('Progress') }}</th><th>{{ __('Color') }}</th><th>{{ __('Actions') }}</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($phases as $phase)
|
||||
<tr>
|
||||
<td>{{ $phase->name }}</td>
|
||||
<td>
|
||||
<div class="w-32 bg-gray-200 rounded-full h-2">
|
||||
<div class="bg-primary h-2 rounded-full" style="width: {{ $phase->progress_percent }}%"></div>
|
||||
<div class="flex items-center justify-between gap-3 mb-4">
|
||||
<div>
|
||||
<h3 class="font-bold">{{ __('Phases') }}</h3>
|
||||
<p class="text-sm text-base-content/60">Fases del proyecto y su progreso</p>
|
||||
</div>
|
||||
@can('manage phases')
|
||||
<button wire:click="openForm()" class="btn btn-primary btn-sm gap-2">
|
||||
<x-heroicon-o-plus class="w-4 h-4" /> {{ __('Add Phase') }}
|
||||
</button>
|
||||
@endcan
|
||||
</div>
|
||||
|
||||
{{-- Tabla Rappasoft de fases --}}
|
||||
<livewire:phase-table :project-id="$project->id" :key="'phase-table-'.$project->id" />
|
||||
|
||||
{{-- ================================================================
|
||||
MODAL crear / editar fase
|
||||
================================================================ --}}
|
||||
@if($showForm)
|
||||
<div class="fixed inset-0 z-40 bg-black/50" wire:click="closeForm"></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-5 border-b border-base-300">
|
||||
<h3 class="text-lg font-bold">{{ $editingId ? 'Editar fase' : 'Nueva fase' }}</h3>
|
||||
<button wire:click="closeForm" class="btn btn-sm btn-ghost btn-circle">
|
||||
<x-heroicon-o-x-mark class="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form wire:submit.prevent="save" class="p-5 space-y-4">
|
||||
{{-- Nombre --}}
|
||||
<div class="form-control">
|
||||
<label class="label"><span class="label-text font-medium">Nombre <span class="text-error">*</span></span></label>
|
||||
<input type="text" wire:model="name" autofocus
|
||||
class="input input-bordered w-full @error('name') input-error @enderror"
|
||||
placeholder="Ej.: Cimentación" />
|
||||
@error('name')<label class="label"><span class="label-text-alt text-error">{{ $message }}</span></label>@enderror
|
||||
</div>
|
||||
|
||||
{{-- Descripción --}}
|
||||
<div class="form-control">
|
||||
<label class="label"><span class="label-text font-medium">Descripción</span></label>
|
||||
<textarea wire:model="description"
|
||||
class="textarea textarea-bordered w-full h-20 resize-y"
|
||||
placeholder="Detalle de la fase..."></textarea>
|
||||
</div>
|
||||
|
||||
{{-- Orden + Color + Progreso --}}
|
||||
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
||||
<div class="form-control">
|
||||
<label class="label"><span class="label-text font-medium">Orden <span class="text-error">*</span></span></label>
|
||||
<input type="number" min="0" wire:model="order"
|
||||
class="input input-bordered w-full @error('order') input-error @enderror" />
|
||||
@error('order')<label class="label"><span class="label-text-alt text-error">{{ $message }}</span></label>@enderror
|
||||
</div>
|
||||
{{ $phase->progress_percent }}%
|
||||
</td>
|
||||
<td><div class="w-6 h-6 rounded" style="background: {{ $phase->color }}"></div></td>
|
||||
<td>
|
||||
<a href="{{ route('phases.progress', $phase) }}" class="btn btn-xs btn-info">{{ __('Update') }}</a>
|
||||
<button wire:click="deletePhase({{ $phase->id }})" class="btn btn-xs btn-error">{{ __('Delete') }}</button>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
<button wire:click="addPhase" class="btn btn-sm btn-secondary mt-2">+ {{ __('Add Phase') }}</button>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label"><span class="label-text font-medium">Color</span></label>
|
||||
<input type="color" wire:model="color"
|
||||
class="input input-bordered w-full h-12 p-1 @error('color') input-error @enderror" />
|
||||
@error('color')<label class="label"><span class="label-text-alt text-error">{{ $message }}</span></label>@enderror
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label"><span class="label-text font-medium">Progreso (%)</span></label>
|
||||
<input type="number" min="0" max="100" wire:model="progressPercent"
|
||||
class="input input-bordered w-full @error('progressPercent') input-error @enderror" />
|
||||
@error('progressPercent')<label class="label"><span class="label-text-alt text-error">{{ $message }}</span></label>@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Fechas previstas --}}
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div class="form-control">
|
||||
<label class="label"><span class="label-text font-medium">Inicio previsto</span></label>
|
||||
<input type="date" wire:model="plannedStart"
|
||||
class="input input-bordered w-full @error('plannedStart') input-error @enderror" />
|
||||
@error('plannedStart')<label class="label"><span class="label-text-alt text-error">{{ $message }}</span></label>@enderror
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label"><span class="label-text font-medium">Fin previsto</span></label>
|
||||
<input type="date" wire:model="plannedEnd"
|
||||
class="input input-bordered w-full @error('plannedEnd') input-error @enderror" />
|
||||
@error('plannedEnd')<label class="label"><span class="label-text-alt text-error">{{ $message }}</span></label>@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Fechas reales --}}
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div class="form-control">
|
||||
<label class="label"><span class="label-text font-medium">Inicio real</span></label>
|
||||
<input type="date" wire:model="actualStart"
|
||||
class="input input-bordered w-full @error('actualStart') input-error @enderror" />
|
||||
@error('actualStart')<label class="label"><span class="label-text-alt text-error">{{ $message }}</span></label>@enderror
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label"><span class="label-text font-medium">Fin real</span></label>
|
||||
<input type="date" wire:model="actualEnd"
|
||||
class="input input-bordered w-full @error('actualEnd') input-error @enderror" />
|
||||
@error('actualEnd')<label class="label"><span class="label-text-alt text-error">{{ $message }}</span></label>@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-end gap-3 pt-2 border-t border-base-300">
|
||||
<button type="button" wire:click="closeForm" class="btn btn-ghost">Cancelar</button>
|
||||
<button type="submit" class="btn btn-primary gap-2" wire:loading.attr="disabled" wire:target="save">
|
||||
<span wire:loading.remove wire:target="save"><x-heroicon-o-check class="w-4 h-4" /></span>
|
||||
<span wire:loading wire:target="save" class="loading loading-spinner loading-sm"></span>
|
||||
{{ $editingId ? 'Actualizar fase' : 'Crear fase' }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user