From f088dba4bf78a5dec24ebc4e4ac7b5cf6fec7a0b Mon Sep 17 00:00:00 2001 From: Inext68 Date: Tue, 26 May 2026 11:47:36 +0200 Subject: [PATCH] fino a eventi e report prima del tipo di eventi --- .phpunit.result.cache | 1 + MEMORY.md | 28 + app/Http/Controllers/DocumentoController.php | 12 +- app/Http/Controllers/EmailController.php | 32 +- app/Http/Controllers/EventoController.php | 190 +++- .../Controllers/GruppoAvatarController.php | 77 ++ app/Http/Controllers/GruppoController.php | 132 +-- app/Http/Controllers/ReportController.php | 41 + app/Models/Evento.php | 28 +- app/Models/Gruppo.php | 48 +- ...ge_occorrenza_mese_to_string_in_eventi.php | 22 + .../documenti/preview-fallback.blade.php | 86 ++ resources/views/eventi/create.blade.php | 10 + resources/views/eventi/edit.blade.php | 10 + resources/views/eventi/index.blade.php | 3 + resources/views/gruppi/show.blade.php | 113 ++- .../views/report/print-preview.blade.php | 399 ++++++++ resources/views/report/result.blade.php | 3 + routes/console.php | 14 +- routes/web.php | 5 + .../00edc551e83193362ca154488ca4729a.php | 3 + .../14ee0174ec36b16b90e353b8b794befc.php | 720 -------------- .../2b95271a0c96906d02e3aa9d1bfb863e.php | 75 -- .../409969b30ed6a6609c8c6acb7f2e2713.php | 400 ++++++++ .../565b6f56aa782bc9d430e45e3a15433f.php | 149 --- .../6a06deecbab62a322d4e7146569a3da0.php | 10 + .../770f7793fb2506075291f5825b49a758.php | 350 ------- .../77ae2092ee84e47a55a05ab55f7003a0.php | 438 --------- .../80d6e427e76e80ae16c8694fb235b812.php | 117 --- .../81e2bcc646165a88dad1b7f9520fc235.php | 78 -- .../8888d039c9a4bdb124fcf43b0ae7e371.php | 674 ------------- .../994dbe51ea1920c69a8b0e217fb3f81a.php | 631 ------------ .../9cacf54b36643c217670450c9fcf532e.php | 444 --------- .../a32b10b44eee0941ea0a3f2990b69de8.php | 98 -- .../a4022627a632b7187b550e38ad0744a5.php | 165 ---- .../a4fd62c2ab5143a4dd89e7b8e9c2484a.php | 180 ---- .../a59e859b9d52c149f06a0f5ca0dce3cf.php | 260 ----- .../a6267d64f58c4883f210293e4b730a9c.php | 97 -- .../b7fb0777954b7384c283d9ea1db9ba0f.php | 100 -- .../d751874ab64bcc49bdf4b12b4fefba7a.php | 3 + .../e3b2763292eb5c70536d0e5ce1ceb1b1.php | 104 ++ .../e6056fdcc373077ccd717e502c884188.php | 922 ------------------ .../e8f60d5f5b2a4c688f1bc12477b209df.php | 108 -- .../f7b5acd723ad1e4180d8c10d45f3d46f.php | 529 ---------- .../f98c27feaa80ae6e7f6c002c26f6107d.php | 109 --- .../fc56695b593a318c0d96a4e22b861473.php | 480 --------- tests/Feature/CalendarEventsTest.php | 134 +++ 47 files changed, 1733 insertions(+), 6899 deletions(-) create mode 100644 .phpunit.result.cache create mode 100644 app/Http/Controllers/GruppoAvatarController.php create mode 100644 database/migrations/2026_05_26_082316_change_occorrenza_mese_to_string_in_eventi.php create mode 100644 resources/views/documenti/preview-fallback.blade.php create mode 100644 resources/views/report/print-preview.blade.php delete mode 100755 storage/framework/views/14ee0174ec36b16b90e353b8b794befc.php delete mode 100755 storage/framework/views/2b95271a0c96906d02e3aa9d1bfb863e.php create mode 100755 storage/framework/views/409969b30ed6a6609c8c6acb7f2e2713.php delete mode 100755 storage/framework/views/565b6f56aa782bc9d430e45e3a15433f.php delete mode 100755 storage/framework/views/770f7793fb2506075291f5825b49a758.php delete mode 100755 storage/framework/views/77ae2092ee84e47a55a05ab55f7003a0.php delete mode 100755 storage/framework/views/80d6e427e76e80ae16c8694fb235b812.php delete mode 100755 storage/framework/views/81e2bcc646165a88dad1b7f9520fc235.php delete mode 100755 storage/framework/views/8888d039c9a4bdb124fcf43b0ae7e371.php delete mode 100755 storage/framework/views/994dbe51ea1920c69a8b0e217fb3f81a.php delete mode 100755 storage/framework/views/9cacf54b36643c217670450c9fcf532e.php delete mode 100755 storage/framework/views/a32b10b44eee0941ea0a3f2990b69de8.php delete mode 100755 storage/framework/views/a4022627a632b7187b550e38ad0744a5.php delete mode 100755 storage/framework/views/a4fd62c2ab5143a4dd89e7b8e9c2484a.php delete mode 100755 storage/framework/views/a59e859b9d52c149f06a0f5ca0dce3cf.php delete mode 100755 storage/framework/views/a6267d64f58c4883f210293e4b730a9c.php delete mode 100755 storage/framework/views/b7fb0777954b7384c283d9ea1db9ba0f.php create mode 100755 storage/framework/views/e3b2763292eb5c70536d0e5ce1ceb1b1.php delete mode 100755 storage/framework/views/e6056fdcc373077ccd717e502c884188.php delete mode 100755 storage/framework/views/e8f60d5f5b2a4c688f1bc12477b209df.php delete mode 100755 storage/framework/views/f7b5acd723ad1e4180d8c10d45f3d46f.php delete mode 100755 storage/framework/views/f98c27feaa80ae6e7f6c002c26f6107d.php delete mode 100755 storage/framework/views/fc56695b593a318c0d96a4e22b861473.php create mode 100644 tests/Feature/CalendarEventsTest.php diff --git a/.phpunit.result.cache b/.phpunit.result.cache new file mode 100644 index 00000000..389fec3b --- /dev/null +++ b/.phpunit.result.cache @@ -0,0 +1 @@ +{"version":2,"defects":{"Tests\\Feature\\ExampleTest::test_the_application_returns_a_successful_response":7,"Tests\\Feature\\CalendarEventsTest::test_generate_settimanale_events_produces_weekly_occurrences":7},"times":{"Tests\\Unit\\ExampleTest::test_that_true_is_true":0,"Tests\\Feature\\ExampleTest::test_the_application_returns_a_successful_response":0.111,"Tests\\Feature\\CalendarEventsTest::test_find_first_sunday_of_june_2026":0.015,"Tests\\Feature\\CalendarEventsTest::test_find_second_saturday_of_june_2026":0.001,"Tests\\Feature\\CalendarEventsTest::test_find_fifth_sunday_returns_null_when_not_in_month":0.001,"Tests\\Feature\\CalendarEventsTest::test_generate_mensile_events_for_all_months":0.014,"Tests\\Feature\\CalendarEventsTest::test_generate_mensile_events_respects_selected_months":0.002,"Tests\\Feature\\CalendarEventsTest::test_generate_annuale_events_produces_correct_dates":0.002,"Tests\\Feature\\CalendarEventsTest::test_generate_settimanale_events_produces_weekly_occurrences":0.004}} \ No newline at end of file diff --git a/MEMORY.md b/MEMORY.md index e08a2b3c..a0db9bf5 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -21,6 +21,7 @@ Laravel 13 / PHP 8.4 project for parish management (Glastree). Full codebase exi ### ⚠️ IN COMPLETAMENTO - Sistema Email: funziona al 95%, SMTP potrebbe necessitare credenziali corrette +- Nuova implementazione: avatar gruppi, event types, email sync logging --- @@ -489,3 +490,30 @@ php artisan route:list --name=email - `app/Http/Controllers/ReportController.php`: righe 389-397 e 532, corretto nome colonna (Last updated: 25 Maggio 2026 - Fix report eventi_calendario, colonna data) + +### 25 Maggio 2026 - Fix Gruppi Table Hierarchy +- **Problema**: La visualizzazione a tabella dei gruppi non mostrava correttamente la gerarchia padre-figlio +- **Soluzione**: + - Aggiunto metodo `sortGruppiHierarchically()` in `GruppoController` per ordinare i gruppi in modo gerarchico + - La tabella ora mostra prima i gruppi root, poi i loro figli in ordine annidato + - Aggiunta eager loading `avatar` per supportare il futuro avatar dei gruppi +- **Files modificati**: + - `app/Http/Controllers/GruppoController.php`: aggiunto `sortGruppiHierarchically()`, `addChildrenRecursive()`, aggiunto 'avatar' a eager loading + +### 25 Maggio 2026 - Group Avatar Support +- **Funzionalità**: I gruppi ora possono avere un avatar/logo come gli individui +- **Implementazione**: + - Aggiunto metodo `avatar()` in `Gruppo.php` (relazione HasOne a Documento con tipologia 'avatar') + - Aggiunto accessor `getAvatarUrlAttribute()` per ottenere l'URL dell'avatar + - Eager loading `avatar` aggiunto in `GruppoController@index()` + - View `gruppi/index.blade.php` aggiornata per mostrare l'avatar nella tabella + - View `gruppi/show.blade.php` aggiornata per mostrare l'avatar del gruppo + - View `gruppi/create.blade.php` e `edit.blade.php` aggiornate per permettere upload avatar +- **Files modificati**: + - `app/Models/Gruppo.php`: aggiunto `avatar()`, `getAvatarUrlAttribute()` + - `app/Http/Controllers/GruppoController.php`: aggiunto eager loading `avatar` + - `resources/views/gruppi/index.blade.php`: colonna avatar nella tabella + - `resources/views/gruppi/show.blade.php`: avatar nella header card + - `resources/views/gruppi/create.blade.php` e `edit.blade.php`: upload avatar + +(Last updated: 25 Maggio 2026 - Fix gruppi hierarchy, group avatar support) diff --git a/app/Http/Controllers/DocumentoController.php b/app/Http/Controllers/DocumentoController.php index e040e095..1a47f76b 100644 --- a/app/Http/Controllers/DocumentoController.php +++ b/app/Http/Controllers/DocumentoController.php @@ -192,11 +192,19 @@ class DocumentoController extends Controller $fullPath = Storage::disk('local')->path($documento->file_path); $mimeType = $documento->mime_type; - if (str_starts_with($mimeType, 'image/')) { + $previewableMimeTypes = [ + 'image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml', + 'application/pdf', + 'text/plain', 'text/html', 'text/csv', + ]; + + if (in_array($mimeType, $previewableMimeTypes)) { return response()->file($fullPath, ['Content-Type' => $mimeType]); } - return response()->file($fullPath, ['Content-Type' => $mimeType]); + return response()->view('documenti.preview-fallback', [ + 'documento' => $documento, + ])->header('X-Preview-Fallback', 'true'); } public function destroy($documento) diff --git a/app/Http/Controllers/EmailController.php b/app/Http/Controllers/EmailController.php index 7798dcd8..658ad289 100644 --- a/app/Http/Controllers/EmailController.php +++ b/app/Http/Controllers/EmailController.php @@ -342,8 +342,11 @@ class EmailController extends Controller public function syncEmails() { + \Illuminate\Support\Facades\Log::info('Email sync started'); + $settings = EmailSetting::getActive(); if (!$settings) { + \Illuminate\Support\Facades\Log::warning('Email sync aborted: no active email configuration'); throw new \Exception('Nessuna configurazione email attiva'); } @@ -351,6 +354,8 @@ class EmailController extends Controller $mailbox = $this->connectImap($settings); + \Illuminate\Support\Facades\Log::info('IMAP connection established', ['host' => $settings->imap_host]); + $folderMappings = [ 'INBOX' => 'inbox', 'Sent' => 'sent', @@ -362,11 +367,19 @@ class EmailController extends Controller '[Gmail]/Trash' => 'trash', ]; + $totalProcessed = 0; + $totalNew = 0; + foreach (array_keys($folderMappings) as $imapFolderName) { try { $folder = $mailbox->folders()->find($imapFolderName); - if (!$folder) continue; + if (!$folder) { + \Illuminate\Support\Facades\Log::debug('IMAP folder not found', ['folder' => $imapFolderName]); + continue; + } + \Illuminate\Support\Facades\Log::info('Processing IMAP folder', ['folder' => $imapFolderName]); + $messages = $folder->messages() ->withHeaders() ->withBody() @@ -374,14 +387,31 @@ class EmailController extends Controller ->limit(100) ->get(); + \Illuminate\Support\Facades\Log::info('Messages fetched from folder', ['folder' => $imapFolderName, 'count' => count($messages)]); + foreach ($messages as $imapMessage) { + $totalProcessed++; + $messageId = $imapMessage->messageId() ?? uniqid('msg_'); + $existing = EmailMessage::where('message_id', $messageId)->first(); + + if ($existing) { + continue; + } + $this->processImapMessage($imapMessage, $imapFolderName); + $totalNew++; } } catch (\Exception $e) { + \Illuminate\Support\Facades\Log::error('Error processing IMAP folder', ['folder' => $imapFolderName, 'error' => $e->getMessage()]); continue; } } + \Illuminate\Support\Facades\Log::info('Email sync completed', [ + 'processed' => $totalProcessed, + 'new' => $totalNew, + ]); + return true; } diff --git a/app/Http/Controllers/EventoController.php b/app/Http/Controllers/EventoController.php index f3625dc4..2ee5ae59 100644 --- a/app/Http/Controllers/EventoController.php +++ b/app/Http/Controllers/EventoController.php @@ -67,14 +67,15 @@ class EventoController extends Controller 'giorno_settimana' => 'nullable|integer|min:0|max:6', 'giorno_mese' => 'nullable|integer|min:1|max:31', 'occorrenza_mese' => 'nullable|string|max:10', - 'mesi_recorrenza' => 'nullable|string', + 'mesi_recorrenza' => 'nullable|array', + 'mesi_recorrenza.*' => 'integer|min:1|max:12', 'mese_annuale' => 'nullable|integer|min:1|max:12', 'ora_inizio' => 'nullable|date_format:H:i', 'data_specifica' => 'nullable|date', 'durata_minuti' => 'nullable|integer|min:1', 'descrizione' => 'nullable|string', 'note' => 'nullable|string', - 'is_incontro_gruppo' => 'nullable|boolean', + 'is_incontro_gruppo' => 'nullable', 'gruppi' => 'nullable|array', 'gruppi.*' => 'exists:gruppi,id', 'responsabili' => 'nullable|array', @@ -144,14 +145,15 @@ class EventoController extends Controller 'giorno_settimana' => 'nullable|integer|min:0|max:6', 'giorno_mese' => 'nullable|integer|min:1|max:31', 'occorrenza_mese' => 'nullable|string|max:10', - 'mesi_recorrenza' => 'nullable|string', + 'mesi_recorrenza' => 'nullable|array', + 'mesi_recorrenza.*' => 'integer|min:1|max:12', 'mese_annuale' => 'nullable|integer|min:1|max:12', 'ora_inizio' => 'nullable|date_format:H:i', 'data_specifica' => 'nullable|date', 'durata_minuti' => 'nullable|integer|min:1', 'descrizione' => 'nullable|string', 'note' => 'nullable|string', - 'is_incontro_gruppo' => 'nullable|boolean', + 'is_incontro_gruppo' => 'nullable', 'gruppi' => 'nullable|array', 'gruppi.*' => 'exists:gruppi,id', 'responsabili' => 'nullable|array', @@ -237,40 +239,168 @@ class EventoController extends Controller foreach ($eventi as $evento) { if ($evento->tipo_recorrenza === 'singolo' || $evento->tipo_recorrenza === null) { if ($evento->data_specifica) { - $events[] = [ - 'id' => $evento->id, - 'title' => $evento->nome_evento, - 'start' => $evento->data_specifica->format('Y-m-d') . ($evento->ora_inizio ? 'T' . $evento->ora_inizio->format('H:i') : ''), - 'url' => $baseUrl . '/eventi/' . $evento->id, - 'backgroundColor' => $this->getEventoColor($evento), - 'borderColor' => $this->getEventoColor($evento), - ]; + $events[] = $this->buildCalendarEvent($evento, $evento->data_specifica); } } elseif ($evento->tipo_recorrenza === 'settimanale' && $evento->giorno_settimana !== null) { - $startDate = \Carbon\Carbon::parse($start); - $endDate = \Carbon\Carbon::parse($end); - - $current = $startDate->copy(); - while ($current <= $endDate) { - $nextOccurrence = $current->copy()->next($evento->giorno_settimana); - if ($nextOccurrence >= $startDate && $nextOccurrence <= $endDate) { - $events[] = [ - 'id' => $evento->id . '_' . $nextOccurrence->format('Ymd'), - 'title' => $evento->nome_evento, - 'start' => $nextOccurrence->format('Y-m-d') . ($evento->ora_inizio ? 'T' . $evento->ora_inizio->format('H:i') : ''), - 'url' => $baseUrl . '/eventi/' . $evento->id, - 'backgroundColor' => $this->getEventoColor($evento), - 'borderColor' => $this->getEventoColor($evento), - ]; - } - $current->addWeek(); - } + $events = array_merge($events, $this->generateSettimanaleEvents($evento, $start, $end, $baseUrl)); + } elseif ($evento->tipo_recorrenza === 'mensile' && $evento->occorrenza_mese) { + $events = array_merge($events, $this->generateMensileEvents($evento, $start, $end, $baseUrl)); + } elseif ($evento->tipo_recorrenza === 'annuale' && $evento->mese_annuale) { + $events = array_merge($events, $this->generateAnnualeEvents($evento, $start, $end, $baseUrl)); + } elseif ($evento->tipo_recorrenza === 'altro' && $evento->giorno_settimana !== null) { + $events = array_merge($events, $this->generateAltroEvents($evento, $start, $end, $baseUrl)); } } return response()->json($events); } + protected function buildCalendarEvent(Evento $evento, $date, ?string $baseUrl = null): array + { + if ($date instanceof \Carbon\Carbon) { + $carbon = $date; + } elseif (is_string($date)) { + $carbon = \Carbon\Carbon::parse($date); + } else { + $carbon = $date; + } + + $baseUrl = $baseUrl ?? request()->getSchemeAndHttpHost(); + + return [ + 'id' => $evento->id . '_' . $carbon->format('Ymd'), + 'title' => $evento->nome_evento, + 'start' => $carbon->format('Y-m-d') . ($evento->ora_inizio ? 'T' . $evento->ora_inizio->format('H:i') : ''), + 'url' => $baseUrl . '/eventi/' . $evento->id, + 'backgroundColor' => $this->getEventoColor($evento), + 'borderColor' => $this->getEventoColor($evento), + ]; + } + + protected function generateSettimanaleEvents(Evento $evento, $start, $end, $baseUrl): array + { + $startDate = \Carbon\Carbon::parse($start); + $endDate = \Carbon\Carbon::parse($end); + $events = []; + + $current = $startDate->copy()->startOfWeek(); + $targetDay = $evento->giorno_settimana; + + while ($current <= $endDate) { + $dayOfWeek = (int) $current->format('w'); + if ($dayOfWeek === $targetDay && $current >= $startDate && $current <= $endDate) { + $events[] = $this->buildCalendarEvent($evento, $current->copy(), $baseUrl); + } + $current->addDay(); + } + + return $events; + } + + protected function generateMensileEvents(Evento $evento, $start, $end, $baseUrl): array + { + $startDate = \Carbon\Carbon::parse($start); + $endDate = \Carbon\Carbon::parse($end); + $events = []; + + $parts = explode(',', $evento->occorrenza_mese); + if (count($parts) !== 2) { + return $events; + } + + $occorrenza = (int) $parts[0]; + $giornoSettimana = (int) $parts[1]; + + $mesiSelezionati = []; + if ($evento->mesi_recorrenza) { + $mesiSelezionati = array_map('intval', explode(',', $evento->mesi_recorrenza)); + } + + $currentMonth = $startDate->copy()->startOfMonth(); + $endMonth = $endDate->copy()->startOfMonth(); + + while ($currentMonth <= $endMonth) { + $monthNumber = (int) $currentMonth->format('n'); + + if (empty($mesiSelezionati) || in_array($monthNumber, $mesiSelezionati)) { + $occurrenceDate = $this->findNthWeekdayOfMonth($currentMonth, $occorrenza, $giornoSettimana); + + if ($occurrenceDate && $occurrenceDate >= $startDate && $occurrenceDate <= $endDate) { + $events[] = $this->buildCalendarEvent($evento, $occurrenceDate, $baseUrl); + } + } + + $currentMonth->addMonth(); + } + + return $events; + } + + protected function findNthWeekdayOfMonth(\Carbon\Carbon $month, int $occurrence, int $targetDayOfWeek): ?\Carbon\Carbon + { + $firstOfMonth = $month->copy()->startOfMonth(); + $firstDayOfWeek = (int) $firstOfMonth->format('w'); + + $daysUntilTarget = ($targetDayOfWeek - $firstDayOfWeek + 7) % 7; + $firstOccurrence = $firstOfMonth->copy()->addDays($daysUntilTarget); + + $targetDate = $firstOccurrence->copy()->addWeeks($occurrence - 1); + + if ((int) $targetDate->format('n') !== (int) $month->format('n')) { + return null; + } + + return $targetDate; + } + + protected function generateAnnualeEvents(Evento $evento, $start, $end, $baseUrl): array + { + $startDate = \Carbon\Carbon::parse($start); + $endDate = \Carbon\Carbon::parse($end); + $events = []; + + $year = $startDate->year; + $endYear = $endDate->year; + + while ($year <= $endYear + 1) { + $day = $evento->giorno_mese ?? 1; + $eventDate = \Carbon\Carbon::create($year, $evento->mese_annuale, $day); + + $daysInMonth = $eventDate->daysInMonth; + if ($evento->giorno_mese && $evento->giorno_mese > $daysInMonth) { + $eventDate = $eventDate->endOfMonth(); + } + + if ($eventDate >= $startDate && $eventDate <= $endDate) { + $events[] = $this->buildCalendarEvent($evento, $eventDate, $baseUrl); + } + + $year++; + } + + return $events; + } + + protected function generateAltroEvents(Evento $evento, $start, $end, $baseUrl): array + { + $startDate = \Carbon\Carbon::parse($start); + $endDate = \Carbon\Carbon::parse($end); + $events = []; + + $current = $startDate->copy()->startOfWeek(); + $targetDay = $evento->giorno_settimana; + + while ($current <= $endDate) { + $dayOfWeek = (int) $current->format('w'); + if ($dayOfWeek === $targetDay && $current >= $startDate && $current <= $endDate) { + $events[] = $this->buildCalendarEvent($evento, $current->copy(), $baseUrl); + } + $current->addDay(); + } + + return $events; + } + private function getEventoColor(Evento $evento): string { $colors = [ diff --git a/app/Http/Controllers/GruppoAvatarController.php b/app/Http/Controllers/GruppoAvatarController.php new file mode 100644 index 00000000..28b654c9 --- /dev/null +++ b/app/Http/Controllers/GruppoAvatarController.php @@ -0,0 +1,77 @@ +authorizeWrite('gruppi'); + + $request->validate([ + 'avatar' => 'required|image|mimes:jpeg,png,gif,webp|max:2048', + ]); + + $existing = $gruppo->avatar; + if ($existing) { + if ($existing->file_path && Storage::disk('local')->exists($existing->file_path)) { + Storage::disk('local')->delete($existing->file_path); + } + $existing->delete(); + } + + $file = $request->file('avatar'); + $path = $file->store('avatars/gruppi', 'local'); + + $documento = Documento::create([ + 'user_id' => auth()->id(), + 'nome_file' => $file->getClientOriginalName(), + 'file_path' => $path, + 'tipologia' => 'avatar', + 'visibilita' => 'gruppo', + 'visibilita_target_id' => $gruppo->id, + 'visibilita_target_type' => Gruppo::class, + 'mime_type' => $file->getMimeType(), + 'dimensione' => $file->getSize(), + ]); + + $gruppo->avatar()->save($documento); + + return response()->json(['success' => true, 'avatar_url' => $documento->file_path]); + } + + public function show(Gruppo $gruppo) + { + $this->authorizeRead('gruppi'); + + $avatar = $gruppo->avatar; + if (!$avatar || !$avatar->file_path || !Storage::disk('local')->exists($avatar->file_path)) { + abort(404); + } + + $fullPath = Storage::disk('local')->path($avatar->file_path); + return response()->file($fullPath, ['Content-Type' => $avatar->mime_type]); + } + + public function destroy(Gruppo $gruppo) + { + $this->authorizeWrite('gruppi'); + + $avatar = $gruppo->avatar; + if ($avatar) { + if ($avatar->file_path && Storage::disk('local')->exists($avatar->file_path)) { + Storage::disk('local')->delete($avatar->file_path); + } + $avatar->delete(); + } + + return response()->json(['success' => true]); + } +} diff --git a/app/Http/Controllers/GruppoController.php b/app/Http/Controllers/GruppoController.php index d6e53998..bd4c2303 100644 --- a/app/Http/Controllers/GruppoController.php +++ b/app/Http/Controllers/GruppoController.php @@ -1,5 +1,7 @@ orderBy('nome') - ->get() - ->map(function ($gruppo) { - $depth = 0; - $parent = $gruppo->parent; - while ($parent) { - $depth++; - $parent = $parent->parent; - } - $gruppo->depth = $depth; - return $gruppo; - }); - - if ($viewMode === 'table') { - $gruppi = $this->sortGruppiHierarchically($allGruppi); - } else { - $gruppi = $allGruppi; - } - - return view('gruppi.index', compact( - 'gruppi', - 'allColumns', - 'visibleColumns', - 'viewMode', - 'vista' - )); - } - - protected function sortGruppiHierarchically($gruppi) - { - $rootGroups = $gruppi->filter(fn($g) => $g->parent_id === null)->sortBy('nome'); - $sorted = collect(); - - foreach ($rootGroups as $root) { - $sorted->push($root); - $this->addChildrenRecursive($root, $gruppi, $sorted); - } - - return $sorted; - } - - protected function addChildrenRecursive($parent, $allGruppi, &$sorted) - { - $children = $allGruppi->filter(fn($g) => $g->parent_id === $parent->id)->sortBy('nome'); - - foreach ($children as $child) { - $sorted->push($child); - $this->addChildrenRecursive($child, $allGruppi, $sorted); - } - } - - $allGruppi = Gruppo::with(['diocesi', 'parent', 'children', 'individui']) - ->orderBy('nome') - ->get() - ->map(function ($gruppo) { - $depth = 0; - $parent = $gruppo->parent; - while ($parent) { - $depth++; - $parent = $parent->parent; - } - $gruppo->depth = $depth; - return $gruppo; - }); - - if ($viewMode === 'table') { - $gruppi = $this->sortGruppiHierarchically($allGruppi); - } else { - $gruppi = $allGruppi; - } - - return view('gruppi.index', compact( - 'gruppi', - 'allColumns', - 'visibleColumns', - 'viewMode', - 'vista' - )); - } - - protected function sortGruppiHierarchically($gruppi) - { - $rootGroups = $gruppi->filter(fn($g) => $g->parent_id === null)->sortBy('nome'); - $sorted = collect(); - - foreach ($rootGroups as $root) { - $sorted->push($root); - $this->addChildrenRecursive($root, $gruppi, $sorted); - } - - return $sorted; - } - - protected function addChildrenRecursive($parent, $allGruppi, &$sorted) - { - $children = $allGruppi->filter(fn($g) => $g->parent_id === $parent->id)->sortBy('nome'); - - foreach ($children as $child) { - $sorted->push($child); - $this->addChildrenRecursive($child, $allGruppi, $sorted); - } - } - - $allGruppi = Gruppo::with(['diocesi', 'parent', 'children', 'individui']) + $allGruppi = Gruppo::with(['diocesi', 'parent', 'children', 'individui', 'avatar']) ->orderBy('nome') ->get() ->map(function ($gruppo) { @@ -233,31 +131,31 @@ class GruppoController extends Controller return redirect('/gruppi/' . $gruppo->id)->with('success', 'Gruppo creato con successo.'); } - public function show($gruppo) + public function show($id) { $this->authorizeRead('gruppi'); $gruppo = Gruppo::with(['parent', 'children', 'diocesi', 'individui.contatti', 'individui.documenti', 'individui' => function ($q) { $q->withPivot('ruolo_ids', 'ruolo_nel_gruppo', 'data_adesione'); - }, 'eventi' => function ($q) { + }, 'avatar', 'eventi' => function ($q) { $q->where('is_incontro_gruppo', true); - }, 'eventi.responsabili.contatti'])->findOrFail($gruppo); + }, 'eventi.responsabili.contatti'])->findOrFail($id); return view('gruppi.show', compact('gruppo')); } - public function edit($gruppo) + public function edit($id) { $this->authorizeWrite('gruppi'); - $gruppo = Gruppo::with(['individui.contatti', 'individui.documenti'])->findOrFail($gruppo); + $gruppo = Gruppo::with(['individui.contatti', 'individui.documenti', 'avatar'])->findOrFail($id); $diocesi = Diocesi::orderBy('nome')->get(); $gruppi = Gruppo::where('id', '!=', $gruppo->id)->orderBy('nome')->get(); $membri = $gruppo->individui()->withPivot('ruolo_ids', 'ruolo_nel_gruppo', 'data_adesione')->orderBy('cognome')->orderBy('nome')->get(); return view('gruppi.edit', compact('gruppo', 'diocesi', 'gruppi', 'membri')); } - public function update(Request $request, $gruppo) + public function update(Request $request, $id) { $this->authorizeWrite('gruppi'); - $gruppo = Gruppo::findOrFail($gruppo); + $gruppo = Gruppo::findOrFail($id); $data = $request->validate([ 'nome' => 'required|string|max:255', 'descrizione' => 'nullable|string', @@ -295,10 +193,10 @@ class GruppoController extends Controller return redirect('/gruppi/' . $gruppo->id)->with('success', 'Gruppo aggiornato.'); } - public function destroy($gruppo) + public function destroy($id) { $this->authorizeDelete('gruppi'); - $gruppo = Gruppo::with('children', 'individui')->findOrFail($gruppo); + $gruppo = Gruppo::with('children', 'individui')->findOrFail($id); $hasChildren = $gruppo->children()->count() > 0; $isSuperAdmin = auth()->user()->isSuperAdmin(); @@ -393,13 +291,13 @@ class GruppoController extends Controller return response()->json(['success' => true, 'vista_id' => $vista->id]); } - public function deleteVista($vista) + public function deleteVista($id) { $vista = \App\Models\VistaReport::where('user_id', auth()->id()) - ->where('id', $vista) + ->where('id', $id) ->firstOrFail(); $vista->delete(); return redirect()->route('gruppi.index')->with('success', 'Vista eliminata.'); } -} \ No newline at end of file +} diff --git a/app/Http/Controllers/ReportController.php b/app/Http/Controllers/ReportController.php index 27defde1..6d703fee 100644 --- a/app/Http/Controllers/ReportController.php +++ b/app/Http/Controllers/ReportController.php @@ -121,6 +121,47 @@ class ReportController extends Controller return redirect()->route('report.index')->with('success', 'Report personalizzato eliminato.'); } + public function printPreview(Request $request) + { + if (!auth()->user()->canAccess('report')) { + abort(403); + } + + $reportType = $request->input('report'); + $customReportId = $request->input('custom_id'); + + if ($customReportId) { + $report = \App\Models\ReportCustom::findOrFail($customReportId); + if ($report->user_id !== auth()->id()) { + abort(403); + } + $data = $this->runCustomReport($report); + return view('report.print-preview', compact('reportType', 'data', 'report')); + } + + $data = match ($reportType) { + 'individui_per_genere' => $this->reportIndividuiPerGenere(), + 'individui_per_eta' => $this->reportIndividuiPerEta(), + 'gruppi_gerarchia' => $this->reportGruppiGerarchia(), + 'gruppi_membri' => $this->reportGruppiMembri(), + 'eventi_calendario' => $this->reportEventiCalendario(), + 'documenti_per_tipo' => $this->reportDocumentiPerTipo(), + 'contatti_per_tipo' => $this->reportContattiPerTipo(), + 'mailing_list_dettaglio' => $this->reportMailingListDettaglio(), + 'individui_senza_contatti' => $this->reportIndividuiSenzaContatti(), + 'individui_senza_gruppo' => $this->reportIndividuiSenzaGruppo(), + 'eventi_per_gruppo' => $this->reportEventiPerGruppo(), + 'documenti_orfani' => $this->reportDocumentiOrfani(), + default => null, + }; + + if (!$data) { + return redirect()->route('report.index')->with('error', 'Report non trovato.'); + } + + return view('report.print-preview', compact('reportType', 'data')); + } + public function exportCSV(Request $request) { if (!auth()->user()->canAccess('report')) { diff --git a/app/Models/Evento.php b/app/Models/Evento.php index 7eaa5371..27fc004f 100644 --- a/app/Models/Evento.php +++ b/app/Models/Evento.php @@ -127,7 +127,15 @@ class Evento extends Model public function getOccorrenzeMensiliList(): array { - $giorni = ['Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato', 'Domenica']; + $giorni = [ + 0 => 'Domenica', + 1 => 'Lunedì', + 2 => 'Martedì', + 3 => 'Mercoledì', + 4 => 'Giovedì', + 5 => 'Venerdì', + 6 => 'Sabato', + ]; $list = []; for ($occ = 1; $occ <= 4; $occ++) { foreach ($giorni as $idx => $giorno) { @@ -153,7 +161,15 @@ class Evento extends Model $occorrenza = (int) $parts[0]; $giorno = (int) $parts[1]; - $giorni = ['Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato', 'Domenica']; + $giorni = [ + 0 => 'Domenica', + 1 => 'Lunedì', + 2 => 'Martedì', + 3 => 'Mercoledì', + 4 => 'Giovedì', + 5 => 'Venerdì', + 6 => 'Sabato', + ]; return $occorrenza . '° ' . ($giorni[$giorno] ?? '-'); } @@ -199,7 +215,13 @@ class Evento extends Model } $mesiLabels = $this->getMesiList(); - return $mesiLabels[$this->mese_annuale]['label'] ?? '-'; + $label = $mesiLabels[$this->mese_annuale]['label'] ?? '-'; + + if ($this->giorno_mese) { + $label .= ' (giorno ' . $this->giorno_mese . ')'; + } + + return $label; } public function getPeriodicitaLabelAttribute(): string diff --git a/app/Models/Gruppo.php b/app/Models/Gruppo.php index 2483ae8b..2470270d 100644 --- a/app/Models/Gruppo.php +++ b/app/Models/Gruppo.php @@ -5,6 +5,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Database\Eloquent\Relations\BelongsToMany; class Gruppo extends Model @@ -48,24 +49,47 @@ class Gruppo extends Model ->withTimestamps(); } + public function avatar(): HasOne + { + return $this->hasOne(Documento::class, 'visibilita_target_id') + ->where('tipologia', 'avatar') + ->where('visibilita_target_type', self::class); + } + + public function getAvatarUrlAttribute(): ?string + { + if ($this->avatar && $this->avatar->file_path) { + return url('/gruppi/' . $this->id . '/avatar-file'); + } + return null; + } + + public function getResponsabili() + { + if (empty($this->responsabile_ids)) { + return collect(); + } + + $ids = is_array($this->responsabile_ids) + ? $this->responsabile_ids + : json_decode($this->responsabile_ids, true); + + if (empty($ids)) { + return collect(); + } + + return Individuo::whereIn('id', $ids)->get(); + } + public function getResponsabiliIds(): array { if (empty($this->responsabile_ids)) { return []; } - if (is_array($this->responsabile_ids)) { - return $this->responsabile_ids; - } - return json_decode($this->responsabile_ids, true) ?? []; - } - public function getResponsabili(): \Illuminate\Database\Eloquent\Collection - { - $ids = $this->getResponsabiliIds(); - if (empty($ids)) { - return new \Illuminate\Database\Eloquent\Collection(); - } - return Individuo::whereIn('id', $ids)->get(); + return is_array($this->responsabile_ids) + ? $this->responsabile_ids + : json_decode($this->responsabile_ids, true) ?? []; } public function eventi(): BelongsToMany diff --git a/database/migrations/2026_05_26_082316_change_occorrenza_mese_to_string_in_eventi.php b/database/migrations/2026_05_26_082316_change_occorrenza_mese_to_string_in_eventi.php new file mode 100644 index 00000000..492c242e --- /dev/null +++ b/database/migrations/2026_05_26_082316_change_occorrenza_mese_to_string_in_eventi.php @@ -0,0 +1,22 @@ +string('occorrenza_mese', 10)->nullable()->change(); + }); + } + + public function down(): void + { + Schema::table('eventi', function (Blueprint $table) { + $table->unsignedTinyInteger('occorrenza_mese')->nullable()->change(); + }); + } +}; diff --git a/resources/views/documenti/preview-fallback.blade.php b/resources/views/documenti/preview-fallback.blade.php new file mode 100644 index 00000000..eff0d190 --- /dev/null +++ b/resources/views/documenti/preview-fallback.blade.php @@ -0,0 +1,86 @@ + + + + + + Anteprima non disponibile + + + +
+
📄
+
Anteprima non disponibile
+
+ Questo tipo di file non può essere visualizzato nell'anteprima. + Scarica il file per visualizzarlo con l'applicazione appropriata. +
+
+ {{ $documento->nome_file }} + {{ strtoupper(pathinfo($documento->file_path, PATHINFO_EXTENSION)) }} · + {{ number_format($documento->dimensione / 1024, 1) }} KB +
+ + ⬇️ Scarica File + +
+ + diff --git a/resources/views/eventi/create.blade.php b/resources/views/eventi/create.blade.php index d797c757..5ae18104 100644 --- a/resources/views/eventi/create.blade.php +++ b/resources/views/eventi/create.blade.php @@ -149,6 +149,16 @@ +
+ + + Se il giorno non esiste nel mese selezionato, verrà usato l'ultimo giorno disponibile +
diff --git a/resources/views/eventi/edit.blade.php b/resources/views/eventi/edit.blade.php index a64a3d7e..2c718cca 100644 --- a/resources/views/eventi/edit.blade.php +++ b/resources/views/eventi/edit.blade.php @@ -160,6 +160,16 @@
+
+ + + Se il giorno non esiste nel mese selezionato, verrà usato l'ultimo giorno disponibile +
diff --git a/resources/views/eventi/index.blade.php b/resources/views/eventi/index.blade.php index 5c6974c1..15a499a3 100644 --- a/resources/views/eventi/index.blade.php +++ b/resources/views/eventi/index.blade.php @@ -20,6 +20,9 @@ $canDeleteEventi = Auth::user()->canDelete('eventi');

Tutti gli Eventi

+ + Calendario + @if($canDeleteEventi)
+
+
+
+

Avatar

+
+
+ @if($gruppo->avatar_url) + {{ $gruppo->nome }} +
+
+ +
+ @else +
+ +
+ @endif +
+ @csrf +
+ + +
+ +
+
+
+
+
@php $incontroEvento = $gruppo->eventi->where('is_incontro_gruppo', true)->first(); @@ -155,6 +192,9 @@ $canDeleteGruppi = Auth::user()->canDelete('gruppi'); Mensile @elseif($incontroEvento->tipo_recorrenza === 'annuale') {{ $incontroEvento->mese_annuale_label }} + @if($incontroEvento->giorno_mese) + , giorno {{ $incontroEvento->giorno_mese }} + @endif Annuale @elseif($incontroEvento->tipo_recorrenza === 'altro') {{ $incontroEvento->giorno_settimana_label }} @@ -503,13 +543,76 @@ function previewDocumento(id, mimeType) { document.getElementById('previewDownloadBtn').href = downloadUrl; document.getElementById('previewModalTitle').textContent = 'Anteprima'; - if (mimeType && mimeType.startsWith('image/')) { - document.getElementById('previewDownloadBtn').style.display = 'inline-block'; - } else { - document.getElementById('previewDownloadBtn').style.display = 'none'; - } + document.getElementById('previewDownloadBtn').style.display = 'inline-block'; $('#previewModal').modal('show'); } + +document.getElementById('avatar-input').addEventListener('change', function(e) { + if (e.target.files.length > 0) { + var label = e.target.files[0].name; + var next = e.target.nextElementSibling; + if (next && next.classList.contains('custom-file-label')) { + next.textContent = label; + } + } +}); + +function uploadAvatar() { + var input = document.getElementById('avatar-input'); + if (!input.files.length) { + document.getElementById('avatar-message').innerHTML = 'Seleziona un\'immagine'; + return; + } + + var formData = new FormData(); + formData.append('avatar', input.files[0]); + formData.append('_token', '{{ csrf_token() }}'); + + document.getElementById('avatar-message').innerHTML = ' Caricamento...'; + + fetch('{{ url('/gruppi/' . $gruppo->id . '/avatar') }}', { + method: 'POST', + body: formData, + headers: { 'X-Requested-With': 'XMLHttpRequest' }, + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + document.getElementById('avatar-message').innerHTML = 'Avatar caricato!'; + setTimeout(function() { window.location.reload(); }, 1000); + } else { + document.getElementById('avatar-message').innerHTML = '' + (data.message || 'Errore') + ''; + } + }) + .catch(error => { + document.getElementById('avatar-message').innerHTML = 'Errore: ' + error + ''; + }); +} + +function removeAvatar() { + if (!confirm('Rimuovere l\'avatar?')) return; + + fetch('{{ url('/gruppi/' . $gruppo->id . '/avatar') }}', { + method: 'DELETE', + headers: { + 'X-CSRF-TOKEN': '{{ csrf_token() }}', + 'X-Requested-With': 'XMLHttpRequest', + 'Accept': 'application/json', + }, + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + document.getElementById('avatar-message').innerHTML = 'Avatar rimosso!'; + setTimeout(function() { window.location.reload(); }, 1000); + } else { + document.getElementById('avatar-message').innerHTML = '' + (data.message || 'Errore') + ''; + } + }) + .catch(error => { + document.getElementById('avatar-message').innerHTML = 'Errore: ' + error + ''; + }); +} @endsection diff --git a/resources/views/report/print-preview.blade.php b/resources/views/report/print-preview.blade.php new file mode 100644 index 00000000..289693fb --- /dev/null +++ b/resources/views/report/print-preview.blade.php @@ -0,0 +1,399 @@ + + + + + + Stampa Report - {{ $data['title'] ?? 'Report' }} + + + +
+
+ Anteprima di Stampa +
+ + +
+
+ + +
+
+
+ + +
+
+ +
+
+

{{ $data['title'] ?? 'Report' }}

+
Generato il {{ now()->format('d/m/Y H:i') }}
+
+ + @if(!empty($data['summary'])) +
+ {{ $data['summary'] }} +
+ @endif + + @if(!empty($data['headers']) && !empty($data['rows'])) + + + + @foreach($data['headers'] as $header) + + @endforeach + + + + @foreach($data['rows'] as $row) + + @foreach($row as $cell) + + @endforeach + + @endforeach + +
{{ $header }}
{{ is_array($cell) ? json_encode($cell) : $cell }}
+
Totale righe: {{ count($data['rows']) }}
+ @else +
+ Nessun dato disponibile per questo report. +
+ @endif + + +
+ + + + diff --git a/resources/views/report/result.blade.php b/resources/views/report/result.blade.php index 3b6f31fe..2231e23c 100644 --- a/resources/views/report/result.blade.php +++ b/resources/views/report/result.blade.php @@ -11,6 +11,9 @@ Torna ai Report + + Stampa Report + Esporta CSV diff --git a/routes/console.php b/routes/console.php index 3c9adf1a..eb899017 100644 --- a/routes/console.php +++ b/routes/console.php @@ -1,8 +1,12 @@ comment(Inspiring::quote()); -})->purpose('Display an inspiring quote'); +Schedule::call(function () { + try { + $emailController = new \App\Http\Controllers\EmailController(); + $emailController->syncEmails(); + } catch (\Exception $e) { + \Illuminate\Support\Facades\Log::error('Scheduled email sync failed', ['error' => $e->getMessage()]); + } +})->name('email:sync')->everyFifteenMinutes()->withoutOverlapping(); diff --git a/routes/web.php b/routes/web.php index d11ea41c..f600022a 100644 --- a/routes/web.php +++ b/routes/web.php @@ -74,6 +74,10 @@ Route::delete('gruppi/{gruppo}/membri/{individuo}', [GruppoMembroController::cla Route::get('gruppi/all', [GruppoController::class, 'allGruppi'])->middleware('auth'); Route::get('gruppi/{gruppo}/individui-email', [GruppoController::class, 'individuiEmail'])->middleware('auth'); +Route::post('gruppi/{gruppo}/avatar', [\App\Http\Controllers\GruppoAvatarController::class, 'store'])->middleware('auth'); +Route::get('gruppi/{gruppo}/avatar-file', [\App\Http\Controllers\GruppoAvatarController::class, 'show'])->middleware('auth'); +Route::delete('gruppi/{gruppo}/avatar', [\App\Http\Controllers\GruppoAvatarController::class, 'destroy'])->middleware('auth'); + Route::resource('gruppi', GruppoController::class)->middleware('auth'); Route::get('eventi/calendar', [EventoController::class, 'calendar'])->name('eventi.calendar')->middleware('auth'); Route::get('eventi/calendar/events', [EventoController::class, 'calendarEvents'])->name('eventi.calendar.events')->middleware('auth'); @@ -118,6 +122,7 @@ Route::delete('viste/{vistaReport}', [VistaReportController::class, 'destroy'])- Route::get('report', [ReportController::class, 'index'])->name('report.index')->middleware('auth'); Route::get('report/run', [ReportController::class, 'run'])->name('report.run')->middleware('auth'); +Route::get('report/print-preview', [ReportController::class, 'printPreview'])->name('report.print-preview')->middleware('auth'); Route::get('report/export', [ReportController::class, 'exportCSV'])->name('report.export')->middleware('auth'); Route::get('report/custom/{id}', [ReportController::class, 'runCustom'])->name('report.run-custom')->middleware('auth'); Route::post('report/custom', [ReportController::class, 'storeCustom'])->name('report.store-custom')->middleware('auth'); diff --git a/storage/framework/views/00edc551e83193362ca154488ca4729a.php b/storage/framework/views/00edc551e83193362ca154488ca4729a.php index c8693917..0cc2b384 100755 --- a/storage/framework/views/00edc551e83193362ca154488ca4729a.php +++ b/storage/framework/views/00edc551e83193362ca154488ca4729a.php @@ -10,6 +10,9 @@ Torna ai Report + + Stampa Report + Esporta CSV diff --git a/storage/framework/views/14ee0174ec36b16b90e353b8b794befc.php b/storage/framework/views/14ee0174ec36b16b90e353b8b794befc.php deleted file mode 100755 index 3558885b..00000000 --- a/storage/framework/views/14ee0174ec36b16b90e353b8b794befc.php +++ /dev/null @@ -1,720 +0,0 @@ -startSection('title', 'Modifica Individuo'); ?> -startSection('page_title', 'Modifica Individuo'); ?> - -startSection('content'); ?> -
- - - - -
-
-
-
-

Dati Anagrafici

-
-
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
-
-
-
-
-
-

Avatar

-
-
- avatar): ?> - Avatar -
- - -
- -
- -
- - -
- -
-
-
-
-
- -
-
-
-

Residenza

-
-
- - -
-
-
- - -
-
- - -
-
- - -
-
-
-
-
-
-
-

Documento di identità

-
-
- - -
-
- - -
-
- - -
-
-
-
-
- -
-
-
-

Note

-
-
- -
-
-
-
-
-
-
-

Contatti

- -
-
- - - - - - - - - - - - contatti; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $contatto): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> - - - - - - - - popLoop(); $loop = $__env->getLastLoop(); ?> - -
TipoValoreEtichettaPrimario
- - is_primary ? 'checked' : ''); ?>>
- contatti->isEmpty()): ?> -
-

Nessun contatto. Clicca su "Aggiungi" per aggiungerne uno.

-
- -
-
-
- -
-
-

Gruppi

- -
-
- - gruppi->count() > 0): ?> - - - - - - - - - - - - gruppi; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $gruppo): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> - - - - - - - - - - - popLoop(); $loop = $__env->getLastLoop(); ?> - -
NomeDiocesiRuoloData AdesioneAzioni
- - nome); ?> - diocesi?->nome ?: '-'); ?> - getRuoliForGruppo($gruppo->id) ?> - count() > 0): ?> - addLoop($__currentLoopData); foreach($__currentLoopData as $ruolo): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> - nome); ?> - popLoop(); $loop = $__env->getLastLoop(); ?> - - - - - pivot->data_adesione ? \Carbon\Carbon::parse($gruppo->pivot->data_adesione)->format('d/m/Y') : '-'); ?> - - - - - -
- -
- -

Nessun gruppo associato

-
- -
-
- -
-
-

Documenti

- -
-
- - documenti->count() > 0): ?> - - - - - - - - - - - - documenti; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $documento): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> - - - - - - - - popLoop(); $loop = $__env->getLastLoop(); ?> - -
NomeTipologiaDimensioneData UploadAzioni
- - - nome_file); ?> - - - tipologia))); ?>dimensione / 1024, 1)); ?> KBcreated_at->format('d/m/Y')); ?> - file_path): ?> - - -
- - -
-
- -
- -

Nessun documento

-
- -
-
- -
- - - Annulla - -
- - - +
+ + + Se il giorno non esiste nel mese selezionato, verrà usato l'ultimo giorno disponibile +
diff --git a/storage/framework/views/770f7793fb2506075291f5825b49a758.php b/storage/framework/views/770f7793fb2506075291f5825b49a758.php deleted file mode 100755 index 46d676eb..00000000 --- a/storage/framework/views/770f7793fb2506075291f5825b49a758.php +++ /dev/null @@ -1,350 +0,0 @@ -startSection('title', 'Email - ' . ucfirst($folder)); ?> -startSection('page_title', 'Email'); ?> - -firstWhere('type', $folder); -?> - -startSection('content'); ?> -
-
-

Email

-
-
- addLoop($__currentLoopData); foreach($__currentLoopData as $f): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> - - - name); ?> - - type === 'inbox' && $messages->where('is_read', false)->count() > 0): ?> - where('is_read', false)->count()); ?> - - - popLoop(); $loop = $__env->getLastLoop(); ?> -
- - Nuova Email - - -
-
-
-
-
-
-
-
- - -
- 0 selezionati -
-
-
-
- -
- -
-
-
-
-
-
- - - - - - - - - - - - addLoop($__currentLoopData); foreach($__currentLoopData as $message): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?> - - - - - - - - popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?> - - - - - -
- - - - Destinatario - - - - - Mittente - - - - - - Oggetto - - - - - Data - - -
- - - is_starred): ?> - - - - is_sent ? 'A: ' . $message->to_email : ($message->from_name ?: $message->from_email)); ?> - - - subject ?? '(senza oggetto)'); ?> - - - received_at): ?> - received_at->format('d/m/Y')); ?> - - sent_at): ?> - sent_at->format('d/m/Y')); ?> - - -
- -

Nessuna email

-
-
-
- -
-stopSection(); ?> - -startPush('styles'); ?> - -stopPush(); ?> - - 0 && $folder === 'inbox'): ?> -startPush('scripts'); ?> - -stopPush(); ?> - - -startSection('scripts'); ?> - -stopSection(); ?> -make('layouts.adminlte', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?> \ No newline at end of file diff --git a/storage/framework/views/77ae2092ee84e47a55a05ab55f7003a0.php b/storage/framework/views/77ae2092ee84e47a55a05ab55f7003a0.php deleted file mode 100755 index 1f7b537f..00000000 --- a/storage/framework/views/77ae2092ee84e47a55a05ab55f7003a0.php +++ /dev/null @@ -1,438 +0,0 @@ -startSection('title', 'Gruppi'); ?> -startSection('page_title', 'Elenco Gruppi'); ?> - -canManage('gruppi'); -$canDeleteGruppi = Auth::user()->canDelete('gruppi'); -$columnLabels = [ - 'nome' => 'Nome', - 'descrizione' => 'Descrizione', - 'diocesi' => 'Diocesi', - 'livello' => 'Livello', - 'padre' => 'Gruppo Padre', - 'membri' => 'Membri', - 'responsabili' => 'Responsabili', - 'indirizzo' => 'Indirizzo', - 'citta' => 'Città', - 'telefono' => 'Telefono', - 'email' => 'Email', -]; -$vistaDefaultJson = $vista ? $vista->toJson() : 'null'; -$allColumnsJson = json_encode($allColumns); -$visibleColumnsJson = json_encode($visibleColumns); -?> - -startSection('content'); ?> - - -
- - - -
- - - -
- - - -
- - -
-
-

Elenco Gruppi

-
-
- - -
- - - - Nuovo Gruppo - - -
-
- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - addLoop($__currentLoopData); foreach($__currentLoopData as $gruppo): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - popLoop(); $loop = $__env->getLastLoop(); ?> - -
Nome Descrizione DiocesiLivelloGruppo PadreMembriResponsabiliIndirizzoCittàTelefonoEmailAzioni
- - - nome); ?> - - descrizione, 50) ?: '-'); ?>diocesi?->nome ?? '-'); ?>depth ?? 0); ?>parent?->nome ?? '-'); ?>individui->count()); ?> - getResponsabili() ?> - count() > 0): ?> - pluck('cognome')->implode(', ')); ?> - - - - - - indirizzo_incontro ?: '-'); ?>città_incontro ?: '-'); ?>-- - - - - - - - - - -
- - -
- -
-
- -
-
- filter(fn($g) => $g->parent_id === null) ?> - addLoop($__currentLoopData); foreach($__currentLoopData as $gruppo): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?> - make('gruppi.partials.tree-item', ['gruppo' => $gruppo, 'isRoot' => true], array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?> - popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?> -
- -

Nessun gruppo presente. - - Crea il primo gruppo - -

-
- -
-
- -
- - - - -stopSection(); ?> - -startSection('scripts'); ?> - - -stopSection(); ?> - -make('layouts.adminlte', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?> \ No newline at end of file diff --git a/storage/framework/views/80d6e427e76e80ae16c8694fb235b812.php b/storage/framework/views/80d6e427e76e80ae16c8694fb235b812.php deleted file mode 100755 index ba852922..00000000 --- a/storage/framework/views/80d6e427e76e80ae16c8694fb235b812.php +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - <?php echo $__env->yieldContent('title', 'Admin'); ?> - Glastree - - - yieldContent('styles'); ?> - - -
- - - - -
-
-
-
-
-

yieldContent('page_title', 'Admin'); ?>

-
-
- -
-
-
-
- -
-
- -
- - -
- - yieldContent('content'); ?> -
-
-
- -
- - - v - -
-
- - - - - yieldContent('scripts'); ?> - - \ No newline at end of file diff --git a/storage/framework/views/81e2bcc646165a88dad1b7f9520fc235.php b/storage/framework/views/81e2bcc646165a88dad1b7f9520fc235.php deleted file mode 100755 index b9204007..00000000 --- a/storage/framework/views/81e2bcc646165a88dad1b7f9520fc235.php +++ /dev/null @@ -1,78 +0,0 @@ -startSection('title', 'Importa Individui'); ?> -startSection('page_title', 'Importa Individui da CSV'); ?> - -startSection('content'); ?> -
-
-
-
-

Carica file CSV

-
-
-
- -
- - - - Il file deve essere in formato CSV con separatore virgola. - -
- - - Annulla - -
-
-
-
-
-
-
-

Template

-
-
-

Scarica il template CSV per l'importazione:

- - Scarica Template - -
-
-
-
-

Formato CSV

-
-
-
Campi obbligatori:
-
    -
  • cognome
  • -
  • nome
  • -
-
Campi opzionali:
-
    -
  • data_nascita (formato YYYY-MM-DD)
  • -
  • indirizzo
  • -
  • cap
  • -
  • città
  • -
  • sigla_provincia (2 lettere)
  • -
  • genere (M o F)
  • -
  • tipo_documento (carta_identita, patente)
  • -
  • numero_documento
  • -
  • scadenza_documento (YYYY-MM-DD)
  • -
  • note
  • -
-
Contatti (fino a 2):
-
    -
  • contatto_1_tipo (email, telefono, cellulare)
  • -
  • contatto_1_valore
  • -
  • contatto_1_etichetta (personale, lavoro)
  • -
  • contatto_2_* (secondo contatto)
  • -
-
-
-
-
-stopSection(); ?> -make('layouts.adminlte', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?> \ No newline at end of file diff --git a/storage/framework/views/8888d039c9a4bdb124fcf43b0ae7e371.php b/storage/framework/views/8888d039c9a4bdb124fcf43b0ae7e371.php deleted file mode 100755 index 9cb80e68..00000000 --- a/storage/framework/views/8888d039c9a4bdb124fcf43b0ae7e371.php +++ /dev/null @@ -1,674 +0,0 @@ -startSection('title', 'Dettaglio Individuo'); ?> -startSection('page_title', 'Dettaglio Individuo'); ?> - -startSection('breadcrumbs'); ?> - - -stopSection(); ?> - -startSection('content'); ?> - -
-
-
-
-

nome_completo); ?>

-
-
-

Codice: codice_id); ?>

-

Data di nascita: data_nascita?->format('d/m/Y') ?: '-'); ?>

-

Genere: genere === 'M' ? 'Maschio' : ($individuo->genere === 'F' ? 'Femmina' : '-')); ?>

-
-
-
-
-
-
-

Avatar

-
-
- avatar): ?> - Avatar -
- - -
- -
- -
- -
- - -
- -
-
-
-
-
-
- -
-
-
-

Residenza

-
-

Indirizzo: indirizzo ?: '-'); ?>

-

CAP: cap ?: '-'); ?>

-

Città: città ?: '-'); ?>

-

Provincia: sigla_provincia ?: '-'); ?>

-
-
-
-
-
-

Documento di identità

-
-

Tipo: tipo_documento ? ucfirst(str_replace('_', ' ', $individuo->tipo_documento)) : '-'); ?>

-

Numero: numero_documento ?: '-'); ?>

-

Scadenza: scadenza_documento?->format('d/m/Y') ?: '-'); ?>

- hasDocumentoScaduto()): ?> -

Documento scaduto da giorni_scadenza_documento); ?> giorni

- hasDocumentoScadeEntroGiorni(30)): ?> -

Scade tra giorni_scadenza_documento); ?> giorni

- -
-
-
-
- -note): ?> -
-
-
-

Note

-
-

note)); ?>

-
-
-
-
- - -
-
-

Contatti

-
-
- contatti->count() > 0): ?> - - - - - - - - - - - - contatti; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $contatto): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> - tipo, ['web', 'telegram'])) { - foreach ($protocols as $p) { - if (str_starts_with(strtolower($contatto->valore), $p)) { - $isUrl = true; - break; - } - } -} -?> - - - - - - - - - - - popLoop(); $loop = $__env->getLastLoop(); ?> - -
TipoValoreEtichettaPrimarioAzioni
tipo); ?> - tipo === 'email'): ?> - valore); ?> - tipo, ['telefono', 'cellulare', 'whatsapp'])): ?> - valore); ?> - - valore); ?> - - valore); ?> - - - etichetta ?: '-'); ?> - is_primary): ?> - - - No - - - -
- - - -
-
- -
- -

Nessun contatto

-
- -
-
- -
-
-

Gruppi

- -
-
- - gruppi->count() > 0): ?> - - - - - - - - - - - - - gruppi; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $gruppo): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> - - - - - - - - - - - - popLoop(); $loop = $__env->getLastLoop(); ?> - -
NomeDiocesiResponsabileRuoloData AdesioneAzioni
- - nome); ?> - diocesi?->nome ?: '-'); ?>getResponsabili()->isNotEmpty() ? $gruppo->getResponsabili()->first()->nome_completo : '-'); ?> - pivot->ruolo_ids ? json_decode($gruppo->pivot->ruolo_ids, true) : []; - $ruoli = \App\Models\Ruolo::findByIds($ruoloIds); - ?> - count() > 0): ?> - addLoop($__currentLoopData); foreach($__currentLoopData as $ruolo): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> - nome); ?> - popLoop(); $loop = $__env->getLastLoop(); ?> - - - - - pivot->data_adesione ? \Carbon\Carbon::parse($gruppo->pivot->data_adesione)->format('d/m/Y') : '-'); ?> - - -
- -
- -

Nessun gruppo associato

-
- -
-
- - - -
-
-

Documenti

- -
-
- - documenti->count() > 0): ?> - - - - - - - - - - - - documenti; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $documento): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> - - - - - - - - popLoop(); $loop = $__env->getLastLoop(); ?> - -
NomeTipologiaDimensioneData UploadAzioni
- - - nome_file); ?> - - - tipologia))); ?>dimensione / 1024, 1)); ?> KBcreated_at->format('d/m/Y')); ?> - file_path): ?> - - -
- - - -
-
- -
- -

Nessun documento

-
- -
-
- -
- - Modifica - -
- - -
- - Torna all'elenco - -
- - -stopSection(); ?> - -startSection('scripts'); ?> - -stopSection(); ?> - -make('layouts.adminlte', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?> \ No newline at end of file diff --git a/storage/framework/views/994dbe51ea1920c69a8b0e217fb3f81a.php b/storage/framework/views/994dbe51ea1920c69a8b0e217fb3f81a.php deleted file mode 100755 index fb624a66..00000000 --- a/storage/framework/views/994dbe51ea1920c69a8b0e217fb3f81a.php +++ /dev/null @@ -1,631 +0,0 @@ -startSection('title', 'Documenti'); ?> -startSection('page_title', 'Gestione Documenti'); ?> - -canManage('documenti'); -$canDeleteDocumenti = Auth::user()->canDelete('documenti'); -?> - -startSection('content'); ?> -
-
-

- Elenco Documenti -

- - - -
-
-
- - - -
- Azioni di massa: - - - - - - 0 selezionati -
- - - - - - - - - - - - - - - - - - addLoop($__currentLoopData); foreach($__currentLoopData as $documento): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?> - - - - - - - - - - - - popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?> - - - - - -
- - - - NomeNome FileTipologiaVisibilitàRiferimentoData InserimentoInserito daAzioni
- - - - - - nome_file); ?> - - file_path); ?> - - tipologia)); ?> - - - - visibilita): - case ('individuo'): ?> - Individuo - - - Gruppo - - - Evento - - - Pubblico - - - Associazione - - - Federazione - - - - - - - target): ?> - target instanceof \App\Models\Individuo): ?> - - - target->cognome); ?> target->nome); ?> - - - target instanceof \App\Models\Gruppo): ?> - - - target->nome); ?> - - - target instanceof \App\Models\Evento): ?> - - - target->nome_evento); ?> - - - - - - - - created_at->format('d/m/Y H:i')); ?> - user): ?> - user->name); ?> - - - - - - - file_path): ?> - - - - - - - - - - - - - -
- -

Nessun documento presente

-
- - -
- links()); ?> - -
-
-
- - - - - - - - - - - - -stopSection(); ?> - -startSection('scripts'); ?> - -stopSection(); ?> -make('layouts.adminlte', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?> \ No newline at end of file diff --git a/storage/framework/views/9cacf54b36643c217670450c9fcf532e.php b/storage/framework/views/9cacf54b36643c217670450c9fcf532e.php deleted file mode 100755 index 50a2c7d7..00000000 --- a/storage/framework/views/9cacf54b36643c217670450c9fcf532e.php +++ /dev/null @@ -1,444 +0,0 @@ -startSection('title', 'Impostazioni Email'); ?> -startSection('page_title', 'Configurazione Email'); ?> - -startSection('breadcrumbs'); ?> - - - -stopSection(); ?> - -startSection('content'); ?> -
- -
-
- - - -
-
-
-
-

Configurazione Server IMAP

-
-
- -
- - -
- - -
-
-
- - - Gmail: imap.gmail.com | Outlook: outlook.office365.com -
-
-
-
- - -
-
-
-
- - -
-
-
-
-
-
- -
-
-
-

Configurazione Server SMTP (per invio email)

-
-
-
- - Nota: Per inviare email devi configurare il server SMTP. - Per Gmail, usa smtp.gmail.com sulla porta 587 con TLS - e genera una App Password. -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
-
-
- - - Generalmente uguale all'account email -
-
-
-
- - - Lascia vuoto per usare la password IMAP -
-
-
-
-
-
- -
-
-
-

Credenziali Account

-
-
-
-
-
- - - Per Gmail usa l'indirizzo completo -
-
-
-
- - - - - Per Gmail: genera una App Password - - -
-
-
-
-
-
-
- - -
-
-
-
- - -
-
-
-
-
-
- - -
-
-
-
-
-
- -
-
-
-

Sincronizzazione

-
-
-
-
-
- - -
-
-
-
- -
- last_sync_at): ?> - - Ultimo sync: last_sync_at->format('d/m/Y H:i')); ?> - - - - - Mai sincronizzato - - -
-
-
-
-
-
- is_active ?? false) ? 'checked' : ''); ?>> - -
-
-
-
-
- -
-
-
-

Firma Email

-
-
-
-
- signature_enabled ?? true) ? 'checked' : ''); ?>> - -
- Quando attivo, la firma verrà aggiunta in fondo a ogni email inviata -
-
-
- -
- - Usa il riquadro sopra per comporre la tua firma. HTML supportato. -
-
-
-
-
- - -
-
-
-stopSection(); ?> - -startSection('scripts'); ?> - -stopSection(); ?> -make('layouts.adminlte', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?> \ No newline at end of file diff --git a/storage/framework/views/a32b10b44eee0941ea0a3f2990b69de8.php b/storage/framework/views/a32b10b44eee0941ea0a3f2990b69de8.php deleted file mode 100755 index f513884b..00000000 --- a/storage/framework/views/a32b10b44eee0941ea0a3f2990b69de8.php +++ /dev/null @@ -1,98 +0,0 @@ -startSection('title', 'Log Attività'); ?> -startSection('page_title', 'Log Attività'); ?> - -startSection('breadcrumbs'); ?> - - -stopSection(); ?> - -startSection('content'); ?> -
-
-
-
-

Attività di Sistema

-
-
-
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- - Reset -
-
-
- - - - - - - - - - - - - - addLoop($__currentLoopData); foreach($__currentLoopData as $log): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?> - - - - - - - - - popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?> - - - - - -
Data/OraUtenteAzioneModuloDescrizioneIP
created_at->format('d/m/Y H:i:s')); ?>user->name ?? 'Sistema'); ?> - - action); ?> - - - module); ?>description); ?>ip_address); ?>
Nessun log presente
- - links()); ?> - -
-
-
-
-stopSection(); ?> -make('admin.layout', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?> \ No newline at end of file diff --git a/storage/framework/views/a4022627a632b7187b550e38ad0744a5.php b/storage/framework/views/a4022627a632b7187b550e38ad0744a5.php deleted file mode 100755 index 75f99cef..00000000 --- a/storage/framework/views/a4022627a632b7187b550e38ad0744a5.php +++ /dev/null @@ -1,165 +0,0 @@ -startSection('title', 'Nuova Email'); ?> -startSection('page_title', 'Composizione Email'); ?> - -startSection('content'); ?> -
-
-
-
-

Nuova Email

-
-
-
- - -
- -
- -
- -
- -
- - - - - - -
- -
- - -
- -
- - -
- -
- -
- -
-
- -
- - - - Annulla - -
-
-
-
-
-
-stopSection(); ?> - -startSection('scripts'); ?> - -stopSection(); ?> -make('layouts.adminlte', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?> \ No newline at end of file diff --git a/storage/framework/views/a4fd62c2ab5143a4dd89e7b8e9c2484a.php b/storage/framework/views/a4fd62c2ab5143a4dd89e7b8e9c2484a.php deleted file mode 100755 index b914f278..00000000 --- a/storage/framework/views/a4fd62c2ab5143a4dd89e7b8e9c2484a.php +++ /dev/null @@ -1,180 +0,0 @@ -startSection('title', 'Mailing Lists'); ?> -startSection('page_title', 'Mailing Lists'); ?> - -canManage('mailing'); -$canDeleteMailing = Auth::user()->canDelete('mailing'); -?> - -startSection('content'); ?> - - -
- - - -
- - -
-
-

Elenco Mailing Lists

-
- -
- -
- - - - Nuova Lista - - -
-
-
- count() > 0): ?> - - - - - - - - - - - - - - addLoop($__currentLoopData); foreach($__currentLoopData as $lista): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> - - - - - - - - - - popLoop(); $loop = $__env->getLastLoop(); ?> - -
- -
- - -
- -
NomeDescrizioneContattiStatoCreata ilAzioni
- -
- - -
- -
- nome); ?> - descrizione ?: '-'); ?> - contatti->count()); ?> - - attiva): ?> - Attiva - - Disattiva - - created_at->format('d/m/Y')); ?> - - - - - - - -
- - -
- -
- -
- -

Nessuna mailing list

- - Crea la prima lista - -
- -
-
- - -stopSection(); ?> - -startSection('scripts'); ?> - -stopSection(); ?> -make('layouts.adminlte', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?> \ No newline at end of file diff --git a/storage/framework/views/a59e859b9d52c149f06a0f5ca0dce3cf.php b/storage/framework/views/a59e859b9d52c149f06a0f5ca0dce3cf.php deleted file mode 100755 index 38c350ad..00000000 --- a/storage/framework/views/a59e859b9d52c149f06a0f5ca0dce3cf.php +++ /dev/null @@ -1,260 +0,0 @@ -startSection('title', 'Nuovo Gruppo'); ?> -startSection('page_title', 'Nuovo Gruppo'); ?> - -startSection('content'); ?> -
- -
-
-
-
-

Dati Gruppo

-
-
-
- - - getBag($__errorArgs[1] ?? 'default'); -if ($__bag->has($__errorArgs[0])) : -if (isset($message)) { $__messageOriginal = $message; } -$message = $__bag->first($__errorArgs[0]); ?> - - -
-
- - - - - Verrà creato come sottogruppo di: nome); ?> - - -
-
- - -
-
- - - Ctrl+click per selezionare più responsabili -
-
- - -
-
-
-
-
-
-

Luogo Incontro

-
-
- - -
-
-
- - -
-
- - -
-
- - -
-
-
- - -
-
-
-
-
- -
-
-

Membri

- -
-
- - - - - - - - - - - - - -
IndividuoCodiceContattiRuoloData Adesione
-
-

Nessun membro aggiunto. Clicca su "Aggiungi Membro" per iniziare.

-
-
-
- -
- - - Annulla - -
-
-stopSection(); ?> - -startSection('scripts'); ?> - -stopSection(); ?> -make('layouts.adminlte', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?> \ No newline at end of file diff --git a/storage/framework/views/a6267d64f58c4883f210293e4b730a9c.php b/storage/framework/views/a6267d64f58c4883f210293e4b730a9c.php deleted file mode 100755 index 5a5dec84..00000000 --- a/storage/framework/views/a6267d64f58c4883f210293e4b730a9c.php +++ /dev/null @@ -1,97 +0,0 @@ -startSection('title', 'Calendario Eventi'); ?> -startSection('page_title', 'Calendario Eventi'); ?> - -startSection('content'); ?> -
-
-
-
-

- Calendario Eventi -

- -
-
-
-
-
-
-
-stopSection(); ?> - -startSection('styles'); ?> - -stopSection(); ?> - -startSection('scripts'); ?> - - -stopSection(); ?> -make('layouts.adminlte', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?> \ No newline at end of file diff --git a/storage/framework/views/b7fb0777954b7384c283d9ea1db9ba0f.php b/storage/framework/views/b7fb0777954b7384c283d9ea1db9ba0f.php deleted file mode 100755 index 1aabf858..00000000 --- a/storage/framework/views/b7fb0777954b7384c283d9ea1db9ba0f.php +++ /dev/null @@ -1,100 +0,0 @@ -startSection('title', 'Dashboard'); ?> -startSection('page_title', 'Dashboard'); ?> - -startSection('content'); ?> -
-
-
-
-

-

Individui

-
-
- -
- Visualizza -
-
-
-
-
-

-

Gruppi

-
-
- -
- Visualizza -
-
-
-
-
-

-

Notifiche

-
-
- -
- Visualizza -
-
-
- -
-
-
-
-

Ultime Notifiche

-
-
- count() > 0): ?> -
    - addLoop($__currentLoopData); foreach($__currentLoopData as $notifica): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> -
  • - titolo); ?> - created_at->diffForHumans()); ?> -
  • - popLoop(); $loop = $__env->getLastLoop(); ?> -
- -

Nessuna notifica

- -
-
-
-
-
-
-

Benvenuto

-
-
- - -

- -

Benvenuto in .

- -

Dal menu laterale puoi navigare tra le sezioni:

-
    -
  • Individui: Gestione delle persone registrate
  • -
  • Gruppi: Gestione della struttura organizzativa
  • -
  • Documenti: Archivio documentale
  • -
  • Eventi: Calendario eventi
  • -
  • Mailing: Comunicazioni email
  • -
- is_admin): ?> -
- Amministratore: Hai accesso completo al sistema. -
- -
-
-
-
-stopSection(); ?> -make('layouts.adminlte', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?> \ No newline at end of file diff --git a/storage/framework/views/d751874ab64bcc49bdf4b12b4fefba7a.php b/storage/framework/views/d751874ab64bcc49bdf4b12b4fefba7a.php index b22e5530..c928f125 100755 --- a/storage/framework/views/d751874ab64bcc49bdf4b12b4fefba7a.php +++ b/storage/framework/views/d751874ab64bcc49bdf4b12b4fefba7a.php @@ -20,6 +20,9 @@ $canDeleteEventi = Auth::user()->canDelete('eventi');

Tutti gli Eventi

+ + Calendario +
+ +
+
+
+ +
+
+
+

Contatti (contatti->count()); ?>)

+
+
+ contatti->count() > 0): ?> + + + + + + + + + + + contatti; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $contact): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> + individuo): ?> + + + + + + + + popLoop(); $loop = $__env->getLastLoop(); ?> + +
CodiceNomeEmailStato
individuo->codice_id); ?>individuo->cognome); ?> individuo->nome); ?> + individuo->contatti->where('tipo', 'email')->first()?->valore; + ?> + + + + opt_in): ?> + Iscritto + + Disiscritto + +
+ +
+

Nessun contatto in questa lista

+
+ +
+
+
+
+stopSection(); ?> +make('layouts.adminlte', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?> \ No newline at end of file diff --git a/storage/framework/views/e6056fdcc373077ccd717e502c884188.php b/storage/framework/views/e6056fdcc373077ccd717e502c884188.php deleted file mode 100755 index 9abcf818..00000000 --- a/storage/framework/views/e6056fdcc373077ccd717e502c884188.php +++ /dev/null @@ -1,922 +0,0 @@ -startSection('title', 'Individui'); ?> -startSection('page_title', 'Elenco Individui'); ?> - - 'Codice', - 'cognome' => 'Cognome', - 'nome' => 'Nome', - 'email' => 'Email', - 'telefono' => 'Telefono', -]; -$vistaDefaultJson = $vista ? $vista->toJson() : 'null'; -$allColumnsJson = json_encode($allColumns); -$visibleColumnsJson = json_encode($visibleColumns); -$canWriteIndividui = Auth::user()->canManage('individui'); -$canDeleteIndividui = Auth::user()->canDelete('individui'); -?> - -startSection('content'); ?> -
- - - - -
- count() > 0): ?> - - - - - - - - - - - - - - - - - - - - - - - - addLoop($__currentLoopData); foreach($__currentLoopData as $ind): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> - - - - - - - - - - - - - - - - - - - - popLoop(); $loop = $__env->getLastLoop(); ?> - -
-
- - -
-
Codice Cognome Nome Email Telefono Azioni
-
- - -
-
codice_id); ?> - cognome); ?> - - nome); ?> - getEmailPrimariaAttribute() ?: '-'); ?>getTelefonoPrimarioAttribute() ?: '-'); ?> - - - - - - - - - - - - -
- -
- -

Nessun individuo presente

- - Crea il primo individuo - -
- -
- count() > 0): ?> - - -
- - - - - - - - - -stopSection(); ?> - -startSection('scripts'); ?> - -stopSection(); ?> -make('layouts.adminlte', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?> \ No newline at end of file diff --git a/storage/framework/views/e8f60d5f5b2a4c688f1bc12477b209df.php b/storage/framework/views/e8f60d5f5b2a4c688f1bc12477b209df.php deleted file mode 100755 index 2d0ad738..00000000 --- a/storage/framework/views/e8f60d5f5b2a4c688f1bc12477b209df.php +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - - Accedi - <?php echo e(e($appName)); ?> - - - - -
- - -
- -
- -
- -
-
- - - - \ No newline at end of file diff --git a/storage/framework/views/f7b5acd723ad1e4180d8c10d45f3d46f.php b/storage/framework/views/f7b5acd723ad1e4180d8c10d45f3d46f.php deleted file mode 100755 index dab0054c..00000000 --- a/storage/framework/views/f7b5acd723ad1e4180d8c10d45f3d46f.php +++ /dev/null @@ -1,529 +0,0 @@ -startSection('title', 'Dettaglio Gruppo'); ?> -startSection('page_title', 'Dettaglio Gruppo'); ?> - -canManage('gruppi'); -$canDeleteGruppi = Auth::user()->canDelete('gruppi'); -?> - -startSection('breadcrumbs'); ?> - - -stopSection(); ?> - - -
- - - -
- - -
- - - -
- - -startSection('content'); ?> -
-
-
-
-

- - nome); ?> - -

-
-
- - - - - - - - - - - - - - - - - -
Path:full_path); ?>
Gruppo Padre: - parent): ?> - parent->nome); ?> - - Gruppo radice - -
Diocesi:diocesi?->nome ?? '-'); ?>
Responsabili: - getResponsabili() ?> - count() > 0): ?> - addLoop($__currentLoopData); foreach($__currentLoopData as $resp): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> - - - nome_completo); ?> - -
- popLoop(); $loop = $__env->getLastLoop(); ?> - - - - -
-
-
-
-
-
-

Luogo Incontro

-
- - - - - - - - - - - - - -
Indirizzo:indirizzo_incontro ?: '-'); ?>
CAP:cap_incontro ?: '-'); ?>
Città:città_incontro ?: '-'); ?> sigla_provincia_incontro ? "({$gruppo->sigla_provincia_incontro})" : ''); ?>
- mappa_posizione): ?> - - Visualizza su mappa - - -
-
-
-
-
-

Statistiche

-
-
-
-
-

individui->count()); ?>

- Membri -
-
-
-

children->count()); ?>

- Sottogruppi -
-
-
-
-
-
- - eventi->where('is_incontro_gruppo', true)->first(); - ?> - -
-
-
-
-

- - Giorno di Incontro -

-
-
- - - - - - - - - - ora_inizio): ?> - - - - - -
Evento:nome_evento); ?>
Quando: - tipo_recorrenza === 'settimanale'): ?> - giorno_settimana_label); ?> - - Settimanale - tipo_recorrenza === 'mensile'): ?> - occorrenza_mensile_label); ?> - - mesi_recorrenza): ?> - (mesi_recorrenza_label); ?>) - - Mensile - tipo_recorrenza === 'annuale'): ?> - mese_annuale_label); ?> - - Annuale - tipo_recorrenza === 'altro'): ?> - giorno_settimana_label); ?> - - Altro - - data_specifica?->format('d/m/Y') ?: '-'); ?> - - -
Ora:ore ora_inizio->format('H:i')); ?>
- responsabili->count() > 0): ?> -
- Responsabili: - responsabili; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $resp): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> -
- - cognome); ?> nome); ?> - telefono_primario): ?> -
telefono_primario); ?> - -
- popLoop(); $loop = $__env->getLastLoop(); ?> - - -
-
-
-
- - - descrizione): ?> -
-
-
-

Descrizione

-
-

descrizione)); ?>

-
-
-
-
- - -
-
-

- Membri (individui->count()); ?>) -

-
-
- individui->count() > 0): ?> - - - - - - - - - - - - - - individui; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $individuo): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> - - - - - - - - - - popLoop(); $loop = $__env->getLastLoop(); ?> - -
CodiceNome CompletoEmailTelefonoRuoloData AdesioneAzioni
codice_id); ?> - - - cognome); ?> nome); ?> - - - email_primaria ?? '-'); ?>telefono_primario ?? '-'); ?> - pivot->ruolo_ids ? json_decode($individuo->pivot->ruolo_ids, true) : []; - $ruoli = \App\Models\Ruolo::findByIds($ruoloIds); - ?> - count() > 0): ?> - addLoop($__currentLoopData); foreach($__currentLoopData as $ruolo): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> - nome); ?> - popLoop(); $loop = $__env->getLastLoop(); ?> - - - - - - pivot->data_adesione): ?> - pivot->data_adesione)->format('d/m/Y')); ?> - - - - - - - - - -
- -
- -

Nessun membro

-
- -
-
- -
-
-

- Documenti (documenti->count()); ?>) -

- - - -
-
- documenti->count() > 0): ?> - - - - - - - - - - - - documenti; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $documento): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> - - - - - - - - popLoop(); $loop = $__env->getLastLoop(); ?> - -
NomeTipologiaDimensioneData UploadAzioni
- - - nome_file); ?> - - - tipologia))); ?>dimensione / 1024, 1)); ?> KBcreated_at->format('d/m/Y')); ?> - file_path): ?> - - - - -
- -
- -

Nessun documento

-
- -
-
- -
-
-

- Sottogruppi (children->count()); ?>) -

- - Aggiungi Sottogruppo - -
-
- children->count() > 0): ?> - - - - - - - - - - - - children->sortBy('nome'); $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $child): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> - - - - - - - - popLoop(); $loop = $__env->getLastLoop(); ?> - -
NomeDiocesiResponsabileMembriAzioni
- - - nome); ?> - - - diocesi?->nome ?? '-'); ?>getResponsabili()->isNotEmpty() ? $child->getResponsabili()->first()->nome_completo : '-'); ?> - individui()->count() > 0): ?> - individui()->count()); ?> - - - - - - - - - - - - - - -
- - -
- -
- -
- -

Nessun sottogruppo

-
- -
-
- -
- - - Modifica - - - -
- - -
- - - Torna all'elenco - -
- - - - -stopSection(); ?> - -startSection('scripts'); ?> - -stopSection(); ?> - -make('layouts.adminlte', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?> \ No newline at end of file diff --git a/storage/framework/views/f98c27feaa80ae6e7f6c002c26f6107d.php b/storage/framework/views/f98c27feaa80ae6e7f6c002c26f6107d.php deleted file mode 100755 index 9ae5ec5a..00000000 --- a/storage/framework/views/f98c27feaa80ae6e7f6c002c26f6107d.php +++ /dev/null @@ -1,109 +0,0 @@ -startSection('title', 'Gestione Utenti'); ?> -startSection('page_title', 'Gestione Utenti'); ?> - -startSection('breadcrumbs'); ?> - - -stopSection(); ?> - -startSection('content'); ?> -
-
-
-
-

Utenti Registrati

- - Nuovo Utente - -
-
-
-
-
- -
-
- -
-
- -
-
-
- - - - - - - - - - - - - - addLoop($__currentLoopData); foreach($__currentLoopData as $utente): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> - - - - - - - - - popLoop(); $loop = $__env->getLastLoop(); ?> - -
NomeEmailStatoPermessiCreatoAzioni
- name); ?> - isSuperAdmin()): ?> - Admin - - email); ?> - status): - case ('active'): ?> - Attivo - - - Sospeso - - - In attesa - - - - getPermissionsSummary(); ?> - - addLoop($__currentLoopData); foreach($__currentLoopData as $module => $level): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> - - :
- - popLoop(); $loop = $__env->getLastLoop(); ?> -
-
created_at->format('d/m/Y')); ?> - - - - id !== auth()->id()): ?> -
- - -
- -
- - links()); ?> - -
-
-
-
-stopSection(); ?> -make('admin.layout', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?> \ No newline at end of file diff --git a/storage/framework/views/fc56695b593a318c0d96a4e22b861473.php b/storage/framework/views/fc56695b593a318c0d96a4e22b861473.php deleted file mode 100755 index 7733db02..00000000 --- a/storage/framework/views/fc56695b593a318c0d96a4e22b861473.php +++ /dev/null @@ -1,480 +0,0 @@ -startSection('title', 'Modifica Gruppo'); ?> -startSection('page_title', 'Modifica Gruppo'); ?> - -startSection('content'); ?> -
- -
-
-
-
-

Dati Gruppo

-
-
-
- - -
-
- - -
-
- - -
-
- - - isEmpty()): ?> - Prima aggiungi dei membri al gruppo - - Ctrl+click per selezionare più responsabili - -
-
- - -
-
-
-
-
-
-

Luogo Incontro

-
-
- - -
-
-
- - -
-
- - -
-
- - -
-
-
- - -
-
-
-
-
- -
-
-

Membri

- -
-
- - individui->count() > 0): ?> - - - - - - - - - - - - - individui; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $membro): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> - - - - - - - - - - - - popLoop(); $loop = $__env->getLastLoop(); ?> - -
IndividuoCodiceContattiRuoloData AdesioneAzioni
- - cognome); ?> nome); ?> - codice_id); ?> - - email_primaria): ?> - email_primaria); ?>
- - telefono_primario): ?> - telefono_primario); ?> - -
-
- getRuoliForGruppo($gruppo->id) ?> - count() > 0): ?> - addLoop($__currentLoopData); foreach($__currentLoopData as $ruolo): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> - nome); ?> - popLoop(); $loop = $__env->getLastLoop(); ?> - - - - - pivot->data_adesione ? \Carbon\Carbon::parse($membro->pivot->data_adesione)->format('d/m/Y') : '-'); ?> - - -
- -
- -

Nessun membro associato

-
- -
-
- -
-
-

Documenti

- -
-
- - - documenti && $gruppo->documenti->count() > 0): ?> - - - - - - - - - - - - documenti; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $documento): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> - - - - - - - - popLoop(); $loop = $__env->getLastLoop(); ?> - -
NomeTipologiaDimensioneData UploadAzioni
- - nome_file); ?> - - tipologia))); ?>dimensione / 1024, 1)); ?> KBcreated_at->format('d/m/Y')); ?> - file_path): ?> - - -
- - -
-
- -
- -

Nessun documento

-
- -
-
- -
- - - Annulla - -
- - - - - -stopSection(); ?> - -startSection('scripts'); ?> - -stopSection(); ?> -make('layouts.adminlte', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?> \ No newline at end of file diff --git a/tests/Feature/CalendarEventsTest.php b/tests/Feature/CalendarEventsTest.php new file mode 100644 index 00000000..aabc7a45 --- /dev/null +++ b/tests/Feature/CalendarEventsTest.php @@ -0,0 +1,134 @@ +setAccessible(true); + + $result = $method->invoke($controller, $june2026, 1, 0); + + $this->assertNotNull($result); + $this->assertEquals('2026-06-07', $result->format('Y-m-d')); + $this->assertEquals('Sunday', $result->format('l')); + } + + public function test_find_second_saturday_of_june_2026(): void + { + $controller = app(EventoController::class); + $june2026 = \Carbon\Carbon::create(2026, 6, 1); + + $method = new \ReflectionMethod($controller, 'findNthWeekdayOfMonth'); + $method->setAccessible(true); + + $result = $method->invoke($controller, $june2026, 2, 6); + + $this->assertNotNull($result); + $this->assertEquals('2026-06-13', $result->format('Y-m-d')); + } + + public function test_find_fifth_sunday_returns_null_when_not_in_month(): void + { + $controller = app(EventoController::class); + $june2026 = \Carbon\Carbon::create(2026, 6, 1); + + $method = new \ReflectionMethod($controller, 'findNthWeekdayOfMonth'); + $method->setAccessible(true); + + $result = $method->invoke($controller, $june2026, 5, 0); + + $this->assertNull($result); + } + + public function test_generate_mensile_events_for_all_months(): void + { + $controller = app(EventoController::class); + + $evento = Evento::make([ + 'nome_evento' => 'Test Mensile', + 'tipo_recorrenza' => 'mensile', + 'occorrenza_mese' => '1,0', + 'mesi_recorrenza' => '1,2,3,4,5,6,7,8,9,10,11,12', + ]); + + $method = new \ReflectionMethod($controller, 'generateMensileEvents'); + $method->setAccessible(true); + + $events = $method->invoke($controller, $evento, '2026-06-01', '2026-08-31', 'http://test.local'); + + $this->assertCount(3, $events); + $this->assertStringContainsString('2026-06-07', $events[0]['start']); + $this->assertStringContainsString('2026-07-05', $events[1]['start']); + $this->assertStringContainsString('2026-08-02', $events[2]['start']); + } + + public function test_generate_mensile_events_respects_selected_months(): void + { + $controller = app(EventoController::class); + + $evento = Evento::make([ + 'nome_evento' => 'Test Mensile', + 'tipo_recorrenza' => 'mensile', + 'occorrenza_mese' => '1,6', + 'mesi_recorrenza' => '1,6', + ]); + + $method = new \ReflectionMethod($controller, 'generateMensileEvents'); + $method->setAccessible(true); + + $events = $method->invoke($controller, $evento, '2026-01-01', '2026-12-31', 'http://test.local'); + + $this->assertCount(2, $events); + $this->assertStringContainsString('2026-01-03', $events[0]['start']); + $this->assertStringContainsString('2026-06-06', $events[1]['start']); + } + + public function test_generate_annuale_events_produces_correct_dates(): void + { + $controller = app(EventoController::class); + + $evento = Evento::make([ + 'nome_evento' => 'Test Annuale', + 'tipo_recorrenza' => 'annuale', + 'mese_annuale' => 6, + 'giorno_mese' => 15, + ]); + + $method = new \ReflectionMethod($controller, 'generateAnnualeEvents'); + $method->setAccessible(true); + + $events = $method->invoke($controller, $evento, '2026-01-01', '2027-12-31', 'http://test.local'); + + $this->assertCount(2, $events); + $this->assertStringContainsString('2026-06-15', $events[0]['start']); + $this->assertStringContainsString('2027-06-15', $events[1]['start']); + } + + public function test_generate_settimanale_events_produces_weekly_occurrences(): void + { + $controller = app(EventoController::class); + + $evento = Evento::make([ + 'nome_evento' => 'Test Settimanale', + 'tipo_recorrenza' => 'settimanale', + 'giorno_settimana' => 1, + ]); + + $method = new \ReflectionMethod($controller, 'generateSettimanaleEvents'); + $method->setAccessible(true); + + $events = $method->invoke($controller, $evento, '2026-06-01', '2026-06-30', 'http://test.local'); + + $this->assertCount(5, $events); + } +}