refactor(livewire): organizar componentes y vistas por dominio en subnamespaces
- app/Livewire: 34 componentes agrupados en Issues/, Projects/, Phases/, Companies/, Users/, Admin/, Inspections/, Layers/, Media/, Common/ (Client/, Reports/, Forms/, Actions/ ya estaban). Namespaces actualizados. - resources/views/livewire: vistas sueltas movidas a subcarpetas espejo (companies/, users/, phases/, roles/, inspections/, media/, common/); render() actualizado. - Referencias actualizadas sin romper nada: rutas (FQN, nombres de ruta intactos), tags <livewire:...>/@livewire() a alias con punto, y use de los tests. - No tocado: Volt de Breeze (auth/profile/navigation), y el portal cliente (user-nav/client-projects) que ya tenía referencias inconsistentes. Verificado: 69 rutas OK, vistas compilan, suite 69 passing (solo 2 pre-existentes sqlite). autoload regenerado con --ignore-platform-reqs (PHP 8.2). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire\Projects;
|
||||
|
||||
use Rappasoft\LaravelLivewireTables\DataTableComponent;
|
||||
use Rappasoft\LaravelLivewireTables\Views\Column;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\Models\Project;
|
||||
|
||||
class ProjectTable extends DataTableComponent
|
||||
{
|
||||
protected $model = Project::class;
|
||||
|
||||
public function configure(): void
|
||||
{
|
||||
$this->setPrimaryKey('id')
|
||||
->setDefaultSort('created_at', 'desc')
|
||||
->setSortingPillsEnabled(false)
|
||||
->setAdditionalSelects(['projects.id as id', 'projects.created_at as created_at']);
|
||||
}
|
||||
|
||||
public function builder(): Builder
|
||||
{
|
||||
return Project::accessibleBy(Auth::user())
|
||||
->with('phases');
|
||||
}
|
||||
|
||||
public function columns(): array
|
||||
{
|
||||
return [
|
||||
Column::make('Referencia', 'reference')
|
||||
->sortable()
|
||||
->searchable()
|
||||
->format(function ($value, $row) {
|
||||
$url = route('projects.dashboard', $row->id);
|
||||
return $value
|
||||
? '<a href="'.$url.'" class="font-mono text-xs text-primary hover:underline" wire:navigate>'.e($value).'</a>'
|
||||
: '<span class="text-gray-300">—</span>';
|
||||
})
|
||||
->html(),
|
||||
|
||||
Column::make(__('Name'), 'name')
|
||||
->sortable()
|
||||
->searchable(),
|
||||
|
||||
Column::make(__('Address'), 'address')
|
||||
->sortable()
|
||||
->searchable()
|
||||
->format(fn ($value) => $value
|
||||
? '<span class="truncate block max-w-xs" title="'.e($value).'">'.e($value).'</span>'
|
||||
: '<span class="text-gray-400">—</span>')
|
||||
->html(),
|
||||
|
||||
Column::make(__('Status'), 'status')
|
||||
->sortable()
|
||||
->format(function ($value) {
|
||||
$map = [
|
||||
'planning' => ['badge-ghost', 'Planificación'],
|
||||
'in_progress' => ['badge-primary', 'En progreso'],
|
||||
'paused' => ['badge-warning', 'Pausado'],
|
||||
'completed' => ['badge-success', 'Completado'],
|
||||
];
|
||||
[$cls, $label] = $map[$value] ?? ['badge-ghost', ucfirst($value)];
|
||||
return '<span class="badge '.$cls.'">'.$label.'</span>';
|
||||
})
|
||||
->html(),
|
||||
|
||||
Column::make(__('Progress'))
|
||||
->label(function ($row) {
|
||||
$avg = $row->phases->avg('progress_percent') ?? 0;
|
||||
$pct = round($avg);
|
||||
return '
|
||||
<div class="flex items-center gap-2 min-w-[100px]">
|
||||
<div class="flex-1 bg-gray-200 rounded-full h-2">
|
||||
<div class="bg-primary h-2 rounded-full" style="width:'.$pct.'%"></div>
|
||||
</div>
|
||||
<span class="text-xs text-gray-500 w-8 text-right">'.$pct.'%</span>
|
||||
</div>';
|
||||
})
|
||||
->html(),
|
||||
|
||||
Column::make(__('Start Date'), 'start_date')
|
||||
->sortable()
|
||||
->format(fn ($value) => $value ? $value->format('d/m/Y') : '—'),
|
||||
|
||||
Column::make(__('Est. End'), 'end_date_estimated')
|
||||
->sortable()
|
||||
->format(fn ($value) => $value ? $value->format('d/m/Y') : '—'),
|
||||
|
||||
Column::make(__('Actions'))
|
||||
->label(function ($row) {
|
||||
$dashboard = route('projects.dashboard', $row->id);
|
||||
$map = route('projects.map', $row->id);
|
||||
$edit = route('projects.edit', $row->id);
|
||||
|
||||
$canEdit = Auth::user()->can('edit projects');
|
||||
|
||||
$html = '<div class="flex items-center gap-1">';
|
||||
$html .= '<a href="'.$dashboard.'" class="btn btn-xs btn-outline" title="Dashboard" wire:navigate>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zm10 0a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zm10 0a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z"/></svg>
|
||||
</a>';
|
||||
$html .= '<a href="'.$map.'" class="btn btn-xs btn-outline" title="Mapa" wire:navigate>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 20l-5.447-2.724A1 1 0 013 16.382V5.618a1 1 0 011.447-.894L9 7m0 13l6-3m-6 3V7m6 10l4.553 2.276A1 1 0 0021 18.382V7.618a1 1 0 00-.553-.894L15 4m0 13V4m0 0L9 7"/></svg>
|
||||
</a>';
|
||||
if ($canEdit) {
|
||||
$html .= '<a href="'.$edit.'" class="btn btn-xs btn-warning" title="Editar" wire:navigate>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/></svg>
|
||||
</a>';
|
||||
}
|
||||
$html .= '</div>';
|
||||
return $html;
|
||||
})
|
||||
->html(),
|
||||
];
|
||||
}
|
||||
|
||||
public function filters(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user