2026-05-12 14:04:07 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace App\Livewire;
|
|
|
|
|
|
|
|
|
|
use Rappasoft\LaravelLivewireTables\DataTableComponent;
|
|
|
|
|
use Rappasoft\LaravelLivewireTables\Views\Column;
|
2026-06-16 18:05:53 +02:00
|
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
|
|
|
use Illuminate\Support\Facades\Auth;
|
2026-05-12 14:04:07 +02:00
|
|
|
use App\Models\Project;
|
|
|
|
|
|
|
|
|
|
class ProjectTable extends DataTableComponent
|
|
|
|
|
{
|
|
|
|
|
protected $model = Project::class;
|
|
|
|
|
|
|
|
|
|
public function configure(): void
|
|
|
|
|
{
|
|
|
|
|
$this->setPrimaryKey('id')
|
|
|
|
|
->setDefaultSort('created_at', 'desc')
|
2026-06-16 18:05:53 +02:00
|
|
|
->setSortingPillsEnabled(false)
|
|
|
|
|
->setAdditionalSelects(['projects.id as id', 'projects.created_at as created_at']);
|
|
|
|
|
}
|
2026-05-27 13:38:23 +02:00
|
|
|
|
2026-06-16 18:05:53 +02:00
|
|
|
public function builder(): Builder
|
|
|
|
|
{
|
|
|
|
|
return Project::accessibleBy(Auth::user())
|
|
|
|
|
->with('phases');
|
2026-05-12 14:04:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function columns(): array
|
|
|
|
|
{
|
|
|
|
|
return [
|
2026-06-16 18:05:53 +02:00
|
|
|
Column::make('Referencia', 'reference')
|
2026-05-27 13:38:23 +02:00
|
|
|
->sortable()
|
2026-06-16 18:05:53 +02:00
|
|
|
->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')
|
2026-05-12 14:04:07 +02:00
|
|
|
->sortable()
|
|
|
|
|
->searchable(),
|
2026-06-16 18:05:53 +02:00
|
|
|
|
2026-05-12 14:04:07 +02:00
|
|
|
Column::make(__('Address'), 'address')
|
|
|
|
|
->sortable()
|
2026-06-16 18:05:53 +02:00
|
|
|
->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(),
|
2026-05-27 13:38:23 +02:00
|
|
|
|
2026-05-12 14:04:07 +02:00
|
|
|
Column::make(__('Status'), 'status')
|
2026-06-16 18:05:53 +02:00
|
|
|
->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(),
|
2026-05-27 13:38:23 +02:00
|
|
|
|
2026-05-12 14:04:07 +02:00
|
|
|
Column::make(__('Start Date'), 'start_date')
|
|
|
|
|
->sortable()
|
2026-06-16 18:05:53 +02:00
|
|
|
->format(fn ($value) => $value ? $value->format('d/m/Y') : '—'),
|
2026-05-27 13:38:23 +02:00
|
|
|
|
2026-06-16 18:05:53 +02:00
|
|
|
Column::make(__('Est. End'), 'end_date_estimated')
|
2026-05-12 14:04:07 +02:00
|
|
|
->sortable()
|
2026-06-16 18:05:53 +02:00
|
|
|
->format(fn ($value) => $value ? $value->format('d/m/Y') : '—'),
|
2026-05-27 13:38:23 +02:00
|
|
|
|
2026-05-12 14:04:07 +02:00
|
|
|
Column::make(__('Actions'))
|
2026-06-16 18:05:53 +02:00
|
|
|
->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(),
|
2026-05-12 14:04:07 +02:00
|
|
|
];
|
|
|
|
|
}
|
2026-05-27 13:38:23 +02:00
|
|
|
|
|
|
|
|
public function filters(): array
|
|
|
|
|
{
|
|
|
|
|
return [];
|
|
|
|
|
}
|
2026-06-16 18:05:53 +02:00
|
|
|
}
|