18 KiB
Executable File
18 KiB
Executable File
🦶 FOOTER - Documentazione Completa NetGescon
Componente Footer dell'interfaccia universale
📅 Creato: 21/07/2025
🔄 Ultimo aggiornamento: 21/07/2025
🎯 Priorità: 🔥 CRITICA
📋 OVERVIEW FOOTER
Il Footer NetGescon è il componente FIXED BOTTOM che contiene:
- 📊 Progress Bar Sistema
- ℹ️ Info Applicazione
- 👤 User Status Quick
- 🕐 Sistema Timestamp
- 📡 Connection Status
- 🔄 Auto-refresh Indicator
📐 Specifiche Layout
- Altezza:
70pxfisso - Posizione:
fixed bottom-0sempre visibile - Z-index:
999sopra content ma sotto header - Background: Sfumatura grigio scuro NetGescon
🎨 DESIGN SPECIFICATIONS
🌈 Color Palette
/* Footer Background */
.netgescon-footer {
background: linear-gradient(135deg,
var(--netgescon-gray-800) 0%,
var(--netgescon-gray-900) 100%
);
border-top: 1px solid var(--netgescon-gray-700);
color: var(--netgescon-gray-300);
}
/* Progress Bar */
.footer-progress {
background: var(--netgescon-primary);
height: 3px;
transition: width 0.3s ease;
}
/* Status Indicators */
.status-online { color: var(--netgescon-success); }
.status-offline { color: var(--netgescon-danger); }
.status-warning { color: var(--netgescon-warning); }
📏 Dimensions
.netgescon-footer {
height: 70px;
padding: 0 1.5rem;
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 999;
display: flex;
align-items: center;
justify-content: space-between;
}
🧩 STRUTTURA FOOTER
📁 File: components/menu/sections/footer.blade.php
<footer class="netgescon-footer">
<!-- Progress Bar (top edge) -->
<div class="footer-progress-container absolute top-0 left-0 right-0 h-1 bg-gray-700">
<div id="footer-progress" class="footer-progress h-full w-0"></div>
</div>
<div class="footer-content flex items-center justify-between w-full">
<!-- Left Section - App Info -->
<div class="footer-left flex items-center space-x-6">
<!-- App Version -->
<div class="app-info flex items-center space-x-2 text-sm">
<i class="fas fa-code text-blue-400"></i>
<span class="text-gray-300">NetGescon</span>
<span class="text-blue-400 font-medium">v2.1.0</span>
</div>
<!-- Connection Status -->
<div class="connection-status flex items-center space-x-2 text-sm">
<i id="connection-icon" class="fas fa-wifi status-online"></i>
<span id="connection-text" class="text-gray-300">Online</span>
</div>
<!-- System Status -->
<div class="system-status flex items-center space-x-2 text-sm">
<i id="system-icon" class="fas fa-server text-green-400"></i>
<span id="system-text" class="text-gray-300">Sistema OK</span>
</div>
</div>
<!-- Center Section - Quick Actions (Desktop Only) -->
<div class="footer-center hidden lg:flex items-center space-x-4">
<!-- Auto-refresh -->
<div class="auto-refresh flex items-center space-x-2 text-sm">
<button id="auto-refresh-toggle"
class="flex items-center space-x-1 text-gray-400 hover:text-gray-200 transition-colors"
onclick="toggleAutoRefresh()">
<i id="refresh-icon" class="fas fa-sync-alt"></i>
<span>Auto-refresh</span>
</button>
<span id="refresh-timer" class="text-xs text-gray-500">30s</span>
</div>
<!-- Quick Stats -->
<div class="quick-stats flex items-center space-x-4 text-xs text-gray-400">
<span>CPU: <span id="cpu-usage" class="text-green-400">12%</span></span>
<span>Mem: <span id="mem-usage" class="text-blue-400">45%</span></span>
<span>Users: <span id="active-users" class="text-yellow-400">8</span></span>
</div>
</div>
<!-- Right Section - User & Time -->
<div class="footer-right flex items-center space-x-6">
<!-- Current User -->
<div class="current-user flex items-center space-x-2 text-sm">
<img src="{{ auth()->user()->avatar ?? asset('images/avatar-default.svg') }}"
alt="User" class="w-6 h-6 rounded-full border border-gray-600">
<span class="text-gray-300 hidden sm:block">{{ auth()->user()->name }}</span>
<span class="text-xs text-gray-500 hidden md:block">({{ auth()->user()->role }})</span>
</div>
<!-- Current Date/Time -->
<div class="datetime flex items-center space-x-2 text-sm">
<i class="fas fa-clock text-gray-400"></i>
<div class="flex flex-col items-end">
<span id="current-time" class="text-gray-300 font-medium">--:--</span>
<span id="current-date" class="text-xs text-gray-500 hidden lg:block">-- --- ----</span>
</div>
</div>
<!-- Session Timer -->
<div class="session-timer flex items-center space-x-1 text-xs text-gray-500">
<i class="fas fa-hourglass-half"></i>
<span id="session-time">0h 0m</span>
</div>
</div>
</div>
</footer>
⚡ JAVASCRIPT FUNCTIONALITY
📁 File: /public/js/components/footer.js
/**
* Footer NetGescon - JavaScript Functions
*/
let autoRefreshInterval;
let autoRefreshEnabled = false;
let autoRefreshCountdown = 30;
let sessionStartTime = new Date();
// Inizializza footer
function initializeFooter() {
updateDateTime();
updateSessionTimer();
monitorConnection();
initializeSystemStatus();
initializeProgressBar();
// Update ogni secondo
setInterval(() => {
updateDateTime();
updateSessionTimer();
updateAutoRefreshTimer();
}, 1000);
// System stats ogni 30 secondi
setInterval(() => {
updateSystemStats();
}, 30000);
}
// Date/Time updates
function updateDateTime() {
const now = new Date();
// Time
const timeString = now.toLocaleTimeString('it-IT', {
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
document.getElementById('current-time').textContent = timeString;
// Date (desktop only)
const dateString = now.toLocaleDateString('it-IT', {
weekday: 'short',
day: '2-digit',
month: 'short',
year: 'numeric'
});
const dateEl = document.getElementById('current-date');
if (dateEl) dateEl.textContent = dateString;
}
// Session timer
function updateSessionTimer() {
const now = new Date();
const diff = now - sessionStartTime;
const hours = Math.floor(diff / (1000 * 60 * 60));
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
document.getElementById('session-time').textContent = `${hours}h ${minutes}m`;
}
// Auto-refresh functionality
function toggleAutoRefresh() {
autoRefreshEnabled = !autoRefreshEnabled;
const icon = document.getElementById('refresh-icon');
const button = document.getElementById('auto-refresh-toggle');
if (autoRefreshEnabled) {
icon.classList.add('fa-spin');
button.classList.add('text-blue-400');
button.classList.remove('text-gray-400');
startAutoRefresh();
} else {
icon.classList.remove('fa-spin');
button.classList.remove('text-blue-400');
button.classList.add('text-gray-400');
stopAutoRefresh();
}
}
function startAutoRefresh() {
autoRefreshCountdown = 30;
autoRefreshInterval = setInterval(() => {
// Refresh current page data
refreshPageData();
autoRefreshCountdown = 30; // Reset
}, 30000);
}
function stopAutoRefresh() {
if (autoRefreshInterval) {
clearInterval(autoRefreshInterval);
autoRefreshInterval = null;
}
document.getElementById('refresh-timer').textContent = '30s';
}
function updateAutoRefreshTimer() {
if (autoRefreshEnabled && autoRefreshCountdown > 0) {
autoRefreshCountdown--;
document.getElementById('refresh-timer').textContent = `${autoRefreshCountdown}s`;
}
}
// Connection monitoring
function monitorConnection() {
const updateConnectionStatus = (online) => {
const icon = document.getElementById('connection-icon');
const text = document.getElementById('connection-text');
if (online) {
icon.className = 'fas fa-wifi status-online';
text.textContent = 'Online';
} else {
icon.className = 'fas fa-wifi-slash status-offline';
text.textContent = 'Offline';
}
};
// Check connection status
window.addEventListener('online', () => updateConnectionStatus(true));
window.addEventListener('offline', () => updateConnectionStatus(false));
// Initial check
updateConnectionStatus(navigator.onLine);
// Periodic ping check
setInterval(async () => {
try {
const response = await fetch('/api/ping', {
method: 'HEAD',
cache: 'no-cache'
});
updateConnectionStatus(response.ok);
} catch {
updateConnectionStatus(false);
}
}, 10000);
}
// System status monitoring
function initializeSystemStatus() {
updateSystemStats();
}
async function updateSystemStats() {
try {
const response = await fetch('/api/system-stats');
const stats = await response.json();
// CPU Usage
document.getElementById('cpu-usage').textContent = `${stats.cpu}%`;
document.getElementById('cpu-usage').className = getCpuClass(stats.cpu);
// Memory Usage
document.getElementById('mem-usage').textContent = `${stats.memory}%`;
document.getElementById('mem-usage').className = getMemClass(stats.memory);
// Active Users
document.getElementById('active-users').textContent = stats.activeUsers;
// System Status
updateSystemStatus(stats.status);
} catch (error) {
console.warn('Unable to fetch system stats:', error);
}
}
function getCpuClass(cpu) {
if (cpu < 50) return 'text-green-400';
if (cpu < 80) return 'text-yellow-400';
return 'text-red-400';
}
function getMemClass(memory) {
if (memory < 60) return 'text-blue-400';
if (memory < 85) return 'text-yellow-400';
return 'text-red-400';
}
function updateSystemStatus(status) {
const icon = document.getElementById('system-icon');
const text = document.getElementById('system-text');
switch (status) {
case 'ok':
icon.className = 'fas fa-server status-online';
text.textContent = 'Sistema OK';
break;
case 'warning':
icon.className = 'fas fa-exclamation-triangle status-warning';
text.textContent = 'Attenzione';
break;
case 'error':
icon.className = 'fas fa-exclamation-circle status-offline';
text.textContent = 'Errore';
break;
}
}
// Progress bar for page loading
function initializeProgressBar() {
const progressBar = document.getElementById('footer-progress');
// Show progress on AJAX requests
let activeRequests = 0;
// Listen to fetch requests
const originalFetch = window.fetch;
window.fetch = function(...args) {
activeRequests++;
updateProgressBar();
return originalFetch.apply(this, args)
.finally(() => {
activeRequests--;
updateProgressBar();
});
};
}
function updateProgressBar() {
const progressBar = document.getElementById('footer-progress');
if (activeRequests > 0) {
progressBar.style.width = '70%';
setTimeout(() => {
if (activeRequests === 0) {
progressBar.style.width = '100%';
setTimeout(() => {
progressBar.style.width = '0%';
}, 200);
}
}, 500);
}
}
// Page data refresh
async function refreshPageData() {
try {
const currentPath = window.location.pathname;
const response = await fetch(currentPath, {
headers: {
'X-Requested-With': 'XMLHttpRequest',
'X-Refresh-Data': 'true'
}
});
if (response.ok) {
// Update dynamic content only
const data = await response.json();
updateDynamicContent(data);
}
} catch (error) {
console.warn('Auto-refresh failed:', error);
}
}
function updateDynamicContent(data) {
// Update stats cards
if (data.stats) {
Object.keys(data.stats).forEach(key => {
const element = document.querySelector(`[data-stat="${key}"]`);
if (element) {
element.textContent = data.stats[key];
}
});
}
// Update notifications badge
if (data.notifications) {
const badge = document.querySelector('.notification-badge');
if (badge) {
badge.textContent = data.notifications.count;
badge.style.display = data.notifications.count > 0 ? 'flex' : 'none';
}
}
// Show update indicator
showUpdateIndicator();
}
function showUpdateIndicator() {
const indicator = document.createElement('div');
indicator.className = 'update-indicator fixed top-20 right-6 bg-green-500 text-white px-3 py-1 rounded text-sm z-50';
indicator.innerHTML = '<i class="fas fa-check mr-1"></i> Aggiornato';
document.body.appendChild(indicator);
setTimeout(() => {
indicator.style.opacity = '0';
setTimeout(() => indicator.remove(), 300);
}, 2000);
}
// Initialize on DOM ready
document.addEventListener('DOMContentLoaded', initializeFooter);
📱 RESPONSIVE BEHAVIOR
🖥️ Desktop (≥1024px)
.netgescon-footer {
padding: 0 24px;
}
.footer-center {
display: flex;
}
.footer-right .hidden {
display: block;
}
📱 Tablet (768px - 1023px)
.footer-center {
display: none;
}
.footer-left,
.footer-right {
flex-wrap: wrap;
}
📱 Mobile (≤767px)
.netgescon-footer {
padding: 0 16px;
font-size: 0.875rem;
}
.footer-left {
flex-direction: column;
align-items: flex-start;
space-y: 2px;
}
.footer-right {
flex-direction: column;
align-items: flex-end;
space-y: 2px;
}
.hidden-mobile {
display: none;
}
🔧 CONFIGURATION OPTIONS
⚙️ Footer Settings
// Configuration object
const footerConfig = {
autoRefresh: {
enabled: true,
interval: 30000, // 30 seconds
showTimer: true
},
systemStats: {
enabled: true,
interval: 30000,
showCpu: true,
showMemory: true,
showUsers: true
},
connection: {
monitoring: true,
pingInterval: 10000,
pingEndpoint: '/api/ping'
},
progress: {
showOnAjax: true,
animationDuration: 300
}
};
🎛️ Customization Options
/* Custom footer height */
:root {
--footer-height: 70px;
}
/* Custom progress bar color */
.footer-progress {
background: var(--netgescon-accent);
}
/* Custom status colors */
.status-custom {
color: #your-color;
}
🧪 TESTING CHECKLIST
✅ Functional Tests
- Date/time updates correctly
- Session timer accurate
- Auto-refresh toggle works
- Connection status monitoring
- System stats display
- Progress bar animations
✅ Visual Tests
- Footer height consistent (70px)
- Elements alignment correct
- Icons display properly
- Text readability good
- Mobile layout responsive
✅ Performance Tests
- No memory leaks in timers
- Efficient update intervals
- Smooth animations
- Low CPU usage
🐛 COMMON ISSUES & FIXES
🚨 Footer copre contenuto
Causa: Padding bottom mancante nel body
Fix:
body { padding-bottom: 70px; }
.content-area { margin-bottom: 70px; }
🚨 Timer non funziona
Causa: JavaScript intervals non inizializzati
Fix: Verifica initializeFooter() chiamata
🚨 Stats non si aggiornano
Causa: Endpoint API /api/system-stats mancante
Fix: Implementa route API o disabilita feature
🚨 Progress bar non appare
Causa: CSS z-index conflicts
Fix: Verifica z-index footer e progress bar
📊 PERFORMANCE METRICS
🎯 Target Performance
- Update Frequency: 1Hz (1 update/second)
- API Calls: Max 2/minute
- Memory Usage: < 5MB
- CPU Impact: < 1%
📈 Monitoring
// Performance monitoring
const footerPerformance = {
updateCount: 0,
lastUpdate: Date.now(),
avgUpdateTime: 0,
measureUpdate(fn) {
const start = performance.now();
fn();
const end = performance.now();
this.updateCount++;
this.avgUpdateTime = (this.avgUpdateTime + (end - start)) / 2;
this.lastUpdate = Date.now();
}
};
📚 FILES CORRELATI
🧩 Templates
/resources/views/components/menu/sections/footer.blade.php
🎨 Styles
/public/css/components/footer.css/public/css/netgescon-admin.css
⚡ JavaScript
/public/js/components/footer.js/public/js/netgescon-admin.js
🔗 API Endpoints
/api/ping- Connection check/api/system-stats- System statistics/api/refresh-data- Page data refresh
🎯 NEXT STEPS
🔮 Planned Improvements
- Real-time Notifications - WebSocket integration
- System Health Dashboard - Detailed metrics
- User Activity Tracker - Session analytics
- Quick Actions Menu - Footer dropdown
- Theme Preferences - Footer controls
📝 Documento mantenuto da: GitHub Copilot AI Assistant
🔗 Componente: Footer NetGescon Interface v2.1.0