netgescon-master/netgescon-laravel/resources/views/components/layout/alerts.blade.php

321 lines
9.8 KiB
PHP

{{--
========================================
ALERT E MESSAGGI MODULARI
========================================
Sistema completo di messaggi flash, validazione
e notifiche con auto-dismiss e stack.
Props:
- $showValidation (bool): Mostra errori di validazione
- $showFlash (bool): Mostra messaggi flash
- $autoDismiss (int): Secondi per auto-dismiss (0 = mai)
- $position (string): Posizione (top, bottom)
Autore: NetGesCon Development Team
Data: 2024
========================================
--}}
@props([
'showValidation' => true,
'showFlash' => true,
'autoDismiss' => 5,
'position' => 'top'
])
<div class="netgescon-alerts position-relative">
{{-- Errori di Validazione --}}
@if($showValidation && $errors->any())
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<div class="d-flex align-items-start">
<i class="fas fa-exclamation-triangle me-2 mt-1"></i>
<div class="flex-grow-1">
<h6 class="alert-heading mb-2">Errori di validazione</h6>
<ul class="mb-0 small">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
</div>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Chiudi"></button>
</div>
@endif
{{-- Messaggi Flash di Successo --}}
@if($showFlash && session('success'))
<div class="alert alert-success alert-dismissible fade show"
role="alert"
@if($autoDismiss > 0) data-auto-dismiss="{{ $autoDismiss }}" @endif>
<div class="d-flex align-items-start">
<i class="fas fa-check-circle me-2 mt-1"></i>
<div class="flex-grow-1">
<strong>Successo!</strong>
<div>{{ session('success') }}</div>
</div>
</div>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Chiudi"></button>
</div>
@endif
{{-- Messaggi Flash di Errore --}}
@if($showFlash && session('error'))
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<div class="d-flex align-items-start">
<i class="fas fa-times-circle me-2 mt-1"></i>
<div class="flex-grow-1">
<strong>Errore!</strong>
<div>{{ session('error') }}</div>
</div>
</div>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Chiudi"></button>
</div>
@endif
{{-- Messaggi Flash di Warning --}}
@if($showFlash && session('warning'))
<div class="alert alert-warning alert-dismissible fade show"
role="alert"
@if($autoDismiss > 0) data-auto-dismiss="{{ $autoDismiss }}" @endif>
<div class="d-flex align-items-start">
<i class="fas fa-exclamation-triangle me-2 mt-1"></i>
<div class="flex-grow-1">
<strong>Attenzione!</strong>
<div>{{ session('warning') }}</div>
</div>
</div>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Chiudi"></button>
</div>
@endif
{{-- Messaggi Flash Informativi --}}
@if($showFlash && session('info'))
<div class="alert alert-info alert-dismissible fade show"
role="alert"
@if($autoDismiss > 0) data-auto-dismiss="{{ $autoDismiss }}" @endif>
<div class="d-flex align-items-start">
<i class="fas fa-info-circle me-2 mt-1"></i>
<div class="flex-grow-1">
<strong>Informazione</strong>
<div>{{ session('info') }}</div>
</div>
</div>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Chiudi"></button>
</div>
@endif
{{-- Messaggi Flash Generici (con tipo personalizzato) --}}
@if($showFlash && session('message'))
@php
$messageType = session('message_type', 'info');
$icons = [
'success' => 'fas fa-check-circle',
'error' => 'fas fa-times-circle',
'warning' => 'fas fa-exclamation-triangle',
'info' => 'fas fa-info-circle',
'primary' => 'fas fa-star',
'secondary' => 'fas fa-bell'
];
$icon = $icons[$messageType] ?? 'fas fa-info-circle';
@endphp
<div class="alert alert-{{ $messageType }} alert-dismissible fade show"
role="alert"
@if($autoDismiss > 0) data-auto-dismiss="{{ $autoDismiss }}" @endif>
<div class="d-flex align-items-start">
<i class="{{ $icon }} me-2 mt-1"></i>
<div class="flex-grow-1">
{{ session('message') }}
</div>
</div>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Chiudi"></button>
</div>
@endif
{{-- Container per alert dinamici (JavaScript) --}}
<div id="dynamic-alerts"></div>
</div>
{{-- CSS per alert --}}
@push('styles')
<style>
.netgescon-alerts {
margin-bottom: 1rem;
}
.netgescon-alerts .alert {
border: none;
border-radius: 0.5rem;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
margin-bottom: 0.75rem;
}
.netgescon-alerts .alert:last-child {
margin-bottom: 0;
}
.netgescon-alerts .alert-heading {
font-size: 1rem;
font-weight: 600;
}
.netgescon-alerts .alert ul {
padding-left: 1rem;
}
.netgescon-alerts .alert ul li {
margin-bottom: 0.25rem;
}
.netgescon-alerts .alert ul li:last-child {
margin-bottom: 0;
}
/* Animazioni */
.netgescon-alerts .alert {
animation: slideInDown 0.3s ease-out;
}
@keyframes slideInDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.netgescon-alerts .alert.fade.show {
transition: opacity 0.3s ease, transform 0.3s ease;
}
/* Auto-dismiss progress bar */
.alert[data-auto-dismiss] {
position: relative;
overflow: hidden;
}
.alert[data-auto-dismiss]::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
height: 3px;
background-color: currentColor;
opacity: 0.3;
animation: progressBar var(--duration, 5s) linear forwards;
}
@keyframes progressBar {
from { width: 100%; }
to { width: 0%; }
}
/* Tema scuro */
.dark .netgescon-alerts .alert {
border: 1px solid rgba(255, 255, 255, 0.1);
}
/* Responsive */
@media (max-width: 768px) {
.netgescon-alerts .alert {
margin-bottom: 0.5rem;
border-radius: 0.375rem;
}
.netgescon-alerts .alert-heading {
font-size: 0.9rem;
}
}
/* Posizionamento fisso per toast */
.netgescon-alerts.position-fixed {
top: 20px;
right: 20px;
z-index: 1050;
max-width: 400px;
}
.netgescon-alerts.position-fixed.bottom {
top: auto;
bottom: 20px;
}
</style>
@endpush
{{-- JavaScript per funzionalità alert --}}
@push('scripts')
<script>
document.addEventListener('DOMContentLoaded', function() {
// Auto-dismiss alerts
const autoDismissAlerts = document.querySelectorAll('[data-auto-dismiss]');
autoDismissAlerts.forEach(alert => {
const duration = parseInt(alert.dataset.autoDismiss) * 1000;
// Imposta durata CSS
alert.style.setProperty('--duration', alert.dataset.autoDismiss + 's');
setTimeout(() => {
const bsAlert = new bootstrap.Alert(alert);
bsAlert.close();
}, duration);
});
// Funzione globale per creare alert dinamici
window.showAlert = function(message, type = 'info', autoDismiss = true) {
const alertContainer = document.getElementById('dynamic-alerts');
if (!alertContainer) return;
const icons = {
'success': 'fas fa-check-circle',
'error': 'fas fa-times-circle',
'warning': 'fas fa-exclamation-triangle',
'info': 'fas fa-info-circle',
'primary': 'fas fa-star',
'secondary': 'fas fa-bell'
};
const icon = icons[type] || icons.info;
const alertId = 'alert-' + Date.now();
const alertHtml = `
<div class="alert alert-${type} alert-dismissible fade show"
id="${alertId}"
role="alert"
${autoDismiss ? 'data-auto-dismiss="5"' : ''}>
<div class="d-flex align-items-start">
<i class="${icon} me-2 mt-1"></i>
<div class="flex-grow-1">${message}</div>
</div>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Chiudi"></button>
</div>
`;
alertContainer.insertAdjacentHTML('beforeend', alertHtml);
// Auto-dismiss se richiesto
if (autoDismiss) {
const alertElement = document.getElementById(alertId);
alertElement.style.setProperty('--duration', '5s');
setTimeout(() => {
const bsAlert = new bootstrap.Alert(alertElement);
bsAlert.close();
}, 5000);
}
};
// Funzioni helper
window.showSuccess = (message) => window.showAlert(message, 'success');
window.showError = (message) => window.showAlert(message, 'error');
window.showWarning = (message) => window.showAlert(message, 'warning');
window.showInfo = (message) => window.showAlert(message, 'info');
});
</script>
@endpush