Compare commits
2 Commits
049e5505ef
...
c1dde7914c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1dde7914c | ||
|
|
dbb972e490 |
71
app/javascript/controllers/countdown_controller.js
Normal file
71
app/javascript/controllers/countdown_controller.js
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import { Controller } from "@hotwired/stimulus"
|
||||||
|
|
||||||
|
// Countdown controller for displaying remaining time until order expiration
|
||||||
|
export default class extends Controller {
|
||||||
|
static values = {
|
||||||
|
expiresAt: String, // ISO timestamp when the order expires
|
||||||
|
orderId: Number // Order ID for identification
|
||||||
|
}
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
// Parse the expiration timestamp
|
||||||
|
this.expirationTime = new Date(this.expiresAtValue).getTime()
|
||||||
|
|
||||||
|
// Find the countdown element
|
||||||
|
this.countdownElement = this.element.querySelector('.countdown-timer')
|
||||||
|
|
||||||
|
if (this.countdownElement && !isNaN(this.expirationTime)) {
|
||||||
|
// Start the countdown
|
||||||
|
this.updateCountdown()
|
||||||
|
this.timer = setInterval(() => this.updateCountdown(), 1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect() {
|
||||||
|
// Clean up the interval when the controller disconnects
|
||||||
|
if (this.timer) {
|
||||||
|
clearInterval(this.timer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCountdown() {
|
||||||
|
const now = new Date().getTime()
|
||||||
|
const distance = this.expirationTime - now
|
||||||
|
|
||||||
|
// If the countdown is finished
|
||||||
|
if (distance < 0) {
|
||||||
|
this.countdownElement.innerHTML = "EXPIRÉ"
|
||||||
|
this.countdownElement.classList.add("text-red-600", "font-bold")
|
||||||
|
this.countdownElement.classList.remove("text-orange-600")
|
||||||
|
|
||||||
|
// Add a more urgent visual indicator
|
||||||
|
this.element.classList.add("bg-red-50", "border-red-200")
|
||||||
|
this.element.classList.remove("bg-orange-50", "border-orange-200")
|
||||||
|
|
||||||
|
// Stop the timer
|
||||||
|
if (this.timer) {
|
||||||
|
clearInterval(this.timer)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate time components
|
||||||
|
const seconds = Math.floor(distance / 1000)
|
||||||
|
|
||||||
|
// Display the result
|
||||||
|
this.countdownElement.innerHTML = `${seconds} secondes`
|
||||||
|
|
||||||
|
// Add urgency styling when time is running low
|
||||||
|
if (seconds < 60) {
|
||||||
|
this.countdownElement.classList.add("text-red-600", "font-bold")
|
||||||
|
this.countdownElement.classList.remove("text-orange-600")
|
||||||
|
|
||||||
|
// Add background warning for extra urgency
|
||||||
|
this.element.classList.add("bg-red-50", "border-red-200")
|
||||||
|
this.element.classList.remove("bg-orange-50", "border-orange-200")
|
||||||
|
} else if (seconds < 300) { // Less than 5 minutes
|
||||||
|
this.countdownElement.classList.add("text-orange-600", "font-bold")
|
||||||
|
this.element.classList.add("bg-orange-50", "border-orange-200")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,3 +24,6 @@ application.register("qr-code", QrCodeController);
|
|||||||
|
|
||||||
import EventFormController from "./event_form_controller";
|
import EventFormController from "./event_form_controller";
|
||||||
application.register("event-form", EventFormController);
|
application.register("event-form", EventFormController);
|
||||||
|
|
||||||
|
import CountdownController from "./countdown_controller";
|
||||||
|
application.register("countdown", CountdownController);
|
||||||
|
|||||||
@@ -135,10 +135,6 @@
|
|||||||
<span class="text-gray-600">Sous-total</span>
|
<span class="text-gray-600">Sous-total</span>
|
||||||
<span class="text-gray-900"><%= @order.total_amount_euros - 1.0 %>€</span>
|
<span class="text-gray-900"><%= @order.total_amount_euros - 1.0 %>€</span>
|
||||||
</div>
|
</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">
|
<div class="flex items-center justify-between text-lg pt-2 border-t border-gray-200">
|
||||||
<span class="font-medium text-gray-900">Total à payer</span>
|
<span class="font-medium text-gray-900">Total à payer</span>
|
||||||
<span class="font-bold text-2xl text-red-600">
|
<span class="font-bold text-2xl text-red-600">
|
||||||
|
|||||||
@@ -124,16 +124,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Total -->
|
<!-- Total -->
|
||||||
<div class="border-t border-gray-200 pt-6 mt-6">
|
<div class="mt-6">
|
||||||
<div class="space-y-2">
|
<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">
|
<div class="flex items-center justify-between text-lg pt-2 border-t border-gray-200">
|
||||||
<span class="font-medium text-gray-900">Total payé</span>
|
<span class="font-medium text-gray-900">Total payé</span>
|
||||||
<span class="font-bold text-2xl text-green-600">
|
<span class="font-bold text-2xl text-green-600">
|
||||||
@@ -205,7 +197,7 @@
|
|||||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"/>
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"/>
|
||||||
</svg>
|
</svg>
|
||||||
Retour au Tableau de Bord
|
Retour au tableau de bord
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<%= 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 %>
|
<%= 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 %>
|
||||||
@@ -213,7 +205,7 @@
|
|||||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"/>
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"/>
|
||||||
</svg>
|
</svg>
|
||||||
Voir l'Événement Complet
|
Voir la fiche de l'événement
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -129,7 +129,10 @@
|
|||||||
<% @promoter_events.each do |event| %>
|
<% @promoter_events.each do |event| %>
|
||||||
<div class="border border-gray-200 rounded-xl p-4 hover:shadow-md transition-shadow">
|
<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 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>
|
<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' %>">
|
<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 %>
|
<%= event.state.humanize %>
|
||||||
</span>
|
</span>
|
||||||
@@ -246,7 +249,12 @@
|
|||||||
Tentatives: <%= order.payment_attempts %>/3
|
Tentatives: <%= order.payment_attempts %>/3
|
||||||
</div>
|
</div>
|
||||||
<% if order.expiring_soon? %>
|
<% if order.expiring_soon? %>
|
||||||
<span class="text-orange-600 font-medium">⚠️ Expire dans <%= time_ago_in_words(order.expires_at) %></span>
|
<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 %>
|
<% else %>
|
||||||
<span class="text-gray-500">Expire dans <%= time_ago_in_words(order.expires_at) %></span>
|
<span class="text-gray-500">Expire dans <%= time_ago_in_words(order.expires_at) %></span>
|
||||||
<% end %>
|
<% end %>
|
||||||
@@ -385,6 +393,7 @@
|
|||||||
<% @upcoming_preview_events.each do |event| %>
|
<% @upcoming_preview_events.each do |event| %>
|
||||||
<div class="bg-gray-50 rounded-xl p-4 hover:shadow-md transition-shadow">
|
<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>
|
<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="text-sm text-gray-600 space-y-1">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<i data-lucide="calendar" class="w-4 h-4 mr-2"></i>
|
<i data-lucide="calendar" class="w-4 h-4 mr-2"></i>
|
||||||
|
|||||||
Reference in New Issue
Block a user