From b9b9e999f7bac41c23c384f8cba7b2b81e95207e Mon Sep 17 00:00:00 2001 From: michele Date: Sat, 4 Apr 2026 14:04:03 +0000 Subject: [PATCH] feat: aggiunge archivio e modal alla lavagna post-it --- .../Pages/Strumenti/PostItGestione.php | 198 ++++++++++++++---- .../strumenti/post-it-gestione.blade.php | 114 +++++++++- 2 files changed, 264 insertions(+), 48 deletions(-) diff --git a/app/Filament/Pages/Strumenti/PostItGestione.php b/app/Filament/Pages/Strumenti/PostItGestione.php index ba22bcc..ad8bb17 100644 --- a/app/Filament/Pages/Strumenti/PostItGestione.php +++ b/app/Filament/Pages/Strumenti/PostItGestione.php @@ -48,6 +48,10 @@ class PostItGestione extends Page public string $tecnicoScopeFilter = 'tutti'; + public ?string $selectedGroupModalKey = null; + + public string $selectedGroupModalMode = 'open'; + /** @var array */ public array $riaperturaNote = []; @@ -68,7 +72,7 @@ public function mount(): void $focus = (int) request()->query('focus_post_it', 0); $this->focusPostItId = $focus > 0 ? $focus : null; - if (in_array((string) request()->query('tab'), ['storico', 'lavagna'], true)) { + if (in_array((string) request()->query('tab'), ['storico', 'lavagna', 'archivio'], true)) { $this->activeTab = (string) request()->query('tab'); } } @@ -245,53 +249,76 @@ public function getRecentiVisibiliProperty() ->values(); } + public function getRecentiApertiVisibiliProperty() + { + return $this->recentiVisibili + ->filter(fn(ChiamataPostIt $postIt): bool => (string) $postIt->stato !== 'chiusa') + ->values(); + } + + public function getRecentiChiusiVisibiliProperty() + { + return $this->recentiVisibili + ->filter(fn(ChiamataPostIt $postIt): bool => (string) $postIt->stato === 'chiusa') + ->values(); + } + public function getRecentiRaggruppatiProperty() { - $groups = []; + return $this->buildGroupedCollection($this->recentiApertiVisibili); + } - foreach ($this->recentiVisibili as $postIt) { - if ($this->isInternalPostIt($postIt)) { - continue; - } + public function getRecentiChiusiRaggruppatiProperty() + { + return $this->buildGroupedCollection($this->recentiChiusiVisibili); + } - $groupKey = $this->buildGroupedPostItKey($postIt); - if (isset($groups[$groupKey])) { - $groups[$groupKey]['items'][] = $postIt; - $groups[$groupKey]['count']++; - $groups[$groupKey]['last_at'] = optional($postIt->chiamata_il)->format('d/m/Y H:i') ?: '-'; - $groups[$groupKey]['latest'] = $this->resolveLatestGroupedPostIt($groups[$groupKey]['items']); - $groups[$groupKey]['caller_label'] = $this->resolveGroupedCallerLabel($groups[$groupKey]['items']); - continue; - } + public function openGroupModal(string $modalKey, string $mode = 'open'): void + { + $this->selectedGroupModalKey = $modalKey; + $this->selectedGroupModalMode = in_array($mode, ['open', 'closed'], true) ? $mode : 'open'; + } - $groups[$groupKey] = [ - 'key' => $groupKey, - 'items' => [$postIt], - 'count' => 1, - 'latest' => $postIt, - 'caller_label' => $postIt->nome_chiamante ?: 'Chiamante non identificato', - 'phone' => (string) ($postIt->telefono ?? ''), - 'first_at' => optional($postIt->chiamata_il)->format('d/m/Y H:i') ?: '-', - 'last_at' => optional($postIt->chiamata_il)->format('d/m/Y H:i') ?: '-', - ]; + public function closeGroupModal(): void + { + $this->selectedGroupModalKey = null; + $this->selectedGroupModalMode = 'open'; + } + + public function getSelectedGroupModalProperty(): ?array + { + if ($this->selectedGroupModalKey === null) { + return null; } - return collect(array_values($groups)) - ->map(function (array $group): array { - usort($group['items'], function (ChiamataPostIt $left, ChiamataPostIt $right): int { - return ($right->chiamata_il?->getTimestamp() ?? 0) <=> ($left->chiamata_il?->getTimestamp() ?? 0); - }); + $groups = $this->selectedGroupModalMode === 'closed' + ? $this->recentiChiusiRaggruppati + : $this->recentiRaggruppati; - $group['latest'] = $this->resolveLatestGroupedPostIt($group['items']); - $oldest = collect($group['items']) - ->sortBy(fn(ChiamataPostIt $item) => $item->chiamata_il?->getTimestamp() ?? 0) - ->first(); - $group['first_at'] = optional($oldest?->chiamata_il)->format('d/m/Y H:i') ?: '-'; - $group['last_at'] = optional($group['latest']->chiamata_il)->format('d/m/Y H:i') ?: '-'; + return $groups->firstWhere('modal_key', $this->selectedGroupModalKey); + } - return $group; + public function getSelectedGroupModalDaysProperty() + { + $group = $this->selectedGroupModal; + if (! is_array($group)) { + return collect(); + } + + return collect($group['items']) + ->groupBy(function (ChiamataPostIt $item): string { + return $item->chiamata_il?->format('d/m/Y') ?: 'Data non disponibile'; + }) + ->map(function ($items, string $day): array { + $sorted = collect($items) + ->sortByDesc(fn(ChiamataPostIt $item) => $item->chiamata_il?->getTimestamp() ?? 0) + ->values(); + + return [ + 'day' => $day, + 'items' => $sorted, + ]; }) - ->sortByDesc(fn(array $group) => $group['latest']->chiamata_il?->getTimestamp() ?? 0) ->values(); } @@ -585,6 +612,11 @@ private function buildTicketDescriptionFromPostIt(int $postItId, ChiamataPostIt private function buildGroupedPostItKey(ChiamataPostIt $postIt): string { + $rubricaId = $this->resolveGroupedRubricaId($postIt); + if ($rubricaId !== null) { + return 'rubrica:' . $rubricaId; + } + $phone = $this->normalizeGroupedPhone((string) ($postIt->telefono ?? '')); if ($phone !== '') { return 'phone:' . $phone; @@ -600,6 +632,11 @@ private function isInternalPostIt(ChiamataPostIt $postIt): bool return $this->isInternalSmdrMessage($message); } + $phone = preg_replace('/\D+/', '', (string) ($postIt->telefono ?? '')); + if (is_string($phone) && $phone !== '' && $this->isKnownPbxExtension($phone)) { + return true; + } + return false; } @@ -625,6 +662,16 @@ private function normalizeGroupedPhone(string $phone): string return preg_replace('/\D+/', '', $phone) ?: ''; } + private function resolveGroupedRubricaId(ChiamataPostIt $postIt): ?int + { + $rubricaId = (int) ($postIt->rubrica_id ?? 0); + if ($rubricaId > 0) { + return $rubricaId; + } + + return $this->resolveRubricaIdByPhone((string) ($postIt->telefono ?? '')); + } + /** * @param array $items */ @@ -643,6 +690,17 @@ private function resolveLatestGroupedPostIt(array $items): ChiamataPostIt private function resolveGroupedCallerLabel(array $items): string { foreach ($items as $item) { + $rubricaId = $this->resolveGroupedRubricaId($item); + if ($rubricaId) { + $rubrica = RubricaUniversale::query()->find($rubricaId, ['ragione_sociale', 'nome', 'cognome']); + if ($rubrica) { + $label = trim((string) ($rubrica->ragione_sociale ?: (($rubrica->nome ?? '') . ' ' . ($rubrica->cognome ?? '')))); + if ($label !== '') { + return $label; + } + } + } + $label = trim((string) ($item->nome_chiamante ?? '')); if ($label !== '') { return $label; @@ -652,6 +710,70 @@ private function resolveGroupedCallerLabel(array $items): string return 'Chiamante non identificato'; } + private function resolveGroupedPhoneLabel(array $items): string + { + foreach ($items as $item) { + $phone = trim((string) ($item->telefono ?? '')); + if ($phone !== '') { + return $phone; + } + } + + return ''; + } + + private function buildGroupedCollection($items) + { + $groups = []; + + foreach ($items as $postIt) { + if ($this->isInternalPostIt($postIt)) { + continue; + } + + $groupKey = $this->buildGroupedPostItKey($postIt); + if (isset($groups[$groupKey])) { + $groups[$groupKey]['items'][] = $postIt; + $groups[$groupKey]['count']++; + continue; + } + + $groups[$groupKey] = [ + 'key' => $groupKey, + 'modal_key' => md5($groupKey), + 'items' => [$postIt], + 'count' => 1, + 'latest' => $postIt, + 'caller_label' => $postIt->nome_chiamante ?: 'Chiamante non identificato', + 'phone' => (string) ($postIt->telefono ?? ''), + 'first_at' => optional($postIt->chiamata_il)->format('d/m/Y H:i') ?: '-', + 'last_at' => optional($postIt->chiamata_il)->format('d/m/Y H:i') ?: '-', + ]; + } + + return collect(array_values($groups)) + ->map(function (array $group): array { + usort($group['items'], function (ChiamataPostIt $left, ChiamataPostIt $right): int { + return ($right->chiamata_il?->getTimestamp() ?? 0) <=> ($left->chiamata_il?->getTimestamp() ?? 0); + }); + + $group['latest'] = $this->resolveLatestGroupedPostIt($group['items']); + $oldest = collect($group['items']) + ->sortBy(fn(ChiamataPostIt $item) => $item->chiamata_il?->getTimestamp() ?? 0) + ->first(); + $group['first_at'] = optional($oldest?->chiamata_il)->format('d/m/Y H:i') ?: '-'; + $group['last_at'] = optional($group['latest']->chiamata_il)->format('d/m/Y H:i') ?: '-'; + $group['caller_label'] = $this->resolveGroupedCallerLabel($group['items']); + $group['phone'] = $this->resolveGroupedPhoneLabel($group['items']); + $group['visible_items'] = collect($group['items'])->take(4)->values()->all(); + $group['hidden_count'] = max(0, count($group['items']) - count($group['visible_items'])); + + return $group; + }) + ->sortByDesc(fn(array $group) => $group['latest']->chiamata_il?->getTimestamp() ?? 0) + ->values(); + } + public function richiediClickToCallDaMessaggio(int $messageId): void { $user = Auth::user(); diff --git a/resources/views/filament/pages/strumenti/post-it-gestione.blade.php b/resources/views/filament/pages/strumenti/post-it-gestione.blade.php index 4979b05..649d2f0 100644 --- a/resources/views/filament/pages/strumenti/post-it-gestione.blade.php +++ b/resources/views/filament/pages/strumenti/post-it-gestione.blade.php @@ -18,6 +18,9 @@ + @@ -118,10 +121,10 @@
@forelse($this->recentiRaggruppati as $gruppo) @php($box = $gruppo['latest']) -
+
-
{{ $box->oggetto ?: 'Post-it chiamate' }}
+
{{ $box->direzione === 'in_uscita' ? 'Chiamata in uscita' : 'Chiamata in arrivo' }}
{{ $gruppo['caller_label'] }} @if($gruppo['phone'] !== '') @@ -140,27 +143,32 @@ Aperto dal {{ $gruppo['first_at'] }} al {{ $gruppo['last_at'] }}
-
- @foreach($gruppo['items'] as $item) -
+
+ @foreach($gruppo['visible_items'] as $item) +
-
{{ $item->oggetto ?: 'Senza oggetto' }}
-
{{ optional($item->chiamata_il)->format('d/m/Y H:i') }}
+
{{ $item->oggetto ?: 'Senza oggetto' }}
+
{{ optional($item->chiamata_il)->format('d/m/Y H:i') }}
{{ $item->stato }}
@if($item->stabile) -
{{ $item->stabile->denominazione ?: ('Stabile #' . $item->stabile->id) }}
+
{{ $item->stabile->denominazione ?: ('Stabile #' . $item->stabile->id) }}
@endif - -
{{ $item->nota }}
@endforeach + + @if($gruppo['hidden_count'] > 0) +
+ Altre {{ $gruppo['hidden_count'] }} chiamate visibili nel dettaglio. +
+ @endif
+ Vedi dettaglio Apri Post-it @if($box->ticket_id) Apri ticket @@ -172,6 +180,49 @@ @endforelse
+ @elseif($activeTab === 'archivio') +
+
+

Archivio Post-it chiusi

+

I Post-it chiusi restano collegati al numero o al nominativo e possono essere riaperti quando serve. Anche qui le chiamate interne sono escluse.

+
+ +
+ @forelse($this->recentiChiusiRaggruppati as $gruppo) + @php($box = $gruppo['latest']) +
+
+
+
Archivio chiuso
+
{{ $gruppo['caller_label'] }}@if($gruppo['phone'] !== '') - {{ $gruppo['phone'] }}@endif
+
+ {{ $gruppo['count'] }} chiusi +
+ +
Dal {{ $gruppo['first_at'] }} al {{ $gruppo['last_at'] }}
+ +
+ @foreach($gruppo['visible_items'] as $item) +
+
{{ $item->oggetto ?: 'Senza oggetto' }}
+
{{ optional($item->chiamata_il)->format('d/m/Y H:i') }}
+
+ @endforeach + @if($gruppo['hidden_count'] > 0) +
Altri {{ $gruppo['hidden_count'] }} Post-it chiusi nel dettaglio.
+ @endif +
+ +
+ Vedi dettaglio + Apri ultimo Post-it +
+
+ @empty +
Nessun Post-it chiuso disponibile in archivio.
+ @endforelse +
+
@elseif(in_array($activeTab, ['smdr', 'csta'], true))
@php($isCstaTab = $activeTab === 'csta') @@ -333,6 +384,49 @@
@endif + + @if($this->selectedGroupModal) +
+
+
+
+
{{ $this->selectedGroupModal['caller_label'] }}@if($this->selectedGroupModal['phone'] !== '') - {{ $this->selectedGroupModal['phone'] }}@endif
+
{{ $this->selectedGroupModal['count'] }} chiamate totali ยท {{ $selectedGroupModalMode === 'closed' ? 'archivio chiusi' : 'lavagna aperti' }}
+
+ +
+ +
+
+ @foreach($this->selectedGroupModalDays as $day) +
+
{{ $day['day'] }}
+
+ @foreach($day['items'] as $item) +
+
+
+
{{ $item->oggetto ?: 'Senza oggetto' }}
+
{{ optional($item->chiamata_il)->format('d/m/Y H:i') }}
+
+ {{ $item->stato }} +
+ + @if($item->stabile) +
{{ $item->stabile->denominazione ?: ('Stabile #' . $item->stabile->id) }}
+ @endif + +
{{ $item->nota }}
+
+ @endforeach +
+
+ @endforeach +
+
+
+
+ @endif @endif