- Add Payout model with associations to User and Event - Create payout requests for completed events with proper earnings calculation - Exclude refunded tickets from payout calculations - Add promoter dashboard views for managing payouts - Implement admin interface for processing payouts - Integrate with Stripe for actual payment processing - Add comprehensive tests for payout functionality Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
274 lines
15 KiB
Plaintext
274 lines
15 KiB
Plaintext
<% content_for(:title, "Mes événements") %>
|
|
|
|
<div class="min-h-screen max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
|
|
|
<!-- Breadcrumb -->
|
|
<%= render 'components/breadcrumb', crumbs: [
|
|
{ name: 'Accueil', path: root_path },
|
|
{ name: 'Tableau de bord', path: dashboard_path },
|
|
{ name: 'Mes événements' }
|
|
] %>
|
|
|
|
<div class="mb-8">
|
|
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
|
|
<div>
|
|
<h1 class="text-2xl sm: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 justify-center px-6 py-3 bg-gray-900 text-white font-medium rounded-lg hover:bg-gray-800 transition-colors duration-200 w-full sm:w-auto" do %>
|
|
<i data-lucide="plus" class="w-4 h-4 mr-2"></i>
|
|
Créer un événement
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
|
|
<% if @events.any? %>
|
|
<!-- Desktop Table View -->
|
|
<div class="hidden lg:block bg-white rounded-2xl shadow-xl 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 w-48 lg:w-auto">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 %>
|
|
|
|
<% if event.event_ended? && event.can_request_payout? %>
|
|
<% case event.payout_status %>
|
|
<% when "not_requested" %>
|
|
<span class="inline-flex px-2 py-1 text-xs font-semibold rounded-full bg-orange-100 text-orange-800 ml-1">
|
|
<i data-lucide="dollar-sign" class="w-3 h-3 mr-1"></i>
|
|
Paiement disponible
|
|
</span>
|
|
<% when "requested" %>
|
|
<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="clock" class="w-3 h-3 mr-1"></i>
|
|
Paiement demandé
|
|
</span>
|
|
<% when "processing" %>
|
|
<span class="inline-flex px-2 py-1 text-xs font-semibold rounded-full bg-blue-100 text-blue-800 ml-1">
|
|
<i data-lucide="refresh-cw" class="w-3 h-3 mr-1"></i>
|
|
Paiement en cours
|
|
</span>
|
|
<% when "completed" %>
|
|
<span class="inline-flex px-2 py-1 text-xs font-semibold rounded-full bg-green-100 text-green-800 ml-1">
|
|
<i data-lucide="check-circle" class="w-3 h-3 mr-1"></i>
|
|
Paiement effectué
|
|
</span>
|
|
<% when "failed" %>
|
|
<span class="inline-flex px-2 py-1 text-xs font-semibold rounded-full bg-red-100 text-red-800 ml-1">
|
|
<i data-lucide="x-circle" class="w-3 h-3 mr-1"></i>
|
|
Paiement échoué
|
|
</span>
|
|
<% end %>
|
|
<% 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 w-48 lg:w-auto">
|
|
<div class="flex flex-col lg:flex-row items-stretch lg:items-center space-y-2 lg:space-y-0 lg:space-x-2 min-w-0">
|
|
<%= link_to promoter_event_path(event), class: "flex-1 lg:flex-initial inline-flex items-center justify-center px-3 py-2 bg-gray-100 text-gray-700 text-sm font-medium rounded-lg hover:bg-gray-200 transition-colors lg:bg-transparent lg:text-gray-400 lg:hover:text-gray-600 lg:p-0 lg:rounded-none whitespace-nowrap", title: "Voir" do %>
|
|
<i data-lucide="eye" class="w-4 h-4 lg:mr-0 mr-2"></i>
|
|
<span class="lg:hidden">Voir</span>
|
|
<% end %>
|
|
<%= link_to edit_promoter_event_path(event), class: "flex-1 lg:flex-initial inline-flex items-center justify-center px-3 py-2 bg-blue-100 text-blue-700 text-sm font-medium rounded-lg hover:bg-blue-200 transition-colors lg:bg-transparent lg:text-gray-400 lg:hover:text-blue-600 lg:p-0 lg:rounded-none whitespace-nowrap", title: "Modifier" do %>
|
|
<i data-lucide="edit" class="w-4 h-4 lg:mr-0 mr-2"></i>
|
|
<span class="lg:hidden">Modifier</span>
|
|
<% end %>
|
|
<% if event.draft? %>
|
|
<%= button_to publish_promoter_event_path(event), method: :patch, class: "flex-1 lg:flex-initial inline-flex items-center justify-center px-3 py-2 bg-green-100 text-green-700 text-sm font-medium rounded-lg hover:bg-green-200 transition-colors lg:bg-transparent lg:text-gray-400 lg:hover:text-green-600 lg:p-0 lg:rounded-none whitespace-nowrap", title: "Publier" do %>
|
|
<i data-lucide="upload" class="w-4 h-4 lg:mr-0 mr-2"></i>
|
|
<span class="lg:hidden">Publier</span>
|
|
<% end %>
|
|
<% elsif event.published? %>
|
|
<%= button_to unpublish_promoter_event_path(event), method: :patch, class: "flex-1 lg:flex-initial inline-flex items-center justify-center px-3 py-2 bg-yellow-100 text-yellow-700 text-sm font-medium rounded-lg hover:bg-yellow-200 transition-colors lg:bg-transparent lg:text-gray-400 lg:hover:text-yellow-600 lg:p-0 lg:rounded-none whitespace-nowrap", title: "Dépublier" do %>
|
|
<i data-lucide="download" class="w-4 h-4 lg:mr-0 mr-2"></i>
|
|
<span class="lg:hidden">Dépublier</span>
|
|
<% end %>
|
|
<% end %>
|
|
<%= button_to promoter_event_path(event), method: :delete,
|
|
data: { confirm: "Êtes-vous sûr de vouloir supprimer cet événement ?" },
|
|
class: "flex-1 lg:flex-initial inline-flex items-center justify-center px-3 py-2 bg-red-100 text-red-700 text-sm font-medium rounded-lg hover:bg-red-200 transition-colors lg:bg-transparent lg:text-gray-400 lg:hover:text-red-600 lg:p-0 lg:rounded-none whitespace-nowrap", title: "Supprimer" do %>
|
|
<i data-lucide="trash-2" class="w-4 h-4 lg:mr-0 mr-2"></i>
|
|
<span class="lg:hidden">Supprimer</span>
|
|
<% end %>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<% end %>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Mobile Card View -->
|
|
<div class="lg:hidden space-y-4">
|
|
<% @events.each do |event| %>
|
|
<div class="bg-white rounded-2xl shadow-lg border border-gray-200 overflow-hidden">
|
|
<div class="p-4">
|
|
<!-- Event Header -->
|
|
<div class="flex items-start space-x-4 mb-4">
|
|
<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="flex-1 min-w-0">
|
|
<h3 class="text-lg font-semibold text-gray-900 mb-1">
|
|
<%= link_to event.name, promoter_event_path(event), class: "hover:text-purple-600 transition-colors" %>
|
|
</h3>
|
|
<p class="text-sm text-gray-500 line-clamp-2">
|
|
<%= event.description.truncate(100) %>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Status -->
|
|
<div class="flex flex-wrap items-center gap-2 mb-4">
|
|
<% case event.state %>
|
|
<% when "draft" %>
|
|
<span class="inline-flex items-center 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 items-center 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 items-center 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 items-center 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 items-center px-2 py-1 text-xs font-semibold rounded-full bg-yellow-100 text-yellow-800">
|
|
<i data-lucide="star" class="w-3 h-3 mr-1"></i>
|
|
À la une
|
|
</span>
|
|
<% end %>
|
|
</div>
|
|
|
|
<!-- Details Grid -->
|
|
<div class="grid grid-cols-2 gap-4 mb-4 text-sm">
|
|
<div>
|
|
<dt class="font-medium text-gray-500 mb-1">Date</dt>
|
|
<dd class="text-gray-900">
|
|
<% if event.start_time %>
|
|
<div><%= event.start_time.strftime("%d/%m/%Y") %></div>
|
|
<div class="text-xs text-gray-500"><%= event.start_time.strftime("%H:%M") %></div>
|
|
<% else %>
|
|
<span class="text-gray-400">Non définie</span>
|
|
<% end %>
|
|
</dd>
|
|
</div>
|
|
<div>
|
|
<dt class="font-medium text-gray-500 mb-1">Lieu</dt>
|
|
<dd class="text-gray-900">
|
|
<div class="truncate"><%= event.venue_name %></div>
|
|
<div class="text-xs text-gray-500 truncate"><%= event.venue_address %></div>
|
|
</dd>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Action Buttons -->
|
|
<div class="space-y-2 pt-4 border-t border-gray-100">
|
|
<%= link_to promoter_event_path(event), class: "w-full inline-flex items-center justify-center px-3 py-2 bg-gray-100 text-gray-700 text-sm font-medium rounded-lg hover:bg-gray-200 transition-colors" do %>
|
|
<i data-lucide="eye" class="w-4 h-4 mr-2"></i>
|
|
Voir
|
|
<% end %>
|
|
<%= link_to edit_promoter_event_path(event), class: "w-full inline-flex items-center justify-center px-3 py-2 bg-blue-100 text-blue-700 text-sm font-medium rounded-lg hover:bg-blue-200 transition-colors" do %>
|
|
<i data-lucide="edit" class="w-4 h-4 mr-2"></i>
|
|
Modifier
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
|
|
<div class="mt-6">
|
|
<%= paginate @events if respond_to?(:paginate) %>
|
|
</div>
|
|
<% else %>
|
|
<div class="bg-white rounded-2xl border-2 border-dashed border-gray-300 p-6 sm:p-12 text-center">
|
|
<div class="mx-auto h-20 w-20 sm:h-24 sm:w-24 rounded-full bg-gray-100 flex items-center justify-center mb-6">
|
|
<i data-lucide="calendar-plus" class="w-10 h-10 sm:w-12 sm:h-12 text-gray-400"></i>
|
|
</div>
|
|
<h3 class="text-lg sm:text-xl font-semibold text-gray-900 mb-2">Aucun événement</h3>
|
|
<p class="text-gray-500 mb-6 px-4">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 justify-center px-6 py-3 bg-gray-900 text-white font-medium rounded-lg hover:bg-gray-800 transition-colors duration-200 w-full sm:w-auto" do %>
|
|
<i data-lucide="plus" class="w-4 h-4 mr-2"></i>
|
|
Créer mon premier événement
|
|
<% end %>
|
|
</div>
|
|
<% end %>
|
|
</div>
|