From 32a6982aabba738cc176db96cc5e3341944db222 Mon Sep 17 00:00:00 2001 From: michele Date: Mon, 31 Aug 2026 19:38:20 +0200 Subject: [PATCH] feat(stabile-ui): modernizzazione blade scheda stabile, rimozione bottoni header unita e compattazione dropdown multi-nominativo --- app/Filament/Pages/UnitaImmobiliarePage.php | 200 +---------------- .../pages/condomini/stabile.blade.php | 209 +++++++++++++----- skill-netgescon/control-tower/CURRENT-205.md | 11 +- 3 files changed, 166 insertions(+), 254 deletions(-) diff --git a/app/Filament/Pages/UnitaImmobiliarePage.php b/app/Filament/Pages/UnitaImmobiliarePage.php index 35e59b3..0ee93f3 100755 --- a/app/Filament/Pages/UnitaImmobiliarePage.php +++ b/app/Filament/Pages/UnitaImmobiliarePage.php @@ -310,197 +310,7 @@ public function updatedUnitaId(): void protected function getHeaderActions(): array { - $prevId = $this->getPrevUnitaId(); - $nextId = $this->getNextUnitaId(); - - return [ - Action::make('modifica_unita') - ->label('Modifica unità') - ->icon('heroicon-o-pencil-square') - ->modalWidth('5xl') - ->visible(fn(): bool => (bool) $this->unitaId && $this->unita instanceof UnitaImmobiliare) - ->fillForm(fn(): array=> $this->getEditUnitaFormData()) - ->form([ - TextInput::make('codice_unita') - ->label('Codice unità') - ->maxLength(100) - ->columnSpan(3), - TextInput::make('denominazione') - ->label('Denominazione') - ->maxLength(255) - ->columnSpan(5), - TextInput::make('tipo_unita') - ->label('Tipologia') - ->maxLength(100) - ->columnSpan(2), - TextInput::make('categoria_catastale') - ->label('Categoria catastale') - ->maxLength(20) - ->columnSpan(2), - TextInput::make('scala') - ->label('Scala') - ->maxLength(50) - ->columnSpan(2), - TextInput::make('piano') - ->label('Piano') - ->maxLength(50) - ->columnSpan(2), - TextInput::make('interno') - ->label('Interno') - ->maxLength(50) - ->columnSpan(2), - TextInput::make('stato_occupazione') - ->label('Stato occupazione') - ->maxLength(100) - ->columnSpan(3), - TextInput::make('utilizzo_attuale') - ->label('Utilizzo attuale') - ->maxLength(100) - ->columnSpan(3), - Toggle::make('attiva') - ->label('Unità attiva') - ->columnSpan(2), - TextInput::make('acqua_contatore_seriale') - ->label('Seriale contatore acqua') - ->maxLength(100) - ->columnSpan(3), - TextInput::make('acqua_gateway_device_id') - ->label('ID dispositivo gateway acqua') - ->helperText('Identificativo inviato dal gateway per associare le letture a questa unità.') - ->maxLength(120) - ->columnSpan(3), - Textarea::make('note') - ->label('Note') - ->rows(4) - ->columnSpanFull(), - ]) - ->action(function (array $data): void { - $this->saveEditedUnita($data); - }), - Action::make('prev_unita') - ->label('Precedente') - ->icon('heroicon-o-arrow-left') - ->color('gray') - ->visible(fn(): bool => (bool) $this->getPrevUnitaId()) - ->url(fn(): string => $this->makeSelfUrl($prevId)), - Action::make('next_unita') - ->label('Successiva') - ->icon('heroicon-o-arrow-right') - ->color('gray') - ->visible(fn(): bool => (bool) $this->getNextUnitaId()) - ->url(fn(): string => $this->makeSelfUrl($nextId)), - Action::make('storico_ruoli') - ->label('Storico ruoli') - ->icon('heroicon-o-clock') - ->modalWidth('7xl') - ->visible(fn(): bool => (bool) $this->unitaId) - ->form([ - Repeater::make('ruoli') - ->label('Storico proprietari / inquilini') - ->defaultItems(0) - ->reorderable(true) - ->schema([ - Hidden::make('id'), - Select::make('rubrica_id') - ->label('Persona') - ->required() - ->searchable() - ->getSearchResultsUsing(function (string $search): array { - return RubricaUniversale::query() - ->ricerca($search) - ->limit(30) - ->get() - ->mapWithKeys(fn(RubricaUniversale $r) => [ - $r->id => $r->nome_completo . ($r->email ? (' · ' . $r->email) : ''), - ]) - ->all(); - }) - ->getOptionLabelUsing(function ($value): ?string { - if (! $value) { - return null; - } - $r = RubricaUniversale::query()->find($value); - return $r ? ($r->nome_completo . ($r->email ? (' · ' . $r->email) : '')) : null; - }) - ->columnSpan(5), - DatePicker::make('data_inizio') - ->label('Dal') - ->columnSpan(3), - DatePicker::make('data_fine') - ->label('Fino al') - ->columnSpan(3), - Select::make('ruolo') - ->label('Ruolo') - ->options($this->getRuoliLabels()) - ->columnSpan(3), - Toggle::make('attivo') - ->label('Attivo') - ->columnSpan(2), - ]) - ->columns(9), - ]), - Action::make('recapiti_email') - ->label('Recapiti email') - ->icon('heroicon-o-envelope') - ->modalWidth('7xl') - ->visible(fn(): bool => (bool) $this->unitaId) - ->form([ - Repeater::make('recapiti') - ->label('Recapiti email per servizio') - ->defaultItems(0) - ->reorderable(true) - ->schema([ - Hidden::make('id'), - Select::make('tipo_servizio') - ->label('Servizio') - ->options(UnitaRecapitoServizio::serviceLabels()) - ->native(false) - ->required() - ->columnSpan(3), - Select::make('persona_id') - ->label('Persona collegata') - ->options(fn(): array=> $this->getPersonaRecapitoOptions()) - ->searchable() - ->preload() - ->native(false) - ->columnSpan(4), - TextInput::make('email') - ->label('Email da usare') - ->email() - ->required() - ->placeholder('nome@example.it') - ->helperText('Scegli la persona collegata e usa una delle email mostrate nel relativo riepilogo.') - ->columnSpan(5), - TextInput::make('etichetta') - ->label('Etichetta') - ->maxLength(120) - ->columnSpan(4), - TextInput::make('note') - ->label('Note') - ->maxLength(255) - ->columnSpan(4), - Toggle::make('is_default') - ->label('Predefinita') - ->default(true) - ->columnSpan(2), - Toggle::make('attivo') - ->label('Attiva') - ->default(true) - ->columnSpan(2), - ]) - ->columns(12), - ]) - ->fillForm(fn(): array=> ['recapiti' => $this->getRecapitiServizioFormRows()]) - ->action(function (array $data): void { - $this->saveRecapitiServizioOverrides($data['recapiti'] ?? []); - $this->loadUnita(); - - \Filament\Notifications\Notification::make() - ->title('Recapiti email aggiornati') - ->success() - ->send(); - }), - ]; + return []; } protected function getRuoliLabels(): array @@ -1254,7 +1064,13 @@ protected function refreshUnitaOptions(): void } } if (is_string($owner) && trim($owner) !== '') { - $label .= ' — ' . trim($owner); + $ownerTrimmed = trim($owner); + $parts = array_values(array_filter(array_map('trim', explode('/', $ownerTrimmed)))); + if (count($parts) > 1) { + $label .= ' — ' . $parts[0] . ' (+' . (count($parts) - 1) . ')'; + } else { + $label .= ' — ' . $ownerTrimmed; + } } if ($u->trashed()) { $label .= ' [archiviata]'; diff --git a/resources/views/filament/pages/condomini/stabile.blade.php b/resources/views/filament/pages/condomini/stabile.blade.php index f225779..09dcccd 100755 --- a/resources/views/filament/pages/condomini/stabile.blade.php +++ b/resources/views/filament/pages/condomini/stabile.blade.php @@ -1,62 +1,155 @@ -
- -
- @if(! $stabile) -
- Nessuno stabile attivo selezionato. Apri prima uno stabile da "Stabili" o dal Cruscotto. -
- @else -
-
-
-

- {{ $stabile->denominazione ?: ('Stabile #' . $stabile->id) }} -

-
- Codice: {{ $stabile->codice_operatore ?: '—' }} - @if($stabile->indirizzo) - · {{ $stabile->indirizzo }} - @endif - @if($stabile->citta) - · {{ $stabile->citta }} - @endif -
-
+ +
+ {{-- BARRA NAVIGAZIONE UNIFICATA E COMPATTA --}} + - -
- -
- -
- @include($this->tabView(), ['stabile' => $stabile]) -
+ @if($stabile) +
+ + + Stabile {{ $stabile->codice_stabile ?: $stabile->id }} +
@endif
-
-
+ + @if(! $stabile) +
+
+ ⚠️ +
+

Nessuno stabile attivo selezionato

+

Seleziona uno stabile dall'elenco stabili o dal cruscotto per visualizzarne i dettagli di gestione.

+
+
+
+ @else + {{-- HERO HEADER CARD DELLO STABILE --}} +
+
+
+
+

+ {{ $stabile->denominazione ?: ('Stabile #' . $stabile->id) }} +

+ + COD. {{ $stabile->codice_stabile ?: ($stabile->codice_operatore ?: '—') }} + + @if($stabile->codice_fiscale) + + CF: {{ $stabile->codice_fiscale }} + + @endif +
+
+ @if($stabile->indirizzo) + + 📍 + {{ $stabile->indirizzo }} + + @endif + @if($stabile->citta) + · {{ $stabile->cap ? $stabile->cap . ' ' : '' }}{{ $stabile->citta }} ({{ $stabile->provincia ?? 'RM' }}) + @endif + @if($stabile->foglio && $stabile->particella_catasto) + + Catasto: Fg. {{ $stabile->foglio }}, Part. {{ $stabile->particella_catasto }} + + @endif +
+
+ + {{-- QUICK ACTIONS PILLS --}} + +
+
+ + {{-- TAB NAVIGATION PILLS BAR --}} + @php + $tabIcons = [ + 'dati-generali' => '📋', + 'unita-immobiliari' => '🏠', + 'palazzine' => '🏢', + 'assicurazioni' => '🛡️', + 'tabelle-millesimali' => '📐', + 'rate-emesse' => '💶', + 'gestioni' => '📅', + 'documentazione' => '📁', + 'posta-ufficiale' => '✉️', + 'protocollo-comunicazioni' => '📜', + 'dati-bancari' => '🏦', + ]; + @endphp + +
+ +
+ + {{-- TAB CONTENT CONTAINER --}} +
+ @include($this->tabView(), ['stabile' => $stabile]) +
+ @endif +
+ diff --git a/skill-netgescon/control-tower/CURRENT-205.md b/skill-netgescon/control-tower/CURRENT-205.md index 7765505..4f1676a 100644 --- a/skill-netgescon/control-tower/CURRENT-205.md +++ b/skill-netgescon/control-tower/CURRENT-205.md @@ -16,9 +16,10 @@ ## Obiettivo 3. **Ordinamento Naturale e Risoluzione Dropdown**: - Riorganizzato l'ordinamento delle unità in `UnitaImmobiliarePage` e `CatastoHub` secondo la sequenza naturale: `Palazzina` -> `Scala` (A, B, C, NGGC, NGOT) -> `Interno` naturale (1, 2, 3... 10... 163) -> `Piano` -> `ID`. - `Scala A - Int. 1 [0013-A-1] — SPADAVECCHIA ALDO` è ora stabilmente e nativamente posizionata al 1° posto senza necessità di ricerca manuale. -4. **Sincronizzazione Scheda Unità Immobiliare (Tab Catasto)**: - - Implementati gli accessors sul Model `UnitaImmobiliare` per ereditare correttamente Foglio (`403`) e Particella (`60`) dallo stabile. - - Aggiornato il tab Catasto in `unita-immobiliare.blade.php` per visualizzare puntualmente: `Foglio 403`, `Particella 60`, `Subalterno 509`, `Categoria A/2`, `Classe 03`, `Consistenza 8,5 vani`, `Rendita € 2.524,18`. + - Rimozione dei pulsanti di header ingombranti in cima alla pagina (`getHeaderActions` -> `[]`). + - Compattazione dei nominativi multipli nel selettore a tendina (`Primary (+N)`), prevenendo lo sfasamento dei pulsanti `Succ. >` e del selettore ruolo. +4. **Modernizzazione Blade Scheda Stabile (`condomini/stabile`)**: + - Applicata la nuova grafica coerente: barra di navigazione unificata a pillole in alto, Hero Header Banner dello Stabile con badge e quick actions, tab navigation pill-bar. ## Output del Giro Operativo @@ -26,13 +27,14 @@ ## Output del Giro Operativo TASK_ID: task-87b64082c1 REPOSITORY: ssh://git@git.netgescon.it:2222/michele/netgescon-day0.git BRANCH: stabilization/205-zero -COMMIT: fc8351b +COMMIT: in_pubblicazione FILE_O_AREE_TOCCATE: - app/Console/Commands/GesconBonificaStabile0013Command.php - app/Models/UnitaImmobiliare.php - app/Filament/Pages/UnitaImmobiliarePage.php - app/Filament/Pages/Condomini/CatastoHub.php - resources/views/filament/pages/unita-immobiliare.blade.php +- resources/views/filament/pages/condomini/stabile.blade.php - tests/Feature/CatastoHubDbDrivenTest.php TEST_ESEGUITI: - ./vendor/bin/pest tests/Feature/CatastoHubDbDrivenTest.php tests/Feature/UnitaCondominoInquilinoRoleToggleTest.php tests/Feature/UnitaImmobiliarePageTest.php tests/Feature/UnitaGestioneTemporaleTest.php tests/Feature/AnagraficaUnicaCanonicaTest.php tests/Feature/BenedettoBonificaIdempotenteTest.php tests/Feature/ControlTowerPollCommandTest.php (19 passed, 111 assertions) @@ -40,6 +42,7 @@ ## Output del Giro Operativo - UNITA_REALI_0013: 42 unità canoniche (Scala A 1-10, Scala B 1-10 + Cantina 11, Scala C 1-10, NGGC 163-175, NGOT 99-111). - INQUILINO_NGGC_163: *Ottaviano Supershop Srls* correttamente associato come inquilino attivo. - FIRST_UNITA_ORDER: *0013-A-1 (Spadavecchia Aldo)* al primo posto nei dropdown e liste. +- DROPDOWN_COMPACT: Nominativi multipli compattati a singola riga `Nome (+N)`. - ZERO_MOCK: Dati catastali 100% DB-driven e Sister API live. BLOCCO_DATI: no BLOCCO_CONTRATTO: no