netgescon-day0/resources/views/admin/palazzine/index.blade.php

246 lines
15 KiB
PHP
Executable File

@extends('admin.layouts.netgescon')
@section('title', 'Palazzine dello stabile')
@section('content')
<div class="container-fluid">
<div class="d-flex flex-column flex-md-row justify-content-between align-items-md-center mb-4">
<div class="mb-3 mb-md-0">
<h1 class="h2 mb-2">
<i class="fas fa-city me-3 text-primary"></i>
Palazzine dello stabile
<span class="text-muted">{{ $stabile->denominazione ?? $stabile->codice_stabile }}</span>
</h1>
<p class="text-muted mb-0">
<i class="fas fa-map-marker-alt me-2"></i>
{{ $stabile->indirizzo ?? 'Indirizzo non disponibile' }}
</p>
</div>
<div class="d-flex gap-2">
<a href="{{ route('admin.stabili.show', ['stabile' => $stabile->id]) }}" class="btn btn-outline-secondary">
<i class="fas fa-arrow-left me-2"></i>
Torna allo stabile
</a>
<a href="{{ route('admin.palazzine.create', ['stabile_id' => $stabile->id]) }}" class="btn btn-netgescon-primary">
<i class="fas fa-plus me-2"></i>
Nuova Palazzina
</a>
</div>
</div>
@php
$totalePalazzine = $palazzine->count();
$totaleUnitaStabile = $palazzine->getCollection()->sum(fn ($palazzina) => $palazzina->unitaImmobiliari->count());
$formatPiano = static function ($value): string {
if ($value === null || $value === '') {
return 'Piano N/D';
}
if (is_numeric($value)) {
$piano = (int) $value;
return match (true) {
$piano === 0 => 'Piano terra',
$piano < 0 => 'Interrato ' . abs($piano),
default => 'Piano ' . $piano,
};
}
$normalized = strtoupper(trim((string) $value));
return match ($normalized) {
'T', 'PT', 'R', 'PR' => 'Piano terra',
'S', 'PS' => 'Interrato 1',
default => 'Piano ' . $normalized,
};
};
$sortPiano = static function ($value): int {
if ($value === null || $value === '') {
return -999;
}
if (is_numeric($value)) {
return (int) $value;
}
return match (strtoupper(trim((string) $value))) {
'T', 'PT', 'R', 'PR' => 0,
'S', 'PS' => -1,
default => is_numeric((string) $value) ? (int) $value : -999,
};
};
@endphp
<div class="row g-3 mb-4">
<div class="col-12 col-md-4">
<div class="card border-0 shadow-sm h-100">
<div class="card-body">
<div class="text-muted text-uppercase small">Palazzine</div>
<div class="display-6 fw-semibold mb-0">{{ $totalePalazzine }}</div>
</div>
</div>
</div>
<div class="col-12 col-md-4">
<div class="card border-0 shadow-sm h-100">
<div class="card-body">
<div class="text-muted text-uppercase small">Unità visibili</div>
<div class="display-6 fw-semibold mb-0">{{ $totaleUnitaStabile }}</div>
</div>
</div>
</div>
<div class="col-12 col-md-4">
<div class="card border-0 shadow-sm h-100">
<div class="card-body">
<div class="text-muted text-uppercase small">Vista operativa</div>
<div class="small text-muted">Ogni palazzina mostra le unità per scala e per piano, con adiacenze orizzontali e riferimenti verticali utili per guasti e perdite.</div>
</div>
</div>
</div>
</div>
@if($palazzine->isEmpty())
<div class="card shadow-sm border-0">
<div class="card-body py-5 text-center text-muted">
<i class="fas fa-building fa-3x mb-3"></i>
<p class="mb-2">Non ci sono ancora palazzine censite per questo stabile.</p>
<p class="small">Usa il pulsante "Nuova Palazzina" per iniziare oppure importa i dati dallo strumento Gescon.</p>
</div>
</div>
@else
<div class="d-grid gap-4">
@foreach($palazzine as $palazzina)
@php
$totaleUnita = $palazzina->unitaImmobiliari->count();
$unitaOccupate = $palazzina->unitaImmobiliari->whereIn('stato_occupazione', ['occupata_proprietario', 'occupata_inquilino'])->count();
$unitaLibere = $palazzina->unitaImmobiliari->where('stato_occupazione', 'libera')->count();
$scaleGroups = $palazzina->unitaImmobiliari
->groupBy(fn ($unita) => trim((string) ($unita->scala ?? 'A')) ?: 'A')
->sortKeys();
@endphp
<div class="card border-0 shadow-sm">
<div class="card-body p-4">
<div class="d-flex flex-column flex-xl-row justify-content-between gap-3 mb-4">
<div>
<h2 class="h4 mb-1">
<i class="fas fa-building me-2 text-primary"></i>
Palazzina {{ $palazzina->codice_palazzina ?? '-' }}
</h2>
<p class="text-muted mb-2">{{ $palazzina->denominazione ?? 'Senza denominazione' }}</p>
<div class="d-flex flex-wrap gap-2 small text-muted">
<span class="badge bg-light text-dark">{{ $totaleUnita }} unità</span>
<span class="badge bg-success-subtle text-success">{{ $unitaOccupate }} occupate</span>
<span class="badge bg-warning-subtle text-warning">{{ $unitaLibere }} libere</span>
<span class="badge bg-info-subtle text-info">{{ $scaleGroups->count() }} scale</span>
</div>
</div>
<div class="d-flex flex-wrap gap-2 align-items-start">
<span class="text-muted small align-self-center">Aggiornata {{ optional($palazzina->updated_at)->diffForHumans() ?? 'N/D' }}</span>
<a href="{{ route('admin.palazzine.show', $palazzina) }}" class="btn btn-sm btn-outline-primary">
<i class="fas fa-eye me-1"></i>Dettagli
</a>
<a href="{{ route('admin.palazzine.edit', $palazzina) }}" class="btn btn-sm btn-outline-secondary">
<i class="fas fa-edit me-1"></i>Modifica
</a>
</div>
</div>
@if($scaleGroups->isEmpty())
<div class="rounded border border-dashed border-secondary-subtle bg-light p-4 text-center text-muted">
Nessuna unità collegata a questa palazzina.
</div>
@else
<div class="row g-4">
@foreach($scaleGroups as $scala => $scaleUnits)
@php
$orderedScaleUnits = $scaleUnits->sortBy([
fn ($unit) => -1 * $sortPiano($unit->piano),
fn ($unit) => (string) ($unit->interno ?? ''),
fn ($unit) => (int) $unit->id,
])->values();
$floorGroups = $scaleUnits
->groupBy(fn ($unit) => (string) ($unit->piano ?? 'nd'))
->sortByDesc(fn ($units, $key) => $sortPiano($key));
@endphp
<div class="col-12 col-xl-6">
<div class="rounded-4 border border-secondary-subtle bg-light p-3 h-100">
<div class="d-flex justify-content-between align-items-center mb-3">
<div>
<div class="text-uppercase small text-muted">Scala</div>
<div class="h5 mb-0">{{ $scala }}</div>
</div>
<span class="badge bg-dark-subtle text-dark">{{ $scaleUnits->count() }} unità</span>
</div>
<div class="d-grid gap-3">
@foreach($floorGroups as $pianoKey => $floorUnits)
@php
$orderedFloorUnits = $floorUnits->sortBy(fn ($unit) => (string) ($unit->interno ?? ''))->values();
@endphp
<div class="rounded-3 border border-white bg-white p-3 shadow-sm">
<div class="d-flex align-items-center gap-2 mb-3">
<span class="badge bg-primary-subtle text-primary">{{ $formatPiano($pianoKey) }}</span>
<span class="text-muted small">Adiacenze orizzontali sulla stessa riga</span>
</div>
<div class="row g-3">
@foreach($orderedFloorUnits as $index => $unita)
@php
$prev = $orderedFloorUnits->get($index - 1);
$next = $orderedFloorUnits->get($index + 1);
$stack = $orderedScaleUnits
->filter(fn ($candidate) => trim((string) ($candidate->interno ?? '')) === trim((string) ($unita->interno ?? '')))
->values();
$stackIndex = $stack->search(fn ($candidate) => (int) $candidate->id === (int) $unita->id);
$above = $stackIndex !== false && $stackIndex > 0 ? $stack->get($stackIndex - 1) : null;
$below = $stackIndex !== false ? $stack->get($stackIndex + 1) : null;
$status = (string) ($unita->stato_occupazione ?? '');
$statusClass = match ($status) {
'occupata_proprietario', 'occupata_inquilino' => 'bg-success-subtle text-success',
'libera' => 'bg-warning-subtle text-warning',
default => 'bg-secondary-subtle text-secondary',
};
@endphp
<div class="col-12 col-md-6 col-xxl-4">
<div class="rounded-3 border border-secondary-subtle p-3 h-100 bg-light">
<div class="d-flex justify-content-between align-items-start gap-2 mb-2">
<div>
<div class="fw-semibold text-dark">Interno {{ $unita->interno ?? 'N/D' }}</div>
<div class="small text-muted">{{ $unita->codice_unita ?? ('Unità #' . $unita->id) }}</div>
</div>
<span class="badge {{ $statusClass }}">{{ $status !== '' ? str_replace('_', ' ', $status) : 'stato N/D' }}</span>
</div>
<div class="small text-dark mb-2">{{ $unita->denominazione ?? 'Denominazione non disponibile' }}</div>
<div class="small text-muted d-grid gap-1">
<div><strong>Accanto SX:</strong> {{ $prev?->interno ? 'Int. ' . $prev->interno : '—' }}</div>
<div><strong>Accanto DX:</strong> {{ $next?->interno ? 'Int. ' . $next->interno : '—' }}</div>
<div><strong>Sopra:</strong> {{ $above?->piano !== null ? $formatPiano($above->piano) . ' · Int. ' . ($above->interno ?? 'N/D') : '—' }}</div>
<div><strong>Sotto:</strong> {{ $below?->piano !== null ? $formatPiano($below->piano) . ' · Int. ' . ($below->interno ?? 'N/D') : '—' }}</div>
</div>
</div>
</div>
@endforeach
</div>
</div>
@endforeach
</div>
</div>
</div>
@endforeach
</div>
@endif
</div>
</div>
@endforeach
</div>
<div class="mt-4">
{{ $palazzine->withQueryString()->links() }}
</div>
@endif
</div>
@endsection