chore: cleanup dead code + format with Pint

- Remove unused FeaturesController (empty stubs, no routes)
- Remove ConvertSpatialFile CLI command (unused; service used in LayerManager)
- Remove MigrateGeojsonToFeatures CLI command (one-shot migration, not referenced)
- Remove .claude/worktrees/ (11 old agent worktrees from June)
- Apply Laravel Pint formatting across 219 files (style only, no functional changes)

Tests: 101 passing (319 assertions)
API routes: unchanged (8 routes intact)
This commit is contained in:
Javier Braña
2026-08-28 13:04:28 +02:00
parent 2dccd59385
commit 90630379fb
139 changed files with 2888 additions and 2510 deletions
+122 -86
View File
@@ -2,19 +2,19 @@
namespace App\Livewire\Layers;
use Livewire\Component;
use Livewire\WithFileUploads;
use Livewire\Attributes\Layout;
use Livewire\Attributes\On;
use App\Models\Project;
use App\Models\Phase;
use App\Models\Layer;
use App\Models\Feature;
use App\Models\InspectionTemplate;
use App\Models\Layer;
use App\Models\Phase;
use App\Models\Project;
use App\Services\SpatialFileConverter;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Livewire\Attributes\Layout;
use Livewire\Attributes\On;
use Livewire\Component;
use Livewire\WithFileUploads;
#[Layout('layouts.app')]
class LayerManager extends Component
@@ -22,29 +22,39 @@ class LayerManager extends Component
use WithFileUploads;
public Project $project;
public Phase $phase;
public Phase $phase;
public $layers;
public $selectedLayer = null;
public $visibleLayers = [];
public $uploadFile = null;
public $layerName = '';
public $layerColor = '#3b82f6';
public $uploadFile = null;
public $layerName = '';
public $layerColor = '#3b82f6';
// Batch assign
public $templates = [];
public $templates = [];
public $batchTemplateId = null;
public $batchStatus = '';
public $batchStatus = '';
public function mount(Project $project, Phase $phase)
{
$this->project = $project;
$this->phase = $phase;
$this->phase = $phase;
if ($this->phase->project_id !== $this->project->id) abort(404);
if ($this->phase->project_id !== $this->project->id) {
abort(404);
}
$user = Auth::user();
if (!$user->can('manage all') && !$project->users()->where('user_id', $user->id)->exists()) {
if (! $user->can('manage all') && ! $project->users()->where('user_id', $user->id)->exists()) {
abort(403);
}
@@ -71,28 +81,28 @@ class LayerManager extends Component
private function buildLayerPayload(Layer $layer): array
{
$color = $layer->color ?: '#3b82f6';
$color = $layer->color ?: '#3b82f6';
$features = ($layer->relationLoaded('features') ? $layer->features : $layer->features()->get())
->map(fn($f) => [
'type' => 'Feature',
'id' => $f->id,
'geometry' => $f->geometry,
->map(fn ($f) => [
'type' => 'Feature',
'id' => $f->id,
'geometry' => $f->geometry,
'properties' => [
'name' => $f->name ?? 'Elemento',
'progress' => $f->progress,
'status' => $f->status ?? 'planned',
'name' => $f->name ?? 'Elemento',
'progress' => $f->progress,
'status' => $f->status ?? 'planned',
'responsible' => $f->responsible,
'template_id' => $f->template_id,
],
])->values()->toArray();
return [
'id' => $layer->id,
'color' => $color,
'id' => $layer->id,
'color' => $color,
'geojson' => [
'type' => 'FeatureCollection',
'type' => 'FeatureCollection',
'features' => $features,
'style' => ['color' => $color],
'style' => ['color' => $color],
],
];
}
@@ -101,8 +111,8 @@ class LayerManager extends Component
{
$this->layers->loadMissing('features');
$this->dispatch('initialLayersData', [
'layers' => $this->layers->map(fn($l) => $this->buildLayerPayload($l)),
'visibleLayers' => $this->visibleLayers,
'layers' => $this->layers->map(fn ($l) => $this->buildLayerPayload($l)),
'visibleLayers' => $this->visibleLayers,
'selectedLayerId' => $this->selectedLayer?->id,
]);
}
@@ -113,6 +123,7 @@ class LayerManager extends Component
{
if ($this->selectedLayer && $this->selectedLayer->id == $layerId) {
$this->dispatch('notify', 'No puedes ocultar la capa que estás editando');
return;
}
if (in_array($layerId, $this->visibleLayers)) {
@@ -128,9 +139,11 @@ class LayerManager extends Component
public function selectLayer($layerId)
{
$this->selectedLayer = Layer::with('features')->find($layerId);
if (!$this->selectedLayer) return;
if (! $this->selectedLayer) {
return;
}
if (!in_array($layerId, $this->visibleLayers)) {
if (! in_array($layerId, $this->visibleLayers)) {
$this->visibleLayers[] = $layerId;
$this->dispatch('visibilityChanged', $this->visibleLayers);
}
@@ -139,9 +152,9 @@ class LayerManager extends Component
$this->dispatch('layerSelectedForEdit', [
'layerId' => $layerId,
'geojson' => $payload['geojson'],
'color' => $payload['color'],
'color' => $payload['color'],
]);
$this->dispatch('notify', 'Editando: ' . $this->selectedLayer->name);
$this->dispatch('notify', 'Editando: '.$this->selectedLayer->name);
}
// ── Import file ───────────────────────────────────────────────────────────
@@ -149,32 +162,35 @@ class LayerManager extends Component
public function importFile()
{
$user = Auth::user();
if (!$user->can('upload layers')) {
if (! $user->can('upload layers')) {
$this->dispatch('notify', 'Sin permisos para subir capas');
return;
}
$this->validate([
'uploadFile' => 'required|file|max:51200',
'layerName' => 'required|string|max:255',
'layerName' => 'required|string|max:255',
'layerColor' => 'nullable|string|size:7',
]);
$ext = strtolower($this->uploadFile->getClientOriginalExtension());
$ext = strtolower($this->uploadFile->getClientOriginalExtension());
$allowed = ['geojson', 'json', 'kmz', 'kml', 'shp', 'dwg', 'zip'];
if (!in_array($ext, $allowed)) {
$this->dispatch('notify', 'Extensión no permitida. Válidas: ' . implode(', ', $allowed));
if (! in_array($ext, $allowed)) {
$this->dispatch('notify', 'Extensión no permitida. Válidas: '.implode(', ', $allowed));
return;
}
$geojson = SpatialFileConverter::convertToGeoJson($this->uploadFile);
if (!$geojson) {
if (! $geojson) {
$this->dispatch('notify', 'No se pudo convertir el archivo. Comprueba que sea GeoJSON, KML o Shapefile válido.');
return;
}
$layerColor = $this->layerColor ?: '#3b82f6';
$layerName = $this->layerName;
$layerName = $this->layerName;
try {
DB::transaction(function () use ($geojson, $layerColor, $layerName, $user) {
@@ -183,28 +199,30 @@ class LayerManager extends Component
);
$layer = Layer::create([
'project_id' => $this->project->id,
'phase_id' => $this->phase->id,
'name' => $layerName,
'color' => $layerColor,
'project_id' => $this->project->id,
'phase_id' => $this->phase->id,
'name' => $layerName,
'color' => $layerColor,
'original_file' => $path,
'uploaded_by' => $user->id,
'uploaded_by' => $user->id,
]);
$idx = 0;
foreach ($geojson['features'] ?? [] as $fd) {
$idx++;
$name = trim($fd['properties']['name'] ?? '');
if ($name === '') $name = $layerName . ' — Elemento ' . $idx;
if ($name === '') {
$name = $layerName.' — Elemento '.$idx;
}
Feature::create([
'layer_id' => $layer->id,
'name' => $name,
'geometry' => $fd['geometry'],
'properties' => $fd['properties'] ?? [],
'layer_id' => $layer->id,
'name' => $name,
'geometry' => $fd['geometry'],
'properties' => $fd['properties'] ?? [],
'template_id' => $fd['properties']['template_id'] ?? null,
'progress' => $fd['properties']['progress'] ?? 0,
'status' => in_array($fd['properties']['status'] ?? '', Feature::STATUSES)
'progress' => $fd['properties']['progress'] ?? 0,
'status' => in_array($fd['properties']['status'] ?? '', Feature::STATUSES)
? $fd['properties']['status']
: 'planned',
'responsible' => $fd['properties']['responsible'] ?? null,
@@ -214,7 +232,8 @@ class LayerManager extends Component
$this->visibleLayers[] = $layer->id;
});
} catch (\Throwable $e) {
$this->dispatch('notify', 'Error al importar: ' . $e->getMessage());
$this->dispatch('notify', 'Error al importar: '.$e->getMessage());
return;
}
@@ -229,18 +248,19 @@ class LayerManager extends Component
public function createEmptyLayer()
{
$user = Auth::user();
if (!$user->can('upload layers')) {
if (! $user->can('upload layers')) {
$this->dispatch('notify', 'Sin permisos para crear capas');
return;
}
$layer = Layer::create([
'project_id' => $this->project->id,
'phase_id' => $this->phase->id,
'name' => $this->layerName ?: 'Nueva capa',
'color' => $this->layerColor ?: '#3b82f6',
'project_id' => $this->project->id,
'phase_id' => $this->phase->id,
'name' => $this->layerName ?: 'Nueva capa',
'color' => $this->layerColor ?: '#3b82f6',
'original_file' => null,
'uploaded_by' => $user->id,
'uploaded_by' => $user->id,
]);
$this->loadLayers();
@@ -255,18 +275,20 @@ class LayerManager extends Component
#[On('save-manual-geojson')]
public function saveManualGeojson($geojsonString)
{
if (!$this->selectedLayer) {
if (! $this->selectedLayer) {
$this->dispatch('notify', 'No hay capa seleccionada');
return;
}
$geojson = json_decode($geojsonString, true);
if (json_last_error() !== JSON_ERROR_NONE || !isset($geojson['features'])) {
if (json_last_error() !== JSON_ERROR_NONE || ! isset($geojson['features'])) {
$this->dispatch('notify', 'GeoJSON inválido');
return;
}
$layerId = $this->selectedLayer->id;
$layerId = $this->selectedLayer->id;
$layerName = $this->selectedLayer->name;
try {
@@ -278,16 +300,18 @@ class LayerManager extends Component
foreach ($geojson['features'] as $fd) {
$idx++;
$name = trim($fd['properties']['name'] ?? '');
if ($name === '') $name = $layerName . ' — Elemento ' . $idx;
if ($name === '') {
$name = $layerName.' — Elemento '.$idx;
}
Feature::create([
'layer_id' => $layerId,
'name' => $name,
'geometry' => $fd['geometry'],
'properties' => $fd['properties'] ?? [],
'layer_id' => $layerId,
'name' => $name,
'geometry' => $fd['geometry'],
'properties' => $fd['properties'] ?? [],
'template_id' => $fd['properties']['template_id'] ?? null,
'progress' => $fd['properties']['progress'] ?? 0,
'status' => in_array($fd['properties']['status'] ?? '', Feature::STATUSES)
'progress' => $fd['properties']['progress'] ?? 0,
'status' => in_array($fd['properties']['status'] ?? '', Feature::STATUSES)
? $fd['properties']['status']
: 'planned',
'responsible' => $fd['properties']['responsible'] ?? null,
@@ -295,14 +319,15 @@ class LayerManager extends Component
}
});
} catch (\Throwable $e) {
$this->dispatch('notify', 'Error al guardar: ' . $e->getMessage());
$this->dispatch('notify', 'Error al guardar: '.$e->getMessage());
return;
}
$this->loadLayers();
$this->selectLayer($this->selectedLayer->id);
$this->emitInitialLayersData();
$this->dispatch('notify', count($geojson['features']) . ' elementos guardados');
$this->dispatch('notify', count($geojson['features']).' elementos guardados');
}
// ── Delete layer ──────────────────────────────────────────────────────────
@@ -310,13 +335,19 @@ class LayerManager extends Component
public function deleteLayer($layerId)
{
$user = Auth::user();
if (!$user->can('delete layers')) abort(403);
if (! $user->can('delete layers')) {
abort(403);
}
// Verify it belongs to this phase (prevents cross-project deletion)
$layer = Layer::where('id', $layerId)->where('phase_id', $this->phase->id)->first();
if (!$layer) return;
if (! $layer) {
return;
}
if ($layer->original_file) Storage::disk('public')->delete($layer->original_file);
if ($layer->original_file) {
Storage::disk('public')->delete($layer->original_file);
}
$layer->features()->delete();
$layer->delete();
@@ -337,25 +368,27 @@ class LayerManager extends Component
->where('id', $layerId)
->where('phase_id', $this->phase->id)
->first();
if (!$layer) return;
if (! $layer) {
return;
}
$fc = [
'type' => 'FeatureCollection',
'name' => $layer->name,
'features' => $layer->features->map(fn($f) => [
'type' => 'Feature',
'geometry' => $f->geometry,
'type' => 'FeatureCollection',
'name' => $layer->name,
'features' => $layer->features->map(fn ($f) => [
'type' => 'Feature',
'geometry' => $f->geometry,
'properties' => array_merge($f->properties ?? [], [
'name' => $f->name,
'progress' => $f->progress,
'status' => $f->status,
'name' => $f->name,
'progress' => $f->progress,
'status' => $f->status,
'responsible' => $f->responsible,
'template_id' => $f->template_id,
]),
])->values()->toArray(),
];
$filename = preg_replace('/[^a-z0-9_\-]/i', '_', $layer->name) . '.geojson';
$filename = preg_replace('/[^a-z0-9_\-]/i', '_', $layer->name).'.geojson';
return response()->streamDownload(function () use ($fc) {
echo json_encode($fc, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
@@ -367,7 +400,9 @@ class LayerManager extends Component
public function batchAssign($layerId)
{
$layer = Layer::where('id', $layerId)->where('phase_id', $this->phase->id)->first();
if (!$layer) return;
if (! $layer) {
return;
}
$data = [];
if ($this->batchStatus && in_array($this->batchStatus, Feature::STATUSES)) {
@@ -378,6 +413,7 @@ class LayerManager extends Component
}
if (empty($data)) {
$this->dispatch('notify', 'Selecciona un estado o template para asignar');
return;
}