287 lines
14 KiB
Plaintext
287 lines
14 KiB
Plaintext
<div class="min-h-screen bg-gradient-to-br from-gray-50 to-gray-100 py-8">
|
|
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<!-- Breadcrumb -->
|
|
<nav class="inline-flex items-center gap-2 bg-white px-4 py-3 rounded-xl shadow-sm border border-gray-100 mb-8" aria-label="Breadcrumb">
|
|
<div class="inline-flex items-center text-sm font-medium">
|
|
<%= link_to root_path, class: "text-gray-700 hover:text-purple-600 transition-colors" do %>
|
|
<i data-lucide="home" class="w-4 h-4 mr-2"></i>
|
|
Accueil
|
|
<% end %>
|
|
</div>
|
|
<i data-lucide="chevron-right" class="w-4 h-4 text-gray-400"></i>
|
|
<div class="inline-flex items-center text-sm font-medium">
|
|
<%= link_to events_path, class: "text-gray-700 hover:text-purple-600 transition-colors" do %>
|
|
Événements
|
|
<% end %>
|
|
</div>
|
|
<i data-lucide="chevron-right" class="w-4 h-4 text-gray-400"></i>
|
|
<div class="inline-flex items-center text-sm font-medium">
|
|
<%= link_to event_path(@order.event.slug, @order.event), class: "text-gray-700 hover:text-purple-600 transition-colors" do %>
|
|
<%= @order.event.name %>
|
|
<% end %>
|
|
</div>
|
|
<i data-lucide="chevron-right" class="w-4 h-4 text-gray-400"></i>
|
|
<div class="text-sm font-medium text-purple-600">
|
|
Commande #<%= @order.id %>
|
|
</div>
|
|
</nav>
|
|
|
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
|
<!-- Order Summary -->
|
|
<div class="bg-white rounded-2xl shadow-xl p-6 md:p-8 h-fit">
|
|
<!-- Warning for expiring order -->
|
|
<% if @expiring_soon %>
|
|
<div class="mb-6 bg-orange-50 border border-orange-200 rounded-lg p-4">
|
|
<div class="flex items-start">
|
|
<i data-lucide="alert-triangle" class="w-5 h-5 text-orange-600 mr-2 mt-0.5 flex-shrink-0"></i>
|
|
<div>
|
|
<h3 class="font-medium text-orange-800 mb-1">Attention - Commande bientôt expirée</h3>
|
|
<p class="text-orange-700 text-sm">Votre commande va expirer dans quelques minutes. Veuillez procéder rapidement au paiement pour éviter son expiration automatique.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
|
|
<!-- Payment attempts warning -->
|
|
<% if @order.payment_attempts > 0 %>
|
|
<div class="mb-6 bg-blue-50 border border-blue-200 rounded-lg p-4">
|
|
<div class="flex items-start">
|
|
<i data-lucide="info" class="w-5 h-5 text-blue-600 mr-2 mt-0.5 flex-shrink-0"></i>
|
|
<div>
|
|
<h3 class="font-medium text-blue-800 mb-1">Nouvelle tentative de paiement</h3>
|
|
<p class="text-blue-700 text-sm">
|
|
Tentative <%= @order.payment_attempts + 1 %> sur <%= @order.class::MAX_PAYMENT_ATTEMPTS %>.
|
|
<% if @order.payment_attempts >= @order.class::MAX_PAYMENT_ATTEMPTS - 1 %>
|
|
<strong>Dernière tentative avant expiration !</strong>
|
|
<% end %>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
|
|
<div class="border-b border-gray-200 pb-6 mb-6">
|
|
<h1 class="text-2xl font-bold text-gray-900 mb-2">Commande pour <%= @order.event.name %></h1>
|
|
<div class="flex items-center text-sm text-gray-600 space-x-4">
|
|
<div class="flex items-center">
|
|
<i data-lucide="clock" class="w-4 h-4 mr-1"></i>
|
|
<% if @order.expires_at %>
|
|
Expire dans <%= time_ago_in_words(@order.expires_at, include_seconds: true) %>
|
|
<% end %>
|
|
</div>
|
|
<div class="flex items-center">
|
|
<i data-lucide="file-text" class="w-4 h-4 mr-1"></i>
|
|
Commande #<%= @order.id %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Order Items -->
|
|
<div class="space-y-4 mb-6">
|
|
<h3 class="text-lg font-semibold text-gray-900 mb-4">Récapitulatif de votre commande</h3>
|
|
|
|
<% @tickets.each do |ticket| %>
|
|
<div class="flex items-center justify-between py-3 border-b border-gray-100 last:border-b-0">
|
|
<div class="flex-1 min-w-0">
|
|
<h4 class="text-sm font-medium text-gray-900 truncate"><%= ticket.ticket_type.name %></h4>
|
|
<div class="flex items-center text-xs text-gray-500 mt-1">
|
|
<i data-lucide="user" class="w-3 h-3 mr-1"></i>
|
|
<%= ticket.first_name %> <%= ticket.last_name %>
|
|
</div>
|
|
</div>
|
|
<div class="text-right">
|
|
<div class="text-lg font-semibold text-gray-900"><%= ticket.price_euros %>€</div>
|
|
<% if ticket.ticket_type.description.present? %>
|
|
<div class="text-xs text-gray-500"><%= truncate(ticket.ticket_type.description, length: 30) %></div>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
|
|
<!-- Order Total -->
|
|
<div class="border-t border-gray-200 pt-6">
|
|
<div class="space-y-2">
|
|
<div class="flex items-center justify-between">
|
|
<span class="text-gray-600">Sous-total</span>
|
|
<span class="text-gray-900"><%= @order.total_amount_euros - 1.0 %>€</span>
|
|
</div>
|
|
<div class="flex items-center justify-between">
|
|
<span class="text-gray-600">Frais de service</span>
|
|
<span class="text-gray-900">1.00€</span>
|
|
</div>
|
|
<div class="flex items-center justify-between text-lg pt-2 border-t border-gray-200">
|
|
<span class="font-medium text-gray-900">Total</span>
|
|
<span class="font-bold text-2xl text-purple-600"><%= @order.total_amount_euros %>€</span>
|
|
</div>
|
|
</div>
|
|
<p class="text-xs text-gray-500 mt-2">TVA incluse</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Payment Section -->
|
|
<div class="bg-white rounded-2xl shadow-xl p-6 md:p-8 h-fit">
|
|
<div class="border-b border-gray-200 pb-6 mb-6">
|
|
<h2 class="text-xl font-bold text-gray-900 mb-2">Paiement sécurisé</h2>
|
|
<p class="text-sm text-gray-600">Procédez au paiement pour finaliser votre commande</p>
|
|
</div>
|
|
|
|
<% if @checkout_session.present? %>
|
|
<!-- Stripe Checkout -->
|
|
<div class="space-y-6">
|
|
<div class="bg-gradient-to-r from-purple-50 to-pink-50 rounded-lg p-4 border border-purple-200">
|
|
<div class="flex items-start">
|
|
<i data-lucide="shield" class="w-5 h-5 text-purple-600 mr-2 mt-0.5 flex-shrink-0"></i>
|
|
<div>
|
|
<h3 class="font-medium text-purple-800 mb-1">Paiement 100% sécurisé</h3>
|
|
<p class="text-purple-700 text-sm">Vos données bancaires sont protégées par le cryptage SSL et traitées par Stripe, leader mondial du paiement en ligne.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<button
|
|
id="checkout-button"
|
|
class="w-full btn btn-primary py-4 px-6 rounded-xl transition-all duration-200 transform hover:scale-105 active:scale-95 shadow-lg hover:shadow-xl"
|
|
>
|
|
<div class="flex items-center justify-center">
|
|
<i data-lucide="credit-card" class="w-5 h-5 mr-2"></i>
|
|
Payer <%= @order.total_amount_euros %>€
|
|
</div>
|
|
</button>
|
|
|
|
<div class="flex items-center justify-center space-x-4 text-xs text-gray-500">
|
|
<span class="flex items-center">
|
|
<i data-lucide="credit-card" class="w-4 h-4 mr-1"></i>
|
|
Visa
|
|
</span>
|
|
<span class="flex items-center">
|
|
<i data-lucide="credit-card" class="w-4 h-4 mr-1"></i>
|
|
Mastercard
|
|
</span>
|
|
<span class="flex items-center">
|
|
<i data-lucide="shield" class="w-4 h-4 mr-1"></i>
|
|
Sécurisé par Stripe
|
|
</span>
|
|
</div>
|
|
|
|
<script src="https://js.stripe.com/v3/"></script>
|
|
<script>
|
|
// Wait for Stripe library to load and DOM to be ready
|
|
function initializeStripeCheckout() {
|
|
if (typeof Stripe === 'undefined') {
|
|
console.log('Waiting for Stripe library to load...');
|
|
setTimeout(initializeStripeCheckout, 100);
|
|
return;
|
|
}
|
|
|
|
console.log('Initializing Stripe with publishable key:', '<%= Rails.application.config.stripe[:publishable_key] %>');
|
|
const stripe = Stripe('<%= Rails.application.config.stripe[:publishable_key] %>');
|
|
|
|
const checkoutButton = document.getElementById('checkout-button');
|
|
if (!checkoutButton) {
|
|
console.error('Checkout button not found');
|
|
return;
|
|
}
|
|
|
|
checkoutButton.addEventListener('click', async function() {
|
|
console.log('Checkout button clicked');
|
|
const button = this;
|
|
button.disabled = true;
|
|
button.innerHTML = `
|
|
<div class="flex items-center justify-center">
|
|
<svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
</svg>
|
|
Initialisation du paiement...
|
|
</div>
|
|
`;
|
|
|
|
try {
|
|
// Increment payment attempt counter
|
|
console.log('Incrementing payment attempt for order:', '<%= @order.id %>');
|
|
const response = await fetch('<%= increment_payment_attempt_order_path(@order) %>', {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
|
|
'Content-Type': 'application/json'
|
|
}
|
|
});
|
|
|
|
if (!response.ok) {
|
|
console.error('Payment attempt increment failed:', response.status, response.statusText);
|
|
throw new Error('Failed to increment payment attempt');
|
|
}
|
|
|
|
console.log('Payment attempt incremented successfully');
|
|
|
|
// Update button text for redirect
|
|
button.innerHTML = `
|
|
<div class="flex items-center justify-center">
|
|
<svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
</svg>
|
|
Redirection vers le paiement...
|
|
</div>
|
|
`;
|
|
|
|
// Redirect to Stripe
|
|
console.log('Redirecting to Stripe with session ID:', '<%= @checkout_session&.id %>');
|
|
const stripeResult = await stripe.redirectToCheckout({
|
|
sessionId: '<%= @checkout_session.id %>'
|
|
});
|
|
|
|
if (stripeResult.error) {
|
|
throw new Error(stripeResult.error.message);
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('Checkout error:', error);
|
|
// Reset button on error
|
|
button.disabled = false;
|
|
button.innerHTML = `
|
|
<div class="flex items-center justify-center">
|
|
<i data-lucide="credit-card" class="w-5 h-5 mr-2"></i>
|
|
Payer <%= @order.total_amount_euros %>€
|
|
</div>
|
|
`;
|
|
alert('Erreur: ' + error.message);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Initialize when DOM is ready
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', initializeStripeCheckout);
|
|
} else {
|
|
initializeStripeCheckout();
|
|
}
|
|
</script>
|
|
</div>
|
|
<% else %>
|
|
<!-- No Stripe Configuration -->
|
|
<div class="text-center py-8">
|
|
<div class="bg-yellow-50 border border-yellow-200 rounded-lg p-6">
|
|
<i data-lucide="alert-triangle" class="w-12 h-12 text-yellow-600 mx-auto mb-4"></i>
|
|
<h3 class="font-semibold text-yellow-800 mb-2">Paiement temporairement indisponible</h3>
|
|
<p class="text-yellow-700 text-sm">Le système de paiement n'est pas encore configuré. Veuillez contacter l'organisateur pour plus d'informations.</p>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
|
|
<!-- Order Actions -->
|
|
<div class="border-t border-gray-200 pt-6 mt-6">
|
|
<div class="space-y-3">
|
|
<%= link_to event_path(@order.event.slug, @order.event), class: "block w-full text-center py-3 px-4 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50 transition-colors" do %>
|
|
<div class="flex items-center justify-center">
|
|
<i data-lucide="arrow-left" class="w-4 h-4 mr-2"></i>
|
|
Retour à l'événement
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div> |