From aa5dccb5086716d7a092163fdd0a34e3163d346b Mon Sep 17 00:00:00 2001 From: kbe Date: Sun, 31 Aug 2025 19:08:51 +0200 Subject: [PATCH] feat: Implement comprehensive event management system for promoters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Co-Authored-By: Happy --- app/controllers/promoter/events_controller.rb | 117 +++++++++ .../controllers/event_form_controller.js | 28 +++ app/javascript/controllers/index.js | 3 + app/models/user.rb | 12 + app/views/pages/dashboard.html.erb | 18 +- app/views/promoter/events/edit.html.erb | 184 ++++++++++++++ app/views/promoter/events/index.html.erb | 136 +++++++++++ app/views/promoter/events/new.html.erb | 146 +++++++++++ app/views/promoter/events/show.html.erb | 231 ++++++++++++++++++ config/routes.rb | 12 + 10 files changed, 886 insertions(+), 1 deletion(-) create mode 100644 app/controllers/promoter/events_controller.rb create mode 100644 app/javascript/controllers/event_form_controller.js create mode 100644 app/views/promoter/events/edit.html.erb create mode 100644 app/views/promoter/events/index.html.erb create mode 100644 app/views/promoter/events/new.html.erb create mode 100644 app/views/promoter/events/show.html.erb diff --git a/app/controllers/promoter/events_controller.rb b/app/controllers/promoter/events_controller.rb new file mode 100644 index 0000000..3f2deda --- /dev/null +++ b/app/controllers/promoter/events_controller.rb @@ -0,0 +1,117 @@ +# Promoter Events Controller +# +# Handles event management for promoters (event organizers) +# Allows promoters to create, edit, delete and manage their events +class Promoter::EventsController < ApplicationController + before_action :authenticate_user! + before_action :ensure_can_manage_events! + before_action :set_event, only: [:show, :edit, :update, :destroy, :publish, :unpublish, :cancel, :mark_sold_out] + + # Display all events for the current promoter + def index + @events = current_user.events.order(created_at: :desc).page(params[:page]).per(10) + end + + # Display a specific event for the promoter + def show + # Event is set by set_event callback + end + + # Show form to create a new event + def new + @event = current_user.events.build + end + + # Create a new event + def create + @event = current_user.events.build(event_params) + + if @event.save + redirect_to promoter_event_path(@event), notice: 'Event créé avec succès!' + else + render :new, status: :unprocessable_entity + end + end + + # Show form to edit an existing event + def edit + # Event is set by set_event callback + end + + # Update an existing event + def update + if @event.update(event_params) + redirect_to promoter_event_path(@event), notice: 'Event mis à jour avec succès!' + else + render :edit, status: :unprocessable_entity + end + end + + # Delete an event + def destroy + @event.destroy + redirect_to promoter_events_path, notice: 'Event supprimé avec succès!' + end + + # Publish an event (make it visible to public) + def publish + if @event.draft? + @event.update(state: :published) + redirect_to promoter_event_path(@event), notice: 'Event publié avec succès!' + else + redirect_to promoter_event_path(@event), alert: 'Cet event ne peut pas être publié.' + end + end + + # Unpublish an event (make it draft) + def unpublish + if @event.published? + @event.update(state: :draft) + redirect_to promoter_event_path(@event), notice: 'Event dépublié avec succès!' + else + redirect_to promoter_event_path(@event), alert: 'Cet event ne peut pas être dépublié.' + end + end + + # Cancel an event + def cancel + if @event.published? + @event.update(state: :canceled) + redirect_to promoter_event_path(@event), notice: 'Event annulé avec succès!' + else + redirect_to promoter_event_path(@event), alert: 'Cet event ne peut pas être annulé.' + end + end + + # Mark event as sold out + def mark_sold_out + if @event.published? + @event.update(state: :sold_out) + redirect_to promoter_event_path(@event), notice: 'Event marqué comme complet!' + else + redirect_to promoter_event_path(@event), alert: 'Cet event ne peut pas être marqué comme complet.' + end + end + + private + + def ensure_can_manage_events! + unless current_user.can_manage_events? + redirect_to dashboard_path, alert: 'Vous n\'avez pas les permissions nécessaires pour gérer des événements.' + end + end + + def set_event + @event = current_user.events.find(params[:id]) + rescue ActiveRecord::RecordNotFound + redirect_to promoter_events_path, alert: 'Event non trouvé ou vous n\'avez pas accès à cet event.' + end + + def event_params + params.require(:event).permit( + :name, :slug, :description, :image, + :venue_name, :venue_address, :latitude, :longitude, + :start_time, :end_time, :featured + ) + end +end \ No newline at end of file diff --git a/app/javascript/controllers/event_form_controller.js b/app/javascript/controllers/event_form_controller.js new file mode 100644 index 0000000..cc031b1 --- /dev/null +++ b/app/javascript/controllers/event_form_controller.js @@ -0,0 +1,28 @@ +import { Controller } from "@hotwired/stimulus" + +// Event form controller for handling form interactions +// Handles auto-slug generation from event names +export default class extends Controller { + static targets = ["name", "slug"] + + connect() { + console.log("Event form controller connected") + } + + // Auto-generate slug from name input + generateSlug() { + // Only auto-generate if slug field is empty + if (this.slugTarget.value === "") { + const slug = this.nameTarget.value + .toLowerCase() + .normalize("NFD") + .replace(/[\u0300-\u036f]/g, "") // Remove accents + .replace(/[^a-z0-9\s-]/g, "") // Remove special chars + .replace(/\s+/g, "-") // Replace spaces with dashes + .replace(/-+/g, "-") // Remove duplicate dashes + .replace(/^-|-$/g, "") // Remove leading/trailing dashes + + this.slugTarget.value = slug + } + } +} \ No newline at end of file diff --git a/app/javascript/controllers/index.js b/app/javascript/controllers/index.js index 89b7279..593b714 100755 --- a/app/javascript/controllers/index.js +++ b/app/javascript/controllers/index.js @@ -19,6 +19,9 @@ application.register("ticket-selection", TicketSelectionController); import HeaderController from "./header_controller" application.register("header", HeaderController); +import EventFormController from "./event_form_controller" +application.register("event-form", EventFormController); + diff --git a/app/models/user.rb b/app/models/user.rb index bb14b14..8076d13 100755 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -27,4 +27,16 @@ class User < ApplicationRecord validates :last_name, length: { minimum: 3, maximum: 12, allow_blank: true } validates :first_name, length: { minimum: 3, maximum: 12, allow_blank: true } validates :company_name, length: { minimum: 3, maximum: 12, allow_blank: true } + + # Authorization methods + def can_manage_events? + # For now, all authenticated users can manage events + # This can be extended later with role-based permissions + true + end + + def promoter? + # Alias for can_manage_events? to make views more semantic + can_manage_events? + end end diff --git a/app/views/pages/dashboard.html.erb b/app/views/pages/dashboard.html.erb index a611596..b476858 100755 --- a/app/views/pages/dashboard.html.erb +++ b/app/views/pages/dashboard.html.erb @@ -1,7 +1,23 @@
-

Tableau de bord

+
+

Tableau de bord

+ + + <% if current_user.promoter? %> +
+ <%= link_to promoter_events_path, class: "inline-flex items-center px-4 py-2 bg-purple-600 text-white font-medium rounded-lg hover:bg-purple-700 transition-colors duration-200" do %> + + Mes événements + <% end %> + <%= link_to new_promoter_event_path, class: "inline-flex items-center px-4 py-2 bg-black text-white font-medium rounded-lg hover:bg-gray-800 transition-colors duration-200" do %> + + Créer un événement + <% end %> +
+ <% end %> +
<%= render partial: 'components/metric_card', locals: { title: "Mes réservations", value: @booked_events, classes: "from-green-100 to-emerald-100" } %> diff --git a/app/views/promoter/events/edit.html.erb b/app/views/promoter/events/edit.html.erb new file mode 100644 index 0000000..8139a5d --- /dev/null +++ b/app/views/promoter/events/edit.html.erb @@ -0,0 +1,184 @@ +<% content_for(:title, "Modifier #{@event.name}") %> + +
+
+
+
+ <%= link_to promoter_event_path(@event), class: "text-gray-400 hover:text-gray-600 transition-colors" do %> + + <% end %> +
+

Modifier l'événement

+

<%= @event.name %>

+
+
+
+ + <%= form_with model: [:promoter, @event], local: true, class: "space-y-8", data: { controller: "event-form" } do |form| %> + <% if @event.errors.any? %> +
+
+
+ +
+
+

+ <%= pluralize(@event.errors.count, "erreur") %> à corriger : +

+
+
    + <% @event.errors.full_messages.each do |message| %> +
  • <%= message %>
  • + <% end %> +
+
+
+
+
+ <% end %> + + +
+

Informations générales

+ +
+
+ <%= 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" } %> +
+ +
+ <%= 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" } %> +

+ <% if @event.published? %> + + Attention: Modifier le slug d'un événement publié peut casser les liens existants. + <% else %> + Utilisé dans l'URL de l'événement + <% end %> +

+
+
+ +
+ <%= 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..." %> +
+ +
+ <%= 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" %> +

URL de l'image de couverture de l'événement

+
+
+ + +
+

Date et heure

+ +
+
+ <%= 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, + value: @event.start_time&.strftime("%Y-%m-%dT%H:%M"), + class: "w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent" %> +
+ +
+ <%= 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, + value: @event.end_time&.strftime("%Y-%m-%dT%H:%M"), + class: "w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent" %> +
+
+ + <% if @event.published? && @event.tickets.any? %> +
+
+ +

+ Des billets ont déjà été vendus pour cet événement. Modifier la date pourrait impacter les participants. +

+
+
+ <% end %> +
+ + +
+

Lieu de l'événement

+ +
+
+ <%= 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" %> +
+ +
+ <%= 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" %> +
+ +
+
+ <%= 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" %> +
+ +
+ <%= 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" %> +
+
+ +

+ + Utilisez un service comme latlong.net pour obtenir les coordonnées GPS. +

+
+ + <% if @event.published? && @event.tickets.any? %> +
+
+ +

+ Des billets ont déjà été vendus pour cet événement. Modifier le lieu pourrait impacter les participants. +

+
+
+ <% end %> +
+ + +
+

Options

+ +
+ <%= 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" %> +
+

Les événements mis en avant apparaissent en premier sur la page d'accueil.

+
+ + +
+
+ <%= link_to promoter_event_path(@event), class: "text-gray-500 hover:text-gray-700 transition-colors" do %> + Annuler + <% end %> + <% if @event.published? && @event.tickets.any? %> +

+ + <%= @event.tickets.count %> billet(s) déjà vendu(s) +

+ <% end %> +
+ +
+ <%= form.submit "Sauvegarder les modifications", class: "inline-flex items-center px-6 py-3 bg-purple-600 text-white font-medium rounded-lg hover:bg-purple-700 transition-colors duration-200" %> +
+
+ <% end %> +
+
\ No newline at end of file diff --git a/app/views/promoter/events/index.html.erb b/app/views/promoter/events/index.html.erb new file mode 100644 index 0000000..adfca3c --- /dev/null +++ b/app/views/promoter/events/index.html.erb @@ -0,0 +1,136 @@ +<% content_for(:title, "Mes événements") %> + +
+
+
+

Mes événements

+

Gérez tous vos événements depuis cette interface

+
+ <%= 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 %> + + Créer un événement + <% end %> +
+ + <% if @events.any? %> +
+
+ + + + + + + + + + + + <% @events.each do |event| %> + + + + + + + + <% end %> + +
ÉvénementStatutDateLieuActions
+
+
+ +
+
+
+ <%= link_to event.name, promoter_event_path(event), class: "hover:text-purple-600 transition-colors" %> +
+
+ <%= event.description.truncate(60) %> +
+
+
+
+ <% case event.state %> + <% when "draft" %> + + + Brouillon + + <% when "published" %> + + + Publié + + <% when "canceled" %> + + + Annulé + + <% when "sold_out" %> + + + Complet + + <% end %> + + <% if event.featured? %> + + + À la une + + <% end %> + + <% if event.start_time %> +
<%= event.start_time.strftime("%d/%m/%Y") %>
+
<%= event.start_time.strftime("%H:%M") %>
+ <% else %> + Date non définie + <% end %> +
+
<%= event.venue_name %>
+
<%= event.venue_address %>
+
+
+ <%= link_to promoter_event_path(event), class: "text-gray-400 hover:text-gray-600 transition-colors", title: "Voir" do %> + + <% end %> + <%= link_to edit_promoter_event_path(event), class: "text-gray-400 hover:text-blue-600 transition-colors", title: "Modifier" do %> + + <% 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 %> + + <% 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 %> + + <% 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 %> + + <% end %> +
+
+
+
+ +
+ <%= paginate @events if respond_to?(:paginate) %> +
+ <% else %> +
+
+ +
+

Aucun événement

+

Vous n'avez pas encore créé d'événement. Commencez dès maintenant !

+ <%= 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 %> + + Créer mon premier événement + <% end %> +
+ <% end %> +
\ No newline at end of file diff --git a/app/views/promoter/events/new.html.erb b/app/views/promoter/events/new.html.erb new file mode 100644 index 0000000..39b9777 --- /dev/null +++ b/app/views/promoter/events/new.html.erb @@ -0,0 +1,146 @@ +<% content_for(:title, "Créer un événement") %> + +
+
+
+
+ <%= link_to promoter_events_path, class: "text-gray-400 hover:text-gray-600 transition-colors" do %> + + <% end %> +
+

Créer un événement

+

Remplissez les informations de votre événement

+
+
+
+ + <%= form_with model: [:promoter, @event], local: true, class: "space-y-8", data: { controller: "event-form" } do |form| %> + <% if @event.errors.any? %> +
+
+
+ +
+
+

+ <%= pluralize(@event.errors.count, "erreur") %> à corriger : +

+
+
    + <% @event.errors.full_messages.each do |message| %> +
  • <%= message %>
  • + <% end %> +
+
+
+
+
+ <% end %> + + +
+

Informations générales

+ +
+
+ <%= 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" } %> +
+ +
+ <%= 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" } %> +

Utilisé dans l'URL de l'événement

+
+
+ +
+ <%= 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..." %> +
+ +
+ <%= 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" %> +

URL de l'image de couverture de l'événement

+
+
+ + +
+

Date et heure

+ +
+
+ <%= 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" %> +
+ +
+ <%= 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" %> +
+
+
+ + +
+

Lieu de l'événement

+ +
+
+ <%= 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" %> +
+ +
+ <%= 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" %> +
+ +
+
+ <%= 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" %> +
+ +
+ <%= 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" %> +
+
+ +

+ + Utilisez un service comme latlong.net pour obtenir les coordonnées GPS. +

+
+
+ + +
+

Options

+ +
+ <%= 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" %> +
+

Les événements mis en avant apparaissent en premier sur la page d'accueil.

+
+ + +
+
+ <%= link_to promoter_events_path, class: "text-gray-500 hover:text-gray-700 transition-colors" do %> + Annuler + <% end %> +
+ +
+ <%= 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" %> +
+
+ <% end %> +
+
+ diff --git a/app/views/promoter/events/show.html.erb b/app/views/promoter/events/show.html.erb new file mode 100644 index 0000000..f43bbf5 --- /dev/null +++ b/app/views/promoter/events/show.html.erb @@ -0,0 +1,231 @@ +<% content_for(:title, @event.name) %> + +
+ +
+
+
+ <%= link_to promoter_events_path, class: "text-gray-400 hover:text-gray-600 transition-colors" do %> + + <% end %> +
+

<%= @event.name %>

+
+ + + <%= @event.start_time&.strftime("%d/%m/%Y à %H:%M") || "Date non définie" %> + + + + <%= @event.venue_name %> + +
+
+
+
+ <%= link_to edit_promoter_event_path(@event), class: "inline-flex items-center px-4 py-2 bg-white border border-gray-300 text-gray-700 font-medium rounded-lg hover:bg-gray-50 transition-colors duration-200" do %> + + Modifier + <% end %> + + <% if @event.draft? %> + <%= button_to publish_promoter_event_path(@event), method: :patch, class: "inline-flex items-center px-4 py-2 bg-green-600 text-white font-medium rounded-lg hover:bg-green-700 transition-colors duration-200" do %> + + Publier + <% end %> + <% elsif @event.published? %> + <%= button_to unpublish_promoter_event_path(@event), method: :patch, class: "inline-flex items-center px-4 py-2 bg-yellow-600 text-white font-medium rounded-lg hover:bg-yellow-700 transition-colors duration-200" do %> + + Dépublier + <% end %> + <% end %> + + <% if @event.published? %> + <%= button_to cancel_promoter_event_path(@event), method: :patch, class: "inline-flex items-center px-4 py-2 bg-red-600 text-white font-medium rounded-lg hover:bg-red-700 transition-colors duration-200", data: { confirm: "Êtes-vous sûr de vouloir annuler cet événement ?" } do %> + + Annuler + <% end %> + <% end %> +
+
+
+ + +
+ <% case @event.state %> + <% when "draft" %> +
+
+ +
+

Événement en brouillon

+

Cet événement n'est pas visible publiquement. Publiez-le pour le rendre accessible aux utilisateurs.

+
+
+
+ <% when "published" %> +
+
+ +
+

Événement publié

+

Cet événement est visible publiquement et les utilisateurs peuvent acheter des billets.

+
+
+ <%= link_to event_path(@event.slug, @event), target: "_blank", class: "text-green-600 hover:text-green-800 font-medium text-sm" do %> + Voir publiquement + <% end %> +
+
+
+ <% when "canceled" %> +
+
+ +
+

Événement annulé

+

Cet événement a été annulé et n'est plus accessible aux utilisateurs.

+
+
+
+ <% when "sold_out" %> +
+
+ +
+

Événement complet

+

Tous les billets pour cet événement ont été vendus.

+
+
+
+ <% end %> + + <% if @event.featured? %> +
+
+ +
+

Événement à la une

+

Cet événement est mis en avant sur la page d'accueil.

+
+
+
+ <% end %> +
+ + +
+ +
+ + <% if @event.image.present? %> +
+ <%= @event.name %> +
+ <% end %> + + +
+

Description

+
+ <%= simple_format(@event.description) %> +
+
+ + +
+

Lieu

+
+
+ +
+

<%= @event.venue_name %>

+

<%= @event.venue_address %>

+
+
+
+ + <%= @event.latitude %>, <%= @event.longitude %> +
+
+
+
+ + +
+ +
+

Statistiques

+
+
+ Types de billets + <%= @event.ticket_types.count %> +
+
+ Billets vendus + <%= @event.tickets.count %> +
+
+ Revenus + + <%= number_to_currency(@event.tickets.sum(:price_cents) / 100.0, unit: "€") %> + +
+
+
+ + +
+

Informations

+
+
+ Slug +

<%= @event.slug %>

+
+
+ Créé le +

<%= @event.created_at.strftime("%d/%m/%Y à %H:%M") %>

+
+
+ Modifié le +

<%= @event.updated_at.strftime("%d/%m/%Y à %H:%M") %>

+
+ <% if @event.start_time %> +
+ Début +

<%= @event.start_time.strftime("%d/%m/%Y à %H:%M") %>

+
+ <% end %> + <% if @event.end_time %> +
+ Fin +

<%= @event.end_time.strftime("%d/%m/%Y à %H:%M") %>

+
+ <% end %> +
+
+ + +
+

Actions rapides

+
+ <%= link_to "#", class: "w-full inline-flex items-center px-4 py-2 bg-gray-50 text-gray-700 font-medium rounded-lg hover:bg-gray-100 transition-colors duration-200" do %> + + Gérer les billets + <% end %> + <%= button_to mark_sold_out_promoter_event_path(@event), method: :patch, class: "w-full inline-flex items-center px-4 py-2 bg-gray-50 text-gray-700 font-medium rounded-lg hover:bg-gray-100 transition-colors duration-200", disabled: !@event.published? do %> + + Marquer comme complet + <% end %> +
+ <%= button_to promoter_event_path(@event), method: :delete, + data: { confirm: "Êtes-vous sûr de vouloir supprimer cet événement ? Cette action est irréversible." }, + class: "w-full inline-flex items-center px-4 py-2 text-red-600 font-medium rounded-lg hover:bg-red-50 transition-colors duration-200" do %> + + Supprimer l'événement + <% end %> +
+
+
+
+
\ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index b73975e..fbc4b51 100755 --- a/config/routes.rb +++ b/config/routes.rb @@ -34,6 +34,18 @@ Rails.application.routes.draw do # === Pages === get "dashboard", to: "pages#dashboard", as: "dashboard" + # === Promoter Routes === + namespace :promoter do + resources :events do + member do + patch :publish + patch :unpublish + patch :cancel + patch :mark_sold_out + end + end + end + # === Events === get "events", to: "events#index", as: "events" get "events/:slug.:id", to: "events#show", as: "event"