feat: Implement comprehensive event management system for promoters
This commit adds a complete event management interface allowing promoters to create, edit, and manage their events with full CRUD operations. ## Backend Features - New Promoter::EventsController with full CRUD operations - Event state management (draft, published, canceled, sold_out) - User authorization system with can_manage_events? method - Proper scoping to ensure users only see their own events ## Frontend Features - Modern responsive UI with Tailwind CSS styling - Event listing with status indicators and quick actions - Comprehensive event creation and editing forms - Detailed event show page with metrics and management options - Integration with main dashboard via promoter action buttons ## JavaScript Improvements - Refactored inline JavaScript to dedicated Stimulus controller - Auto-slug generation from event names with proper sanitization - Improved code organization following Rails conventions ## Routes & Navigation - Namespaced promoter routes under /promoter/ - RESTful endpoints with state management actions - Proper breadcrumb navigation and user flow ## Files Added/Modified - app/controllers/promoter/events_controller.rb (new) - app/javascript/controllers/event_form_controller.js (new) - app/views/promoter/events/*.html.erb (4 new view files) - app/models/user.rb (added authorization methods) - app/views/pages/dashboard.html.erb (added promoter buttons) - config/routes.rb (added promoter namespace) - app/javascript/controllers/index.js (registered new controller) 🎯 Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
136
app/views/promoter/events/index.html.erb
Normal file
136
app/views/promoter/events/index.html.erb
Normal file
@@ -0,0 +1,136 @@
|
||||
<% content_for(:title, "Mes événements") %>
|
||||
|
||||
<div class="container py-8">
|
||||
<div class="mb-8 flex items-center justify-between">
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold text-gray-900 mb-2">Mes événements</h1>
|
||||
<p class="text-gray-600">Gérez tous vos événements depuis cette interface</p>
|
||||
</div>
|
||||
<%= link_to new_promoter_event_path, class: "inline-flex items-center px-6 py-3 bg-black text-white font-medium rounded-lg hover:bg-gray-800 transition-colors duration-200" do %>
|
||||
<i data-lucide="plus" class="w-4 h-4 mr-2"></i>
|
||||
Créer un événement
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% if @events.any? %>
|
||||
<div class="bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden">
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full">
|
||||
<thead class="bg-gray-50 border-b border-gray-200">
|
||||
<tr>
|
||||
<th class="px-6 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Événement</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Statut</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Lieu</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-200">
|
||||
<% @events.each do |event| %>
|
||||
<tr class="hover:bg-gray-50 transition-colors duration-150">
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center">
|
||||
<div class="h-12 w-12 rounded-lg bg-gradient-to-br from-purple-500 to-pink-500 flex items-center justify-center flex-shrink-0">
|
||||
<i data-lucide="calendar" class="w-6 h-6 text-white"></i>
|
||||
</div>
|
||||
<div class="ml-4">
|
||||
<div class="text-sm font-medium text-gray-900">
|
||||
<%= link_to event.name, promoter_event_path(event), class: "hover:text-purple-600 transition-colors" %>
|
||||
</div>
|
||||
<div class="text-sm text-gray-500 truncate max-w-xs">
|
||||
<%= event.description.truncate(60) %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<% case event.state %>
|
||||
<% when "draft" %>
|
||||
<span class="inline-flex px-2 py-1 text-xs font-semibold rounded-full bg-gray-100 text-gray-800">
|
||||
<i data-lucide="edit-3" class="w-3 h-3 mr-1"></i>
|
||||
Brouillon
|
||||
</span>
|
||||
<% when "published" %>
|
||||
<span class="inline-flex px-2 py-1 text-xs font-semibold rounded-full bg-green-100 text-green-800">
|
||||
<i data-lucide="eye" class="w-3 h-3 mr-1"></i>
|
||||
Publié
|
||||
</span>
|
||||
<% when "canceled" %>
|
||||
<span class="inline-flex px-2 py-1 text-xs font-semibold rounded-full bg-red-100 text-red-800">
|
||||
<i data-lucide="x-circle" class="w-3 h-3 mr-1"></i>
|
||||
Annulé
|
||||
</span>
|
||||
<% when "sold_out" %>
|
||||
<span class="inline-flex px-2 py-1 text-xs font-semibold rounded-full bg-blue-100 text-blue-800">
|
||||
<i data-lucide="users" class="w-3 h-3 mr-1"></i>
|
||||
Complet
|
||||
</span>
|
||||
<% end %>
|
||||
|
||||
<% if event.featured? %>
|
||||
<span class="inline-flex px-2 py-1 text-xs font-semibold rounded-full bg-yellow-100 text-yellow-800 ml-1">
|
||||
<i data-lucide="star" class="w-3 h-3 mr-1"></i>
|
||||
À la une
|
||||
</span>
|
||||
<% end %>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm text-gray-500">
|
||||
<% if event.start_time %>
|
||||
<div><%= event.start_time.strftime("%d/%m/%Y") %></div>
|
||||
<div class="text-xs text-gray-400"><%= event.start_time.strftime("%H:%M") %></div>
|
||||
<% else %>
|
||||
<span class="text-gray-400">Date non définie</span>
|
||||
<% end %>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm text-gray-500">
|
||||
<div><%= event.venue_name %></div>
|
||||
<div class="text-xs text-gray-400 truncate max-w-xs"><%= event.venue_address %></div>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center space-x-2">
|
||||
<%= link_to promoter_event_path(event), class: "text-gray-400 hover:text-gray-600 transition-colors", title: "Voir" do %>
|
||||
<i data-lucide="eye" class="w-4 h-4"></i>
|
||||
<% end %>
|
||||
<%= link_to edit_promoter_event_path(event), class: "text-gray-400 hover:text-blue-600 transition-colors", title: "Modifier" do %>
|
||||
<i data-lucide="edit" class="w-4 h-4"></i>
|
||||
<% end %>
|
||||
<% if event.draft? %>
|
||||
<%= button_to publish_promoter_event_path(event), method: :patch, class: "text-gray-400 hover:text-green-600 transition-colors", title: "Publier" do %>
|
||||
<i data-lucide="upload" class="w-4 h-4"></i>
|
||||
<% end %>
|
||||
<% elsif event.published? %>
|
||||
<%= button_to unpublish_promoter_event_path(event), method: :patch, class: "text-gray-400 hover:text-yellow-600 transition-colors", title: "Dépublier" do %>
|
||||
<i data-lucide="download" class="w-4 h-4"></i>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<%= button_to promoter_event_path(event), method: :delete,
|
||||
data: { confirm: "Êtes-vous sûr de vouloir supprimer cet événement ?" },
|
||||
class: "text-gray-400 hover:text-red-600 transition-colors", title: "Supprimer" do %>
|
||||
<i data-lucide="trash-2" class="w-4 h-4"></i>
|
||||
<% end %>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6">
|
||||
<%= paginate @events if respond_to?(:paginate) %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="bg-white rounded-lg border-2 border-dashed border-gray-300 p-12 text-center">
|
||||
<div class="mx-auto h-24 w-24 rounded-full bg-gray-100 flex items-center justify-center mb-6">
|
||||
<i data-lucide="calendar-plus" class="w-12 h-12 text-gray-400"></i>
|
||||
</div>
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-2">Aucun événement</h3>
|
||||
<p class="text-gray-500 mb-6">Vous n'avez pas encore créé d'événement. Commencez dès maintenant !</p>
|
||||
<%= link_to new_promoter_event_path, class: "inline-flex items-center px-6 py-3 bg-black text-white font-medium rounded-lg hover:bg-gray-800 transition-colors duration-200" do %>
|
||||
<i data-lucide="plus" class="w-4 h-4 mr-2"></i>
|
||||
Créer mon premier événement
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
Reference in New Issue
Block a user