netgescon-day0/docs/90-UI-interfaccia-unica/04-FOOTER.md

18 KiB
Executable File
Raw Blame History

🦶 FOOTER - Documentazione Completa NetGescon

Componente Footer dell'interfaccia universale
📅 Creato: 21/07/2025
🔄 Ultimo aggiornamento: 21/07/2025
🎯 Priorità: 🔥 CRITICA


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: 70px fisso
  • Posizione: fixed bottom-0 sempre visibile
  • Z-index: 999 sopra 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;
}

📁 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

// 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

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