422 lines
20 KiB
Plaintext
Executable File
422 lines
20 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 }
|
|
] %>
|
|
|
|
<!-- 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">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>
|
|
|
|
<div class="bg-gradient-to-br from-orange-50 to-orange-100 rounded-2xl p-6 border border-orange-200">
|
|
<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>
|
|
</div>
|
|
</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'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>
|