17 KiB
Executable File
17 KiB
Executable File
📋 SIDEBAR - Documentazione Completa NetGescon
Componente Sidebar dell'interfaccia universale
📅 Creato: 21/07/2025
🔄 Ultimo aggiornamento: 21/07/2025
🎯 Priorità: 🔥 CRITICA
📋 OVERVIEW SIDEBAR
La Sidebar NetGescon è il componente NAVIGATION PRINCIPALE che contiene:
- 🏠 Dashboard Links
- 🏢 Stabili Management
- 🏘️ Condomini Management
- 💰 Contabilità & Fiscale
- 👥 User & Admin Tools
- ⚙️ Sistema Permessi Integrato
📐 Specifiche Layout
- Larghezza:
280pxdesktop,100%mobile - Posizione:
fixed leftsempre visibile desktop - Altezza:
calc(100vh - 70px)(header escluso) - Scroll: Interno quando contenuto > viewport
🎨 DESIGN SPECIFICATIONS
🌈 Color Palette
/* Sidebar Background */
.netgescon-sidebar {
background: var(--netgescon-gray-900);
border-right: 1px solid var(--netgescon-gray-700);
}
/* Menu Items */
.sidebar-link {
color: var(--netgescon-gray-300);
background: transparent;
}
.sidebar-link:hover {
color: var(--netgescon-gray-100);
background: var(--netgescon-gray-800);
}
.sidebar-link.active {
color: var(--netgescon-primary-light);
background: rgba(37, 99, 235, 0.1);
border-right: 3px solid var(--netgescon-primary);
}
📏 Dimensions
.netgescon-sidebar {
width: 280px;
height: calc(100vh - 70px);
top: 70px;
left: 0;
position: fixed;
z-index: 999;
overflow-y: auto;
overflow-x: hidden;
}
/* Mobile */
@media (max-width: 767px) {
.netgescon-sidebar {
width: 100%;
transform: translateX(-100%);
transition: transform 0.3s ease;
}
.netgescon-sidebar.mobile-open {
transform: translateX(0);
}
}
🧩 STRUTTURA MODULARE
📁 Directory Structure
resources/views/components/menu/
├── sidebar.blade.php # File principale
└── sections/ # Componenti modulari
├── header.blade.php # Header sidebar con user info
├── dashboard.blade.php # Dashboard links
├── stabili.blade.php # Gestione stabili (submenu)
├── condomini.blade.php # Gestione condomini (submenu)
├── contabilita.blade.php # Contabilità (submenu)
├── fiscale.blade.php # Fiscale (submenu)
├── menu-semplici.blade.php # Menu senza submenu
├── footer.blade.php # Footer sidebar
├── menu-helpers.blade.php # Helper funzioni
└── permissions.blade.php # Sistema permessi
🎯 Main Sidebar Component
<!-- resources/views/components/menu/sidebar.blade.php -->
<nav class="netgescon-sidebar">
<!-- Sidebar Header -->
@include('components.menu.sections.header')
<!-- Navigation Menu -->
<div class="sidebar-nav">
<!-- Dashboard -->
@include('components.menu.sections.dashboard')
<!-- Stabili (con permessi) -->
@if(canUserAccessMenu('stabili'))
@include('components.menu.sections.stabili')
@endif
<!-- Condomini (con permessi) -->
@if(canUserAccessMenu('condomini'))
@include('components.menu.sections.condomini')
@endif
<!-- Sezione Economica -->
@if(canUserAccessAnyMenu(['contabilita', 'fiscale']))
<div class="menu-divider"></div>
<h6 class="menu-section-title">Gestione Economica</h6>
@if(canUserAccessMenu('contabilita'))
@include('components.menu.sections.contabilita')
@endif
@if(canUserAccessMenu('fiscale'))
@include('components.menu.sections.fiscale')
@endif
@endif
<!-- Menu Semplici -->
@include('components.menu.sections.menu-semplici')
</div>
<!-- Sidebar Footer -->
@include('components.menu.sections.footer')
</nav>
<!-- Overlay mobile -->
<div class="mobile-overlay hidden md:hidden" onclick="toggleMobileMenu()"></div>
👥 SISTEMA PERMESSI
🔐 Ruoli Definiti
// Definiti in config/netgescon.php
'roles' => [
'super_admin' => 'Super Amministratore',
'admin' => 'Amministratore',
'amministratore' => 'Amministratore Condominio',
'collaboratore' => 'Collaboratore',
'ragioniere' => 'Ragioniere/Commercialista',
'condomino' => 'Condomino',
'guest' => 'Ospite'
];
🛡️ Helper Functions
<!-- resources/views/components/menu/sections/menu-helpers.blade.php -->
@php
/**
* Verifica se l'utente può accedere a una sezione menu
*/
function canUserAccessMenu($menuSection, $userRole = null) {
$userRole = $userRole ?? (auth()->user()->role ?? 'guest');
$permissions = [
'super_admin' => ['*'], // Accesso totale
'admin' => [
'dashboard', 'stabili', 'condomini', 'unita',
'contabilita', 'fiscale', 'comunicazioni',
'utenti', 'reports', 'impostazioni'
],
'amministratore' => [
'dashboard', 'stabili', 'condomini', 'unita',
'contabilita', 'comunicazioni', 'reports'
],
'collaboratore' => [
'dashboard', 'stabili', 'condomini', 'unita', 'comunicazioni'
],
'ragioniere' => [
'dashboard', 'contabilita', 'fiscale', 'reports'
],
'condomino' => [
'dashboard', 'comunicazioni', 'tickets'
],
'guest' => []
];
return in_array('*', $permissions[$userRole] ?? []) ||
in_array($menuSection, $permissions[$userRole] ?? []);
}
/**
* Verifica accesso a qualsiasi menu di una lista
*/
function canUserAccessAnyMenu($menuSections, $userRole = null) {
foreach ($menuSections as $section) {
if (canUserAccessMenu($section, $userRole)) {
return true;
}
}
return false;
}
@endphp
🏠 MENU SECTIONS DETAILED
1. 📊 DASHBOARD
<!-- components/menu/sections/dashboard.blade.php -->
<div class="menu-section">
<a href="{{ route('dashboard') }}"
class="sidebar-link {{ request()->routeIs('dashboard') ? 'active' : '' }}">
<i class="fas fa-tachometer-alt w-5"></i>
<span>Dashboard</span>
</a>
</div>
2. 🏢 STABILI (con Submenu)
<!-- components/menu/sections/stabili.blade.php -->
<div class="menu-section">
<div class="menu-item-with-submenu">
<button class="sidebar-toggle" data-target="submenu-stabili">
<i class="fas fa-building w-5"></i>
<span>Gestione Stabili</span>
<i class="fas fa-chevron-down ml-auto transition-transform"></i>
</button>
<div id="submenu-stabili" class="submenu {{ request()->is('admin/stabili*') ? 'open' : '' }}">
<a href="{{ route('admin.stabili.index') }}"
class="submenu-link {{ request()->routeIs('admin.stabili.index') ? 'active' : '' }}">
<i class="fas fa-list w-4"></i>
<span>Elenco Stabili</span>
</a>
<a href="{{ route('admin.stabili.create') }}"
class="submenu-link {{ request()->routeIs('admin.stabili.create') ? 'active' : '' }}">
<i class="fas fa-plus w-4"></i>
<span>Nuovo Stabile</span>
</a>
<a href="{{ route('admin.stabili.reports') }}"
class="submenu-link {{ request()->routeIs('admin.stabili.reports') ? 'active' : '' }}">
<i class="fas fa-chart-bar w-4"></i>
<span>Report Stabili</span>
</a>
</div>
</div>
</div>
3. 🏘️ CONDOMINI (con Submenu)
<!-- components/menu/sections/condomini.blade.php -->
<div class="menu-section">
<div class="menu-item-with-submenu">
<button class="sidebar-toggle" data-target="submenu-condomini">
<i class="fas fa-home w-5"></i>
<span>Gestione Condomini</span>
<i class="fas fa-chevron-down ml-auto transition-transform"></i>
</button>
<div id="submenu-condomini" class="submenu {{ request()->is('admin/condomini*') ? 'open' : '' }}">
<a href="{{ route('admin.condomini.index') }}"
class="submenu-link {{ request()->routeIs('admin.condomini.index') ? 'active' : '' }}">
<i class="fas fa-list w-4"></i>
<span>Elenco Condomini</span>
</a>
<a href="{{ route('admin.condomini.create') }}"
class="submenu-link {{ request()->routeIs('admin.condomini.create') ? 'active' : '' }}">
<i class="fas fa-plus w-4"></i>
<span>Nuovo Condominio</span>
</a>
<a href="{{ route('admin.unita.index') }}"
class="submenu-link {{ request()->routeIs('admin.unita*') ? 'active' : '' }}">
<i class="fas fa-door-open w-4"></i>
<span>Unità Immobiliari</span>
</a>
</div>
</div>
</div>
4. 💰 CONTABILITÀ (con Submenu)
<!-- components/menu/sections/contabilita.blade.php -->
<div class="menu-section">
<div class="menu-item-with-submenu">
<button class="sidebar-toggle" data-target="submenu-contabilita">
<i class="fas fa-calculator w-5"></i>
<span>Contabilità</span>
<i class="fas fa-chevron-down ml-auto transition-transform"></i>
</button>
<div id="submenu-contabilita" class="submenu {{ request()->is('admin/contabilita*') ? 'open' : '' }}">
<a href="{{ route('admin.contabilita.budget') }}"
class="submenu-link">
<i class="fas fa-chart-pie w-4"></i>
<span>Budget Annuale</span>
</a>
<a href="{{ route('admin.contabilita.spese') }}"
class="submenu-link">
<i class="fas fa-receipt w-4"></i>
<span>Gestione Spese</span>
</a>
<a href="{{ route('admin.contabilita.ripartizioni') }}"
class="submenu-link">
<i class="fas fa-percentage w-4"></i>
<span>Ripartizioni</span>
</a>
</div>
</div>
</div>
⚡ JAVASCRIPT FUNCTIONALITY
📁 File: /public/js/components/sidebar.js
/**
* Sidebar NetGescon - JavaScript Functions
*/
// Inizializza sidebar
function initializeSidebar() {
initializeSubmenuToggles();
initializeActiveStates();
initializeMobileOverlay();
initializeScrollBehavior();
}
// Gestione submenu toggle
function initializeSubmenuToggles() {
const toggles = document.querySelectorAll('.sidebar-toggle');
toggles.forEach(toggle => {
toggle.addEventListener('click', function() {
const targetId = this.getAttribute('data-target');
const submenu = document.getElementById(targetId);
const chevron = this.querySelector('.fa-chevron-down');
// Toggle submenu
submenu.classList.toggle('open');
// Rotate chevron
chevron.classList.toggle('rotate-180');
// Store state in localStorage
localStorage.setItem(`submenu-${targetId}`, submenu.classList.contains('open'));
});
});
}
// Ripristina stato submenu da localStorage
function restoreSubmenuStates() {
const submenus = document.querySelectorAll('.submenu');
submenus.forEach(submenu => {
const stored = localStorage.getItem(`submenu-${submenu.id}`);
if (stored === 'true') {
submenu.classList.add('open');
const toggle = document.querySelector(`[data-target="${submenu.id}"]`);
const chevron = toggle.querySelector('.fa-chevron-down');
chevron.classList.add('rotate-180');
}
});
}
// Active states management
function initializeActiveStates() {
const currentUrl = window.location.pathname;
const links = document.querySelectorAll('.sidebar-link, .submenu-link');
links.forEach(link => {
const href = link.getAttribute('href');
if (href && currentUrl.startsWith(href)) {
link.classList.add('active');
// Se è un submenu link, apri anche il parent
if (link.classList.contains('submenu-link')) {
const submenu = link.closest('.submenu');
if (submenu) {
submenu.classList.add('open');
const toggle = document.querySelector(`[data-target="${submenu.id}"]`);
const chevron = toggle.querySelector('.fa-chevron-down');
chevron.classList.add('rotate-180');
}
}
}
});
}
// Mobile behavior
function toggleMobileMenu() {
const sidebar = document.querySelector('.netgescon-sidebar');
const overlay = document.querySelector('.mobile-overlay');
sidebar.classList.toggle('mobile-open');
if (overlay) {
overlay.classList.toggle('hidden');
} else {
createMobileOverlay();
}
}
function createMobileOverlay() {
const overlay = document.createElement('div');
overlay.className = 'mobile-overlay fixed inset-0 bg-black bg-opacity-50 z-998 md:hidden';
overlay.onclick = toggleMobileMenu;
document.body.appendChild(overlay);
}
// Smooth scroll interno sidebar
function initializeScrollBehavior() {
const sidebar = document.querySelector('.netgescon-sidebar');
// Scroll to active item
const activeItem = sidebar.querySelector('.active');
if (activeItem) {
activeItem.scrollIntoView({
behavior: 'smooth',
block: 'center'
});
}
}
// Initialize on DOM ready
document.addEventListener('DOMContentLoaded', function() {
initializeSidebar();
restoreSubmenuStates();
});
📱 RESPONSIVE BEHAVIOR
🖥️ Desktop (≥768px)
.netgescon-sidebar {
position: fixed;
left: 0;
transform: none;
width: 280px;
}
.content-area {
margin-left: 280px;
}
📱 Mobile (≤767px)
.netgescon-sidebar {
position: fixed;
left: 0;
width: 100%;
transform: translateX(-100%);
transition: transform 0.3s ease;
z-index: 1001;
}
.netgescon-sidebar.mobile-open {
transform: translateX(0);
}
.content-area {
margin-left: 0;
}
.mobile-overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 1000;
}
🎨 STYLING CLASSES
🔧 CSS Custom Properties
/* Sidebar Animations */
.submenu {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
}
.submenu.open {
max-height: 500px;
}
/* Hover Effects */
.sidebar-link:hover {
transform: translateX(4px);
transition: all 0.2s ease;
}
/* Active State */
.sidebar-link.active::before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 3px;
background: var(--netgescon-primary);
}
/* Icon Spacing */
.sidebar-link i {
min-width: 20px;
margin-right: 12px;
}
/* Mobile Specific */
@media (max-width: 767px) {
.sidebar-link {
padding: 16px 20px;
font-size: 16px;
}
.submenu-link {
padding: 12px 40px;
}
}
🧪 TESTING CHECKLIST
✅ Functional Tests
- Submenu expand/collapse
- Active state highlighting
- Permission-based visibility
- Mobile menu toggle
- Scroll behavior
- State persistence
✅ Visual Tests
- Icon alignment
- Hover effects
- Active states styling
- Mobile responsive
- Smooth animations
✅ Accessibility Tests
- Keyboard navigation
- Screen reader compatibility
- Focus indicators
- ARIA labels
🐛 COMMON ISSUES & FIXES
🚨 Submenu non si apre
Causa: JavaScript non inizializzato o selettori errati
Fix: Verifica inizializzazione e selettori CSS
🚨 Active state non funziona
Causa: URL routing non corrispondente
Fix: Aggiorna logica comparazione URL
🚨 Mobile overlay non scompare
Causa: Event listener click non agganciato
Fix: Verifica function toggleMobileMenu()
🚨 Permessi non funzionano
Causa: Helper functions non caricate o ruoli errati
Fix: Verifica file permissions.blade.php e user roles
📚 FILES CORRELATI
🧩 Templates
/resources/views/components/menu/sidebar.blade.php/resources/views/components/menu/sections/(directory)
🎨 Styles
/public/css/components/sidebar.css/public/css/netgescon-admin.css
⚡ JavaScript
/public/js/components/sidebar.js/public/js/netgescon-admin.js
🎯 NEXT STEPS
🔮 Planned Improvements
- Sidebar Customization - User preferences
- Quick Search - Search in menu items
- Favorites - Pin frequently used items
- Breadcrumb Integration - Sync with sidebar state
- Dark Mode - Theme switch
📝 Documento mantenuto da: GitHub Copilot AI Assistant
🔗 Componente: Sidebar NetGescon Interface v2.1.0