2026-05-26 08:14:29 +02:00
|
|
|
@extends('layouts.adminlte')
|
|
|
|
|
@section('title', 'Gruppi')
|
|
|
|
|
@section('page_title', 'Elenco Gruppi')
|
|
|
|
|
|
|
|
|
|
@php
|
|
|
|
|
$canWriteGruppi = Auth::user()->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',
|
2026-06-09 11:02:01 +02:00
|
|
|
'tag' => 'Tag',
|
2026-05-26 08:14:29 +02:00
|
|
|
];
|
|
|
|
|
$vistaDefaultJson = $vista ? $vista->toJson() : 'null';
|
|
|
|
|
$allColumnsJson = json_encode($allColumns);
|
|
|
|
|
$visibleColumnsJson = json_encode($visibleColumns);
|
2026-06-10 14:03:43 +02:00
|
|
|
$entityType = $entityType ?? 'gruppi';
|
2026-05-26 08:14:29 +02:00
|
|
|
@endphp
|
|
|
|
|
|
|
|
|
|
@section('content')
|
|
|
|
|
|
|
|
|
|
@if(session('success'))
|
|
|
|
|
<div class="alert alert-success alert-dismissible">
|
|
|
|
|
<button type="button" class="close" data-dismiss="alert">×</button>
|
|
|
|
|
{{ session('success') }}
|
|
|
|
|
</div>
|
|
|
|
|
@endif
|
|
|
|
|
|
|
|
|
|
@if(session('error'))
|
|
|
|
|
<div class="alert alert-danger alert-dismissible">
|
|
|
|
|
<button type="button" class="close" data-dismiss="alert">×</button>
|
|
|
|
|
{{ session('error') }}
|
|
|
|
|
</div>
|
|
|
|
|
@endif
|
|
|
|
|
|
|
|
|
|
<div class="card">
|
|
|
|
|
<div class="card-header">
|
|
|
|
|
<h3 class="card-title"><i class="fas fa-sitemap mr-2"></i>Elenco Gruppi</h3>
|
|
|
|
|
<div class="card-tools">
|
2026-06-10 14:03:43 +02:00
|
|
|
<button type="button" class="btn btn-sm btn-secondary mr-1" onclick="$('#table-settings-modal').modal('show')" title="Impostazioni tabella">
|
|
|
|
|
<i class="fas fa-cog"></i>
|
|
|
|
|
</button>
|
2026-05-26 08:14:29 +02:00
|
|
|
<div class="btn-group mr-2">
|
|
|
|
|
<button type="button" class="btn btn-sm btn-outline-primary {{ $viewMode === 'table' ? 'active' : '' }}" onclick="switchView('table')" id="btn-table-view">
|
|
|
|
|
<i class="fas fa-table mr-1"></i> Tabella
|
|
|
|
|
</button>
|
|
|
|
|
<button type="button" class="btn btn-sm btn-outline-primary {{ $viewMode === 'tree' ? 'active' : '' }}" onclick="switchView('tree')" id="btn-tree-view">
|
|
|
|
|
<i class="fas fa-sitemap mr-1"></i> Albero
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
2026-06-09 11:02:01 +02:00
|
|
|
<div class="btn-group mr-1">
|
|
|
|
|
<button type="button" class="btn btn-sm btn-secondary dropdown-toggle" data-toggle="dropdown">
|
|
|
|
|
<i class="fas fa-cog mr-1"></i> Azioni
|
|
|
|
|
</button>
|
|
|
|
|
<div class="dropdown-menu">
|
|
|
|
|
@if($canWriteGruppi)
|
|
|
|
|
<a class="dropdown-item" href="#" onclick="showMassTagModal(); return false;">
|
|
|
|
|
<i class="fas fa-tags mr-2"></i>Assegna Tag
|
|
|
|
|
</a>
|
|
|
|
|
<div class="dropdown-divider"></div>
|
|
|
|
|
<a class="dropdown-item text-danger" href="#" onclick="deleteSelected(); return false;">
|
|
|
|
|
<i class="fas fa-trash mr-2"></i>Elimina Selezionati
|
|
|
|
|
</a>
|
|
|
|
|
@endif
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-06-10 14:03:43 +02:00
|
|
|
|
2026-05-26 08:14:29 +02:00
|
|
|
@if($canWriteGruppi)
|
2026-06-07 17:27:00 +02:00
|
|
|
<a href="{{ route('gruppi.import') }}" class="btn btn-warning btn-sm mr-1">
|
|
|
|
|
<i class="fas fa-file-import mr-1"></i> Importa
|
|
|
|
|
</a>
|
2026-05-26 08:14:29 +02:00
|
|
|
<a href="{{ route('gruppi.create') }}" class="btn btn-success btn-sm">
|
|
|
|
|
<i class="fas fa-plus"></i> Nuovo Gruppo
|
|
|
|
|
</a>
|
|
|
|
|
@endif
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-06-09 11:02:01 +02:00
|
|
|
@include('partials._tag-filter-bar', ['filterTags' => $allTags])
|
|
|
|
|
|
2026-06-10 14:03:43 +02:00
|
|
|
@include('partials.table-settings')
|
|
|
|
|
|
|
|
|
|
<div id="vista-data" style="display:none;">{{ $vistaDefaultJson }}</div>
|
|
|
|
|
|
2026-05-26 08:14:29 +02:00
|
|
|
@if($viewMode === 'table')
|
|
|
|
|
<div class="card-body p-0">
|
|
|
|
|
<table class="table table-bordered table-hover table-striped mb-0" id="gruppi-table">
|
|
|
|
|
<thead class="thead-light">
|
|
|
|
|
<tr>
|
2026-06-10 14:03:43 +02:00
|
|
|
<th style="width: 40px;" data-column="select">
|
2026-06-09 11:02:01 +02:00
|
|
|
<div class="custom-control custom-checkbox">
|
|
|
|
|
<input type="checkbox" class="custom-control-input" id="select-all" onchange="toggleSelectAll(this)">
|
|
|
|
|
<label class="custom-control-label" for="select-all"></label>
|
|
|
|
|
</div>
|
|
|
|
|
</th>
|
2026-05-26 08:14:29 +02:00
|
|
|
@if(in_array('nome', $visibleColumns))
|
2026-06-10 14:03:43 +02:00
|
|
|
<th data-sortable="true" data-column="nome" onclick="sortTable('nome')" style="cursor:pointer;">Nome <i class="fas fa-sort float-right text-muted"></i></th>
|
2026-05-26 08:14:29 +02:00
|
|
|
@endif
|
|
|
|
|
@if(in_array('descrizione', $visibleColumns))
|
2026-06-10 14:03:43 +02:00
|
|
|
<th data-sortable="true" data-column="descrizione" onclick="sortTable('descrizione')" style="cursor:pointer;">Descrizione <i class="fas fa-sort float-right text-muted"></i></th>
|
2026-05-26 08:14:29 +02:00
|
|
|
@endif
|
|
|
|
|
@if(in_array('diocesi', $visibleColumns))
|
2026-06-10 14:03:43 +02:00
|
|
|
<th data-column="diocesi">Diocesi</th>
|
2026-05-26 08:14:29 +02:00
|
|
|
@endif
|
|
|
|
|
@if(in_array('livello', $visibleColumns))
|
2026-06-10 14:03:43 +02:00
|
|
|
<th style="width: 80px;" data-column="livello">Livello</th>
|
2026-05-26 08:14:29 +02:00
|
|
|
@endif
|
|
|
|
|
@if(in_array('padre', $visibleColumns))
|
2026-06-10 14:03:43 +02:00
|
|
|
<th data-column="padre">Gruppo Padre</th>
|
2026-05-26 08:14:29 +02:00
|
|
|
@endif
|
|
|
|
|
@if(in_array('membri', $visibleColumns))
|
2026-06-10 14:03:43 +02:00
|
|
|
<th style="width: 100px;" data-column="membri">Membri</th>
|
2026-05-26 08:14:29 +02:00
|
|
|
@endif
|
|
|
|
|
@if(in_array('responsabili', $visibleColumns))
|
2026-06-10 14:03:43 +02:00
|
|
|
<th data-column="responsabili">Responsabili</th>
|
2026-05-26 08:14:29 +02:00
|
|
|
@endif
|
|
|
|
|
@if(in_array('indirizzo', $visibleColumns))
|
2026-06-10 14:03:43 +02:00
|
|
|
<th data-column="indirizzo">Indirizzo</th>
|
2026-05-26 08:14:29 +02:00
|
|
|
@endif
|
|
|
|
|
@if(in_array('citta', $visibleColumns))
|
2026-06-10 14:03:43 +02:00
|
|
|
<th data-column="citta">Città</th>
|
2026-05-26 08:14:29 +02:00
|
|
|
@endif
|
|
|
|
|
@if(in_array('telefono', $visibleColumns))
|
2026-06-10 14:03:43 +02:00
|
|
|
<th data-column="telefono">Telefono</th>
|
2026-05-26 08:14:29 +02:00
|
|
|
@endif
|
|
|
|
|
@if(in_array('email', $visibleColumns))
|
2026-06-10 14:03:43 +02:00
|
|
|
<th data-column="email">Email</th>
|
2026-05-26 08:14:29 +02:00
|
|
|
@endif
|
2026-06-09 11:02:01 +02:00
|
|
|
@if(in_array('tag', $visibleColumns))
|
2026-06-10 14:03:43 +02:00
|
|
|
<th data-column="tag">Tag</th>
|
2026-06-09 11:02:01 +02:00
|
|
|
@endif
|
2026-06-10 14:03:43 +02:00
|
|
|
<th style="width: 120px;" data-column="azioni">Azioni</th>
|
2026-05-26 08:14:29 +02:00
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody id="table-body">
|
|
|
|
|
@foreach($gruppi as $gruppo)
|
|
|
|
|
<tr data-id="{{ $gruppo->id }}">
|
2026-06-09 11:02:01 +02:00
|
|
|
<td>
|
|
|
|
|
<div class="custom-control custom-checkbox">
|
|
|
|
|
<input type="checkbox" class="custom-control-input row-checkbox" id="select-{{ $gruppo->id }}" value="{{ $gruppo->id }}">
|
|
|
|
|
<label class="custom-control-label" for="select-{{ $gruppo->id }}"></label>
|
|
|
|
|
</div>
|
|
|
|
|
</td>
|
2026-05-26 08:14:29 +02:00
|
|
|
@if(in_array('nome', $visibleColumns))
|
|
|
|
|
<td>
|
|
|
|
|
<span style="padding-left: {{ ($gruppo->depth ?? 0) * 20 }}px;">
|
|
|
|
|
<i class="fas fa-{{ $gruppo->children->count() > 0 ? 'folder' : 'folder-open' }} text-{{ ($gruppo->depth ?? 0) == 0 ? 'warning' : 'secondary' }} mr-1"></i>
|
|
|
|
|
<a href="{{ route('gruppi.show', $gruppo->id) }}">{{ $gruppo->nome }}</a>
|
|
|
|
|
</span>
|
|
|
|
|
</td>
|
|
|
|
|
@endif
|
|
|
|
|
@if(in_array('descrizione', $visibleColumns))
|
|
|
|
|
<td>{{ Str::limit($gruppo->descrizione, 50) ?: '-' }}</td>
|
|
|
|
|
@endif
|
|
|
|
|
@if(in_array('diocesi', $visibleColumns))
|
|
|
|
|
<td>{{ $gruppo->diocesi?->nome ?? '-' }}</td>
|
|
|
|
|
@endif
|
|
|
|
|
@if(in_array('livello', $visibleColumns))
|
|
|
|
|
<td><span class="badge badge-{{ ($gruppo->depth ?? 0) == 0 ? 'primary' : 'secondary' }}">{{ $gruppo->depth ?? 0 }}</span></td>
|
|
|
|
|
@endif
|
|
|
|
|
@if(in_array('padre', $visibleColumns))
|
|
|
|
|
<td>{{ $gruppo->parent?->nome ?? '-' }}</td>
|
|
|
|
|
@endif
|
|
|
|
|
@if(in_array('membri', $visibleColumns))
|
|
|
|
|
<td><span class="badge badge-info">{{ $gruppo->individui->count() }}</span></td>
|
|
|
|
|
@endif
|
|
|
|
|
@if(in_array('responsabili', $visibleColumns))
|
|
|
|
|
<td>
|
|
|
|
|
@php $resp = $gruppo->getResponsabili() @endphp
|
|
|
|
|
@if($resp->count() > 0)
|
|
|
|
|
{{ $resp->pluck('cognome')->implode(', ') }}
|
|
|
|
|
@else
|
|
|
|
|
-
|
|
|
|
|
@endif
|
|
|
|
|
</td>
|
|
|
|
|
@endif
|
|
|
|
|
@if(in_array('indirizzo', $visibleColumns))
|
|
|
|
|
<td>{{ $gruppo->indirizzo_incontro ?: '-' }}</td>
|
|
|
|
|
@endif
|
|
|
|
|
@if(in_array('citta', $visibleColumns))
|
|
|
|
|
<td>{{ $gruppo->città_incontro ?: '-' }}</td>
|
|
|
|
|
@endif
|
|
|
|
|
@if(in_array('telefono', $visibleColumns))
|
|
|
|
|
<td>-</td>
|
|
|
|
|
@endif
|
|
|
|
|
@if(in_array('email', $visibleColumns))
|
|
|
|
|
<td>-</td>
|
|
|
|
|
@endif
|
2026-06-09 11:02:01 +02:00
|
|
|
@if(in_array('tag', $visibleColumns))
|
|
|
|
|
<td>
|
|
|
|
|
@foreach($gruppo->tags as $tag)
|
|
|
|
|
<a href="{{ route('gruppi.index', ['tag[]' => $tag->slug]) }}" class="badge" style="background-color: {{ $tag->color ?? '#6c757d' }}; color: #fff;">{{ $tag->name }}</a>
|
|
|
|
|
@endforeach
|
|
|
|
|
</td>
|
|
|
|
|
@endif
|
2026-05-26 08:14:29 +02:00
|
|
|
<td>
|
|
|
|
|
<a href="{{ route('gruppi.show', $gruppo->id) }}" class="btn btn-xs btn-info" title="Visualizza">
|
|
|
|
|
<i class="fas fa-eye"></i>
|
|
|
|
|
</a>
|
|
|
|
|
@if($canWriteGruppi)
|
|
|
|
|
<a href="{{ url('/gruppi/' . $gruppo->id . '/edit') }}" class="btn btn-xs btn-warning" title="Modifica">
|
|
|
|
|
<i class="fas fa-edit"></i>
|
|
|
|
|
</a>
|
|
|
|
|
@endif
|
|
|
|
|
@if($canDeleteGruppi)
|
|
|
|
|
<form action="{{ url('/gruppi/' . $gruppo->id) }}" method="POST" class="d-inline">
|
|
|
|
|
@csrf @method('DELETE')
|
|
|
|
|
<button type="submit" class="btn btn-xs btn-danger" onclick="return confirm('Confermi l\'eliminazione?')" title="Elimina">
|
|
|
|
|
<i class="fas fa-trash"></i>
|
|
|
|
|
</button>
|
|
|
|
|
</form>
|
|
|
|
|
@endif
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
@endforeach
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
2026-06-07 23:05:48 +02:00
|
|
|
<div class="card-footer d-flex justify-content-between align-items-center">
|
|
|
|
|
<div>
|
|
|
|
|
<form method="GET" class="form-inline" id="perPageForm">
|
|
|
|
|
<label class="mr-2 small">Righe per pagina:</label>
|
|
|
|
|
<select name="perPage" class="form-control form-control-sm" onchange="this.form.submit()" style="width: auto;">
|
|
|
|
|
@foreach([10, 20, 25, 50, 100] as $p)
|
|
|
|
|
<option value="{{ $p }}" {{ (int) request('perPage', 20) === $p ? 'selected' : '' }}>{{ $p }}</option>
|
|
|
|
|
@endforeach
|
|
|
|
|
</select>
|
|
|
|
|
@foreach(request()->except(['perPage', 'page']) as $key => $value)
|
|
|
|
|
@if(is_array($value))
|
|
|
|
|
@foreach($value as $v)
|
|
|
|
|
<input type="hidden" name="{{ $key }}[]" value="{{ $v }}">
|
|
|
|
|
@endforeach
|
|
|
|
|
@else
|
|
|
|
|
<input type="hidden" name="{{ $key }}" value="{{ $value }}">
|
|
|
|
|
@endif
|
|
|
|
|
@endforeach
|
|
|
|
|
</form>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
{{ $gruppi->links() }}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-05-26 08:14:29 +02:00
|
|
|
@else
|
|
|
|
|
<div class="card-body p-0">
|
|
|
|
|
<div class="tree-view" style="padding: 15px;">
|
|
|
|
|
@php $rootGruppi = $gruppi->filter(fn($g) => $g->parent_id === null) @endphp
|
|
|
|
|
@forelse($rootGruppi as $gruppo)
|
|
|
|
|
@include('gruppi.partials.tree-item', ['gruppo' => $gruppo, 'isRoot' => true])
|
|
|
|
|
@empty
|
|
|
|
|
<div class="text-center text-muted py-4">
|
|
|
|
|
<i class="fas fa-folder-open fa-2x mb-2"></i>
|
|
|
|
|
<p>Nessun gruppo presente.
|
|
|
|
|
@if($canWriteGruppi)
|
|
|
|
|
<a href="{{ route('gruppi.create') }}">Crea il primo gruppo</a>
|
|
|
|
|
@endif
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
@endforelse
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
@endif
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
2026-06-09 11:02:01 +02:00
|
|
|
|
|
|
|
|
{{-- MODAL: Gestione Tag massiva --}}
|
|
|
|
|
<div class="modal fade" id="massTagModal" tabindex="-1" role="dialog">
|
|
|
|
|
<div class="modal-dialog modal-dialog-scrollable" role="document">
|
|
|
|
|
<div class="modal-content">
|
|
|
|
|
<div class="modal-header bg-info">
|
|
|
|
|
<h5 class="modal-title text-white"><i class="fas fa-tags mr-2"></i>Gestione Tag</h5>
|
|
|
|
|
<button type="button" class="close text-white" data-dismiss="modal"><span>×</span></button>
|
|
|
|
|
</div>
|
|
|
|
|
<form id="massTagForm" method="POST" action="/gruppi/mass-tag">
|
|
|
|
|
@csrf
|
|
|
|
|
<div class="modal-body">
|
|
|
|
|
<p class="mb-2">Operazione su <strong id="massTagCount">0</strong> gruppi selezionati.</p>
|
|
|
|
|
<div class="form-group mb-3">
|
|
|
|
|
<label class="font-weight-bold">Azione</label>
|
|
|
|
|
<div class="d-flex" style="gap:1.5rem;">
|
|
|
|
|
<div class="form-check">
|
|
|
|
|
<input class="form-check-input" type="radio" name="mode" id="grMtModeAssign" value="assign" checked>
|
|
|
|
|
<label class="form-check-label" for="grMtModeAssign">Assegna tag</label>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="form-check">
|
|
|
|
|
<input class="form-check-input" type="radio" name="mode" id="grMtModeRemove" value="remove">
|
|
|
|
|
<label class="form-check-label" for="grMtModeRemove">Rimuovi tag</label>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
@include('partials._tag-selector', ['label' => 'Seleziona tag'])
|
|
|
|
|
<input type="hidden" name="ids" id="massTagIds" value="">
|
|
|
|
|
</div>
|
|
|
|
|
<div class="modal-footer">
|
|
|
|
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Annulla</button>
|
|
|
|
|
<button type="submit" class="btn btn-primary"><i class="fas fa-tags mr-1"></i> Applica</button>
|
|
|
|
|
</div>
|
|
|
|
|
</form>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{{-- MODAL: Conferma Eliminazione massiva --}}
|
|
|
|
|
<div class="modal fade" id="deleteModal" tabindex="-1" role="dialog">
|
|
|
|
|
@if($canDeleteGruppi)
|
|
|
|
|
<div class="modal-dialog" role="document">
|
|
|
|
|
<div class="modal-content">
|
|
|
|
|
<div class="modal-header bg-danger">
|
|
|
|
|
<h5 class="modal-title text-white"><i class="fas fa-trash-alt mr-2"></i>Conferma Eliminazione</h5>
|
|
|
|
|
<button type="button" class="close text-white" data-dismiss="modal"><span>×</span></button>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="modal-body">
|
|
|
|
|
<p>Stai per eliminare <strong id="delete-count">0</strong> gruppi.</p>
|
|
|
|
|
<div class="alert alert-warning mt-3 mb-0">
|
|
|
|
|
<small><i class="fas fa-info-circle mr-1"></i>I membri verranno scollegati ma non eliminati.</small>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="modal-footer">
|
|
|
|
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Annulla</button>
|
|
|
|
|
<button type="button" class="btn btn-danger" id="confirm-delete-btn"><i class="fas fa-trash mr-1"></i> Elimina</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
@endif
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-05-26 08:14:29 +02:00
|
|
|
@endsection
|
|
|
|
|
|
|
|
|
|
@section('scripts')
|
2026-06-10 14:03:43 +02:00
|
|
|
<script src="{{ asset('js/column-manager.js') }}"></script>
|
2026-05-26 08:14:29 +02:00
|
|
|
<script>
|
|
|
|
|
function switchView(mode) {
|
|
|
|
|
window.location.href = '?view=' + mode;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-09 11:02:01 +02:00
|
|
|
function toggleSelectAll(source) {
|
|
|
|
|
document.querySelectorAll('.row-checkbox').forEach(function(cb) {
|
|
|
|
|
cb.checked = source.checked;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getSelectedIds() {
|
|
|
|
|
return Array.from(document.querySelectorAll('.row-checkbox:checked')).map(cb => cb.value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function showMassTagModal() {
|
|
|
|
|
const ids = getSelectedIds();
|
|
|
|
|
if (ids.length === 0) {
|
|
|
|
|
alert('Seleziona almeno un gruppo');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
document.getElementById('massTagIds').value = ids.join(',');
|
|
|
|
|
document.getElementById('massTagCount').textContent = ids.length;
|
|
|
|
|
$('#massTagModal').modal('show');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function deleteSelected() {
|
|
|
|
|
const ids = getSelectedIds();
|
|
|
|
|
if (ids.length === 0) {
|
|
|
|
|
alert('Seleziona almeno un gruppo');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
document.getElementById('delete-count').textContent = ids.length;
|
|
|
|
|
document.getElementById('confirm-delete-btn').onclick = function() {
|
|
|
|
|
const form = document.createElement('form');
|
|
|
|
|
form.method = 'POST';
|
|
|
|
|
form.action = '/gruppi/mass-elimina';
|
|
|
|
|
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.content || '{{ csrf_token() }}';
|
|
|
|
|
let html = '<input type="hidden" name="_token" value="' + csrfToken + '">';
|
|
|
|
|
ids.forEach(function(id) {
|
|
|
|
|
html += '<input type="hidden" name="ids[]" value="' + id + '">';
|
|
|
|
|
});
|
|
|
|
|
form.innerHTML = html;
|
|
|
|
|
document.body.appendChild(form);
|
|
|
|
|
form.submit();
|
|
|
|
|
};
|
|
|
|
|
$('#deleteModal').modal('show');
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-26 08:14:29 +02:00
|
|
|
function toggleItem(id) {
|
|
|
|
|
const el = document.getElementById('group-' + id);
|
|
|
|
|
const icon = document.getElementById('icon-' + id);
|
|
|
|
|
if (el.style.display === 'none') {
|
|
|
|
|
el.style.display = 'block';
|
|
|
|
|
icon.classList.remove('fa-chevron-right');
|
|
|
|
|
icon.classList.add('fa-chevron-down');
|
|
|
|
|
} else {
|
|
|
|
|
el.style.display = 'none';
|
|
|
|
|
icon.classList.remove('fa-chevron-down');
|
|
|
|
|
icon.classList.add('fa-chevron-right');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function toggleAllGroups() {
|
|
|
|
|
const collapsed = document.querySelectorAll('.tree-children[style*="display: none"]').length > 0;
|
|
|
|
|
document.querySelectorAll('.tree-children').forEach(el => {
|
|
|
|
|
el.style.display = collapsed ? 'block' : 'none';
|
|
|
|
|
});
|
|
|
|
|
document.querySelectorAll('.tree-toggle i').forEach(icon => {
|
|
|
|
|
if (collapsed) {
|
|
|
|
|
icon.classList.remove('fa-chevron-right');
|
|
|
|
|
icon.classList.add('fa-chevron-down');
|
|
|
|
|
} else {
|
|
|
|
|
icon.classList.remove('fa-chevron-down');
|
|
|
|
|
icon.classList.add('fa-chevron-right');
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let sortDirection = {};
|
|
|
|
|
|
|
|
|
|
function sortTable(column) {
|
|
|
|
|
const tbody = document.getElementById('table-body');
|
|
|
|
|
const rows = Array.from(tbody.querySelectorAll('tr'));
|
|
|
|
|
|
|
|
|
|
sortDirection[column] = sortDirection[column] === 'asc' ? 'desc' : 'asc';
|
|
|
|
|
const dir = sortDirection[column];
|
|
|
|
|
|
|
|
|
|
rows.sort(function(a, b) {
|
|
|
|
|
const cellA = a.querySelector(`td:nth-child(${getColumnIndex(column)})`)?.textContent.trim() || '';
|
|
|
|
|
const cellB = b.querySelector(`td:nth-child(${getColumnIndex(column)})`)?.textContent.trim() || '';
|
|
|
|
|
|
|
|
|
|
if (dir === 'asc') {
|
|
|
|
|
return cellA.localeCompare(cellB, 'it');
|
|
|
|
|
}
|
|
|
|
|
return cellB.localeCompare(cellA, 'it');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
rows.forEach(row => tbody.appendChild(row));
|
|
|
|
|
|
|
|
|
|
document.querySelectorAll('th i.fa-sort').forEach(icon => {
|
|
|
|
|
icon.className = 'fas fa-sort float-right text-muted';
|
|
|
|
|
});
|
|
|
|
|
const th = document.querySelector(`th[data-sortable][onclick="sortTable('${column}')"] i`);
|
|
|
|
|
if (th) {
|
|
|
|
|
th.className = `fas fa-sort-${dir === 'asc' ? 'up' : 'down'} float-right`;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getColumnIndex(column) {
|
|
|
|
|
const th = document.querySelector(`th[onclick="sortTable('${column}')"]`);
|
|
|
|
|
if (th) {
|
|
|
|
|
return Array.from(th.parentNode.children).indexOf(th) + 1;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
<style>
|
|
|
|
|
.tree-item { margin-bottom: 5px; }
|
|
|
|
|
.tree-children {
|
|
|
|
|
margin-left: 25px;
|
|
|
|
|
border-left: 1px dashed #dee2e6;
|
|
|
|
|
padding-left: 10px;
|
|
|
|
|
}
|
|
|
|
|
.tree-toggle {
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
padding: 3px 8px;
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
}
|
|
|
|
|
.tree-toggle:hover {
|
|
|
|
|
background-color: #f8f9fa;
|
|
|
|
|
}
|
|
|
|
|
.tree-label {
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 8px;
|
|
|
|
|
}
|
|
|
|
|
.badge-level {
|
|
|
|
|
font-size: 0.7em;
|
|
|
|
|
padding: 2px 5px;
|
|
|
|
|
}
|
2026-06-10 14:03:43 +02:00
|
|
|
.btn-group .btn.active {
|
|
|
|
|
background-color: #007bff;
|
|
|
|
|
color: white;
|
|
|
|
|
border-color: #007bff;
|
|
|
|
|
}
|
2026-05-26 08:14:29 +02:00
|
|
|
</style>
|
2026-06-10 14:03:43 +02:00
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
|
|
|
const table = document.getElementById('gruppi-table');
|
|
|
|
|
if (table) {
|
|
|
|
|
window.columnManager = new ColumnManager('gruppi-table', {
|
|
|
|
|
entityType: 'gruppi',
|
|
|
|
|
storageKey: 'cm_gruppi',
|
|
|
|
|
resizable: true,
|
|
|
|
|
reorderable: true,
|
|
|
|
|
});
|
|
|
|
|
initTableSettings();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
window.printWithCurrentSettings = function () {
|
|
|
|
|
if (window.columnManager) {
|
|
|
|
|
window.columnManager.printWithSettings();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
</script>
|
2026-05-26 08:14:29 +02:00
|
|
|
@endsection
|