glastree_on_gitea
This commit is contained in:
@@ -0,0 +1,434 @@
|
||||
@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',
|
||||
];
|
||||
$vistaDefaultJson = $vista ? $vista->toJson() : 'null';
|
||||
$allColumnsJson = json_encode($allColumns);
|
||||
$visibleColumnsJson = json_encode($visibleColumns);
|
||||
@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">
|
||||
<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>
|
||||
<button type="button" class="btn btn-primary btn-sm mr-1" onclick="showSaveVistaModal()">
|
||||
<i class="fas fa-save mr-1"></i> Salva Vista
|
||||
</button>
|
||||
@if($canWriteGruppi)
|
||||
<a href="{{ route('gruppi.create') }}" class="btn btn-success btn-sm">
|
||||
<i class="fas fa-plus"></i> Nuovo Gruppo
|
||||
</a>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@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>
|
||||
@if(in_array('nome', $visibleColumns))
|
||||
<th data-sortable="true" onclick="sortTable('nome')" style="cursor:pointer;">Nome <i class="fas fa-sort float-right text-muted"></i></th>
|
||||
@endif
|
||||
@if(in_array('descrizione', $visibleColumns))
|
||||
<th data-sortable="true" onclick="sortTable('descrizione')" style="cursor:pointer;">Descrizione <i class="fas fa-sort float-right text-muted"></i></th>
|
||||
@endif
|
||||
@if(in_array('diocesi', $visibleColumns))
|
||||
<th>Diocesi</th>
|
||||
@endif
|
||||
@if(in_array('livello', $visibleColumns))
|
||||
<th style="width: 80px;">Livello</th>
|
||||
@endif
|
||||
@if(in_array('padre', $visibleColumns))
|
||||
<th>Gruppo Padre</th>
|
||||
@endif
|
||||
@if(in_array('membri', $visibleColumns))
|
||||
<th style="width: 100px;">Membri</th>
|
||||
@endif
|
||||
@if(in_array('responsabili', $visibleColumns))
|
||||
<th>Responsabili</th>
|
||||
@endif
|
||||
@if(in_array('indirizzo', $visibleColumns))
|
||||
<th>Indirizzo</th>
|
||||
@endif
|
||||
@if(in_array('citta', $visibleColumns))
|
||||
<th>Città</th>
|
||||
@endif
|
||||
@if(in_array('telefono', $visibleColumns))
|
||||
<th>Telefono</th>
|
||||
@endif
|
||||
@if(in_array('email', $visibleColumns))
|
||||
<th>Email</th>
|
||||
@endif
|
||||
<th style="width: 120px;">Azioni</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="table-body">
|
||||
@foreach($gruppi as $gruppo)
|
||||
<tr data-id="{{ $gruppo->id }}">
|
||||
@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
|
||||
<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>
|
||||
@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>
|
||||
|
||||
<div class="modal fade" id="saveVistaModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><i class="fas fa-save mr-2"></i>Salva Vista</h5>
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label>Nome Vista *</label>
|
||||
<input type="text" id="vista-nome" class="form-control" placeholder="Es. Elenco gruppi attivi">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Colonne visibili</label>
|
||||
<div class="row" id="colonne-checkboxes">
|
||||
@foreach($allColumns as $col)
|
||||
<div class="col-md-4 mb-2">
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input col-checkbox" id="col-{{ $col }}" value="{{ $col }}" {{ in_array($col, $visibleColumns) ? 'checked' : '' }}>
|
||||
<label class="custom-control-label" for="col-{{ $col }}">{{ $columnLabels[$col] ?? $col }}</label>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="vista-default">
|
||||
<label class="custom-control-label" for="vista-default">Imposta come vista predefinita</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Annulla</button>
|
||||
<button type="button" class="btn btn-primary" onclick="saveVista()">
|
||||
<i class="fas fa-save mr-1"></i> Salva
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="vistaListModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><i class="fas fa-bookmark mr-2"></i>Viste Salvate</h5>
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
@php
|
||||
$visteSalvate = \App\Models\VistaReport::where('user_id', Auth::id())
|
||||
->where('tipo', 'gruppi')
|
||||
->orderBy('is_default', 'desc')
|
||||
->orderBy('nome')
|
||||
->get();
|
||||
@endphp
|
||||
@if($visteSalvate->count() > 0)
|
||||
<div class="list-group">
|
||||
@foreach($visteSalvate as $v)
|
||||
<div class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<a href="?vista_id={{ $v->id }}">{{ $v->nome }}</a>
|
||||
@if($v->is_default)
|
||||
<span class="badge badge-success ml-1">Predefinita</span>
|
||||
@endif
|
||||
</div>
|
||||
<form action="{{ route('gruppi.delete-vista', $v->id) }}" method="POST" class="d-inline">
|
||||
@csrf @method('DELETE')
|
||||
<button type="submit" class="btn btn-xs btn-danger" onclick="return confirm('Eliminare questa vista?')">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
<p class="text-muted text-center">Nessuna vista salvata</p>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('scripts')
|
||||
<script>
|
||||
function switchView(mode) {
|
||||
window.location.href = '?view=' + mode;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
function showSaveVistaModal() {
|
||||
document.getElementById('vista-nome').value = '';
|
||||
document.getElementById('vista-default').checked = false;
|
||||
$('#saveVistaModal').modal('show');
|
||||
}
|
||||
|
||||
function saveVista() {
|
||||
const nome = document.getElementById('vista-nome').value.trim();
|
||||
if (!nome) {
|
||||
alert('Inserisci un nome per la vista');
|
||||
return;
|
||||
}
|
||||
|
||||
const colonneVisibili = Array.from(document.querySelectorAll('.col-checkbox:checked')).map(cb => cb.value);
|
||||
const isDefault = document.getElementById('vista-default').checked;
|
||||
|
||||
fetch('/gruppi/save-vista', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
nome: nome,
|
||||
colonne_visibili: colonneVisibili,
|
||||
is_default: isDefault,
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
$('#saveVistaModal').modal('hide');
|
||||
window.location.reload();
|
||||
} else {
|
||||
alert('Errore nel salvataggio della vista');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
alert('Errore: ' + error.message);
|
||||
});
|
||||
}
|
||||
</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;
|
||||
}
|
||||
.btn-group .btn.active {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border-color: #007bff;
|
||||
}
|
||||
</style>
|
||||
@endsection
|
||||
Reference in New Issue
Block a user