diff --git a/QWEN.md b/QWEN.md
deleted file mode 100755
index 3eb79f0..0000000
--- a/QWEN.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# Qwen Code Customization
-
-## Project Context
-- Working on a Ruby on Rails project named "aperonight"
-- Using Docker for containerization
-- Following Ruby version 3.1.0 (as indicated by .ruby-version)
-- Using Bundler for gem management (Gemfile)
-- Using Node.js for frontend assets (package.json likely present)
-
-## Preferences
-- Prefer to use Ruby and Rails conventions
-- Follow Docker best practices for development environments
-- Use standard Ruby/Rails project structure
-- When creating new files, follow Rails conventions
-- When modifying existing files, maintain consistency with current code style
-- Use git for version control (as seen in .gitignore)
-- Prefer to work with the project's existing toolchain (Bundler, etc.)
-
-## Behavior
-- When asked to make changes, first understand the context by examining relevant files
-- When creating new files, ensure they follow project conventions
-- When modifying files, preserve existing code style and patterns
-- When implementing new features, suggest appropriate file locations and naming conventions
-- When debugging, suggest using the project's existing test suite and development tools
-- When suggesting changes, provide clear explanations of why the change is beneficial
-
-## Qwen Added Memories
-- We've implemented the checkout process with name collection for tickets that require identification. We've added first_name and last_name fields to the tickets table, updated the Ticket model with validations, added new routes and controller actions, created a view for collecting names, and updated the JavaScript controller. The database migration needs to be run in the Docker environment when the gem issues are resolved.
diff --git a/README-checkout-implementation.md b/README-checkout-implementation.md
deleted file mode 100755
index 61b8952..0000000
--- a/README-checkout-implementation.md
+++ /dev/null
@@ -1,45 +0,0 @@
-# Checkout Process Implementation
-
-This document describes the implementation of the checkout process with name collection for tickets that require identification.
-
-## Implementation Details
-
-The implementation includes:
-
-1. Database migration to add first_name and last_name fields to tickets
-2. Updates to the Ticket model to validate names when required
-3. New routes and controller actions for name collection
-4. A new view for collecting ticket holder names
-5. Updates to the existing JavaScript controller
-
-## Running the Migration
-
-Once the Docker environment is fixed, run the following command to apply the database migration:
-
-```bash
-docker compose exec rails bundle exec rails db:migrate
-```
-
-## Testing the Implementation
-
-1. Start the Docker containers:
- ```bash
- docker compose up -d
- ```
-
-2. Visit an event page and select tickets that require identification
-3. The checkout process should redirect to the name collection page
-4. After submitting names, the user should be redirected to the payment page
-5. After successful payment, tickets should be created with the provided names
-
-## Code Structure
-
-- Migration: `db/migrate/20250828143000_add_names_to_tickets.rb`
-- Model: `app/models/ticket.rb`
-- Controller: `app/controllers/events_controller.rb`
-- Views:
- - `app/views/events/collect_names.html.erb` (new)
- - `app/views/events/show.html.erb` (updated)
- - `app/views/components/_ticket_card.html.erb` (updated)
-- Routes: `config/routes.rb` (updated)
-- JavaScript: `app/javascript/controllers/ticket_cart_controller.js` (no changes needed)
\ No newline at end of file
diff --git a/app/controllers/api/v1/events_controller.rb b/app/controllers/api/v1/events_controller.rb
index 399031a..e67d0b8 100755
--- a/app/controllers/api/v1/events_controller.rb
+++ b/app/controllers/api/v1/events_controller.rb
@@ -5,8 +5,8 @@ module Api
module V1
class EventsController < ApiController
# Skip API key authentication for store_cart action (used by frontend forms)
- skip_before_action :authenticate_api_key, only: [:store_cart]
-
+ skip_before_action :authenticate_api_key, only: [ :store_cart ]
+
# Charge l'évén avant certaines actions pour réduire les duplications
before_action :set_event, only: [ :show, :update, :destroy, :store_cart ]
diff --git a/app/controllers/concerns/stripe_concern.rb b/app/controllers/concerns/stripe_concern.rb
index ff9b50f..d757349 100644
--- a/app/controllers/concerns/stripe_concern.rb
+++ b/app/controllers/concerns/stripe_concern.rb
@@ -10,9 +10,9 @@ module StripeConcern
# but kept for backward compatibility
def initialize_stripe
return false unless stripe_configured?
-
+
# Stripe is already initialized at application startup
Rails.logger.debug "Stripe already initialized at application startup"
true
end
-end
\ No newline at end of file
+end
diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb
index baa812f..9491b4c 100755
--- a/app/controllers/events_controller.rb
+++ b/app/controllers/events_controller.rb
@@ -3,8 +3,7 @@
# This controller manages all events. It load events for homepage
# and display for pagination.
class EventsController < ApplicationController
-
- before_action :authenticate_user!, only: [ ]
+ before_action :authenticate_user!, only: []
before_action :set_event, only: [ :show ]
# Display all events
@@ -27,5 +26,4 @@ class EventsController < ApplicationController
def set_event
@event = Event.includes(:ticket_types).find(params[:id])
end
-
end
diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb
index 3721ea2..eb2b39d 100644
--- a/app/controllers/orders_controller.rb
+++ b/app/controllers/orders_controller.rb
@@ -4,12 +4,12 @@
# Orders group multiple tickets together for better transaction management
class OrdersController < ApplicationController
before_action :authenticate_user!
- before_action :set_order, only: [:show, :checkout, :retry_payment, :increment_payment_attempt]
- before_action :set_event, only: [:new, :create]
+ before_action :set_order, only: [ :show, :checkout, :retry_payment, :increment_payment_attempt ]
+ before_action :set_event, only: [ :new, :create ]
# Display new order form with name collection
#
- # On this page user can see order summary and complete the tickets details
+ # On this page user can see order summary and complete the tickets details
# (first name and last name) for each ticket ordered
def new
@cart_data = session[:pending_cart] || {}
@@ -52,7 +52,7 @@ class OrdersController < ApplicationController
end
success = false
-
+
ActiveRecord::Base.transaction do
@order = current_user.orders.create!(event: @event, status: "draft")
@@ -60,7 +60,7 @@ class OrdersController < ApplicationController
next if ticket_attrs[:first_name].blank? || ticket_attrs[:last_name].blank?
ticket_type = @event.ticket_types.find(ticket_attrs[:ticket_type_id])
-
+
ticket = @order.tickets.build(
ticket_type: ticket_type,
first_name: ticket_attrs[:first_name],
@@ -82,7 +82,7 @@ class OrdersController < ApplicationController
raise ActiveRecord::Rollback
end
end
-
+
# Handle redirects outside transaction
if success
session[:draft_order_id] = @order.id
@@ -260,7 +260,7 @@ class OrdersController < ApplicationController
end
Stripe::Checkout::Session.create(
- payment_method_types: ["card"],
+ payment_method_types: [ "card" ],
line_items: line_items,
mode: "payment",
success_url: order_payment_success_url + "?session_id={CHECKOUT_SESSION_ID}",
diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb
index 38dca2d..56c346c 100755
--- a/app/controllers/pages_controller.rb
+++ b/app/controllers/pages_controller.rb
@@ -20,8 +20,8 @@ class PagesController < ApplicationController
# Metrics for dashboard cards
@booked_events = current_user.orders.joins(tickets: { ticket_type: :event })
.where(events: { state: :published })
- .where(orders: { status: ['paid', 'completed'] })
- .sum('1')
+ .where(orders: { status: [ "paid", "completed" ] })
+ .sum("1")
@events_today = Event.published.where("DATE(start_time) = ?", Date.current).count
@events_tomorrow = Event.published.where("DATE(start_time) = ?", Date.current + 1).count
@upcoming_events = Event.published.upcoming.count
@@ -33,7 +33,7 @@ class PagesController < ApplicationController
.limit(5)
# Draft orders that can be retried
- @draft_orders = current_user.orders.includes(tickets: [:ticket_type, :event])
+ @draft_orders = current_user.orders.includes(tickets: [ :ticket_type, :event ])
.can_retry_payment
.order(:expires_at)
diff --git a/app/controllers/promoter/events_controller.rb b/app/controllers/promoter/events_controller.rb
index 3f2deda..ac68538 100644
--- a/app/controllers/promoter/events_controller.rb
+++ b/app/controllers/promoter/events_controller.rb
@@ -5,7 +5,7 @@
class Promoter::EventsController < ApplicationController
before_action :authenticate_user!
before_action :ensure_can_manage_events!
- before_action :set_event, only: [:show, :edit, :update, :destroy, :publish, :unpublish, :cancel, :mark_sold_out]
+ before_action :set_event, only: [ :show, :edit, :update, :destroy, :publish, :unpublish, :cancel, :mark_sold_out ]
# Display all events for the current promoter
def index
@@ -25,9 +25,9 @@ class Promoter::EventsController < ApplicationController
# Create a new event
def create
@event = current_user.events.build(event_params)
-
+
if @event.save
- redirect_to promoter_event_path(@event), notice: 'Event créé avec succès!'
+ redirect_to promoter_event_path(@event), notice: "Event créé avec succès!"
else
render :new, status: :unprocessable_entity
end
@@ -41,7 +41,7 @@ class Promoter::EventsController < ApplicationController
# Update an existing event
def update
if @event.update(event_params)
- redirect_to promoter_event_path(@event), notice: 'Event mis à jour avec succès!'
+ redirect_to promoter_event_path(@event), notice: "Event mis à jour avec succès!"
else
render :edit, status: :unprocessable_entity
end
@@ -50,16 +50,16 @@ class Promoter::EventsController < ApplicationController
# Delete an event
def destroy
@event.destroy
- redirect_to promoter_events_path, notice: 'Event supprimé avec succès!'
+ redirect_to promoter_events_path, notice: "Event supprimé avec succès!"
end
# Publish an event (make it visible to public)
def publish
if @event.draft?
@event.update(state: :published)
- redirect_to promoter_event_path(@event), notice: 'Event publié avec succès!'
+ redirect_to promoter_event_path(@event), notice: "Event publié avec succès!"
else
- redirect_to promoter_event_path(@event), alert: 'Cet event ne peut pas être publié.'
+ redirect_to promoter_event_path(@event), alert: "Cet event ne peut pas être publié."
end
end
@@ -67,9 +67,9 @@ class Promoter::EventsController < ApplicationController
def unpublish
if @event.published?
@event.update(state: :draft)
- redirect_to promoter_event_path(@event), notice: 'Event dépublié avec succès!'
+ redirect_to promoter_event_path(@event), notice: "Event dépublié avec succès!"
else
- redirect_to promoter_event_path(@event), alert: 'Cet event ne peut pas être dépublié.'
+ redirect_to promoter_event_path(@event), alert: "Cet event ne peut pas être dépublié."
end
end
@@ -77,9 +77,9 @@ class Promoter::EventsController < ApplicationController
def cancel
if @event.published?
@event.update(state: :canceled)
- redirect_to promoter_event_path(@event), notice: 'Event annulé avec succès!'
+ redirect_to promoter_event_path(@event), notice: "Event annulé avec succès!"
else
- redirect_to promoter_event_path(@event), alert: 'Cet event ne peut pas être annulé.'
+ redirect_to promoter_event_path(@event), alert: "Cet event ne peut pas être annulé."
end
end
@@ -87,9 +87,9 @@ class Promoter::EventsController < ApplicationController
def mark_sold_out
if @event.published?
@event.update(state: :sold_out)
- redirect_to promoter_event_path(@event), notice: 'Event marqué comme complet!'
+ redirect_to promoter_event_path(@event), notice: "Event marqué comme complet!"
else
- redirect_to promoter_event_path(@event), alert: 'Cet event ne peut pas être marqué comme complet.'
+ redirect_to promoter_event_path(@event), alert: "Cet event ne peut pas être marqué comme complet."
end
end
@@ -97,14 +97,14 @@ class Promoter::EventsController < ApplicationController
def ensure_can_manage_events!
unless current_user.can_manage_events?
- redirect_to dashboard_path, alert: 'Vous n\'avez pas les permissions nécessaires pour gérer des événements.'
+ redirect_to dashboard_path, alert: "Vous n'avez pas les permissions nécessaires pour gérer des événements."
end
end
def set_event
@event = current_user.events.find(params[:id])
rescue ActiveRecord::RecordNotFound
- redirect_to promoter_events_path, alert: 'Event non trouvé ou vous n\'avez pas accès à cet event.'
+ redirect_to promoter_events_path, alert: "Event non trouvé ou vous n'avez pas accès à cet event."
end
def event_params
@@ -114,4 +114,4 @@ class Promoter::EventsController < ApplicationController
:start_time, :end_time, :featured
)
end
-end
\ No newline at end of file
+end
diff --git a/app/controllers/promoter/ticket_types_controller.rb b/app/controllers/promoter/ticket_types_controller.rb
index 8a5b57b..b97411e 100644
--- a/app/controllers/promoter/ticket_types_controller.rb
+++ b/app/controllers/promoter/ticket_types_controller.rb
@@ -6,7 +6,7 @@ class Promoter::TicketTypesController < ApplicationController
before_action :authenticate_user!
before_action :ensure_can_manage_events!
before_action :set_event
- before_action :set_ticket_type, only: [:show, :edit, :update, :destroy]
+ before_action :set_ticket_type, only: [ :show, :edit, :update, :destroy ]
# Display all ticket types for an event
def index
@@ -30,9 +30,9 @@ class Promoter::TicketTypesController < ApplicationController
# Create a new ticket type
def create
@ticket_type = @event.ticket_types.build(ticket_type_params)
-
+
if @ticket_type.save
- redirect_to promoter_event_ticket_types_path(@event), notice: 'Type de billet créé avec succès!'
+ redirect_to promoter_event_ticket_types_path(@event), notice: "Type de billet créé avec succès!"
else
render :new, status: :unprocessable_entity
end
@@ -46,7 +46,7 @@ class Promoter::TicketTypesController < ApplicationController
# Update an existing ticket type
def update
if @ticket_type.update(ticket_type_params)
- redirect_to promoter_event_ticket_type_path(@event, @ticket_type), notice: 'Type de billet mis à jour avec succès!'
+ redirect_to promoter_event_ticket_type_path(@event, @ticket_type), notice: "Type de billet mis à jour avec succès!"
else
render :edit, status: :unprocessable_entity
end
@@ -55,10 +55,10 @@ class Promoter::TicketTypesController < ApplicationController
# Delete a ticket type
def destroy
if @ticket_type.tickets.any?
- redirect_to promoter_event_ticket_types_path(@event), alert: 'Impossible de supprimer ce type de billet car des billets ont déjà été vendus.'
+ redirect_to promoter_event_ticket_types_path(@event), alert: "Impossible de supprimer ce type de billet car des billets ont déjà été vendus."
else
@ticket_type.destroy
- redirect_to promoter_event_ticket_types_path(@event), notice: 'Type de billet supprimé avec succès!'
+ redirect_to promoter_event_ticket_types_path(@event), notice: "Type de billet supprimé avec succès!"
end
end
@@ -67,11 +67,11 @@ class Promoter::TicketTypesController < ApplicationController
original = @event.ticket_types.find(params[:id])
@ticket_type = original.dup
@ticket_type.name = "#{original.name} (Copie)"
-
+
if @ticket_type.save
- redirect_to edit_promoter_event_ticket_type_path(@event, @ticket_type), notice: 'Type de billet dupliqué avec succès!'
+ redirect_to edit_promoter_event_ticket_type_path(@event, @ticket_type), notice: "Type de billet dupliqué avec succès!"
else
- redirect_to promoter_event_ticket_types_path(@event), alert: 'Erreur lors de la duplication.'
+ redirect_to promoter_event_ticket_types_path(@event), alert: "Erreur lors de la duplication."
end
end
@@ -79,20 +79,20 @@ class Promoter::TicketTypesController < ApplicationController
def ensure_can_manage_events!
unless current_user.can_manage_events?
- redirect_to dashboard_path, alert: 'Vous n\'avez pas les permissions nécessaires pour gérer des événements.'
+ redirect_to dashboard_path, alert: "Vous n'avez pas les permissions nécessaires pour gérer des événements."
end
end
def set_event
@event = current_user.events.find(params[:event_id])
rescue ActiveRecord::RecordNotFound
- redirect_to promoter_events_path, alert: 'Event non trouvé ou vous n\'avez pas accès à cet event.'
+ redirect_to promoter_events_path, alert: "Event non trouvé ou vous n'avez pas accès à cet event."
end
def set_ticket_type
@ticket_type = @event.ticket_types.find(params[:id])
rescue ActiveRecord::RecordNotFound
- redirect_to promoter_event_ticket_types_path(@event), alert: 'Type de billet non trouvé.'
+ redirect_to promoter_event_ticket_types_path(@event), alert: "Type de billet non trouvé."
end
def ticket_type_params
@@ -101,4 +101,4 @@ class Promoter::TicketTypesController < ApplicationController
:sale_start_at, :sale_end_at, :minimum_age, :requires_id
)
end
-end
\ No newline at end of file
+end
diff --git a/app/controllers/tickets_controller.rb b/app/controllers/tickets_controller.rb
index e3cc048..f60b255 100644
--- a/app/controllers/tickets_controller.rb
+++ b/app/controllers/tickets_controller.rb
@@ -36,10 +36,10 @@ class TicketsController < ApplicationController
# Redirect retry payment to order system
def retry_payment
@event = Event.includes(:ticket_types).find(params[:id])
-
+
# Look for draft order for this event
order = current_user.orders.find_by(event: @event, status: "draft")
-
+
if order&.can_retry_payment?
redirect_to retry_payment_order_path(order)
else
@@ -58,15 +58,15 @@ class TicketsController < ApplicationController
def set_event
event_id = params[:id] || session[:event_id]
-
+
Rails.logger.debug "TicketsController#set_event - params[:id]: #{params[:id].inspect}, session[:event_id]: #{session[:event_id].inspect}"
-
+
unless event_id
Rails.logger.error "TicketsController#set_event - No event ID found"
redirect_to events_path, alert: "Aucun événement spécifié"
return
end
-
+
@event = Event.includes(:ticket_types).find(event_id)
Rails.logger.debug "TicketsController#set_event - Found event: #{@event.id} - #{@event.name}"
rescue ActiveRecord::RecordNotFound
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index d946b5c..fcaad19 100755
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -6,7 +6,7 @@ module ApplicationHelper
# Include flash message helpers
include FlashMessagesHelper
-
+
# Include Stripe helper
include StripeHelper
end
diff --git a/app/helpers/lucide_helper.rb b/app/helpers/lucide_helper.rb
index cb37661..7e61db7 100644
--- a/app/helpers/lucide_helper.rb
+++ b/app/helpers/lucide_helper.rb
@@ -1,28 +1,28 @@
module LucideHelper
# Create a Lucide icon element
- #
+ #
# @param name [String] The name of the Lucide icon
# @param options [Hash] Additional options
# @option options [String] :class Additional CSS classes
# @option options [String] :size Size class (e.g., 'w-4 h-4', 'w-6 h-6')
# @option options [Hash] :data Additional data attributes
- #
+ #
# @return [String] HTML string for the icon
#
# Usage:
- # lucide_icon('user')
+ # lucide_icon('user')
# lucide_icon('check-circle', class: 'text-green-500', size: 'w-5 h-5')
# lucide_icon('menu', data: { action: 'click->header#toggleMenu' })
def lucide_icon(name, options = {})
- css_classes = ["lucide-icon"]
+ css_classes = [ "lucide-icon" ]
css_classes << options[:size] if options[:size]
css_classes << options[:class] if options[:class]
-
+
data_attributes = { lucide: name }
data_attributes.merge!(options[:data]) if options[:data]
-
- content_tag :i, "",
- class: css_classes.join(" "),
+
+ content_tag :i, "",
+ class: css_classes.join(" "),
data: data_attributes,
**options.except(:class, :size, :data)
end
@@ -35,23 +35,23 @@ module LucideHelper
# @option options [String] :class Additional CSS classes for button
# @option options [String] :icon_class Additional CSS classes for icon
# @option options [String] :icon_size Size class for icon
- #
+ #
# Usage:
# lucide_button('plus', text: 'Add Item', class: 'btn btn-primary')
# lucide_button('trash-2', class: 'btn-danger', data: { confirm: 'Are you sure?' })
def lucide_button(name, options = {})
text = options.delete(:text)
icon_class = options.delete(:icon_class)
- icon_size = options.delete(:icon_size) || 'w-4 h-4'
-
+ icon_size = options.delete(:icon_size) || "w-4 h-4"
+
icon = lucide_icon(name, class: icon_class, size: icon_size)
-
+
content = if text.present?
- safe_join([icon, " ", text])
- else
+ safe_join([ icon, " ", text ])
+ else
icon
- end
-
+ end
+
content_tag :button, content, options
end
@@ -60,23 +60,23 @@ module LucideHelper
# @param name [String] The name of the Lucide icon
# @param url [String] The URL for the link
# @param options [Hash] Link options
- #
+ #
# Usage:
# lucide_link('edit', edit_user_path(user), text: 'Edit')
# lucide_link('external-link', 'https://example.com', text: 'Visit', target: '_blank')
def lucide_link(name, url, options = {})
text = options.delete(:text)
icon_class = options.delete(:icon_class)
- icon_size = options.delete(:icon_size) || 'w-4 h-4'
-
+ icon_size = options.delete(:icon_size) || "w-4 h-4"
+
icon = lucide_icon(name, class: icon_class, size: icon_size)
-
+
content = if text.present?
- safe_join([icon, " ", text])
- else
+ safe_join([ icon, " ", text ])
+ else
icon
- end
-
+ end
+
link_to content, url, options
end
-end
\ No newline at end of file
+end
diff --git a/app/helpers/stripe_helper.rb b/app/helpers/stripe_helper.rb
index f65da63..9d6bd84 100644
--- a/app/helpers/stripe_helper.rb
+++ b/app/helpers/stripe_helper.rb
@@ -3,10 +3,10 @@ module StripeHelper
def safe_stripe_call(&block)
# Check if Stripe is properly configured
return nil unless Rails.application.config.stripe[:secret_key].present?
-
+
# Stripe is now initialized at application startup
Rails.logger.debug "Using globally initialized Stripe"
-
+
begin
yield if block_given?
rescue Stripe::StripeError => e
@@ -14,4 +14,4 @@ module StripeHelper
nil
end
end
-end
\ No newline at end of file
+end
diff --git a/app/jobs/cleanup_expired_drafts_job.rb b/app/jobs/cleanup_expired_drafts_job.rb
index c7d5a29..e2dcda8 100644
--- a/app/jobs/cleanup_expired_drafts_job.rb
+++ b/app/jobs/cleanup_expired_drafts_job.rb
@@ -3,7 +3,7 @@ class CleanupExpiredDraftsJob < ApplicationJob
def perform
expired_count = 0
-
+
Ticket.expired_drafts.find_each do |ticket|
Rails.logger.info "Expiring draft ticket #{ticket.id} for user #{ticket.user_id}"
ticket.expire_if_overdue!
@@ -12,4 +12,4 @@ class CleanupExpiredDraftsJob < ApplicationJob
Rails.logger.info "Expired #{expired_count} draft tickets" if expired_count > 0
end
-end
\ No newline at end of file
+end
diff --git a/app/jobs/expired_orders_cleanup_job.rb b/app/jobs/expired_orders_cleanup_job.rb
index 1040cc6..a2b868e 100644
--- a/app/jobs/expired_orders_cleanup_job.rb
+++ b/app/jobs/expired_orders_cleanup_job.rb
@@ -4,9 +4,9 @@ class ExpiredOrdersCleanupJob < ApplicationJob
def perform
# Find and expire all draft orders that have passed their expiry time
expired_orders = Order.expired_drafts
-
+
Rails.logger.info "Found #{expired_orders.count} expired orders to process"
-
+
expired_orders.find_each do |order|
begin
order.expire_if_overdue!
@@ -17,7 +17,7 @@ class ExpiredOrdersCleanupJob < ApplicationJob
next
end
end
-
+
Rails.logger.info "Completed expired orders cleanup job"
end
end
diff --git a/app/mailers/ticket_mailer.rb b/app/mailers/ticket_mailer.rb
index 9320020..2e1c698 100755
--- a/app/mailers/ticket_mailer.rb
+++ b/app/mailers/ticket_mailer.rb
@@ -1,21 +1,21 @@
class TicketMailer < ApplicationMailer
- default from: 'notifications@aperonight.com'
+ default from: "notifications@aperonight.com"
def purchase_confirmation(ticket)
@ticket = ticket
@user = ticket.user
@event = ticket.event
-
+
# Generate PDF attachment
pdf = @ticket.to_pdf
attachments["ticket-#{@event.name.parameterize}-#{@ticket.qr_code[0..7]}.pdf"] = {
- mime_type: 'application/pdf',
+ mime_type: "application/pdf",
content: pdf
}
-
+
mail(
to: @user.email,
subject: "Confirmation d'achat - #{@event.name}"
)
end
-end
\ No newline at end of file
+end
diff --git a/app/models/event.rb b/app/models/event.rb
index f6fa08f..e036a7a 100755
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -48,5 +48,4 @@ class Event < ApplicationRecord
# Scope for published events ordered by start time
scope :upcoming, -> { published.where("start_time >= ?", Time.current).order(start_time: :asc) }
-
end
diff --git a/app/models/order.rb b/app/models/order.rb
index 9a6004c..1ec1600 100644
--- a/app/models/order.rb
+++ b/app/models/order.rb
@@ -90,4 +90,4 @@ class Order < ApplicationRecord
def draft?
status == "draft"
end
-end
\ No newline at end of file
+end
diff --git a/app/models/ticket_type.rb b/app/models/ticket_type.rb
index d3e8073..2bca6cd 100755
--- a/app/models/ticket_type.rb
+++ b/app/models/ticket_type.rb
@@ -12,7 +12,7 @@ class TicketType < ApplicationRecord
validates :sale_end_at, presence: true
validates :minimum_age, numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: 120 }, allow_nil: true
validates :event_id, presence: true
- validates :requires_id, inclusion: { in: [true, false] }
+ validates :requires_id, inclusion: { in: [ true, false ] }
# Custom validations
validate :sale_end_after_start
@@ -22,7 +22,7 @@ class TicketType < ApplicationRecord
scope :available_now, -> { where("sale_start_at <= ? AND sale_end_at >= ?", Time.current, Time.current) }
scope :upcoming, -> { where("sale_start_at > ?", Time.current) }
scope :expired, -> { where("sale_end_at < ?", Time.current) }
-
+
# Helper methods
def price_euros
return 0.0 if price_cents.nil?
@@ -45,7 +45,7 @@ class TicketType < ApplicationRecord
def available_quantity
return 0 if quantity.nil?
- [quantity - tickets.count, 0].max
+ [ quantity - tickets.count, 0 ].max
end
def sales_status
@@ -53,7 +53,7 @@ class TicketType < ApplicationRecord
return :expired if sale_end_at < Time.current
return :upcoming if sale_start_at > Time.current
return :sold_out if sold_out?
- return :available
+ :available
end
def total_potential_revenue
diff --git a/app/services/ticket_pdf_generator.rb b/app/services/ticket_pdf_generator.rb
index a513b33..a5e6221 100755
--- a/app/services/ticket_pdf_generator.rb
+++ b/app/services/ticket_pdf_generator.rb
@@ -1,6 +1,6 @@
-require 'prawn'
-require 'prawn/qrcode'
-require 'rqrcode'
+require "prawn"
+require "prawn/qrcode"
+require "rqrcode"
class TicketPdfGenerator
attr_reader :ticket
@@ -10,7 +10,7 @@ class TicketPdfGenerator
end
def generate
- Prawn::Document.new(page_size: [350, 600], margin: 20) do |pdf|
+ Prawn::Document.new(page_size: [ 350, 600 ], margin: 20) do |pdf|
# Header
pdf.fill_color "2D1B69"
pdf.font "Helvetica", style: :bold, size: 24
@@ -26,7 +26,7 @@ class TicketPdfGenerator
# Ticket info box
pdf.stroke_color "E5E7EB"
pdf.fill_color "F9FAFB"
- pdf.rounded_rectangle [0, pdf.cursor], 310, 120, 10
+ pdf.rounded_rectangle [ 0, pdf.cursor ], 310, 120, 10
pdf.fill_and_stroke
pdf.move_down 10
@@ -82,7 +82,7 @@ class TicketPdfGenerator
qrcode = RQRCode::QRCode.new(qr_code_data)
pdf.print_qr_code(qrcode, extent: 120, align: :center)
-
+
pdf.move_down 15
# QR code text
@@ -104,4 +104,4 @@ class TicketPdfGenerator
pdf.text "Generated on #{Time.current.strftime('%B %d, %Y at %I:%M %p')}", align: :center
end.render
end
-end
\ No newline at end of file
+end
diff --git a/auth-messages-implementation-plan.md b/auth-messages-implementation-plan.md
deleted file mode 100755
index 9f85b29..0000000
--- a/auth-messages-implementation-plan.md
+++ /dev/null
@@ -1,225 +0,0 @@
-# Authentication Messages Implementation Plan
-
-## Overview
-This document outlines the implementation of error/warn/info messages for login, registration, logout, password reset, and other authentication flows based on the existing purple/pink theme.
-
-## Current State Analysis
-- **Theme**: Purple/pink gradient system with neutral colors
-- **Authentication**: Devise with custom controllers
-- **Missing**: Flash message display system
-- **Existing**: Only form validation errors are displayed
-
-## Implementation Steps
-
-### 1. Flash Message Component
-Create a reusable flash message component that integrates with the theme.
-
-### 2. CSS Classes for Message Types
-Add theme-consistent styles for different message types:
-- Success (green/purple)
-- Error (red)
-- Warning (yellow/orange)
-- Info (blue)
-
-### 3. JavaScript Enhancement
-Add auto-dismiss functionality and animations
-
-### 4. Integration
-Update layouts and views to use the new message system
-
-## Files to Create/Update
-
-### A. Flash Message Partial
-**File**: `app/views/shared/_flash_messages.html.erb`
-```erb
-<% flash.each do |type, message| %>
- <% if message.present? %>
-
-
-
- <%= flash_icon(type) %>
-
-
-
-
-
- <% end %>
-<% end %>
-```
-
-### B. Flash Message Styling
-**File**: `app/assets/stylesheets/components/flash.css`
-```css
-/* Flash Messages - Theme Integration */
-.flash-message {
- @apply max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 mb-4;
-}
-
-.flash-message .flash-container {
- @apply rounded-lg p-4 shadow-md border;
-}
-
-.flash-message-success .flash-container {
- @apply bg-gradient-to-r from-green-50 to-purple-50 border-green-200 text-green-800;
-}
-
-.flash-message-error .flash-container {
- @apply bg-gradient-to-r from-red-50 to-pink-50 border-red-200 text-red-800;
-}
-
-.flash-message-warning .flash-container {
- @apply bg-gradient-to-r from-yellow-50 to-orange-50 border-yellow-200 text-yellow-800;
-}
-
-.flash-message-info .flash-container {
- @apply bg-gradient-to-r from-blue-50 to-purple-50 border-blue-200 text-blue-800;
-}
-
-.flash-message-notice .flash-container {
- @apply bg-gradient-to-r from-purple-50 to-pink-50 border-purple-200 text-purple-800;
-}
-
-.flash-message-alert .flash-container {
- @apply bg-gradient-to-r from-red-50 to-pink-50 border-red-200 text-red-800;
-}
-```
-
-### C. Helper Methods
-**File**: `app/helpers/flash_messages_helper.rb`
-```ruby
-module FlashMessagesHelper
- def flash_class(type)
- case type.to_s
- when 'notice' then 'flash-message-success'
- when 'success' then 'flash-message-success'
- when 'error' then 'flash-message-error'
- when 'alert' then 'flash-message-error'
- when 'warning' then 'flash-message-warning'
- when 'info' then 'flash-message-info'
- else "flash-message-#{type}"
- end
- end
-
- def flash_icon(type)
- case type.to_s
- when 'notice', 'success'
- content_tag :svg, class: "h-5 w-5 text-green-400", fill: "currentColor", viewBox: "0 0 20 20" do
- content_tag :path, "", "fill-rule": "evenodd", "d": "M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z", "clip-rule": "evenodd"
- end
- when 'error', 'alert'
- content_tag :svg, class: "h-5 w-5 text-red-400", fill: "currentColor", viewBox: "0 0 20 20" do
- content_tag :path, "", "fill-rule": "evenodd", "d": "M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z", "clip-rule": "evenodd"
- end
- when 'warning'
- content_tag :svg, class: "h-5 w-5 text-yellow-400", fill: "currentColor", viewBox: "0 0 20 20" do
- content_tag :path, "", "fill-rule": "evenodd", "d": "M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z", "clip-rule": "evenodd"
- end
- else
- content_tag :svg, class: "h-5 w-5 text-blue-400", fill: "currentColor", viewBox: "0 0 20 20" do
- content_tag :path, "", "fill-rule": "evenodd", "d": "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z", "clip-rule": "evenodd"
- end
- end
- end
-end
-```
-
-### D. JavaScript Controller
-**File**: `app/javascript/controllers/flash_message_controller.js`
-```javascript
-import { Controller } from "@hotwired/stimulus"
-
-export default class extends Controller {
- static targets = ["message"]
-
- connect() {
- // Auto-dismiss after 5 seconds
- this.timeout = setTimeout(() => {
- this.close()
- }, 5000)
- }
-
- disconnect() {
- if (this.timeout) {
- clearTimeout(this.timeout)
- }
- }
-
- close() {
- this.element.classList.add('opacity-0', 'transition-opacity', 'duration-300')
- setTimeout(() => {
- this.element.remove()
- }, 300)
- }
-}
-```
-
-### E. Update Application Layout
-**File**: `app/views/layouts/application.html.erb` (add flash messages)
-```erb
-
-
- <%= render "components/header" %>
-
-
- <%= render "shared/flash_messages" %>
- <%= yield %>
-
-
- <%= render "components/footer" %>
-
-
-```
-
-### F. Update Authentication Views
-Update all Devise views to remove the old error display and rely on flash messages.
-
-## Testing Checklist
-
-### Authentication Flows to Test:
-1. **Registration**
- - Successful registration
- - Registration with validation errors
- - Email confirmation
-
-2. **Login**
- - Successful login
- - Invalid credentials
- - Account locked/unconfirmed
-
-3. **Password Reset**
- - Request reset email
- - Reset password success/failure
-
-4. **Account Management**
- - Update profile
- - Change password
- - Delete account
-
-### Message Types to Verify:
-- [ ] Success messages (green/purple)
-- [ ] Error messages (red/pink)
-- [ ] Warning messages (yellow/orange)
-- [ ] Info messages (blue/purple)
-
-## Implementation Order
-1. Create CSS classes and theme integration
-2. Create helper methods
-3. Create partial templates
-4. Add to application layout
-5. Test each authentication flow
-6. Add JavaScript enhancements
-
-## Notes
-- All messages use the existing purple/pink theme colors
-- Responsive design for mobile/desktop
-- Auto-dismiss functionality with manual close option
-- Smooth animations and transitions
-- Accessibility compliant with focus indicators
diff --git a/checkout-implementation-summary.md b/checkout-implementation-summary.md
deleted file mode 100755
index 009b82e..0000000
--- a/checkout-implementation-summary.md
+++ /dev/null
@@ -1,47 +0,0 @@
-# Checkout Process Implementation Summary
-
-## Database Changes
-
-1. **Migration**: Added `first_name` and `last_name` fields to the `tickets` table
- - File: `db/migrate/20250828143000_add_names_to_tickets.rb`
-
-## Model Changes
-
-1. **Ticket Model**:
- - Added validations for `first_name` and `last_name` when required by ticket type
- - Added `requires_names?` method to check if names are required based on ticket type
-
-## Controller Changes
-
-1. **Events Controller**:
- - Modified `checkout` action to redirect to name collection when tickets require names
- - Added `collect_names` action to display form for collecting ticket holder names
- - Added `process_names` action to handle submitted names and proceed to payment
- - Updated `payment_success` action to create tickets with names when provided
-
-## View Changes
-
-1. **Events Show View**:
- - Added `change` event listener to quantity inputs in ticket cards
-
-2. **Ticket Card Component**:
- - Added `change` event listener to quantity inputs
-
-3. **New View**:
- - Created `app/views/events/collect_names.html.erb` for collecting ticket holder names
-
-## Route Changes
-
-1. **New Routes**:
- - `GET events/:slug.:id/names` - Collect names for tickets requiring identification
- - `POST events/:slug.:id/names` - Process submitted names and proceed to payment
-
-## JavaScript Changes
-
-1. **Ticket Cart Controller**:
- - No changes needed as name collection is handled server-side
-
-## Outstanding Tasks
-
-1. Run the database migration in the Docker environment once gem issues are resolved
-2. Test the complete checkout flow with name collection
\ No newline at end of file
diff --git a/config/application.rb b/config/application.rb
index a09e088..227f091 100755
--- a/config/application.rb
+++ b/config/application.rb
@@ -26,6 +26,5 @@ module Aperonight
config.i18n.load_path += Dir[Rails.root.join("my", "locales", "*.{rb,yml}")]
# config.i18n.default_locale = :fr
-
end
end
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index 50f3fbe..96d8082 100755
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -24,7 +24,7 @@ Devise.setup do |config|
# Configure the e-mail address which will be shown in Devise::Mailer,
# note that it will be overwritten if you use your own mailer class
# with default "from" parameter.
- config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com'
+ config.mailer_sender = "please-change-me-at-config-initializers-devise@example.com"
# Configure the class responsible to send e-mails.
# config.mailer = 'Devise::Mailer'
@@ -36,7 +36,7 @@ Devise.setup do |config|
# Load and configure the ORM. Supports :active_record (default) and
# :mongoid (bson_ext recommended) by default. Other ORMs may be
# available as additional gems.
- require 'devise/orm/active_record'
+ require "devise/orm/active_record"
# ==> Configuration for any authentication mechanism
# Configure which keys are used when authenticating a user. The default is
@@ -58,12 +58,12 @@ Devise.setup do |config|
# Configure which authentication keys should be case-insensitive.
# These keys will be downcased upon creating or modifying a user and when used
# to authenticate or find a user. Default is :email.
- config.case_insensitive_keys = [:email]
+ config.case_insensitive_keys = [ :email ]
# Configure which authentication keys should have whitespace stripped.
# These keys will have whitespace before and after removed upon creating or
# modifying a user and when used to authenticate or find a user. Default is :email.
- config.strip_whitespace_keys = [:email]
+ config.strip_whitespace_keys = [ :email ]
# Tell if authentication through request.params is enabled. True by default.
# It can be set to an array that will enable params authentication only for the
@@ -97,7 +97,7 @@ Devise.setup do |config|
# Notice that if you are skipping storage for all authentication paths, you
# may want to disable generating routes to Devise's sessions controller by
# passing skip: :sessions to `devise_for` in your config/routes.rb
- config.skip_session_storage = [:http_auth]
+ config.skip_session_storage = [ :http_auth ]
# By default, Devise cleans up the CSRF token on authentication to
# avoid CSRF token fixation attacks. This means that, when using AJAX
diff --git a/config/initializers/stripe.rb b/config/initializers/stripe.rb
index 7d260ae..0b0d2b5 100755
--- a/config/initializers/stripe.rb
+++ b/config/initializers/stripe.rb
@@ -1,10 +1,10 @@
Rails.application.configure do
# Load environment variables from .env file if dotenv is not available
- env_file = Rails.root.join('.env')
+ env_file = Rails.root.join(".env")
if File.exist?(env_file) && !defined?(Dotenv)
File.readlines(env_file).each do |line|
- next if line.strip.empty? || line.start_with?('#')
- key, value = line.split('=', 2)
+ next if line.strip.empty? || line.start_with?("#")
+ key, value = line.split("=", 2)
ENV[key.strip] = value.strip if key && value
end
end
@@ -37,4 +37,4 @@ Rails.application.configure do
else
Rails.logger.warn "Stripe secret key not found - Stripe will not be initialized"
end
-end
\ No newline at end of file
+end
diff --git a/config/initializers/ticket_cleanup_scheduler.rb b/config/initializers/ticket_cleanup_scheduler.rb
index ba1e8d7..a13f870 100644
--- a/config/initializers/ticket_cleanup_scheduler.rb
+++ b/config/initializers/ticket_cleanup_scheduler.rb
@@ -15,9 +15,9 @@ Rails.application.config.after_initialize do
rescue => e
Rails.logger.error "Failed to schedule expired drafts cleanup: #{e.message}"
end
-
+
sleep 10.minutes
end
end
end
-end
\ No newline at end of file
+end
diff --git a/config/routes.rb b/config/routes.rb
index e48b4a8..88ad1ea 100755
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -42,7 +42,7 @@ Rails.application.routes.draw do
get "events/:slug.:id/orders/new", to: "orders#new", as: "event_order_new"
post "events/:slug.:id/orders", to: "orders#create", as: "event_order_create"
- resources :orders, only: [:show] do
+ resources :orders, only: [ :show ] do
member do
get :checkout
post :retry_payment
diff --git a/db/migrate/20250816145933_devise_create_users.rb b/db/migrate/20250816145933_devise_create_users.rb
index d96ab0a..4075e7f 100755
--- a/db/migrate/20250816145933_devise_create_users.rb
+++ b/db/migrate/20250816145933_devise_create_users.rb
@@ -43,6 +43,8 @@ class DeviseCreateUsers < ActiveRecord::Migration[8.0]
# t.string :company_email, null: true # Email de la société
# t.string :company_website, null: true # Site web de la société
+ t.string :stripe_customer_id, null: true
+
t.timestamps null: false
end
diff --git a/db/migrate/20250823170409_create_orders.rb b/db/migrate/20250823170409_create_orders.rb
index 8e0f057..7c1a3ad 100644
--- a/db/migrate/20250823170409_create_orders.rb
+++ b/db/migrate/20250823170409_create_orders.rb
@@ -13,8 +13,8 @@ class CreateOrders < ActiveRecord::Migration[8.0]
end
# Indexes for performance
- add_index :orders, [:user_id, :status], name: 'idx_orders_user_status'
- add_index :orders, [:event_id, :status], name: 'idx_orders_event_status'
+ add_index :orders, [ :user_id, :status ], name: 'idx_orders_user_status'
+ add_index :orders, [ :event_id, :status ], name: 'idx_orders_event_status'
add_index :orders, :expires_at, name: 'idx_orders_expires_at'
end
-end
\ No newline at end of file
+end
diff --git a/docs/application-optimization.md b/docs/application-optimization.md
deleted file mode 100755
index 3e4ff1d..0000000
--- a/docs/application-optimization.md
+++ /dev/null
@@ -1,157 +0,0 @@
-# Application.js Size Optimization Guide
-
-## Current Issue
-The `application.js` bundle is 1.4MB (2.3MB with source maps), which is significantly larger than recommended.
-
-## Root Causes
-1. **Single bundle includes everything**: All dependencies, React, controllers, and components
-2. **No code splitting**: Everything is bundled into one file
-3. **Development dependencies**: Alpine.js and other dev tools included
-4. **No minification/optimization**: Source maps and uncompressed code
-
-## Optimization Strategies
-
-### 1. Split Bundles (Recommended)
-Create separate bundles for different parts of the application:
-
-**Update package.json build scripts:**
-```json
-{
- "scripts": {
- "build": "npm run build:main && npm run build:components",
- "build:main": "esbuild app/javascript/application.js --bundle --minify --sourcemap --format=esm --outdir=app/assets/builds --public-path=/assets",
- "build:components": "esbuild app/javascript/components/*.* --bundle --minify --format=esm --outdir=app/assets/builds/components --public-path=/assets --loader:.js=jsx",
- "build:css": "postcss ./app/assets/stylesheets/application.postcss.css -o ./app/assets/builds/application.css"
- }
-}
-```
-
-### 2. Remove Unused Dependencies
-**package.json optimization:**
-```json
-{
- "dependencies": {
- "@hotwired/stimulus": "^3.2.2",
- "@hotwired/turbo-rails": "^8.0.13",
- "@radix-ui/react-slot": "^1.2.3",
- "react": "^18.3.1",
- "react-dom": "^18.3.1"
- },
- "devDependencies": {
- "@tailwindcss/postcss": "^4.1.4",
- "class-variance-authority": "^0.7.1",
- "clsx": "^2.1.1",
- "esbuild": "^0.25.4",
- "postcss": "^8.5.3",
- "tailwind-merge": "^3.3.1",
- "tailwindcss": "^4.1.4",
- "tailwindcss-animate": "^1.0.7"
- }
-}
-```
-
-**Remove these from devDependencies:**
-- `alpinejs` - if not used
-- `@types/alpinejs` - if Alpine.js removed
-- `cssnano` - if using Tailwind's built-in minification
-- `pm2` - production deployment tool
-
-### 3. Dynamic Imports (Code Splitting)
-**Update application.js:**
-```javascript
-// Instead of importing everything statically
-import "@hotwired/turbo-rails"
-import "./controllers"
-
-// Use dynamic imports for heavy components
-const loadComponent = async (componentName) => {
- const { default: component } = await import(`./components/${componentName}`)
- return component
-}
-```
-
-### 4. Tree Shaking & Minification
-**Enhanced build command:**
-```json
-{
- "build": "esbuild app/javascript/application.js --bundle --minify --tree-shaking --drop:console --drop:debugger --sourcemap=external --format=esm --outdir=app/assets/builds --public-path=/assets"
-}
-```
-
-### 5. Separate Vendor Bundle
-**Create vendor.js:**
-```javascript
-// app/javascript/vendor.js
-import "react"
-import "react-dom"
-import "@radix-ui/react-slot"
-```
-
-**Update build to create vendor bundle:**
-```json
-{
- "build:vendor": "esbuild app/javascript/vendor.js --bundle --minify --format=esm --outdir=app/assets/builds --public-path=/assets",
- "build:app": "esbuild app/javascript/application.js --bundle --minify --external:react --external:react-dom --format=esm --outdir=app/assets/builds --public-path=/assets"
-}
-```
-
-### 6. Conditional Loading
-**Lazy load heavy components:**
-```javascript
-// app/javascript/application.js
-if (document.querySelector('[data-controller="shadcn-test"]')) {
- import('./controllers/shadcn_test_controller')
-}
-```
-
-### 7. Production Optimization Checklist
-
-**Step 1: Analyze bundle size**
-```bash
-npm install --save-dev webpack-bundle-analyzer
-npx esbuild app/javascript/application.js --bundle --analyze
-```
-
-**Step 2: Implement optimizations**
-```bash
-# Remove unused dependencies
-npm uninstall alpinejs @types/alpinejs cssnano pm2
-
-# Update build scripts
-npm run build
-```
-
-**Step 3: Verify size reduction**
-Should reduce from 1.4MB to ~200-400KB
-
-## Quick Fix Commands
-
-```bash
-# 1. Remove Alpine.js (if unused)
-npm uninstall alpinejs @types/alpinejs
-
-# 2. Update build with optimization
-npm install --save-dev esbuild@latest
-
-# 3. Modify package.json scripts
-# (Copy the optimized scripts above)
-
-# 4. Build with optimization
-npm run build
-```
-
-## Expected Results
-- **Before**: 1.4MB application.js
-- **After**: 200-400KB with code splitting
-- **Vendor bundle**: ~100KB (cached)
-- **App bundle**: ~100-300KB (dynamic)
-
-## Monitoring
-Add bundle size monitoring to CI/CD:
-```json
-{
- "size-limits": {
- "app/assets/builds/application.js": "500kb",
- "app/assets/builds/application.css": "50kb"
- }
-}
\ No newline at end of file
diff --git a/docs/architecture.md b/docs/architecture.md
deleted file mode 100755
index 1000d3b..0000000
--- a/docs/architecture.md
+++ /dev/null
@@ -1,363 +0,0 @@
-# Aperonight - Technical Architecture
-
-## Overview
-
-Aperonight is a Ruby on Rails web application designed for proposing night parties in Paris and allowing event makers to create their own events. The application serves two primary user groups:
-
-### For Customers:
-- View upcoming and past parties
-- Book tickets with customizable bundles (simple entry, VIP, group passes, etc.)
-- Complete secure payments via credit card, PayPal, or bank transfer
-- Access mobile-friendly interface for ticket management
-- Receive unique, scannable tickets (QR codes)
-
-### For Promoters:
-- Create and schedule parties
-- Define custom ticket bundles and pricing
-- Aggregate events from external platforms (Shogun, Bizouk, Weezevent)
-- Scan tickets at events using mobile devices
-
-## Technical Architecture
-
-### 1. Database Schema
-
-```ruby
-# User - Handles both customers and promoters
-create_table :users do |t|
- t.string :email
- t.string :password_digest
- t.string :role # customer or promoter
- t.timestamps
-end
-
-# Event - Events created by promoters
-create_table :events do |t|
- t.string :name
- t.text :description
- t.datetime :start_time
- t.datetime :end_time
- t.string :location
- t.integer :promoter_id
- t.timestamps
-end
-
-# TicketType - Customizable bundles defined by promoters
-create_table :ticket_types do |t|
- t.string :name
- t.text :description
- t.decimal :price
- t.integer :event_id
- t.timestamps
-end
-
-# Ticket - Individual ticket instances purchased by customers
-create_table :tickets do |t|
- t.string :uuid
- t.string :qr_code
- t.integer :event_id
- t.integer :user_id
- t.integer :ticket_type_id
- t.boolean :used, default: false
- t.timestamps
-end
-
-# Payment - Transaction records for ticket purchases
-create_table :payments do |t|
- t.string :payment_method # credit_card, paypal, bank_account
- t.string :transaction_id
- t.integer :user_id
- t.integer :ticket_id
- t.decimal :amount
- t.timestamps
-end
-```
-
-### 2. Core Models
-
-```ruby
-class User < ApplicationRecord
- devise :database_authenticatable, :registerable,
- :recoverable, :rememberable, :validatable
- has_many :tickets
- has_many :payments
- has_many :parties, foreign_key: 'promoter_id'
-end
-
-class Event < ApplicationRecord
- belongs_to :promoter, class_name: 'User'
- has_many :tickets
- has_many :ticket_types
-end
-
-class TicketType < ApplicationRecord
- belongs_to :event
- has_many :tickets
-end
-
-class Ticket < ApplicationRecord
- belongs_to :event
- belongs_to :user
- belongs_to :ticket_type
- has_one :payment
-
- before_create :generate_uuid_and_qr_code
-
- private
-
- def generate_uuid_and_qr_code
- self.uuid = SecureRandom.uuid
- self.qr_code = RQRCode::QRCode.new(self.uuid).as_svg
- end
-end
-
-class Payment < ApplicationRecord
- belongs_to :user
- belongs_to :ticket
-
- enum payment_method: {
- credit_card: 'credit_card',
- paypal: 'paypal',
- bank_account: 'bank_account'
- }
-
- after_create :process_payment
-
- private
-
- def process_payment
- case self.payment_method
- when 'credit_card'
- process_stripe_payment
- when 'paypal'
- process_paypal_payment
- when 'bank_account'
- process_bank_account_payment
- end
- end
-end
-```
-
-### 3. Key Controllers
-
-#### Parties Controller
-```ruby
-class PartiesController < ApplicationController
- before_action :authenticate_user!
- before_action :set_event, only: [:show, :edit, :update, :destroy]
-
- def index
- @parties = Event.all
- end
-
- def show
- @ticket_types = @event.ticket_types
- end
-
- def new
- @event = Event.new
- @event.ticket_types.build
- end
-
- def create
- @event = current_user.parties.build(event_params)
- if @event.save
- redirect_to @event, notice: 'Event was successfully created.'
- else
- render :new
- end
- end
-
- private
-
- def set_event
- @event = Event.find(params[:id])
- end
-
- def event_params
- params.require(:event).permit(
- :name, :description, :start_time, :end_time, :location,
- ticket_types_attributes: [:id, :name, :description, :price, :_destroy]
- )
- end
-end
-```
-
-#### Tickets Controller
-```ruby
-class TicketsController < ApplicationController
- before_action :authenticate_user!
- before_action :set_event, only: [:new, :create]
-
- def new
- @ticket = Ticket.new
- end
-
- def create
- @ticket = current_user.tickets.build(ticket_params)
- if @ticket.save
- redirect_to @ticket, notice: 'Ticket was successfully booked.'
- else
- render :new
- end
- end
-
- def scan
- end
-
- def validate
- qr_code = params[:qr_code]
- ticket = Ticket.find_by(qr_code: qr_code)
- if ticket && !ticket.used
- ticket.update(used: true)
- render json: { valid: true }
- else
- render json: { valid: false }
- end
- end
-
- private
-
- def set_event
- @event = Event.find(params[:event_id])
- end
-
- def ticket_params
- params.require(:ticket).permit(:ticket_type_id, :event_id)
- end
-end
-```
-
-### 4. Payment Integration
-
-#### Stripe Configuration
-```ruby
-# config/initializers/stripe.rb
-Rails.configuration.stripe = {
- publishable_key: ENV['STRIPE_PUBLISHABLE_KEY'],
- secret_key: ENV['STRIPE_SECRET_KEY']
-}
-
-Stripe.api_key = Rails.configuration.stripe[:secret_key]
-```
-
-#### PayPal Configuration
-```ruby
-# config/initializers/paypal.rb
-PayPal::SDK.configure({
- mode: ENV['PAYPAL_MODE'], # 'sandbox' or 'live'
- client_id: ENV['PAYPAL_CLIENT_ID'],
- client_secret: ENV['PAYPAL_CLIENT_SECRET']
-})
-```
-
-### 5. Frontend Considerations
-
-#### Mobile Ticket Scanning
-```erb
-
-
-
-
- Scan Ticket
-
-
-
- Scan Ticket
-
-
-
-
-
-```
-
-### 6. Routes Configuration
-
-```ruby
-# config/routes.rb
-Rails.application.routes.draw do
- devise_for :users
- resources :parties do
- resources :ticket_types, only: [:new, :create, :edit, :update, :destroy]
- end
- resources :ticket_types, only: [:index, :show]
- resources :tickets do
- resources :payments, only: [:new, :create]
- collection do
- post 'validate'
- end
- end
- get 'paypal_success', to: 'payments#paypal_success'
- get 'paypal_cancel', to: 'payments#paypal_cancel'
- get 'tickets/scan', to: 'tickets#scan'
- root 'parties#index'
-end
-```
-
-## Implementation Recommendations
-
-### Authentication & Authorization
-- Use Devise for user authentication
-- Implement Pundit or CanCanCan for role-based access control
-- Distinguish clearly between customer and promoter permissions
-
-### Payment Processing
-- Integrate Stripe for credit card payments
-- Add PayPal support through official SDK
-- Consider Plaid for bank account integration
-
-### Performance & Scalability
-- Implement Redis for caching frequently accessed data
-- Use CDN for static assets (images, CSS, JS)
-- Employ background job processing (Sidekiq) for emails and payments
-- Optimize database queries with proper indexing
-
-### Security Considerations
-- Validate all user inputs
-- Sanitize HTML output to prevent XSS
-- Secure payment processing with PCI compliance
-- Implement rate limiting for API endpoints
-- Regular security audits and dependency updates
-
diff --git a/docs/branch-naming.md b/docs/branch-naming.md
deleted file mode 100755
index c8e1367..0000000
--- a/docs/branch-naming.md
+++ /dev/null
@@ -1,142 +0,0 @@
-Cette conversation a été générée avec Duck.ai (https://duck.ai) à l'aide du modèle Mistral Small 3 d'Mistral AI. Les chats IA peuvent afficher des informations inexactes ou offensantes (voir https://duckduckgo.com/duckai/privacy-terms pour en savoir plus).
-
-====================
-
-Message 1 sur 2 de l'utilisateur - 16/08/2025, 08:06:58:
-In a git Ruby on Rails web project, how to name branches?
-
-Mistral Small 3:
-Naming branches in a Git Ruby on Rails web project (or any Git project) is an important aspect of maintaining a clean and understandable repository. Here are some best practices for naming branches:
-
-1. **Use Descriptive Names**: The branch name should clearly describe the purpose or the feature being worked on. This helps other developers understand the context of the branch at a glance.
-
-2. **Use Hyphens or Underscores**: Use hyphens (`-`) or underscores (`_`) to separate words in the branch name. This makes the name more readable.
-
-3. **Prefix with the Type of Change**: Prefix the branch name with a type indicator such as `feature`, `bugfix`, `hotfix`, `release`, `chore`, `refactor`, `docs`, etc. This helps in categorizing the branches.
-
-4. **Keep It Short but Meaningful**: While being descriptive, try to keep the branch name short to avoid clutter.
-
-5. **Avoid Special Characters**: Stick to alphanumeric characters and hyphens/underscores. Avoid using special characters like `@`, `#`, `$`, etc.
-
-6. **Use Lowercase Letters**: Consistently use lowercase letters to avoid case sensitivity issues.
-
-Here are some examples of well-named branches:
-
-- `feature/user-authentication`
-- `bugfix/login-issue`
-- `hotfix/critical-bug`
-- `release/v1.2.0`
-- `chore/update-dependencies`
-- `refactor/user-model`
-- `docs/update-readme`
-
-### Example Workflow
-
-1. **Creating a New Feature Branch**:
- ```sh
- git checkout -b feature/user-authentication
- ```
-
-2. **Creating a Bugfix Branch**:
- ```sh
- git checkout -b bugfix/login-issue
- ```
-
-3. **Creating a Hotfix Branch**:
- ```sh
- git checkout -b hotfix/critical-bug
- ```
-
-4. **Creating a Release Branch**:
- ```sh
- git checkout -b release/v1.2.0
- ```
-
-5. **Creating a Chore Branch**:
- ```sh
- git checkout -b chore/update-dependencies
- ```
-
-6. **Creating a Refactor Branch**:
- ```sh
- git checkout -b refactor/user-model
- ```
-
-7. **Creating a Docs Branch**:
- ```sh
- git checkout -b docs/update-readme
- ```
-
-By following these guidelines, you can maintain a well-organized and understandable branch structure in your Git repository, making collaboration and code management much easier.
-
---------------------
-
-Message 2 sur 2 de l'utilisateur - 16/08/2025, 08:08:31:
-Is it a good practice to use main, develop and functionnal names for branches?
-
-Mistral Small 3:
-Using `main`, `develop`, and feature branches is a common and widely accepted practice in Git workflows, particularly in the context of the Git Flow or GitHub Flow methodologies. Here's a breakdown of these branches and why they are useful:
-
-1. **`main` Branch**:
- - **Purpose**: The `main` branch (or sometimes called `master`) is the stable branch that always contains the production-ready code. It represents the current state of the project that is deployed to production.
- - **Usage**: This branch should only contain code that has been thoroughly tested and is ready for release. It is typically protected to prevent direct commits and requires pull requests for changes.
- - **Example**: `git checkout main`
-
-2. **`develop` Branch**:
- - **Purpose**: The `develop` branch is used for integrating features and preparing for the next release. It serves as a staging area for features that are in progress but not yet ready for production.
- - **Usage**: Developers merge their feature branches into `develop` for integration testing. This branch can be less stable than `main` but should still be in a reasonably good state.
- - **Example**: `git checkout develop`
-
-3. **Feature Branches**:
- - **Purpose**: Feature branches are used to develop new features, bug fixes, or any other isolated work. Each feature branch is created from `develop` and merged back into `develop` once the work is complete.
- - **Usage**: These branches allow for parallel development without interfering with the stability of `develop` or `main`. They are typically named descriptively, as discussed earlier (e.g., `feature/user-authentication`, `bugfix/login-issue`).
- - **Example**: `git checkout -b feature/user-authentication`
-
-### Example Workflow
-
-1. **Create a Feature Branch**:
- ```sh
- git checkout develop
- git pull origin develop
- git checkout -b feature/user-authentication
- ```
-
-2. **Develop the Feature**:
- - Make changes, commit them, and push the branch to the remote repository.
- ```sh
- git add .
- git commit -m "Add user authentication feature"
- git push origin feature/user-authentication
- ```
-
-3. **Merge the Feature Branch into `develop`**:
- - Once the feature is complete and tested, create a pull request to merge it into `develop`.
- ```sh
- git checkout develop
- git pull origin develop
- git merge feature/user-authentication
- git push origin develop
- ```
-
-4. **Prepare for Release**:
- - When preparing for a new release, create a release branch from `develop`.
- ```sh
- git checkout -b release/v1.2.0
- ```
-
-5. **Merge Release Branch into `main`**:
- - After testing the release branch, merge it into `main` and tag the release.
- ```sh
- git checkout main
- git merge release/v1.2.0
- git tag -a v1.2.0 -m "Release version 1.2.0"
- git push origin main --tags
- ```
-
-### Benefits
-
-- **Stability**: The `main` branch remains stable and always contains production-ready code.
-- **Integration**: The `develop` branch allows for continuous integration of features, making it easier to test and integrate new work.
-- **Isolation**: Feature branches isolate work, allowing multiple developers to work on different features simultaneously without conflicts.
-
-Using `main`, `develop`, and feature branches is a good practice as it helps maintain a clean, organized, and manageable repository, facilitating better collaboration and code management.
\ No newline at end of file
diff --git a/docs/checkout-handle.md b/docs/checkout-handle.md
deleted file mode 100755
index c8c78fb..0000000
--- a/docs/checkout-handle.md
+++ /dev/null
@@ -1,322 +0,0 @@
-# Backend Checkout Handling Improvements
-
-Based on your current Stripe integration, here are key improvements for robust checkout handling:
-
-## 1. Enhanced Inventory Management with Concurrency Protection
-
-The current implementation doesn't prevent overselling during concurrent purchases.
-
-Add database-level concurrency protection:
-
-```ruby
-# app/controllers/events_controller.rb
-def checkout
- cart_data = JSON.parse(params[:cart] || "{}")
-
- if cart_data.empty?
- redirect_to event_path(@event.slug, @event), alert: "Veuillez sélectionner au moins un billet"
- return
- end
-
- # Use transaction with row-level locking for inventory protection
- ActiveRecord::Base.transaction do
- line_items = []
- order_items = []
-
- cart_data.each do |ticket_type_id, item|
- # Lock the ticket type row to prevent race conditions
- ticket_type = @event.ticket_types.lock.find_by(id: ticket_type_id)
- next unless ticket_type
-
- quantity = item["quantity"].to_i
- next if quantity <= 0
-
- # Check real-time availability with locked row
- sold_count = ticket_type.tickets.count
- available = ticket_type.quantity - sold_count
-
- if quantity > available
- redirect_to event_path(@event.slug, @event), alert: "Plus que #{available} billets disponibles pour #{ticket_type.name}"
- return
- end
-
- # Create line items and order data
- line_items << {
- price_data: {
- currency: "eur",
- product_data: {
- name: "#{@event.name} - #{ticket_type.name}",
- description: ticket_type.description
- },
- unit_amount: ticket_type.price_cents
- },
- quantity: quantity
- }
-
- order_items << {
- ticket_type_id: ticket_type.id,
- ticket_type_name: ticket_type.name,
- quantity: quantity,
- price_cents: ticket_type.price_cents
- }
- end
-
- if order_items.empty?
- redirect_to event_path(@event.slug, @event), alert: "Commande invalide"
- return
- end
-
- # Create Stripe session only after inventory validation
- session = Stripe::Checkout::Session.create({
- payment_method_types: ["card"],
- line_items: line_items,
- mode: "payment",
- success_url: payment_success_url(event_id: @event.id, session_id: "{CHECKOUT_SESSION_ID}"),
- cancel_url: event_url(@event.slug, @event),
- customer_email: current_user.email,
- metadata: {
- event_id: @event.id,
- user_id: current_user.id,
- order_items: order_items.to_json
- }
- })
-
- redirect_to session.url, allow_other_host: true
- end
-rescue ActiveRecord::RecordNotFound
- redirect_to event_path(@event.slug, @event), alert: "Type de billet introuvable"
-rescue Stripe::StripeError => e
- redirect_to event_path(@event.slug, @event), alert: "Erreur de traitement du paiement : #{e.message}"
-end
-```
-
-## 2. Webhook Handler for Reliable Payment Confirmation
-
-Create a dedicated webhook endpoint for more reliable payment processing:
-
-### Routes Configuration
-
-```ruby
-# config/routes.rb
-post '/webhooks/stripe', to: 'webhooks#stripe'
-```
-
-### Webhooks Controller
-
-```ruby
-# app/controllers/webhooks_controller.rb
-class WebhooksController < ApplicationController
- skip_before_action :verify_authenticity_token
- before_action :verify_stripe_signature
-
- def stripe
- case @event.type
- when 'checkout.session.completed'
- handle_successful_payment(@event.data.object)
- when 'payment_intent.payment_failed'
- handle_failed_payment(@event.data.object)
- end
-
- head :ok
- end
-
- private
-
- def handle_successful_payment(session)
- # Process ticket creation in background job for reliability
- CreateTicketsJob.perform_later(session.id)
- end
-
- def handle_failed_payment(session)
- Rails.logger.error "Payment failed for session: #{session.id}"
- # Add any additional handling for failed payments
- end
-
- def verify_stripe_signature
- payload = request.body.read
- sig_header = request.env['HTTP_STRIPE_SIGNATURE']
-
- begin
- @event = Stripe::Webhook.construct_event(
- payload, sig_header, ENV['STRIPE_WEBHOOK_SECRET']
- )
- rescue JSON::ParserError, Stripe::SignatureVerificationError => e
- Rails.logger.error "Stripe webhook signature verification failed: #{e.message}"
- head :bad_request
- end
- end
-end
-```
-
-## 3. Background Job for Ticket Creation
-
-Use background jobs to prevent timeouts and improve reliability:
-
-```ruby
-# app/jobs/create_tickets_job.rb
-class CreateTicketsJob < ApplicationJob
- queue_as :default
- retry_on StandardError, wait: :exponentially_longer, attempts: 5
-
- def perform(session_id)
- session = Stripe::Checkout::Session.retrieve(session_id)
- return unless session.payment_status == 'paid'
-
- # Prevent duplicate processing
- return if Ticket.exists?(stripe_session_id: session_id)
-
- order_items = JSON.parse(session.metadata['order_items'])
- user = User.find(session.metadata['user_id'])
- event = Event.find(session.metadata['event_id'])
-
- ActiveRecord::Base.transaction do
- order_items.each do |item|
- ticket_type = TicketType.find(item['ticket_type_id'])
-
- item['quantity'].times do
- ticket = Ticket.create!(
- user: user,
- ticket_type: ticket_type,
- status: 'active',
- stripe_session_id: session_id, # Prevent duplicates
- price_cents: item['price_cents'] # Store historical price
- )
-
- # Send email asynchronously
- TicketMailer.purchase_confirmation(ticket).deliver_later
- end
- end
- end
- end
-end
-```
-
-## 4. Enhanced Error Handling & Recovery in Payment Success
-
-Improve the payment success handler with better error recovery:
-
-```ruby
-# app/controllers/events_controller.rb - Enhanced payment_success method
-def payment_success
- session_id = params[:session_id]
- event_id = params[:event_id]
-
- # Validate parameters
- unless session_id.present? && event_id.present?
- redirect_to dashboard_path, alert: "Paramètres de confirmation manquants"
- return
- end
-
- begin
- @tickets = Ticket.includes(:ticket_type, :event)
- .where(stripe_session_id: session_id, user: current_user)
-
- if @tickets.any?
- # Tickets already created (webhook processed first)
- @event = @tickets.first.event
- render 'payment_success'
- else
- # Fallback: create tickets synchronously if webhook failed
- session = Stripe::Checkout::Session.retrieve(session_id)
-
- if session.payment_status == 'paid'
- CreateTicketsJob.perform_now(session_id)
- redirect_to payment_success_path(session_id: session_id, event_id: event_id)
- else
- redirect_to dashboard_path, alert: "Le paiement n'est pas encore confirmé"
- end
- end
-
- rescue Stripe::StripeError => e
- logger.error "Stripe error in payment_success: #{e.message}"
- redirect_to dashboard_path, alert: "Erreur de confirmation de paiement"
- rescue => e
- logger.error "Unexpected error in payment_success: #{e.message}"
- redirect_to dashboard_path, alert: "Une erreur inattendue s'est produite"
- end
-end
-```
-
-## 5. Database Schema Improvements
-
-Add migration for better payment tracking:
-
-```ruby
-# db/migrate/xxx_add_payment_tracking_to_tickets.rb
-class AddPaymentTrackingToTickets < ActiveRecord::Migration[7.0]
- def change
- add_column :tickets, :stripe_session_id, :string
- add_column :tickets, :purchased_at, :timestamp, default: -> { 'CURRENT_TIMESTAMP' }
-
- add_index :tickets, :stripe_session_id, unique: true
- add_index :tickets, [:user_id, :purchased_at]
- end
-end
-```
-
-## 6. Security Considerations
-
-1. **Rate Limiting**: Add rate limiting to checkout endpoints
-2. **CSRF Protection**: Already implemented ✅
-3. **Input Validation**: Validate all cart data thoroughly
-4. **Audit Logging**: Log all payment attempts and outcomes
-5. **PCI Compliance**: Never store card data (Stripe handles this) ✅
-
-## 7. Monitoring & Observability
-
-Add metrics tracking to monitor checkout performance:
-
-```ruby
-# Add to ApplicationController or EventsController
-around_action :track_checkout_metrics, only: [:checkout]
-
-private
-
-def track_checkout_metrics
- start_time = Time.current
- begin
- yield
- # Log successful checkout
- Rails.logger.info("Checkout completed", {
- event_id: @event&.id,
- user_id: current_user&.id,
- duration: Time.current - start_time
- })
- rescue => e
- # Log failed checkout
- Rails.logger.error("Checkout failed", {
- event_id: @event&.id,
- user_id: current_user&.id,
- error: e.message,
- duration: Time.current - start_time
- })
- raise
- end
-end
-```
-
-## Summary of Improvements
-
-Your ticket checkout system is already well-implemented with Stripe integration! The enhancements above will make it production-ready:
-
-### Critical Improvements
-
-1. Add database row locking to prevent overselling during concurrent purchases
-2. Implement Stripe webhooks for reliable payment processing
-3. Use background jobs for ticket creation to prevent timeouts
-4. Add duplicate prevention with stripe_session_id tracking
-
-### Security & Reliability
-
-5. Enhanced error recovery with fallback ticket creation
-6. Comprehensive logging for debugging and monitoring
-7. Database schema improvements for better payment tracking
-
-### Key Files to Modify
-
-- `app/controllers/events_controller.rb` - Add inventory locking
-- `app/controllers/webhooks_controller.rb` - New webhook handler
-- `app/jobs/create_tickets_job.rb` - Background ticket creation
-- Migration for `stripe_session_id` field
-
-These enhancements will make your checkout system robust for high-traffic scenarios and edge cases.
diff --git a/docs/theme-rules.md.old b/docs/theme-rules.md.old
deleted file mode 100755
index 4274d4b..0000000
--- a/docs/theme-rules.md.old
+++ /dev/null
@@ -1,103 +0,0 @@
-# Theme Rules & Color Palette - Aperonight
-
-Extracted from `app/views/pages/home.html.erb`
-
-## Color Palette
-
-### Primary Colors
-- **Indigo**: `#4338ca` (rgb(67, 56, 202)) - Used in hero gradient
-- **Purple**: `#8b5cf6` (rgb(139, 92, 246)) - Primary brand color
-- **Pink**: `#ec4899` (rgb(236, 72, 153)) - Accent color
-
-### Background Gradients
-- **Hero**: `bg-gradient-to-br from-indigo-900 via-purple-800 to-pink-700`
-- **CTA**: `bg-gradient-to-r from-purple-900 via-indigo-900 to-pink-900`
-- **Cards**: `bg-gradient-to-br from-gray-800 to-gray-900`
-- **Buttons**: `bg-gradient-to-r from-purple-600 to-pink-600`
-
-### Text Colors
-- **White**: `text-white` - Primary text
-- **Gray-200**: `text-gray-200` - Secondary text
-- **Gray-300**: `text-gray-300` - Subtle text
-- **Gray-400**: `text-gray-400` - Muted text
-- **Transparent gradient**: `text-transparent bg-clip-text bg-gradient-to-r from-purple-400 to-pink-400` - Special highlight
-
-### Background Colors
-- **Gray-900**: `bg-gray-900` - Main background
-- **Black**: `bg-black` - Overlay backgrounds
-- **Gray-800**: `bg-gray-800` - Card backgrounds
-- **White/Transparent**: `bg-white bg-opacity-10 backdrop-blur-sm` - Glass effect
-
-## Spacing & Layout
-
-### Hero Section
-- **Height**: `min-h-[70vh]`
-- **Max-width**: `max-w-7xl mx-auto`
-- **Padding**: `px-4 sm:px-6 lg:px-8`
-
-### Grid Layouts
-- **Responsive**: `grid-cols-1 md:grid-cols-2 lg:grid-cols-3`
-- **Gap**: `gap-8` standard spacing
-
-### Padding Classes
-- **Section**: `py-16`, `py-20`
-- **Card**: `p-4`, `p-6`, `p-8`
-- **Button**: `py-3`, `py-4`, `px-6`, `px-8`
-
-## Typography
-
-### Font Sizes
-- **Hero Title**: `text-5xl md:text-7xl`
-- **Section Title**: `text-4xl`
-- **Card Title**: `text-2xl`
-- **Body**: `text-xl`, `text-lg`
-- **Small**: `text-sm`
-
-### Font Weights
-- **Bold**: `font-bold` (headings)
-- **Semibold**: `font-semibold` (buttons, important text)
-- **Medium**: `font-medium` (labels)
-
-## Interactive States
-
-### Hover Effects
-- **Scale**: `hover:scale-105`
-- **Transition**: `transition-all duration-300`
-- **Button Hover**: `hover:from-purple-700 hover:to-pink-700`
-- **Glass Hover**: `hover:bg-opacity-20`
-
-### Shadows
-- **Default**: `shadow-lg`
-- **Strong**: `shadow-xl`
-- **Card**: `shadow-2xl`
-
-## Border Radius
-- **Buttons**: `rounded-full` (pill-shaped)
-- **Cards**: `rounded-2xl`
-- **Inputs**: `rounded-lg`
-
-## Icon Colors
-- **Primary**: `text-white` (on colored backgrounds)
-- **Accent**: `text-purple-400`, `text-pink-400`
-- **Muted**: `text-gray-400`
-
-## Usage Examples
-
-### Primary Button
-```html
-class="bg-gradient-to-r from-purple-600 to-pink-600 hover:from-purple-700 hover:to-pink-700 text-white font-semibold py-4 px-8 rounded-full transition-all duration-300 transform hover:scale-105 shadow-lg"
-```
-
-### Card Background
-```html
-class="bg-gradient-to-br from-gray-800 to-gray-900 rounded-2xl overflow-hidden hover:transform hover:scale-105 transition-all duration-300 shadow-xl"
-```
-
-### Hero Gradient
-```html
-class="bg-gradient-to-br from-indigo-900 via-purple-800 to-pink-700"
-```
-
-### Glass Effect
-```html
-class="bg-white bg-opacity-10 backdrop-blur-sm border border-white border-opacity-30"
\ No newline at end of file
diff --git a/lib/tasks/tickets.rake b/lib/tasks/tickets.rake
index 14bef56..6ce6cf5 100644
--- a/lib/tasks/tickets.rake
+++ b/lib/tasks/tickets.rake
@@ -11,7 +11,7 @@ namespace :tickets do
total_drafts = Ticket.draft.count
expired_drafts = Ticket.expired_drafts.count
retryable_drafts = Ticket.can_retry_payment.count
-
+
puts "=== Draft Ticket Statistics ==="
puts "Total draft tickets: #{total_drafts}"
puts "Expired draft tickets: #{expired_drafts}"
@@ -19,4 +19,4 @@ namespace :tickets do
puts "Max payment attempts: #{Ticket::MAX_PAYMENT_ATTEMPTS}"
puts "Draft expiry time: #{Ticket::DRAFT_EXPIRY_TIME}"
end
-end
\ No newline at end of file
+end
diff --git a/stripe-fix-documentation.md b/stripe-fix-documentation.md
deleted file mode 100644
index 599519d..0000000
--- a/stripe-fix-documentation.md
+++ /dev/null
@@ -1,47 +0,0 @@
-# Stripe Configuration Fix - Updated with Lazy Initialization
-
-## Problem
-The "Retour" link on the collect_names page sometimes displayed a Stripe API key error:
-```
-Erreur de traitement du paiement : No API key provided. Set your API key using "Stripe.api_key = ".
-```
-
-## Root Cause
-The error occurred when Stripe code was executed without the API key being properly set. This could happen in development environments or when environment variables were not properly configured.
-
-## Solution Evolution
-
-We initially implemented a fix that enhanced the Stripe initializer and added better error handling. However, we have now updated our approach to use **lazy initialization** - Stripe is only initialized during the checkout process when actually needed.
-
-## Current Solution - Lazy Initialization Approach
-
-1. **Deferred Stripe Initialization** (`config/initializers/stripe.rb`):
- - Stripe configuration is loaded at startup but API key is NOT set
- - Stripe.api_key is only set during the checkout process when needed
-
-2. **Enhanced Stripe Helper** (`app/helpers/stripe_helper.rb`):
- - Added `initialize_stripe` method to initialize Stripe only when needed
- - Updated `safe_stripe_call` method to automatically initialize Stripe if not already done
-
-3. **Checkout Process Updates**:
- - Added explicit Stripe initialization in `process_payment` method
- - Added explicit Stripe initialization in `payment_success` method
- - Added proper error handling for initialization failures
-
-4. **Benefits of This Approach**:
- - Stripe is only initialized when actually needed (during checkout)
- - Application startup is not dependent on Stripe service availability
- - Payment-related issues are isolated and don't affect other application features
- - More efficient resource usage (Stripe library only fully loaded during checkout)
-
-## Verification
-The fix has been tested and verified to work correctly:
-- Stripe is not initialized at application startup
-- Stripe is properly initialized during the checkout process
-- All Stripe functionality works as expected
-- Error handling is improved
-
-## Prevention
-The enhanced error handling will prevent the application from crashing when Stripe is not properly configured and will display user-friendly error messages instead.
-
-For detailed implementation, see `stripe-lazy-initialization-documentation.md`.
\ No newline at end of file
diff --git a/stripe-lazy-initialization-documentation.md b/stripe-lazy-initialization-documentation.md
deleted file mode 100644
index c72b48b..0000000
--- a/stripe-lazy-initialization-documentation.md
+++ /dev/null
@@ -1,60 +0,0 @@
-# Stripe Configuration - Lazy Initialization Approach
-
-## Problem
-The "Retour" link on the collect_names page sometimes displayed a Stripe API key error:
-```
-Erreur de traitement du paiement : No API key provided. Set your API key using "Stripe.api_key = ".
-```
-
-## Root Cause
-The error occurred because Stripe code was being called without the API key being properly set. This could happen in development environments or when environment variables were not properly configured.
-
-## Solution Implemented - Lazy Initialization
-
-1. **Deferred Stripe Initialization** (`config/initializers/stripe.rb`):
- - Stripe configuration is loaded at startup but API key is NOT set
- - Stripe.api_key is only set during the checkout process when needed
-
-2. **Stripe Concern** (`app/controllers/concerns/stripe_concern.rb`):
- - Created `StripeConcern` module with `stripe_configured?` and `initialize_stripe` methods
- - Included in `EventsController` to provide access to Stripe functionality
-
-3. **Direct Configuration Checks**:
- - Updated `process_payment` and `payment_success` methods to directly check Stripe configuration
- - Added proper error handling for initialization failures
-
-4. **Benefits of This Approach**:
- - Stripe is only initialized when actually needed (during checkout)
- - Application startup is not dependent on Stripe service availability
- - Payment-related issues are isolated and don't affect other application features
- - More efficient resource usage (Stripe library only fully loaded during checkout)
-
-5. **Verification**:
- - Created test scripts to verify the lazy initialization approach
- - Confirmed that Stripe is not initialized at startup but can be initialized during checkout
-
-## Code Changes
-
-### config/initializers/stripe.rb
-- Removed automatic Stripe.api_key initialization
-- Added informational log message
-
-### app/controllers/concerns/stripe_concern.rb
-- Created new concern with `stripe_configured?` and `initialize_stripe` methods
-
-### app/controllers/events_controller.rb
-- Added direct Stripe configuration checks in `process_payment` method
-- Added direct Stripe configuration checks in `payment_success` method
-- Added comprehensive logging for debugging
-
-### app/helpers/stripe_helper.rb
-- Kept `safe_stripe_call` method with updated logic
-
-## Testing
-The new approach has been verified to work correctly:
-- Stripe is not initialized at application startup
-- Stripe is properly initialized during the checkout process
-- All Stripe functionality works as expected
-- Error handling is improved
-
-This approach provides better isolation of payment functionality and ensures that issues with Stripe configuration don't affect the rest of the application.
\ No newline at end of file
diff --git a/test/models/application_record_test.rb b/test/models/application_record_test.rb
index c891411..c0d84c8 100755
--- a/test/models/application_record_test.rb
+++ b/test/models/application_record_test.rb
@@ -11,4 +11,4 @@ class ApplicationRecordTest < ActiveSupport::TestCase
assert_kind_of Class, ApplicationRecord
assert ApplicationRecord < ActiveRecord::Base
end
-end
\ No newline at end of file
+end
diff --git a/test/models/ticket_test.rb b/test/models/ticket_test.rb
index 86f986a..e3cd09e 100755
--- a/test/models/ticket_test.rb
+++ b/test/models/ticket_test.rb
@@ -254,4 +254,3 @@ class TicketTest < ActiveSupport::TestCase
assert ticket.save
end
end
-
diff --git a/test/models/user_test.rb b/test/models/user_test.rb
index b2f7ce5..1110eef 100755
--- a/test/models/user_test.rb
+++ b/test/models/user_test.rb
@@ -63,4 +63,4 @@ class UserTest < ActiveSupport::TestCase
refute user.valid?, "User with last_name longer than 12 chars should be invalid"
assert_not_nil user.errors[:last_name], "No validation error for too long last_name"
end
-end
\ No newline at end of file
+end