I added the features for users to use promotion code and for promoters to create on their events. May be rewrite to discount code?
436 lines
21 KiB
Plaintext
Executable File
436 lines
21 KiB
Plaintext
Executable File
<div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
|
|
|
<!-- Breadcrumb -->
|
|
<!-- Breadcrumb -->
|
|
<%= render 'components/breadcrumb', crumbs: [
|
|
{ name: 'Accueil', path: root_path },
|
|
{ name: 'Tableau de bord', path: dashboard_path }
|
|
] %>
|
|
|
|
<!-- Promoter Page Header -->
|
|
<div class="mb-8">
|
|
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
|
|
<div>
|
|
<h1 class="text-3xl font-bold text-gray-900">Mon tableau de bord promoteur</h1>
|
|
<p class="text-gray-600 mt-1">Gérez vos commandes et accédez à vos billets</p>
|
|
</div>
|
|
|
|
<!-- Promoter Actions -->
|
|
<% if current_user.promoter? %>
|
|
<div class="flex flex-col xs:flex-row items-stretch xs:items-center gap-2">
|
|
<%= link_to promoter_events_path, class: "inline-flex items-center justify-center px-4 py-2 bg-purple-600 text-white font-medium rounded-lg hover:bg-purple-700 transition-colors duration-200" do %>
|
|
<i data-lucide="calendar-plus" class="w-4 h-4 mr-2"></i>
|
|
Mes Événements
|
|
<% end %>
|
|
<%= link_to new_promoter_event_path, class: "inline-flex items-center justify-center px-4 py-2 bg-gray-900 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>
|
|
<% else %>
|
|
<%= link_to events_path, class: "inline-flex items-center justify-center px-4 py-2 bg-purple-600 text-white font-medium rounded-lg hover:bg-purple-700 transition-colors duration-200" do %>
|
|
<i data-lucide="search" class="w-4 h-4 mr-2"></i>
|
|
Découvrir des Événements
|
|
<% end %>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Promoter Dashboard Section -->
|
|
<% if current_user.promoter? && @promoter_events.present? %>
|
|
<!-- Promoter Metrics -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 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="flex items-center justify-between">
|
|
<div>
|
|
<p class="text-green-600 text-sm font-medium">Revenus Total</p>
|
|
<p class="text-2xl font-bold text-green-900">€<%= number_with_delimiter(@total_revenue, delimiter: ' ') %></p>
|
|
</div>
|
|
<div class="bg-green-200 rounded-full p-3">
|
|
<i data-lucide="euro" class="w-6 h-6 text-green-700"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bg-gradient-to-br from-blue-50 to-blue-100 rounded-2xl p-6 border border-blue-200">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<p class="text-blue-600 text-sm font-medium">Billets Vendus</p>
|
|
<p class="text-2xl font-bold text-blue-900"><%= @total_tickets_sold %></p>
|
|
</div>
|
|
<div class="bg-blue-200 rounded-full p-3">
|
|
<i data-lucide="ticket" class="w-6 h-6 text-blue-700"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bg-gradient-to-br from-purple-50 to-purple-100 rounded-2xl p-6 border border-purple-200">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<p class="text-purple-600 text-sm font-medium">Événements Publiés</p>
|
|
<p class="text-2xl font-bold text-purple-900"><%= @active_events_count %></p>
|
|
</div>
|
|
<div class="bg-purple-200 rounded-full p-3">
|
|
<i data-lucide="calendar-check" class="w-6 h-6 text-purple-700"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Brouillons -->
|
|
<div class="bg-gradient-to-br from-orange-50 to-orange-100 rounded-2xl p-6 border border-orange-200">
|
|
<%= link_to promoter_events_path do %>
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<p class="text-orange-600 text-sm font-medium">Brouillons</p>
|
|
<p class="text-2xl font-bold text-orange-900"><%= @draft_events_count %></p>
|
|
</div>
|
|
<div class="bg-orange-200 rounded-full p-3">
|
|
<i data-lucide="edit-3" class="w-6 h-6 text-orange-700"></i>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
</div><!-- /Brouillons -->
|
|
|
|
</div>
|
|
|
|
<!-- Revenue Chart & Recent Events -->
|
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8 mb-8">
|
|
<!-- Monthly Revenue Chart -->
|
|
<div class="lg:col-span-2 bg-white rounded-2xl shadow-lg">
|
|
<div class="border-b border-gray-100 p-6">
|
|
<h2 class="text-xl font-bold text-gray-900">Revenus Mensuels</h2>
|
|
<p class="text-gray-600 mt-1">Derniers 6 mois</p>
|
|
</div>
|
|
<div class="p-6">
|
|
<div class="space-y-3">
|
|
<% @monthly_revenue.each do |month_data| %>
|
|
<div class="flex items-center justify-between">
|
|
<span class="text-sm font-medium text-gray-700"><%= month_data[:month] %></span>
|
|
<div class="flex items-center space-x-2">
|
|
<div class="w-32 bg-gray-200 rounded-full h-3 relative">
|
|
<div class="bg-green-500 h-3 rounded-full" style="width: <%= [month_data[:revenue] / ([@monthly_revenue.max_by{|m| m[:revenue]}[:revenue], 1].max) * 100, 5].max %>%"></div>
|
|
</div>
|
|
<span class="text-sm font-bold text-gray-900 w-16 text-right">€<%= number_with_delimiter(month_data[:revenue], delimiter: ' ') %></span>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recent Events -->
|
|
<div class="bg-white rounded-2xl shadow-lg">
|
|
<div class="border-b border-gray-100 p-6">
|
|
<div class="flex items-center justify-between">
|
|
<h2 class="text-xl font-bold text-gray-900">Mes Événements</h2>
|
|
<%= link_to promoter_events_path, class: "text-purple-600 hover:text-purple-800 font-medium text-sm" do %>
|
|
Voir tout →
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
<div class="p-6">
|
|
<div class="space-y-4">
|
|
<% @promoter_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">
|
|
<%= link_to promoter_event_path(event) do %>
|
|
<h4 class="font-semibold text-gray-900 text-sm"><%= event.name %></h4>
|
|
<% end %>
|
|
|
|
<span class="text-xs px-2 py-1 rounded-full <%= event.state == 'published' ? 'bg-green-100 text-green-800' : event.state == 'draft' ? 'bg-yellow-100 text-yellow-800' : 'bg-red-100 text-red-800' %>">
|
|
<%= event.state.humanize %>
|
|
</span>
|
|
</div>
|
|
<div class="text-xs text-gray-600 space-y-1">
|
|
<div class="flex items-center">
|
|
<i data-lucide="calendar" class="w-3 h-3 mr-2"></i>
|
|
<%= event.start_time&.strftime("%d %B %Y") || "Non programmé" %>
|
|
</div>
|
|
<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>
|
|
<div class="mt-3 flex space-x-2">
|
|
<%= link_to promoter_event_path(event), class: "text-purple-600 hover:text-purple-800 text-xs font-medium" do %>
|
|
Gérer →
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
<div class="mt-4 text-center">
|
|
<%= link_to new_promoter_event_path, class: "inline-flex items-center px-4 py-2 bg-gray-900 text-white text-sm font-medium rounded-lg hover:bg-gray-800 transition-colors" do %>
|
|
<i data-lucide="plus" class="w-4 h-4 mr-2"></i>
|
|
Nouvel Événement
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recent Orders -->
|
|
<% if @recent_orders.any? %>
|
|
<div class="bg-white rounded-2xl shadow-lg mb-8">
|
|
<div class="border-b border-gray-100 p-6">
|
|
<h2 class="text-xl font-bold text-gray-900">Commandes Récentes</h2>
|
|
<p class="text-gray-600 mt-1">Dernières commandes pour vos événements</p>
|
|
</div>
|
|
<div class="p-6">
|
|
<div class="overflow-x-auto">
|
|
<table class="w-full">
|
|
<thead>
|
|
<tr class="text-left border-b border-gray-200">
|
|
<th class="pb-3 text-sm font-medium text-gray-600">Événement</th>
|
|
<th class="pb-3 text-sm font-medium text-gray-600">Client</th>
|
|
<th class="pb-3 text-sm font-medium text-gray-600">Billets</th>
|
|
<th class="pb-3 text-sm font-medium text-gray-600">Montant</th>
|
|
<th class="pb-3 text-sm font-medium text-gray-600">Date</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-gray-100">
|
|
<% @recent_orders.each do |order| %>
|
|
<tr class="hover:bg-gray-50">
|
|
<td class="py-3 text-sm font-medium text-gray-900"><%= order.event.name %></td>
|
|
<td class="py-3 text-sm text-gray-700"><%= order.user.email %></td>
|
|
<td class="py-3 text-sm text-gray-700"><%= order.tickets.count %></td>
|
|
<td class="py-3 text-sm font-medium text-gray-900">€<%= order.total_amount_euros %></td>
|
|
<td class="py-3 text-sm text-gray-500"><%= order.created_at.strftime("%d/%m/%Y") %></td>
|
|
</tr>
|
|
<% end %>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
<% end %>
|
|
|
|
<!-- Draft orders needing payment -->
|
|
<% if @draft_orders.any? %>
|
|
<div class="bg-orange-50 border border-orange-200 rounded-2xl shadow-lg mb-8">
|
|
<div class="bg-orange-100 rounded-t-2xl p-4 sm:p-6">
|
|
<h2 class="text-xl sm:text-2xl font-bold text-orange-900 flex items-center">
|
|
<i data-lucide="alert-triangle" class="w-5 h-5 sm:w-6 sm:h-6 mr-2 text-orange-600"></i>
|
|
Commandes en Attente de Paiement
|
|
</h2>
|
|
<p class="text-gray-700 mt-1">Vous avez des commandes qui nécessitent un paiement</p>
|
|
</div>
|
|
<div class="p-4 sm:p-6">
|
|
<div class="space-y-4">
|
|
<% @draft_orders.each do |order| %>
|
|
<div class="bg-white rounded-xl p-4 border border-orange-200">
|
|
<div class="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-3 mb-3">
|
|
<div>
|
|
<h3 class="font-semibold text-gray-900 text-base sm:text-lg"><%= order.event.name %></h3>
|
|
<p class="text-sm text-gray-600 mt-1 flex items-center">
|
|
<i data-lucide="calendar" class="w-4 h-4 mr-2"></i>
|
|
<%= order.event.start_time.strftime("%d %B %Y à %H:%M") %>
|
|
</p>
|
|
</div>
|
|
<span class="text-sm font-medium text-orange-600 bg-orange-100 px-3 py-1 rounded-full whitespace-nowrap">
|
|
Order #<%= order.id %>
|
|
</span>
|
|
</div>
|
|
|
|
<div class="grid gap-2 mb-4">
|
|
<% order.tickets.each do |ticket| %>
|
|
<div class="flex flex-col sm:flex-row sm:items-center justify-between text-sm bg-gray-50 rounded-lg p-3 gap-2">
|
|
<div>
|
|
<span class="font-medium"><%= ticket.ticket_type.name %></span>
|
|
<span class="text-gray-600">- <%= ticket.first_name %> <%= ticket.last_name %></span>
|
|
</div>
|
|
<div class="flex items-center space-x-2">
|
|
<span class="font-medium text-gray-900"><%= number_to_currency(ticket.price_euros, unit: "€") %></span>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
|
|
<div class="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3">
|
|
<div class="text-sm text-gray-600">
|
|
<div class="mb-1 sm:mb-0">
|
|
Tentatives: <%= order.payment_attempts %>/3
|
|
</div>
|
|
<% if order.expiring_soon? %>
|
|
<span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-orange-50 border border-orange-200 text-orange-600"
|
|
data-controller="countdown"
|
|
data-countdown-expires-at-value="<%= order.expires_at.iso8601 %>"
|
|
data-countdown-order-id-value="<%= order.id %>">
|
|
⚠️ Expire dans <span class="countdown-timer ml-1 font-bold"></span>
|
|
</span>
|
|
<% else %>
|
|
<span class="text-gray-500">Expire dans <%= time_ago_in_words(order.expires_at) %></span>
|
|
<% end %>
|
|
</div>
|
|
|
|
<%= link_to retry_payment_order_path(order), method: :post,
|
|
class: "inline-flex items-center px-4 py-2 bg-orange-600 text-white text-sm font-medium rounded-lg hover:bg-orange-700 transition-colors duration-200 whitespace-nowrap" do %>
|
|
<i data-lucide="credit-card" class="w-4 h-4 mr-2"></i>
|
|
Reprendre le Paiement (€<%= order.total_amount_euros %>)
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
|
|
<!-- User Page Header -->
|
|
<div class="mb-8">
|
|
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
|
|
<div>
|
|
<h1 class="text-3xl font-bold text-gray-900">Mon tableau de bord</h1>
|
|
<p class="text-gray-600 mt-1">Accédez à vos billets et évenements</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- User's Orders Section -->
|
|
<div class="bg-white rounded-2xl shadow-lg mb-8">
|
|
<div class="border-b border-gray-100 p-4 sm:p-6">
|
|
<div class="flex items-center justify-between">
|
|
<h2 class="text-xl sm:text-2xl font-bold text-gray-900">Mes Commandes</h2>
|
|
<span class="text-sm text-gray-600 bg-gray-100 px-3 py-1 rounded-full">
|
|
<%= pluralize(@user_orders.count, 'commande') %>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<div class="p-4 sm:p-6">
|
|
<% if @user_orders.any? %>
|
|
<div class="space-y-4">
|
|
<% @user_orders.each do |order| %>
|
|
<div class="bg-gray-50 rounded-xl p-4 hover:shadow-md transition-shadow">
|
|
<div class="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-3 mb-3">
|
|
<div class="flex-1">
|
|
<div class="flex flex-wrap items-center gap-2 mb-2">
|
|
<h3 class="font-semibold text-gray-900 text-base sm:text-lg"><%= order.event.name %></h3>
|
|
<span class="text-xs px-2 py-1 rounded-full <%= order.status == 'paid' ? 'bg-green-100 text-green-800' : order.status == 'completed' ? 'bg-blue-100 text-blue-800' : 'bg-yellow-100 text-yellow-800' %>">
|
|
<%= order.status.humanize %>
|
|
</span>
|
|
</div>
|
|
|
|
<div class="flex flex-wrap items-center gap-3 text-sm text-gray-600 mb-2">
|
|
<div class="flex items-center">
|
|
<i data-lucide="calendar" class="w-4 h-4 mr-2"></i>
|
|
<%= order.event.start_time.strftime("%d %B %Y à %H:%M") %>
|
|
</div>
|
|
<div class="flex items-center">
|
|
<i data-lucide="map-pin" class="w-4 h-4 mr-2"></i>
|
|
<%= order.event.venue_name %>
|
|
</div>
|
|
<div class="flex items-center">
|
|
<i data-lucide="shopping-bag" class="w-4 h-4 mr-2"></i>
|
|
<%= pluralize(order.tickets.count, 'billet') %>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="text-sm text-gray-500 mt-2">
|
|
Order #<%= order.id %> • <%= order.created_at.strftime("%m/%d/%Y") %> • €<%= order.total_amount_euros %>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex items-center">
|
|
<%= link_to order_path(order),
|
|
class: "inline-flex items-center px-4 py-2 bg-purple-600 hover:bg-purple-700 text-white text-sm font-medium rounded-lg transition-colors duration-200 whitespace-nowrap" do %>
|
|
<i data-lucide="eye" class="w-4 h-4 mr-2"></i>
|
|
Voir les Détails
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Quick tickets preview -->
|
|
<div class="border-t border-gray-200 pt-3">
|
|
<div class="grid gap-2">
|
|
<% order.tickets.limit(3).each do |ticket| %>
|
|
<div class="flex flex-col sm:flex-row sm:items-center justify-between text-sm bg-white rounded-lg p-3 gap-2">
|
|
<div class="flex items-center space-x-2">
|
|
<span class="w-2 h-2 bg-green-500 rounded-full"></span>
|
|
<span class="font-medium"><%= ticket.ticket_type.name %></span>
|
|
<span class="text-gray-500 text-sm">- <%= ticket.first_name %> <%= ticket.last_name %></span>
|
|
</div>
|
|
<div class="flex items-center space-x-2">
|
|
<%= link_to ticket_download_path(ticket.qr_code),
|
|
class: "text-purple-600 hover:text-purple-800" do %>
|
|
<i data-lucide="download" class="w-4 h-4"></i>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
<% if order.tickets.count > 3 %>
|
|
<div class="text-xs text-gray-500 text-center">
|
|
et <%= pluralize(order.tickets.count - 3, 'autre billet') %>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
|
|
<% if @user_orders.count >= 10 %>
|
|
<div class="mt-6 text-center">
|
|
<%= link_to "Voir Toutes Mes Commandes", orders_path, class: "text-purple-600 hover:text-purple-800 font-medium transition-colors duration-200" %>
|
|
</div>
|
|
<% end %>
|
|
<% else %>
|
|
<div class="text-center py-12">
|
|
<div class="w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
|
<i data-lucide="shopping-bag" class="w-8 h-8 text-gray-400"></i>
|
|
</div>
|
|
<h3 class="text-lg font-medium text-gray-900 mb-2">Aucune Commande</h3>
|
|
<p class="text-gray-600 mb-6">Vous n'avez pas encore passé de commandes.</p>
|
|
<%= link_to events_path, class: "inline-flex items-center px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition-colors duration-200" do %>
|
|
<i data-lucide="search" class="w-4 h-4 mr-2"></i>
|
|
Découvrir des Événements
|
|
<% end %>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Quick Events Preview -->
|
|
<% if @user_orders.any? %>
|
|
<div class="bg-white rounded-2xl shadow-lg">
|
|
<div class="border-b border-gray-100 p-4 sm:p-6">
|
|
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3">
|
|
<h2 class="text-lg sm:text-xl font-bold text-gray-900">Découvrir d'autres événements</h2>
|
|
<%= link_to events_path, class: "text-purple-600 hover:text-purple-800 font-medium transition-colors duration-200 whitespace-nowrap" do %>
|
|
Voir tout →
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
<div class="p-4 sm:p-6">
|
|
<% if @upcoming_preview_events.any? %>
|
|
<div class="grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3">
|
|
<% @upcoming_preview_events.each do |event| %>
|
|
<div class="bg-gray-50 rounded-xl p-4 hover:shadow-md transition-shadow">
|
|
<h4 class="font-medium text-gray-900 mb-2 text-base"><%= event.name %></h4>
|
|
|
|
<div class="text-sm text-gray-600 space-y-1">
|
|
<div class="flex items-center">
|
|
<i data-lucide="calendar" class="w-4 h-4 mr-2"></i>
|
|
<%= event.start_time.strftime("%d %B") %>
|
|
</div>
|
|
<div class="flex items-center">
|
|
<i data-lucide="map-pin" class="w-4 h-4 mr-2"></i>
|
|
<%= event.venue_name %>
|
|
</div>
|
|
</div>
|
|
<div class="mt-3">
|
|
<%= link_to event_path(event.slug, event), class: "text-purple-600 hover:text-purple-800 text-sm font-medium" do %>
|
|
Voir l'Événement →
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
<% else %>
|
|
<p class="text-gray-600">Aucun événement à venir pour le moment.</p>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
</div>
|