feat: enhance dashboard and event pages with ended events payout functionality

- Replace 'Recent Ticket Sales' section with 'Événements Terminés' on dashboard
- Add dedicated section for ended events with payout request capabilities
- Display event revenue, ticket sales count, and payout status for ended events
- Implement payout request buttons with status indicators (pending, processing, completed, failed)
- Translate payout section in individual event page to French
- Add visual indicators and confirmations for payout requests
- Improve UX with color-coded status badges and action buttons

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
kbe
2025-09-17 01:37:36 +02:00
parent 59e1854803
commit e4509b1c43
2 changed files with 192 additions and 84 deletions

View File

@@ -39,7 +39,7 @@
<!-- Promoter Dashboard Section --> <!-- Promoter Dashboard Section -->
<% if current_user.promoter? && @promoter_events.present? %> <% if current_user.promoter? && @promoter_events.present? %>
<!-- Promoter Metrics --> <!-- Promoter Metrics -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8"> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-6 mb-8">
<div class="bg-gradient-to-br from-green-50 to-green-100 rounded-2xl p-6 border border-green-200"> <div class="bg-gradient-to-br from-green-50 to-green-100 rounded-2xl p-6 border border-green-200">
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<div> <div>
@@ -87,6 +87,19 @@
</div> </div>
</div> </div>
</div> </div>
<!-- Payout Summary -->
<div class="bg-gradient-to-br from-indigo-50 to-indigo-100 rounded-2xl p-6 border border-indigo-200">
<div class="flex items-center justify-between">
<div>
<p class="text-indigo-600 text-sm font-medium">Paiements en Attente</p>
<p class="text-2xl font-bold text-indigo-900"><%= current_user.payouts.pending.count %></p>
</div>
<div class="bg-indigo-200 rounded-full p-3">
<i data-lucide="dollar-sign" class="w-6 h-6 text-indigo-700"></i>
</div>
</div>
</div>
</div> </div>
<!-- Revenue Chart & Recent Events --> <!-- Revenue Chart & Recent Events -->
@@ -147,18 +160,49 @@
<%= event.tickets.where(status: 'active').count %> billets vendus <%= event.tickets.where(status: 'active').count %> billets vendus
</div> </div>
</div> </div>
<div class="mt-3 flex space-x-2"> <div class="mt-3 flex flex-wrap gap-2">
<%= link_to promoter_event_path(event), class: "text-purple-600 hover:text-purple-800 text-xs font-medium" do %> <%= link_to promoter_event_path(event), class: "text-purple-600 hover:text-purple-800 text-xs font-medium" do %>
Gérer → Gérer →
<% end %> <% end %>
<% if event.event_ended? && event.can_request_payout? %> <% if event.event_ended? && event.can_request_payout? %>
<% if event.payout_status == "not_requested" %> <% if event.payout_status == "not_requested" %>
<%= link_to "Demander le paiement", promoter_payouts_path(event_id: event.id), method: :post, <%= link_to "Demander le paiement", promoter_payouts_path(event_id: event.id), method: :post,
class: "text-green-600 hover:text-green-800 text-xs font-medium" %> class: "text-green-600 hover:text-green-800 text-xs font-medium inline-flex items-center",
<% else %> data: { confirm: "Êtes-vous sûr de vouloir demander le paiement de €#{event.net_earnings_cents / 100.0} ?" } do %>
<%= link_to "Voir le paiement", promoter_payouts_path, <i data-lucide="dollar-sign" class="w-3 h-3 mr-1"></i>
class: "text-gray-600 hover:text-gray-800 text-xs font-medium" %> Paiement
<% end %> <% end %>
<% elsif event.payout_status == "requested" %>
<%= link_to "Paiement demandé", promoter_payouts_path,
class: "text-yellow-600 hover:text-yellow-800 text-xs font-medium inline-flex items-center" do %>
<i data-lucide="clock" class="w-3 h-3 mr-1"></i>
En attente
<% end %>
<% elsif event.payout_status == "processing" %>
<%= link_to "Paiement en cours", promoter_payouts_path,
class: "text-blue-600 hover:text-blue-800 text-xs font-medium inline-flex items-center" do %>
<i data-lucide="refresh-cw" class="w-3 h-3 mr-1"></i>
Traitement
<% end %>
<% elsif event.payout_status == "completed" %>
<%= link_to "Paiement effectué", promoter_payouts_path,
class: "text-green-600 hover:text-green-800 text-xs font-medium inline-flex items-center" do %>
<i data-lucide="check-circle" class="w-3 h-3 mr-1"></i>
Complété
<% end %>
<% elsif event.payout_status == "failed" %>
<%= link_to "Paiement échoué", promoter_payouts_path(event_id: event.id), method: :post,
class: "text-red-600 hover:text-red-800 text-xs font-medium inline-flex items-center",
data: { confirm: "Êtes-vous sûr de vouloir redemander le paiement ?" } do %>
<i data-lucide="x-circle" class="w-3 h-3 mr-1"></i>
Réessayer
<% end %>
<% end %>
<% elsif event.event_ended? %>
<span class="text-gray-500 text-xs font-medium inline-flex items-center">
<i data-lucide="dollar-sign" class="w-3 h-3 mr-1"></i>
Aucun revenu
</span>
<% end %> <% end %>
</div> </div>
</div> </div>
@@ -174,46 +218,88 @@
</div> </div>
</div> </div>
<!-- Recent orders for promoter events --> <!-- Ended Events Requiring Payout -->
<div class="mt-8"> <% ended_events = @promoter_events.select(&:event_ended?) %>
<div class="flex justify-between items-center mb-4"> <% if ended_events.any? %>
<h2 class="text-lg font-medium text-gray-900">Recent Orders</h2> <div class="bg-white rounded-2xl shadow-lg mb-8">
<%= link_to "View All Payouts", promoter_payouts_path, class: "text-sm font-medium text-indigo-600 hover:text-indigo-500" if current_user.promoter? %> <div class="border-b border-gray-100 p-6">
</div> <div class="flex items-center justify-between">
<% if @recent_orders.any? %> <h2 class="text-xl font-bold text-gray-900">Événements Terminés</h2>
<div class="bg-white overflow-hidden shadow rounded-lg"> <%= link_to "Voir tous les paiements", promoter_payouts_path, class: "text-purple-600 hover:text-purple-800 font-medium text-sm" %>
<ul class="divide-y divide-gray-200">
<% @recent_orders.each do |order| %>
<li>
<div class="px-4 py-4 flex items-center sm:px-6">
<div class="min-w-0 flex-1 sm:flex sm:items-center sm:justify-between">
<div class="truncate">
<div class="flex text-sm">
<p class="font-medium text-indigo-600 truncate"><%= order.event.name %></p>
<p class="ml-1 flex-shrink-0 font-normal text-gray-500">for <%= order.user.name.presence || order.user.email %></p>
</div>
<div class="mt-2 flex">
<div class="flex items-center text-sm text-gray-500">
<svg class="flex-shrink-0 mr-1.5 h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z" clip-rule="evenodd" />
</svg>
<span><%= order.created_at.strftime("%B %d, %Y") %></span>
</div> </div>
</div> </div>
<div class="p-6">
<div class="space-y-4">
<% ended_events.each do |event| %>
<div class="border border-gray-200 rounded-xl p-4 hover:shadow-md transition-shadow">
<div class="flex items-start justify-between mb-2">
<div>
<h4 class="font-semibold text-gray-900 text-sm"><%= event.name %></h4>
<p class="text-xs text-gray-500 mt-1">Terminé le <%= event.end_time&.strftime("%d %B %Y") || event.start_time&.strftime("%d %B %Y") %></p>
</div> </div>
<div class="ml-5 flex-shrink-0"> <span class="text-xs px-2 py-1 rounded-full bg-gray-100 text-gray-800">
<p class="text-sm font-medium text-gray-900">€<%= order.total_amount_euros %></p> Terminé
</span>
</div>
<div class="text-xs text-gray-600 space-y-1">
<div class="flex items-center">
<i data-lucide="ticket" class="w-3 h-3 mr-2"></i>
<%= event.tickets.where(status: 'active').count %> billets vendus
</div>
<div class="flex items-center">
<i data-lucide="euro" class="w-3 h-3 mr-2"></i>
Revenus: €<%= event.net_earnings_cents / 100.0 %>
</div> </div>
</div> </div>
</div> <div class="mt-3 flex items-center justify-between">
</li> <%= link_to promoter_event_path(event), class: "text-purple-600 hover:text-purple-800 text-xs font-medium" do %>
Voir l'événement →
<% end %>
<% if event.can_request_payout? %>
<% if event.payout_status == "not_requested" %>
<%= link_to "Demander le paiement", promoter_payouts_path(event_id: event.id), method: :post,
class: "inline-flex items-center px-3 py-1 bg-green-600 text-white text-xs font-medium rounded-lg hover:bg-green-700 transition-colors",
data: { confirm: "Êtes-vous sûr de vouloir demander le paiement de €#{event.net_earnings_cents / 100.0} ?" } do %>
<i data-lucide="dollar-sign" class="w-3 h-3 mr-1"></i>
Demander paiement
<% end %>
<% elsif event.payout_status == "requested" %>
<%= link_to promoter_payouts_path, class: "inline-flex items-center px-3 py-1 bg-yellow-600 text-white text-xs font-medium rounded-lg" do %>
<i data-lucide="clock" class="w-3 h-3 mr-1"></i>
En attente
<% end %>
<% elsif event.payout_status == "processing" %>
<%= link_to promoter_payouts_path, class: "inline-flex items-center px-3 py-1 bg-blue-600 text-white text-xs font-medium rounded-lg" do %>
<i data-lucide="refresh-cw" class="w-3 h-3 mr-1"></i>
En traitement
<% end %>
<% elsif event.payout_status == "completed" %>
<%= link_to promoter_payouts_path, class: "inline-flex items-center px-3 py-1 bg-green-600 text-white text-xs font-medium rounded-lg" do %>
<i data-lucide="check-circle" class="w-3 h-3 mr-1"></i>
Payé
<% end %>
<% elsif event.payout_status == "failed" %>
<%= link_to "Réessayer", promoter_payouts_path(event_id: event.id), method: :post,
class: "inline-flex items-center px-3 py-1 bg-red-600 text-white text-xs font-medium rounded-lg hover:bg-red-700 transition-colors",
data: { confirm: "Êtes-vous sûr de vouloir redemander le paiement ?" } do %>
<i data-lucide="x-circle" class="w-3 h-3 mr-1"></i>
Réessayer
<% end %>
<% end %> <% end %>
</ul>
</div>
<% else %> <% else %>
<p class="text-gray-500">No recent orders.</p> <span class="text-gray-500 text-xs font-medium inline-flex items-center">
<i data-lucide="dollar-sign" class="w-3 h-3 mr-1"></i>
Aucun revenu
</span>
<% end %> <% end %>
</div> </div>
</div>
<% end %>
</div>
</div>
</div>
<% end %>
<% end %> <% end %>
<!-- Draft orders needing payment --> <!-- Draft orders needing payment -->

View File

@@ -293,46 +293,68 @@
<!-- Payout section --> <!-- Payout section -->
<% if @event.event_ended? && @event.can_request_payout? %> <% if @event.event_ended? && @event.can_request_payout? %>
<hr class="border-gray-200"> <hr class="border-gray-200">
<div class="space-y-3"> <div class="space-y-4">
<h4 class="text-md font-medium text-gray-900">Paiement des revenus</h4> <h4 class="text-lg font-medium text-gray-900">Paiement des Revenus</h4>
<div class="text-sm text-gray-500">
<p>Revenus disponibles : <span class="font-medium">€<%= @event.net_earnings_cents / 100.0 %></span></p> <!-- Earnings Summary -->
<p>Frais de plateforme : <span class="font-medium">€<%= @event.total_fees_cents / 100.0 %></span></p> <div class="grid grid-cols-1 sm:grid-cols-3 gap-4">
<div class="bg-gray-50 rounded-lg p-4">
<p class="text-sm text-gray-500">Revenus Bruts</p>
<p class="text-lg font-bold text-gray-900">€<%= @event.total_earnings_cents / 100.0 %></p>
</div> </div>
<div class="bg-gray-50 rounded-lg p-4">
<p class="text-sm text-gray-500">Frais Plateforme</p>
<p class="text-lg font-bold text-gray-900">-€<%= @event.total_fees_cents / 100.0 %></p>
</div>
<div class="payout-summary-card">
<p class="payout-summary-label">Revenus Nets</p>
<p class="payout-summary-amount">€<%= @event.net_earnings_cents / 100.0 %></p>
</div>
</div>
<!-- Payout Status -->
<% if @event.payout_status != "not_requested" %>
<div class="bg-blue-50 rounded-lg p-4 border border-blue-200">
<div class="flex items-center">
<% case @event.payout_status %>
<% when "requested" %>
<i data-lucide="clock" class="w-5 h-5 text-blue-500 mr-2"></i>
<span class="font-medium text-blue-800">Paiement Demandé</span>
<% when "processing" %>
<i data-lucide="refresh-cw" class="w-5 h-5 text-blue-500 mr-2"></i>
<span class="font-medium text-blue-800">Paiement en Traitement</span>
<% when "completed" %>
<i data-lucide="check-circle" class="w-5 h-5 text-green-500 mr-2"></i>
<span class="font-medium text-green-800">Paiement Complété</span>
<% when "failed" %>
<i data-lucide="x-circle" class="w-5 h-5 text-red-500 mr-2"></i>
<span class="font-medium text-red-800">Paiement Échoué</span>
<% end %>
</div>
<p class="text-sm text-gray-600 mt-1">Votre demande de paiement est en cours de traitement. Vous recevrez un email quand elle sera terminée.</p>
</div>
<% end %>
<!-- Payout Action -->
<% if @event.payout_status == "not_requested" %> <% if @event.payout_status == "not_requested" %>
<%= button_to promoter_payouts_path(event_id: @event.id), method: :post, <%= button_to promoter_payouts_path(event_id: @event.id), method: :post,
data: { confirm: "Êtes-vous sûr de vouloir demander le paiement des revenus ?" }, data: { confirm: "Êtes-vous sûr de vouloir demander un paiement de €#{@event.net_earnings_cents / 100.0} ? Cette action ne peut pas être annulée." },
class: "w-full inline-flex items-center justify-center px-4 py-3 bg-green-600 text-white font-medium text-sm rounded-lg hover:bg-green-700 transition-colors duration-200" do %> class: "payout-action-button primary" do %>
<i data-lucide="dollar-sign" class="w-4 h-4 mr-2"></i> <i data-lucide="dollar-sign" class="w-5 h-5 mr-2"></i>
Demander le paiement Demander le Paiement de €<%= @event.net_earnings_cents / 100.0 %>
<% end %> <% end %>
<% elsif @event.payout_status == "requested" %>
<div class="w-full inline-flex items-center justify-center px-4 py-3 bg-yellow-100 text-yellow-800 font-medium text-sm rounded-lg">
<i data-lucide="clock" class="w-4 h-4 mr-2"></i>
Paiement demandé
</div>
<% elsif @event.payout_status == "processing" %>
<div class="w-full inline-flex items-center justify-center px-4 py-3 bg-blue-100 text-blue-800 font-medium text-sm rounded-lg">
<i data-lucide="refresh-cw" class="w-4 h-4 mr-2"></i>
Paiement en cours
</div>
<% elsif @event.payout_status == "completed" %>
<div class="w-full inline-flex items-center justify-center px-4 py-3 bg-green-100 text-green-800 font-medium text-sm rounded-lg">
<i data-lucide="check-circle" class="w-4 h-4 mr-2"></i>
Paiement effectué
</div>
<% elsif @event.payout_status == "failed" %> <% elsif @event.payout_status == "failed" %>
<div class="w-full inline-flex items-center justify-center px-4 py-3 bg-red-100 text-red-800 font-medium text-sm rounded-lg">
<i data-lucide="x-circle" class="w-4 h-4 mr-2"></i>
Paiement échoué
</div>
<%= button_to promoter_payouts_path(event_id: @event.id), method: :post, <%= button_to promoter_payouts_path(event_id: @event.id), method: :post,
data: { confirm: "Êtes-vous sûr de vouloir redemander le paiement des revenus ?" }, data: { confirm: "Êtes-vous sûr de vouloir demander un nouveau paiement de €#{@event.net_earnings_cents / 100.0} ?" },
class: "w-full inline-flex items-center justify-center px-4 py-3 bg-green-600 text-white font-medium text-sm rounded-lg hover:bg-green-700 transition-colors duration-200" do %> class: "payout-action-button warning" do %>
<i data-lucide="dollar-sign" class="w-4 h-4 mr-2"></i> <i data-lucide="refresh-ccw" class="w-5 h-5 mr-2"></i>
Redemander le paiement Réessayer le Paiement
<% end %> <% end %>
<% else %>
<%= link_to "Voir les Détails du Paiement", promoter_payouts_path,
class: "payout-action-button secondary" %>
<% end %> <% end %>
</div> </div>
<% end %> <% end %>