246 lines
15 KiB
PHP
Executable File
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
|