Files
aperonight/app/views/components/_header.html.erb
kbe 46d042b85e feat: Implement comprehensive promoter system with dashboard and role-based access
This commit implements a complete promoter system that allows professional users
(is_professionnal: true) to manage events with advanced analytics and controls.

## Key Features Added:

### Role-Based Access Control
- Update User#can_manage_events? to use is_professionnal field
- Add promoter? alias method for semantic clarity
- Restrict event management to professional users only

### Enhanced Navigation
- Add conditional "Créer un événement" and "Mes événements" links
- Display promoter navigation only for professional users
- Include responsive mobile navigation with appropriate icons
- Maintain clean UI for regular users

### Comprehensive Promoter Dashboard
- Revenue metrics with total earnings calculation
- Tickets sold counter across all events
- Published vs draft events statistics
- Monthly revenue trend chart (6 months)
- Recent events widget with quick management actions
- Recent orders table with customer information

### Advanced Analytics
- Real-time revenue calculations from order data
- Monthly revenue trends with visual progress bars
- Event performance metrics and status tracking
- Customer order history and transaction details

### Event Management Workflow
- Verified existing event CRUD operations are comprehensive
- Maintains easy-to-use interface for event creation/editing
- State management system (draft → published → cancelled)
- Quick action buttons for common operations

### Documentation
- Comprehensive implementation guide in docs/
- Technical details and architecture explanations
- Future enhancement recommendations
- Testing and deployment considerations

## Technical Implementation:

- Optimized database queries to prevent N+1 problems
- Proper eager loading for dashboard performance
- Responsive design with Tailwind CSS components
- Clean separation of promoter vs regular user features
- Maintainable code structure following Rails conventions

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-10 20:49:06 +02:00

182 lines
9.9 KiB
Plaintext
Executable File

<header class="bg-white shadow-lg border-b border-gray-200 sticky top-0 z-50">
<nav data-controller="header" class="container mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex items-center h-16 justify-between">
<!-- Logo -->
<div class="flex-shrink-0 flex items-center">
<%= link_to Rails.application.config.app_name, "/",
class: "text-2xl font-display font-bold text-gray-900 hover:text-brand-primary transition-colors" %>
</div>
<!-- Desktop Navigation -->
<div class="hidden sm:flex items-center space-x-8 w-full justify-center">
<%= link_to events_path,
class: "text-gray-700 hover:text-brand-primary py-2 text-sm font-medium transition-colors duration-200 relative after:absolute after:bottom-0 after:left-0 after:h-0.5 after:w-0 hover:after:w-full after:bg-brand-primary after:transition-all after:duration-200" do %>
Événements & Afterworks
<% end %>
<%= link_to dashboard_path,
class: "text-gray-700 hover:text-brand-primary py-2 text-sm font-medium transition-colors duration-200 relative after:absolute after:bottom-0 after:left-0 after:h-0.5 after:w-0 hover:after:w-full after:bg-brand-primary after:transition-all after:duration-200" do %>
Tableau de bord
<% end %>
<% if user_signed_in? && current_user.promoter? %>
<%= link_to new_promoter_event_path,
class: "text-gray-700 hover:text-brand-primary py-2 text-sm font-medium transition-colors duration-200 relative after:absolute after:bottom-0 after:left-0 after:h-0.5 after:w-0 hover:after:w-full after:bg-brand-primary after:transition-all after:duration-200" do %>
Créer un événement
<% end %>
<%= link_to promoter_events_path,
class: "text-gray-700 hover:text-brand-primary py-2 text-sm font-medium transition-colors duration-200 relative after:absolute after:bottom-0 after:left-0 after:h-0.5 after:w-0 hover:after:w-full after:bg-brand-primary after:transition-all after:duration-200" do %>
Mes événements
<% end %>
<% end %>
<!-- <%= link_to "#",
class: "text-gray-700 hover:text-brand-primary py-2 text-sm font-medium transition-colors duration-200 relative after:absolute after:bottom-0 after:left-0 after:h-0.5 after:w-0 hover:after:w-full after:bg-brand-primary after:transition-all after:duration-200" do %>
Concerts
<% end %> -->
</div>
<!-- Authentication -->
<div class="hidden sm:flex items-center space-x-4">
<% if user_signed_in? %>
<div class="relative" data-header-target="userMenuButton">
<button data-action="click->header#toggleUserMenu"
class="bg-gray-900 text-white font-medium py-2 px-4 rounded-full hover:bg-gray-800 transition-colors duration-200 flex items-center space-x-2">
<span><%= current_user.email.length > 20 ? current_user.email[0,20] + "..." : current_user.email %></span>
<i data-lucide="chevron-down" class="w-4 h-4"></i>
</button>
<!-- User Dropdown Menu -->
<div data-header-target="userMenu" class="hidden absolute right-0 mt-2 w-56 bg-white rounded-2xl shadow-xl border border-gray-100 py-2 z-50">
<div class="px-4 py-3 text-sm text-gray-900 border-b border-gray-100">
<div class="font-semibold"><%= current_user.first_name || current_user.email %></div>
<div class="text-gray-500"><%= current_user.email %></div>
</div>
<%= link_to "#",
class: "flex items-center px-4 py-3 text-sm text-gray-700 hover:bg-gray-50 transition-colors duration-200" do %>
<i data-lucide="calendar" class="w-4 h-4 mr-3"></i>
Réservations
<% end %>
<%= link_to edit_user_registration_path,
class: "flex items-center px-4 py-3 text-sm text-gray-700 hover:bg-gray-50 transition-colors duration-200" do %>
<i data-lucide="settings" class="w-4 h-4 mr-3"></i>
Sécurité
<% end %>
<div class="border-t border-gray-100">
<%= link_to destroy_user_session_path,
data: { controller: "logout", action: "click->logout#signOut", logout_url_value: destroy_user_session_path, login_url_value: new_user_session_path, turbo: false },
class: "flex items-center px-4 py-3 text-sm text-gray-700 hover:bg-gray-50 transition-colors duration-200" do %>
<i data-lucide="log-out" class="w-4 h-4 mr-3"></i>
Déconnexion
<% end %>
</div>
</div>
</div>
<% else %>
<%= link_to new_user_session_path,
class: "text-gray-700 hover:text-brand-primary px-6 py-2 rounded-full text-sm font-medium transition-colors duration-200 whitespace-nowrap" do %>
Se connecter
<% end %>
<%= link_to new_user_registration_path,
class: "bg-gray-900 text-white font-semibold py-2 px-8 rounded-full hover:bg-gray-800 transition-colors duration-200 shadow-lg hover:shadow-xl whitespace-nowrap" do %>
S'inscrire
<% end %>
<% end %>
</div>
<!-- Mobile menu button -->
<div class="flex-shrink-0 sm:hidden">
<button data-action="click->header#toggleMobileMenu" data-header-target="mobileMenuButton" class="p-2 rounded-lg text-gray-600 hover:text-gray-900 hover:bg-gray-100">
<i data-menu-icon="open" data-lucide="menu" class="w-6 h-6"></i>
<i data-menu-icon="close" data-lucide="x" class="w-6 h-6 hidden"></i>
</button>
</div>
</div>
<!-- Mobile Menu -->
<div data-header-target="mobileMenu" class="hidden sm:hidden border-t border-gray-200">
<div class="px-4 pt-4 pb-3 space-y-2">
<%= link_to events_path,
class: "flex items-center px-3 py-2 rounded-lg text-base font-medium text-gray-700 hover:text-brand-primary hover:bg-gray-50" do %>
<i data-lucide="calendar" class="w-4 h-4 mr-3"></i>
Événements & Afterworks
<% end %>
<%= link_to dashboard_path,
class: "flex items-center px-3 py-2 rounded-lg text-base font-medium text-gray-700 hover:text-brand-primary hover:bg-gray-50" do %>
<i data-lucide="bar-chart-3" class="w-4 h-4 mr-3"></i>
Tableau de bord
<% end %>
<% if user_signed_in? && current_user.promoter? %>
<%= link_to new_promoter_event_path,
class: "flex items-center px-3 py-2 rounded-lg text-base font-medium text-gray-700 hover:text-brand-primary hover:bg-gray-50" do %>
<i data-lucide="plus-circle" class="w-4 h-4 mr-3"></i>
Créer un événement
<% end %>
<%= link_to promoter_events_path,
class: "flex items-center px-3 py-2 rounded-lg text-base font-medium text-gray-700 hover:text-brand-primary hover:bg-gray-50" do %>
<i data-lucide="calendar-check" class="w-4 h-4 mr-3"></i>
Mes événements
<% end %>
<% end %>
<!-- <%= link_to events_path,
class: "flex items-center px-3 py-2 rounded-lg text-base font-medium text-gray-700 hover:text-brand-primary hover:bg-gray-50" do %>
<i data-lucide="glass-water" class="w-4 h-4 mr-3"></i>
Afterworks
<% end %> -->
<!-- <%= link_to "#",
class: "flex items-center px-3 py-2 rounded-lg text-base font-medium text-gray-700 hover:text-brand-primary hover:bg-gray-50" do %>
<i data-lucide="music" class="w-4 h-4 mr-3"></i>
Concerts
<% end %> -->
</div>
<div class="pt-4 pb-4 border-t border-gray-200">
<% if user_signed_in? %>
<div class="px-4 mb-3">
<div class="text-base font-semibold text-gray-900">
<%= current_user.first_name || current_user.email %>
</div>
<div class="text-sm text-gray-500"><%= current_user.email %></div>
</div>
<div class="px-4 space-y-2">
<%= link_to "#",
class: "flex items-center px-3 py-2 rounded-lg text-base font-medium text-gray-700 hover:text-brand-primary hover:bg-gray-50" do %>
<i data-lucide="calendar" class="w-4 h-4 mr-3"></i>
Réservations
<% end %>
<%= link_to edit_user_registration_path,
class: "flex items-center px-3 py-2 rounded-lg text-base font-medium text-gray-700 hover:text-brand-primary hover:bg-gray-50" do %>
<i data-lucide="settings" class="w-4 h-4 mr-3"></i>
Sécurité
<% end %>
<%= link_to destroy_user_session_path,
data: { controller: "logout", action: "click->logout#signOut", logout_url_value: destroy_user_session_path, login_url_value: new_user_session_path, turbo: false },
class: "flex items-center px-3 py-2 rounded-lg text-base font-medium text-gray-700 hover:text-brand-primary hover:bg-gray-50" do %>
<i data-lucide="log-out" class="w-4 h-4 mr-3"></i>
Déconnexion
<% end %>
</div>
<% else %>
<div class="px-4 space-y-2">
<%= link_to new_user_session_path,
class: "flex items-center justify-center px-3 py-2 rounded-lg text-base font-medium text-gray-700 hover:text-brand-primary hover:bg-gray-50" do %>
<i data-lucide="log-in" class="w-4 h-4 mr-3"></i>
Se connecter
<% end %>
<%= link_to new_user_registration_path,
class: "flex items-center justify-center px-3 py-2 rounded-lg text-base font-semibold bg-gray-900 text-white hover:bg-gray-800" do %>
<i data-lucide="user-plus" class="w-4 h-4 mr-3"></i>
S'inscrire
<% end %>
</div>
<% end %>
</div>
</div>
</nav>
</header>