glastree_on_gitea

This commit is contained in:
2026-05-26 08:14:29 +02:00
commit 0bed099d05
9556 changed files with 1186307 additions and 0 deletions
+244
View File
@@ -0,0 +1,244 @@
@extends('layouts.adminlte')
@section('title', 'Nuovo Gruppo')
@section('page_title', 'Nuovo Gruppo')
@section('content')
<form action="/gruppi" method="POST">
@csrf
<div class="row">
<div class="col-md-6">
<div class="card card-primary">
<div class="card-header">
<h3 class="card-title"><i class="fas fa-folder mr-2"></i>Dati Gruppo</h3>
</div>
<div class="card-body">
<div class="form-group">
<label>Nome *</label>
<input type="text" name="nome" class="form-control @error('nome') is-invalid @enderror" value="{{ old('nome') }}" required>
@error('nome')
<span class="invalid-feedback">{{ $message }}</span>
@enderror
</div>
<div class="form-group">
<label>Gruppo Padre</label>
<select name="parent_id" class="form-control">
<option value="">Nessuno (gruppo radice)</option>
@foreach($allGruppi as $g)
<option value="{{ $g->id }}" {{ old('parent_id') == $g->id || ($selectedParent && $selectedParent->id == $g->id) ? 'selected' : '' }}>
{{ $g->full_path }}
</option>
@endforeach
</select>
@if($selectedParent)
<small class="form-text text-muted">
Verrà creato come sottogruppo di: <strong>{{ $selectedParent->nome }}</strong>
</small>
@endif
</div>
<div class="form-group">
<label>Diocesi</label>
<select name="diocesi_id" class="form-control">
<option value="">Seleziona...</option>
@foreach($diocesi as $d)
<option value="{{ $d->id }}" {{ old('diocesi_id') == $d->id ? 'selected' : '' }}>{{ $d->nome }}</option>
@endforeach
</select>
</div>
<div class="form-group">
<label>Responsabili</label>
<select name="responsabile_ids[]" class="form-control" multiple size="4" id="responsabile-select">
<option value="">-- Nessuno --</option>
</select>
<small class="text-muted">Ctrl+click per selezionare più responsabili</small>
</div>
<div class="form-group">
<label>Descrizione</label>
<textarea name="descrizione" class="form-control" rows="3">{{ old('descrizione') }}</textarea>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card">
<div class="card-header"><h3 class="card-title"><i class="fas fa-map-marker-alt mr-2"></i>Luogo Incontro</h3></div>
<div class="card-body">
<div class="form-group">
<label>Indirizzo</label>
<input type="text" name="indirizzo_incontro" class="form-control" value="{{ old('indirizzo_incontro') }}">
</div>
<div class="form-row">
<div class="form-group col-md-4">
<label>CAP</label>
<input type="text" name="cap_incontro" class="form-control" value="{{ old('cap_incontro') }}">
</div>
<div class="form-group col-md-5">
<label>Città</label>
<input type="text" name="città_incontro" class="form-control" value="{{ old('città_incontro') }}">
</div>
<div class="form-group col-md-3">
<label>Provincia</label>
<input type="text" name="sigla_provincia_incontro" class="form-control" maxlength="2" value="{{ old('sigla_provincia_incontro') }}">
</div>
</div>
<div class="form-group mb-0">
<label>URL Mappa</label>
<input type="url" name="mappa_posizione" class="form-control" value="{{ old('mappa_posizione') }}" placeholder="https://...">
</div>
</div>
</div>
</div>
</div>
<div class="card mt-3">
<div class="card-header">
<h3 class="card-title"><i class="fas fa-users mr-2"></i>Membri</h3>
<button type="button" class="btn btn-xs btn-success float-right" onclick="aggiungiMembro()">
<i class="fas fa-plus mr-1"></i> Aggiungi Membro
</button>
</div>
<div class="card-body p-0">
<table class="table table-bordered mb-0" id="membri-table">
<thead class="thead-light">
<tr>
<th style="width: 30%;">Individuo</th>
<th>Codice</th>
<th>Contatti</th>
<th style="width: 20%;">Ruolo</th>
<th style="width: 100px;">Data Adesione</th>
<th style="width: 50px;"></th>
</tr>
</thead>
<tbody id="membri-tbody">
</tbody>
</table>
<div id="no-membri-msg" class="text-center text-muted py-4">
<p class="mb-0">Nessun membro aggiunto. Clicca su "Aggiungi Membro" per iniziare.</p>
</div>
</div>
</div>
<div class="mt-3">
<button type="submit" class="btn btn-success">
<i class="fas fa-save mr-1"></i> Salva
</button>
<a href="/gruppi" class="btn btn-secondary">
<i class="fas fa-times mr-1"></i> Annulla
</a>
</div>
</form>
@endsection
@section('scripts')
<script>
let membriIndex = 0;
const membriResponsabiliMap = new Map();
function aggiungiMembro() {
const tbody = document.getElementById('membri-tbody');
const noMsg = document.getElementById('no-membri-msg');
if (noMsg) noMsg.style.display = 'none';
const row = document.createElement('tr');
row.innerHTML = `
<td>
<select name="individui[${membriIndex}][individuo_id]" class="form-control" onchange="updateMembroInfo(this); updateResponsabiliFromMembri();" required>
<option value="">Seleziona...</option>
@foreach($individui as $i)
<option value="{{ $i->id }}" data-codice="{{ $i->codice_id }}" data-email="{{ $i->email_primaria }}" data-telefono="{{ $i->telefono_primario }}">
{{ $i->cognome }} {{ $i->nome }}
</option>
@endforeach
</select>
</td>
<td><span class="text-muted membro-codice">-</span></td>
<td><small class="text-muted membro-contatti">-</small></td>
<td><input type="text" name="individui[${membriIndex}][ruolo_nel_gruppo]" class="form-control" placeholder="Es. Membro"></td>
<td><input type="date" name="individui[${membriIndex}][data_adesione]" class="form-control"></td>
<td><button type="button" class="btn btn-danger btn-xs" onclick="rimuoviMembro(this); updateResponsabiliFromMembri();"><i class="fas fa-trash"></i></button></td>
`;
tbody.appendChild(row);
membriIndex++;
}
function updateMembroInfo(select) {
const row = select.closest('tr');
const option = select.options[select.selectedIndex];
const codice = option.dataset.codice || '-';
const email = option.dataset.email || '';
const telefono = option.dataset.telefono || '';
row.querySelector('.membro-codice').textContent = codice;
let contatti = [];
if (email) contatti.push('<span class="text-primary">'+email+'</span>');
if (telefono) contatti.push('<span class="text-success">'+telefono+'</span>');
row.querySelector('.membro-contatti').innerHTML = contatti.length ? contatti.join(' | ') : '-';
}
function rimuoviMembro(btn) {
const row = btn.closest('tr');
row.remove();
if (document.getElementById('membri-tbody').children.length === 0) {
document.getElementById('no-membri-msg').style.display = 'block';
}
}
function updateResponsabiliFromMembri() {
const respSelect = document.getElementById('responsabile-select');
const currentSelected = Array.from(respSelect.selectedOptions).map(o => o.value);
const tbody = document.getElementById('membri-tbody');
const rows = tbody.querySelectorAll('tr');
const membroIds = new Set();
const membroNames = new Map();
rows.forEach(row => {
const select = row.querySelector('select[name*="individuo_id"]');
if (select && select.value) {
membroIds.add(select.value);
const option = select.options[select.selectedIndex];
membroNames.set(select.value, option.text);
}
});
respSelect.innerHTML = '';
if (membroIds.size === 0) {
const opt = document.createElement('option');
opt.value = '';
opt.textContent = '-- Aggiungi prima dei membri --';
opt.disabled = true;
respSelect.appendChild(opt);
} else {
membroIds.forEach(id => {
const opt = document.createElement('option');
opt.value = id;
opt.textContent = membroNames.get(id);
if (currentSelected.includes(id)) opt.selected = true;
respSelect.appendChild(opt);
});
}
}
const respSelect = document.getElementById('responsabile-select');
const individuiList = @json($individui->map(fn($i) => ['id' => $i->id, 'text' => $i->cognome . ' ' . $i->nome]));
const initialResponsabili = @json(old('responsabile_ids', []));
const optPlaceholder = document.createElement('option');
optPlaceholder.value = '';
optPlaceholder.textContent = '-- Aggiungi prima dei membri --';
optPlaceholder.disabled = true;
respSelect.appendChild(optPlaceholder);
initialResponsabili.forEach(id => {
const match = individuiList.find(i => i.id == id);
if (match) {
const opt = document.createElement('option');
opt.value = match.id;
opt.textContent = match.text;
opt.selected = true;
respSelect.appendChild(opt);
}
});
</script>
@endsection
+477
View File
@@ -0,0 +1,477 @@
@extends('layouts.adminlte')
@section('title', 'Modifica Gruppo')
@section('page_title', 'Modifica Gruppo')
@section('content')
<form action="/gruppi/{{ $gruppo->id }}" method="POST">
@csrf @method('PUT')
<div class="row">
<div class="col-md-6">
<div class="card card-primary">
<div class="card-header">
<h3 class="card-title"><i class="fas fa-folder mr-2"></i>Dati Gruppo</h3>
</div>
<div class="card-body">
<div class="form-group">
<label>Nome *</label>
<input type="text" name="nome" class="form-control" value="{{ old('nome', $gruppo->nome) }}" required>
</div>
<div class="form-group">
<label>Gruppo Padre</label>
<select name="parent_id" class="form-control">
<option value="">Nessuno (gruppo radice)</option>
@foreach($gruppi as $g)
@if($g->id !== $gruppo->id)
<option value="{{ $g->id }}" {{ old('parent_id', $gruppo->parent_id) == $g->id ? 'selected' : '' }}>
{{ $g->full_path }}
</option>
@endif
@endforeach
</select>
</div>
<div class="form-group">
<label>Diocesi</label>
<select name="diocesi_id" class="form-control">
<option value="">Seleziona...</option>
@foreach($diocesi as $d)
<option value="{{ $d->id }}" {{ old('diocesi_id', $gruppo->diocesi_id) == $d->id ? 'selected' : '' }}>{{ $d->nome }}</option>
@endforeach
</select>
</div>
<div class="form-group">
<label>Responsabili (solo membri)</label>
<select name="responsabile_ids[]" class="form-control" multiple size="4">
@foreach($membri as $m)
<option value="{{ $m->id }}" {{ in_array($m->id, old('responsabile_ids', $gruppo->getResponsabiliIds() ?? [])) ? 'selected' : '' }}>
{{ $m->cognome }} {{ $m->nome }}
</option>
@endforeach
</select>
@if($membri->isEmpty())
<small class="text-muted">Prima aggiungi dei membri al gruppo</small>
@else
<small class="text-muted">Ctrl+click per selezionare più responsabili</small>
@endif
</div>
<div class="form-group">
<label>Descrizione</label>
<textarea name="descrizione" class="form-control" rows="3">{{ old('descrizione', $gruppo->descrizione) }}</textarea>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card">
<div class="card-header"><h3 class="card-title"><i class="fas fa-map-marker-alt mr-2"></i>Luogo Incontro</h3></div>
<div class="card-body">
<div class="form-group">
<label>Indirizzo</label>
<input type="text" name="indirizzo_incontro" class="form-control" value="{{ old('indirizzo_incontro', $gruppo->indirizzo_incontro) }}">
</div>
<div class="form-row">
<div class="form-group col-md-4">
<label>CAP</label>
<input type="text" name="cap_incontro" class="form-control" value="{{ old('cap_incontro', $gruppo->cap_incontro) }}">
</div>
<div class="form-group col-md-5">
<label>Città</label>
<input type="text" name="città_incontro" class="form-control" value="{{ old('città_incontro', $gruppo->città_incontro) }}">
</div>
<div class="form-group col-md-3">
<label>Provincia</label>
<input type="text" name="sigla_provincia_incontro" class="form-control" maxlength="2" value="{{ old('sigla_provincia_incontro', $gruppo->sigla_provincia_incontro) }}">
</div>
</div>
<div class="form-group mb-0">
<label>URL Mappa</label>
<input type="url" name="mappa_posizione" class="form-control" value="{{ old('mappa_posizione', $gruppo->mappa_posizione) }}" placeholder="https://...">
</div>
</div>
</div>
</div>
</div>
<div class="card mt-3">
<div class="card-header">
<h3 class="card-title"><i class="fas fa-users mr-2"></i>Membri</h3>
<button type="button" class="btn btn-xs btn-success float-right" onclick="showMembroForm()">
<i class="fas fa-plus mr-1"></i> Aggiungi
</button>
</div>
<div class="card-body p-0">
@if($gruppo->individui->count() > 0)
<table class="table table-bordered table-hover table-striped mb-0">
<thead class="thead-light">
<tr>
<th style="width: 25%;">Individuo</th>
<th style="width: 80px;">Codice</th>
<th style="width: 25%;">Contatti</th>
<th style="width: 130px;">Ruolo</th>
<th style="width: 110px;">Data Adesione</th>
<th style="width: 80px;">Azioni</th>
</tr>
</thead>
<tbody>
@foreach($gruppo->individui as $membro)
<tr id="membro-row-{{ $membro->id }}">
<td>
<i class="fas fa-user text-primary mr-1"></i>
<a href="/individui/{{ $membro->id }}">{{ $membro->cognome }} {{ $membro->nome }}</a>
</td>
<td>{{ $membro->codice_id }}</td>
<td>
<small>
@if($membro->email_primaria)
<span class="text-primary">{{ $membro->email_primaria }}</span><br>
@endif
@if($membro->telefono_primario)
<span class="text-success">{{ $membro->telefono_primario }}</span>
@endif
</small>
</td>
<td>
@php $ruoliMembro = $membro->getRuoliForGruppo($gruppo->id) @endphp
@if($ruoliMembro->count() > 0)
@foreach($ruoliMembro as $ruolo)
<span class="badge badge-info mr-1">{{ $ruolo->nome }}</span>
@endforeach
@else
-
@endif
</td>
<td>{{ $membro->pivot->data_adesione ? \Carbon\Carbon::parse($membro->pivot->data_adesione)->format('d/m/Y') : '-' }}</td>
<td>
<button type="button" class="btn btn-xs btn-warning" onclick="editMembroInline({{ $membro->id }})" title="Modifica">
<i class="fas fa-edit"></i>
</button>
<button type="button" class="btn btn-xs btn-danger" onclick="deleteMembro({{ $membro->id }})" title="Rimuovi">
<i class="fas fa-trash"></i>
</button>
</td>
</tr>
<tr id="membro-edit-{{ $membro->id }}" style="display:none;">
<td colspan="6">
<form action="/gruppi/{{ $gruppo->id }}/membri/{{ $membro->id }}" method="POST" class="mb-0">
@csrf @method('PUT')
<div class="row">
<div class="col-md-4">
<input type="text" class="form-control form-control-sm" value="{{ $membro->cognome }} {{ $membro->nome }}" disabled>
</div>
<div class="col-md-2">
<input type="text" class="form-control form-control-sm" value="{{ $membro->codice_id }}" disabled>
</div>
<div class="col-md-3">
<select name="ruolo_ids[]" class="form-control form-control-sm" multiple size="3">
@foreach(\App\Models\Ruolo::attive() as $ruolo)
@php $selected = in_array($ruolo->id, $membro->getRuoloIdsForGruppo($gruppo->id)) @endphp
<option value="{{ $ruolo->id }}" {{ $selected ? 'selected' : '' }}>{{ $ruolo->nome }}</option>
@endforeach
</select>
</div>
<div class="col-md-2">
<input type="date" name="data_adesione" class="form-control form-control-sm" value="{{ $membro->pivot->data_adesione }}">
</div>
<div class="col-md-1">
<button type="submit" class="btn btn-xs btn-success"><i class="fas fa-check"></i></button>
<button type="button" class="btn btn-xs btn-secondary" onclick="cancelEditMembro({{ $membro->id }})"><i class="fas fa-times"></i></button>
</div>
</div>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
@else
<div class="text-center text-muted py-4">
<i class="fas fa-users fa-2x mb-2"></i>
<p class="mb-0">Nessun membro associato</p>
</div>
@endif
</div>
</div>
<div class="card mt-3">
<div class="card-header">
<h3 class="card-title"><i class="fas fa-file mr-2"></i>Documenti</h3>
<button type="button" class="btn btn-xs btn-success float-right" onclick="showDocumentoForm()">
<i class="fas fa-plus mr-1"></i> Carica
</button>
</div>
<div class="card-body p-0">
<div id="documento-add-form" style="display:none;" class="p-3 bg-light border-bottom">
<form action="/documenti" method="POST" enctype="multipart/form-data" class="mb-0">
@csrf
<input type="hidden" name="visibilita" value="gruppo">
<input type="hidden" name="visibilita_target_id" value="{{ $gruppo->id }}">
<input type="hidden" name="visibilita_target_type" value="App\Models\Gruppo">
<div class="row">
<div class="col-md-3">
<input type="text" name="nome_file" class="form-control form-control-sm" placeholder="Nome documento" required>
</div>
<div class="col-md-3">
<select name="tipologia" class="form-control form-control-sm" required>
<option value="">Tipologia...</option>
<option value="documento">Documento</option>
<option value="statuto">Statuto</option>
<option value="avatar">Avatar</option>
<option value="galleria">Galleria</option>
<option value="altro">Altro</option>
</select>
</div>
<div class="col-md-4">
<input type="file" name="file" class="form-control form-control-sm" required>
</div>
<div class="col-md-2">
<button type="submit" class="btn btn-xs btn-success"><i class="fas fa-upload mr-1"></i>Carica</button>
<button type="button" class="btn btn-xs btn-secondary" onclick="hideDocumentoForm()"><i class="fas fa-times"></i></button>
</div>
</div>
</form>
</div>
@if($gruppo->documenti && $gruppo->documenti->count() > 0)
<table class="table table-bordered table-hover table-striped mb-0">
<thead class="thead-light">
<tr>
<th>Nome</th>
<th style="width: 120px;">Tipologia</th>
<th style="width: 80px;">Dimensione</th>
<th style="width: 130px;">Data Upload</th>
<th style="width: 80px;">Azioni</th>
</tr>
</thead>
<tbody>
@foreach($gruppo->documenti as $documento)
<tr>
<td>
<i class="fas fa-file text-secondary mr-1"></i>
{{ $documento->nome_file }}
</td>
<td>{{ ucfirst(str_replace('_', ' ', $documento->tipologia)) }}</td>
<td>{{ number_format($documento->dimensione / 1024, 1) }} KB</td>
<td>{{ $documento->created_at->format('d/m/Y') }}</td>
<td>
@if($documento->file_path)
<button type="button" class="btn btn-xs btn-primary" onclick="previewDocumento({{ $documento->id }}, '{{ $documento->mime_type }}')" title="Anteprima">
<i class="fas fa-eye"></i>
</button>
@endif
<form action="/documenti/{{ $documento->id }}" method="POST" class="d-inline">
@csrf @method('DELETE')
<button type="submit" class="btn btn-xs btn-danger" onclick="return confirm('Eliminare questo documento?')" title="Elimina">
<i class="fas fa-trash"></i>
</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
@else
<div class="text-center text-muted py-4">
<i class="fas fa-file fa-2x mb-2"></i>
<p class="mb-0">Nessun documento</p>
</div>
@endif
</div>
</div>
<div class="mt-3">
<button type="submit" class="btn btn-success">
<i class="fas fa-save mr-1"></i> Salva Modifiche
</button>
<a href="/gruppi/{{ $gruppo->id }}" class="btn btn-secondary">
<i class="fas fa-times mr-1"></i> Annulla
</a>
</div>
</form>
<div class="card mt-3" id="membro-card" style="display:none; background-color: #fff3cd; border-color: #ffc107;">
<div class="card-header bg-warning">
<h3 class="card-title"><i class="fas fa-user-plus mr-2"></i>Aggiungi Membro</h3>
</div>
<div class="card-body">
<div id="membro-form-container">
<div class="row">
<div class="col-md-4">
<select id="new-membro-individuo" class="form-control form-control-sm">
<option value="">Seleziona individuo...</option>
@foreach(\App\Models\Individuo::whereNotIn('id', $membri->pluck('id'))->orderBy('cognome')->orderBy('nome')->get() as $i)
<option value="{{ $i->id }}">{{ $i->cognome }} {{ $i->nome }}</option>
@endforeach
</select>
</div>
<div class="col-md-3">
<select id="new-membro-ruolo" class="form-control form-control-sm" multiple size="3">
@foreach(\App\Models\Ruolo::attive() as $ruolo)
<option value="{{ $ruolo->id }}">{{ $ruolo->nome }}</option>
@endforeach
</select>
<small class="text-muted">Ctrl+click per selezionare più ruoli</small>
</div>
<div class="col-md-3">
<input type="date" id="new-membro-data" class="form-control form-control-sm">
</div>
<div class="col-md-2">
<button type="button" class="btn btn-success btn-sm" onclick="submitMembroForm()">
<i class="fas fa-check mr-1"></i> Associa
</button>
<button type="button" class="btn btn-secondary btn-sm" onclick="hideMembroForm()">
<i class="fas fa-times"></i>
</button>
</div>
</div>
</div>
</div>
</div>
<div class="modal fade" id="previewModal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-lg" role="document" style="max-width: 90vw;">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><i class="fas fa-file mr-2"></i><span id="previewModalTitle">Anteprima</span></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Chiudi">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body text-center p-0" style="min-height: 400px;">
<iframe id="previewFrame" src="" style="width: 100%; height: 70vh; border: none;"></iframe>
</div>
<div class="modal-footer">
<a id="previewDownloadBtn" href="#" class="btn btn-primary" download>
<i class="fas fa-download mr-1"></i> Scarica
</a>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Chiudi</button>
</div>
</div>
</div>
</div>
@endsection
@section('scripts')
<script>
function showMembroForm() {
console.log('showMembroForm called');
var card = document.getElementById('membro-card');
console.log('Card element:', card);
if (card) {
card.style.display = 'block';
card.scrollIntoView({ behavior: 'smooth', block: 'start' });
console.log('Card shown');
} else {
console.error('Card not found');
}
}
function hideMembroForm() {
var card = document.getElementById('membro-card');
if (card) {
card.style.display = 'none';
}
}
function submitMembroForm() {
var individuoId = document.getElementById('new-membro-individuo').value;
var ruoloSelect = document.getElementById('new-membro-ruolo');
var dataAdesione = document.getElementById('new-membro-data').value;
if (!individuoId) {
alert('Seleziona un individuo');
return;
}
document.getElementById('new-membro-individuo').removeAttribute('required');
var formData = new URLSearchParams();
formData.append('individuo_id', individuoId);
var selectedRuoli = Array.from(ruoloSelect.selectedOptions).map(opt => opt.value).filter(v => v);
selectedRuoli.forEach(function(ruoloId) {
formData.append('ruolo_ids[]', ruoloId);
});
formData.append('data_adesione', dataAdesione);
fetch('/gruppi/{{ $gruppo->id }}/membri', {
method: 'POST',
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}',
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
},
body: formData
})
.then(response => {
if (!response.ok) {
return response.text().then(text => { throw new Error(text); });
}
return response.json();
})
.then(data => {
if (data.success) {
hideMembroForm();
window.location.reload();
} else {
alert(data.error || 'Errore');
}
})
.catch(error => {
alert('Errore: ' + error.message);
});
}
function editMembroInline(id) {
document.getElementById('membro-row-' + id).style.display = 'none';
document.getElementById('membro-edit-' + id).style.display = 'table-row';
}
function cancelEditMembro(id) {
document.getElementById('membro-row-' + id).style.display = 'table-row';
document.getElementById('membro-edit-' + id).style.display = 'none';
}
function deleteMembro(individuoId) {
if (!confirm('Rimuovere questo membro dal gruppo?')) return;
fetch('/gruppi/{{ $gruppo->id }}/membri/' + individuoId, {
method: 'DELETE',
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}',
'Accept': 'application/json'
}
})
.then(response => {
if (!response.ok) {
return response.text().then(text => { throw new Error(text); });
}
return response.json();
})
.then(data => {
if (data.success) {
window.location.reload();
} else {
alert(data.error || 'Errore');
}
})
.catch(error => {
alert('Errore: ' + error.message);
});
}
function showDocumentoForm() {
document.getElementById('documento-add-form').style.display = 'block';
}
function hideDocumentoForm() {
document.getElementById('documento-add-form').style.display = 'none';
}
function previewDocumento(id, mimeType) {
document.getElementById('previewFrame').src = '/documenti/' + id + '/preview';
document.getElementById('previewDownloadBtn').href = '/documenti/' + id + '/download';
$('#previewModal').modal('show');
}
</script>
@endsection
+434
View File
@@ -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">&times;</button>
{{ session('success') }}
</div>
@endif
@if(session('error'))
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert">&times;</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>&times;</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>&times;</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
@@ -0,0 +1,72 @@
@php
$children = $gruppo->children()->with(['diocesi', 'individui'])->orderBy('nome')->get();
$hasChildren = $children->count() > 0;
$canWriteGruppi = Auth::user()->canManage('gruppi');
$responsabili = $gruppo->getResponsabili();
@endphp
<div class="tree-item" style="margin-left: {{ $gruppo->depth ?? 0 }}px;">
<div class="tree-label">
@if($hasChildren)
<span class="tree-toggle" onclick="toggleItem({{ $gruppo->id }})">
<i id="icon-{{ $gruppo->id }}" class="fas fa-chevron-right text-muted"></i>
</span>
@else
<span style="width: 22px; display: inline-block;"></span>
@endif
<i class="fas fa-{{ $hasChildren ? 'folder' : 'folder-open' }} text-{{ $gruppo->depth == 0 ? 'warning' : 'secondary' }} mr-1"></i>
<a href="{{ route('gruppi.show', $gruppo->id) }}" class="{{ ($gruppo->depth ?? 0) == 0 ? 'font-weight-bold' : '' }}">
{{ $gruppo->nome }}
</a>
<span class="badge badge-{{ ($gruppo->depth ?? 0) == 0 ? 'primary' : 'secondary' }} badge-level">{{ $gruppo->depth ?? 0 }}</span>
<small class="text-muted ml-2">
{{ $gruppo->diocesi?->nome ?? '' }}
@if($responsabili->count() > 0)
· <i class="fas fa-user text-info"></i> {{ $responsabili->pluck('cognome')->implode(', ') }}
@endif
</small>
<span class="ml-auto">
@if($gruppo->individui_count > 0)
<span class="badge badge-info">{{ $gruppo->individui_count }} membri</span>
@endif
@if($hasChildren)
<span class="badge badge-warning">{{ $children->count() }} figli</span>
@endif
</span>
<span class="ml-2">
<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>
@php
$isParent = $hasChildren;
$isSuperAdmin = Auth::user()->isSuperAdmin();
$canDelete = !$isParent || $isSuperAdmin;
@endphp
@if($canDelete)
<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? Verranno eliminati anche tutti i sottogruppi.')" title="Elimina">
<i class="fas fa-trash"></i>
</button>
</form>
@else
<button type="button" class="btn btn-xs btn-danger disabled" title="Solo il superamministratore può eliminare gruppi con sottogruppi">
<i class="fas fa-trash"></i>
</button>
@endif
@endif
</span>
</div>
</div>
@if($hasChildren)
<div id="group-{{ $gruppo->id }}" class="tree-children" style="display: none;">
@foreach($children as $child)
@include('gruppi.partials.tree-item', ['gruppo' => $child])
@endforeach
</div>
@endif
+515
View File
@@ -0,0 +1,515 @@
@extends('layouts.adminlte')
@section('title', 'Dettaglio Gruppo')
@section('page_title', 'Dettaglio Gruppo')
@php
$canWriteGruppi = Auth::user()->canManage('gruppi');
$canDeleteGruppi = Auth::user()->canDelete('gruppi');
@endphp
@section('breadcrumbs')
<li class="breadcrumb-item"><a href="{{ route('gruppi.index') }}">Gruppi</a></li>
<li class="breadcrumb-item active">{{ $gruppo->nome }}</li>
@endsection
@if(session('success'))
<div class="alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert">&times;</button>
{{ session('success') }}
</div>
@endif
@if(session('error'))
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert">&times;</button>
{{ session('error') }}
</div>
@endif
@section('content')
<div class="row">
<div class="col-md-4">
<div class="card card-success">
<div class="card-header">
<h3 class="card-title">
<i class="fas fa-folder text-warning mr-2"></i>
{{ $gruppo->nome }}
</h3>
</div>
<div class="card-body">
<table class="table table-sm table-borderless">
<tr>
<td style="width: 130px;"><strong>Path:</strong></td>
<td class="text-muted small">{{ $gruppo->full_path }}</td>
</tr>
<tr>
<td><strong>Gruppo Padre:</strong></td>
<td>
@if($gruppo->parent)
<a href="{{ route('gruppi.show', $gruppo->parent->id) }}">{{ $gruppo->parent->nome }}</a>
@else
<span class="badge badge-success">Gruppo radice</span>
@endif
</td>
</tr>
<tr>
<td><strong>Diocesi:</strong></td>
<td>{{ $gruppo->diocesi?->nome ?? '-' }}</td>
</tr>
<tr>
<td><strong>Responsabili:</strong></td>
<td>
@php $responsabili = $gruppo->getResponsabili() @endphp
@if($responsabili->count() > 0)
@foreach($responsabili as $resp)
<a href="{{ route('individui.show', $resp->id) }}">
<i class="fas fa-user text-info mr-1"></i>
{{ $resp->nome_completo }}
</a><br>
@endforeach
@else
<span class="text-muted">-</span>
@endif
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card">
<div class="card-header"><h3 class="card-title"><i class="fas fa-map-marker-alt mr-2"></i>Luogo Incontro</h3></div>
<div class="card-body">
<table class="table table-sm table-borderless mb-0">
<tr>
<td style="width: 100px;"><strong>Indirizzo:</strong></td>
<td>{{ $gruppo->indirizzo_incontro ?: '-' }}</td>
</tr>
<tr>
<td><strong>CAP:</strong></td>
<td>{{ $gruppo->cap_incontro ?: '-' }}</td>
</tr>
<tr>
<td><strong>Città:</strong></td>
<td>{{ $gruppo->città_incontro ?: '-' }} {{ $gruppo->sigla_provincia_incontro ? "({$gruppo->sigla_provincia_incontro})" : '' }}</td>
</tr>
</table>
@if($gruppo->mappa_posizione)
<a href="{{ $gruppo->mappa_posizione }}" target="_blank" class="btn btn-sm btn-outline-primary mt-2">
<i class="fas fa-external-link-alt mr-1"></i> Visualizza su mappa
</a>
@endif
</div>
</div>
</div>
<div class="col-md-4">
<div class="card">
<div class="card-header"><h3 class="card-title"><i class="fas fa-chart-pie mr-2"></i>Statistiche</h3></div>
<div class="card-body">
<div class="row text-center">
<div class="col-6">
<div class="border-right">
<h2 class="mb-0 text-primary">{{ $gruppo->individui->count() }}</h2>
<small class="text-muted">Membri</small>
</div>
</div>
<div class="col-6">
<h2 class="mb-0 text-warning">{{ $gruppo->children->count() }}</h2>
<small class="text-muted">Sottogruppi</small>
</div>
</div>
</div>
</div>
</div>
</div>
@php
$incontroEvento = $gruppo->eventi->where('is_incontro_gruppo', true)->first();
@endphp
@if($incontroEvento)
<div class="row">
<div class="col-md-4">
<div class="card card-success">
<div class="card-header">
<h3 class="card-title">
<i class="fas fa-calendar-check mr-2"></i>
Giorno di Incontro
</h3>
</div>
<div class="card-body">
<table class="table table-sm table-borderless mb-0">
<tr>
<td style="width: 100px;"><strong>Evento:</strong></td>
<td>{{ $incontroEvento->nome_evento }}</td>
</tr>
<tr>
<td><strong>Quando:</strong></td>
<td>
@if($incontroEvento->tipo_recorrenza === 'settimanale')
{{ $incontroEvento->giorno_settimana_label }}
<span class="badge badge-info ml-1">Settimanale</span>
@elseif($incontroEvento->tipo_recorrenza === 'mensile')
{{ $incontroEvento->occorrenza_mensile_label }}
@if($incontroEvento->mesi_recorrenza)
<small class="text-muted">({{ $incontroEvento->mesi_recorrenza_label }})</small>
@endif
<span class="badge badge-info ml-1">Mensile</span>
@elseif($incontroEvento->tipo_recorrenza === 'annuale')
{{ $incontroEvento->mese_annuale_label }}
<span class="badge badge-info ml-1">Annuale</span>
@elseif($incontroEvento->tipo_recorrenza === 'altro')
{{ $incontroEvento->giorno_settimana_label }}
<span class="badge badge-info ml-1">Altro</span>
@else
{{ $incontroEvento->data_specifica?->format('d/m/Y') ?: '-' }}
@endif
</td>
</tr>
@if($incontroEvento->ora_inizio)
<tr>
<td><strong>Ora:</strong></td>
<td>ore {{ $incontroEvento->ora_inizio->format('H:i') }}</td>
</tr>
@endif
</table>
@if($incontroEvento->responsabili->count() > 0)
<hr>
<small class="text-muted"><strong>Responsabili:</strong></small>
@foreach($incontroEvento->responsabili as $resp)
<div class="mt-1">
<i class="fas fa-user text-info mr-1"></i>
<a href="/individui/{{ $resp->id }}">{{ $resp->cognome }} {{ $resp->nome }}</a>
@if($resp->telefono_primario)
<br><small class="text-success ml-3">{{ $resp->telefono_primario }}</small>
@endif
</div>
@endforeach
@endif
<div class="mt-2">
<a href="/eventi/{{ $incontroEvento->id }}" class="btn btn-xs btn-outline-primary">
<i class="fas fa-eye mr-1"></i> Vedi evento
</a>
</div>
</div>
</div>
</div>
</div>
@endif
@if($gruppo->descrizione)
<div class="row mt-3">
<div class="col-md-8">
<div class="card">
<div class="card-header"><h3 class="card-title"><i class="fas fa-align-left mr-2"></i>Descrizione</h3></div>
<div class="card-body">
<p class="mb-0">{!! nl2br(e($gruppo->descrizione)) !!}</p>
</div>
</div>
</div>
</div>
@endif
<div class="card mt-3">
<div class="card-header">
<h3 class="card-title">
<i class="fas fa-users mr-2"></i>Membri ({{ $gruppo->individui->count() }})
</h3>
</div>
<div class="card-body p-0">
@if($gruppo->individui->count() > 0)
<table class="table table-bordered table-hover table-striped mb-0">
<thead class="thead-light">
<tr>
<th style="width: 100px;">Codice</th>
<th>Nome Completo</th>
<th>Email</th>
<th>Telefono</th>
<th style="width: 150px;">Ruolo</th>
<th style="width: 110px;">Data Adesione</th>
<th style="width: 80px;">Azioni</th>
</tr>
</thead>
<tbody>
@foreach($gruppo->individui as $individuo)
<tr>
<td><span class="badge badge-secondary">{{ $individuo->codice_id }}</span></td>
<td>
<a href="{{ route('individui.show', $individuo->id) }}">
<i class="fas fa-user text-info mr-1"></i>
{{ $individuo->cognome }} {{ $individuo->nome }}
</a>
</td>
<td>{{ $individuo->email_primaria ?? '-' }}</td>
<td>{{ $individuo->telefono_primario ?? '-' }}</td>
<td>
@php
$ruoloIds = $individuo->pivot->ruolo_ids ? json_decode($individuo->pivot->ruolo_ids, true) : [];
$ruoli = \App\Models\Ruolo::findByIds($ruoloIds);
@endphp
@if($ruoli->count() > 0)
@foreach($ruoli as $ruolo)
<span class="badge badge-info mr-1">{{ $ruolo->nome }}</span>
@endforeach
@else
<span class="text-muted">-</span>
@endif
</td>
<td>
@if($individuo->pivot->data_adesione)
{{ \Carbon\Carbon::parse($individuo->pivot->data_adesione)->format('d/m/Y') }}
@else
<span class="text-muted">-</span>
@endif
</td>
<td>
<a href="{{ route('individui.show', $individuo->id) }}" class="btn btn-xs btn-info" title="Visualizza">
<i class="fas fa-eye"></i>
</a>
</td>
</tr>
@endforeach
</tbody>
</table>
@else
<div class="text-center text-muted py-4">
<i class="fas fa-users fa-2x mb-2"></i>
<p class="mb-0">Nessun membro</p>
</div>
@endif
</div>
</div>
<div class="card mt-3">
<div class="card-header">
<h3 class="card-title">
<i class="fas fa-file mr-2"></i>Documenti ({{ $gruppo->documenti->count() }})
</h3>
@if($canWriteGruppi)
<button type="button" class="btn btn-xs btn-primary float-right" data-toggle="modal" data-target="#uploadDocumentoModal">
<i class="fas fa-upload mr-1"></i> Carica
</button>
@endif
</div>
<div class="card-body p-0">
@if($gruppo->documenti->count() > 0)
<table class="table table-bordered table-hover table-striped mb-0">
<thead class="thead-light">
<tr>
<th>Nome</th>
<th style="width: 120px;">Tipologia</th>
<th style="width: 80px;">Dimensione</th>
<th style="width: 130px;">Data Upload</th>
<th style="width: 100px;">Azioni</th>
</tr>
</thead>
<tbody>
@foreach($gruppo->documenti as $documento)
<tr>
<td>
<a href="#" onclick="event.preventDefault(); previewDocumento({{ $documento->id }}, '{{ $documento->mime_type }}');">
<i class="fas fa-file text-secondary mr-1"></i>
{{ $documento->nome_file }}
</a>
</td>
<td>{{ ucfirst(str_replace('_', ' ', $documento->tipologia)) }}</td>
<td>{{ number_format($documento->dimensione / 1024, 1) }} KB</td>
<td>{{ $documento->created_at->format('d/m/Y') }}</td>
<td>
@if($documento->file_path)
<a href="{{ url('/documenti/' . $documento->id . '/download') }}" class="btn btn-xs btn-primary" title="Scarica">
<i class="fas fa-download"></i>
</a>
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
@else
<div class="text-center text-muted py-4">
<i class="fas fa-file fa-2x mb-2"></i>
<p class="mb-0">Nessun documento</p>
</div>
@endif
</div>
</div>
<div class="card mt-3">
<div class="card-header">
<h3 class="card-title">
<i class="fas fa-sitemap mr-2"></i>Sottogruppi ({{ $gruppo->children->count() }})
</h3>
<a href="{{ route('gruppi.create', ['parent_id' => $gruppo->id]) }}" class="btn btn-xs btn-success float-right">
<i class="fas fa-plus mr-1"></i> Aggiungi Sottogruppo
</a>
</div>
<div class="card-body p-0">
@if($gruppo->children->count() > 0)
<table class="table table-bordered table-hover table-striped mb-0">
<thead class="thead-light">
<tr>
<th>Nome</th>
<th>Diocesi</th>
<th>Responsabile</th>
<th style="text-align: center;">Membri</th>
<th style="width: 100px;">Azioni</th>
</tr>
</thead>
<tbody>
@foreach($gruppo->children->sortBy('nome') as $child)
<tr>
<td>
<a href="{{ route('gruppi.show', $child->id) }}">
<i class="fas fa-folder-open text-warning mr-1"></i>
{{ $child->nome }}
</a>
</td>
<td>{{ $child->diocesi?->nome ?? '-' }}</td>
<td>{{ $child->getResponsabili()->isNotEmpty() ? $child->getResponsabili()->first()->nome_completo : '-' }}</td>
<td class="text-center">
@if($child->individui()->count() > 0)
<span class="badge badge-info">{{ $child->individui()->count() }}</span>
@else
<span class="text-muted">-</span>
@endif
</td>
<td>
<a href="{{ route('gruppi.show', $child->id) }}" class="btn btn-xs btn-info" title="Visualizza">
<i class="fas fa-eye"></i>
</a>
@if($canWriteGruppi)
<a href="{{ route('gruppi.edit', $child->id) }}" class="btn btn-xs btn-warning" title="Modifica">
<i class="fas fa-edit"></i>
</a>
@endif
@if($canDeleteGruppi)
<form action="{{ route('gruppi.destroy', $child->id) }}" method="POST" class="d-inline">
@csrf @method('DELETE')
<button type="submit" class="btn btn-xs btn-danger" onclick="return confirm('Eliminare {{ $child->nome }}?')" title="Elimina">
<i class="fas fa-trash"></i>
</button>
</form>
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
@else
<div class="text-center text-muted py-4">
<i class="fas fa-folder-open fa-2x mb-2"></i>
<p class="mb-0">Nessun sottogruppo</p>
</div>
@endif
</div>
</div>
<div class="mt-3">
@if($canWriteGruppi)
<a href="{{ url('/gruppi/' . $gruppo->id . '/edit') }}" class="btn btn-warning">
<i class="fas fa-edit mr-1"></i> Modifica
</a>
@endif
@if($canDeleteGruppi)
<form action="{{ url('/gruppi/' . $gruppo->id) }}" method="POST" class="d-inline">
@csrf @method('DELETE')
<button type="submit" class="btn btn-danger" onclick="return confirm('Confermi l\'eliminazione di {{ $gruppo->nome }}? Verranno eliminati anche tutti i sottogruppi.')">
<i class="fas fa-trash mr-1"></i> Elimina
</button>
</form>
@endif
<a href="{{ route('gruppi.index') }}" class="btn btn-secondary">
<i class="fas fa-arrow-left mr-1"></i> Torna all'elenco
</a>
</div>
<div class="modal fade" id="uploadDocumentoModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header bg-primary text-white">
<h5 class="modal-title"><i class="fas fa-upload mr-2"></i>Carica Documento</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="/documenti" method="POST" enctype="multipart/form-data">
@csrf
<input type="hidden" name="visibilita" value="gruppo">
<input type="hidden" name="visibilita_target_id" value="{{ $gruppo->id }}">
<input type="hidden" name="visibilita_target_type" value="App\Models\Gruppo">
<input type="hidden" name="_redirect" value="{{ url()->current() }}">
<div class="modal-body">
<div class="form-group">
<label>Nome *</label>
<input type="text" name="nome_file" class="form-control" placeholder="Nome del documento" required>
</div>
<div class="form-group">
<label>Tipologia *</label>
<select name="tipologia" class="form-control" required>
<option value="">Seleziona...</option>
<option value="documento">Documento</option>
<option value="statuto">Statuto</option>
<option value="avatar">Avatar</option>
<option value="galleria">Galleria</option>
<option value="altro">Altro</option>
</select>
</div>
<div class="form-group">
<label>File *</label>
<input type="file" name="file" class="form-control" required>
<small class="text-muted">Max 10MB</small>
</div>
</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-upload mr-1"></i> Carica
</button>
</div>
</form>
</div>
</div>
</div>
<div class="modal fade" id="previewModal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-lg" role="document" style="max-width: 90vw;">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><i class="fas fa-file mr-2"></i><span id="previewModalTitle">Anteprima</span></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Chiudi">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body text-center p-0" style="min-height: 400px;">
<iframe id="previewFrame" src="" style="width: 100%; height: 70vh; border: none;"></iframe>
</div>
<div class="modal-footer">
<a id="previewDownloadBtn" href="#" class="btn btn-primary" download>
<i class="fas fa-download mr-1"></i> Scarica
</a>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Chiudi</button>
</div>
</div>
</div>
</div>
@endsection
@section('scripts')
<script>
function previewDocumento(id, mimeType) {
var previewUrl = '/documenti/' + id + '/preview';
var downloadUrl = '/documenti/' + id + '/download';
document.getElementById('previewFrame').src = previewUrl;
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';
}
$('#previewModal').modal('show');
}
</script>
@endsection