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:
kbe
2025-08-31 19:08:51 +02:00
parent 3414057795
commit aa5dccb508
10 changed files with 886 additions and 1 deletions

View File

@@ -0,0 +1,146 @@
<% content_for(:title, "Créer un événement") %>
<div class="container py-8">
<div class="max-w-4xl mx-auto">
<div class="mb-8">
<div class="flex items-center space-x-4">
<%= link_to promoter_events_path, class: "text-gray-400 hover:text-gray-600 transition-colors" do %>
<i data-lucide="arrow-left" class="w-5 h-5"></i>
<% end %>
<div>
<h1 class="text-3xl font-bold text-gray-900 mb-2">Créer un événement</h1>
<p class="text-gray-600">Remplissez les informations de votre événement</p>
</div>
</div>
</div>
<%= form_with model: [:promoter, @event], local: true, class: "space-y-8", data: { controller: "event-form" } do |form| %>
<% if @event.errors.any? %>
<div class="bg-red-50 border border-red-200 rounded-lg p-4">
<div class="flex">
<div class="flex-shrink-0">
<i data-lucide="alert-circle" class="w-5 h-5 text-red-400"></i>
</div>
<div class="ml-3">
<h3 class="text-sm font-medium text-red-800">
<%= pluralize(@event.errors.count, "erreur") %> à corriger :
</h3>
<div class="mt-2 text-sm text-red-700">
<ul class="list-disc list-inside space-y-1">
<% @event.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
</div>
</div>
</div>
<% end %>
<!-- Basic Information -->
<div class="bg-white rounded-lg border border-gray-200 p-6">
<h3 class="text-lg font-semibold text-gray-900 mb-6">Informations générales</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<%= form.label :name, "Nom de l'événement", class: "block text-sm font-medium text-gray-700 mb-2" %>
<%= form.text_field :name, class: "w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent", placeholder: "Ex: Soirée d'ouverture", data: { "event-form-target": "name", action: "input->event-form#generateSlug" } %>
</div>
<div>
<%= form.label :slug, "Slug (URL)", class: "block text-sm font-medium text-gray-700 mb-2" %>
<%= form.text_field :slug, class: "w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent", placeholder: "soiree-ouverture", data: { "event-form-target": "slug" } %>
<p class="mt-1 text-sm text-gray-500">Utilisé dans l'URL de l'événement</p>
</div>
</div>
<div class="mt-6">
<%= form.label :description, "Description", class: "block text-sm font-medium text-gray-700 mb-2" %>
<%= form.text_area :description, rows: 4, class: "w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent", placeholder: "Décrivez votre événement..." %>
</div>
<div class="mt-6">
<%= form.label :image, "Image (URL)", class: "block text-sm font-medium text-gray-700 mb-2" %>
<%= form.url_field :image, class: "w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent", placeholder: "https://example.com/image.jpg" %>
<p class="mt-1 text-sm text-gray-500">URL de l'image de couverture de l'événement</p>
</div>
</div>
<!-- Date & Time -->
<div class="bg-white rounded-lg border border-gray-200 p-6">
<h3 class="text-lg font-semibold text-gray-900 mb-6">Date et heure</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<%= form.label :start_time, "Date et heure de début", class: "block text-sm font-medium text-gray-700 mb-2" %>
<%= form.datetime_local_field :start_time, class: "w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent" %>
</div>
<div>
<%= form.label :end_time, "Date et heure de fin", class: "block text-sm font-medium text-gray-700 mb-2" %>
<%= form.datetime_local_field :end_time, class: "w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent" %>
</div>
</div>
</div>
<!-- Venue Information -->
<div class="bg-white rounded-lg border border-gray-200 p-6">
<h3 class="text-lg font-semibold text-gray-900 mb-6">Lieu de l'événement</h3>
<div class="space-y-6">
<div>
<%= form.label :venue_name, "Nom du lieu", class: "block text-sm font-medium text-gray-700 mb-2" %>
<%= form.text_field :venue_name, class: "w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent", placeholder: "Ex: Le Grand Rex" %>
</div>
<div>
<%= form.label :venue_address, "Adresse", class: "block text-sm font-medium text-gray-700 mb-2" %>
<%= form.text_field :venue_address, class: "w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent", placeholder: "Ex: 1 Boulevard Poissonnière, 75002 Paris" %>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<%= form.label :latitude, "Latitude", class: "block text-sm font-medium text-gray-700 mb-2" %>
<%= form.number_field :latitude, step: :any, class: "w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent", placeholder: "48.8566" %>
</div>
<div>
<%= form.label :longitude, "Longitude", class: "block text-sm font-medium text-gray-700 mb-2" %>
<%= form.number_field :longitude, step: :any, class: "w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent", placeholder: "2.3522" %>
</div>
</div>
<p class="text-sm text-gray-500">
<i data-lucide="info" class="w-4 h-4 inline mr-1"></i>
Utilisez un service comme <a href="https://www.latlong.net/" target="_blank" class="text-purple-600 hover:text-purple-800">latlong.net</a> pour obtenir les coordonnées GPS.
</p>
</div>
</div>
<!-- Options -->
<div class="bg-white rounded-lg border border-gray-200 p-6">
<h3 class="text-lg font-semibold text-gray-900 mb-6">Options</h3>
<div class="flex items-center">
<%= form.check_box :featured, class: "h-4 w-4 text-purple-600 border-gray-300 rounded focus:ring-purple-500" %>
<%= form.label :featured, "Mettre en avant sur la page d'accueil", class: "ml-2 text-sm text-gray-700" %>
</div>
<p class="mt-2 text-sm text-gray-500">Les événements mis en avant apparaissent en premier sur la page d'accueil.</p>
</div>
<!-- Actions -->
<div class="flex items-center justify-between">
<div class="flex items-center space-x-4">
<%= link_to promoter_events_path, class: "text-gray-500 hover:text-gray-700 transition-colors" do %>
Annuler
<% end %>
</div>
<div class="flex items-center space-x-3">
<%= form.submit "Créer en brouillon", class: "inline-flex items-center px-6 py-3 bg-gray-600 text-white font-medium rounded-lg hover:bg-gray-700 transition-colors duration-200" %>
</div>
</div>
<% end %>
</div>
</div>