684 lines
18 KiB
Markdown
Executable File
684 lines
18 KiB
Markdown
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:** `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**
|
||
```css
|
||
/* 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**
|
||
```css
|
||
.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`
|
||
```blade
|
||
<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`
|
||
|
||
```javascript
|
||
/**
|
||
* 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)**
|
||
```css
|
||
.netgescon-footer {
|
||
padding: 0 24px;
|
||
}
|
||
|
||
.footer-center {
|
||
display: flex;
|
||
}
|
||
|
||
.footer-right .hidden {
|
||
display: block;
|
||
}
|
||
```
|
||
|
||
### 📱 **Tablet (768px - 1023px)**
|
||
```css
|
||
.footer-center {
|
||
display: none;
|
||
}
|
||
|
||
.footer-left,
|
||
.footer-right {
|
||
flex-wrap: wrap;
|
||
}
|
||
```
|
||
|
||
### 📱 **Mobile (≤767px)**
|
||
```css
|
||
.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**
|
||
```javascript
|
||
// 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**
|
||
```css
|
||
/* 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:**
|
||
```css
|
||
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**
|
||
```javascript
|
||
// 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*
|