netgescon-day0/docs/90-UI-interfaccia-unica/02-SIDEBAR.md

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: 280px desktop, 100% mobile
  • Posizione: fixed left sempre 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