Compare commits
3 Commits
ca35abe01d
...
60b7bc6aa7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60b7bc6aa7 | ||
|
|
8d2127fce2 | ||
|
|
2fb0e1fdbb |
10
.env.example
10
.env.example
@@ -30,6 +30,16 @@ SMTP_AUTHENTICATION=plain
|
||||
SMTP_ENABLE_STARTTLS=false
|
||||
# SMTP_STARTTLS=true
|
||||
|
||||
# Invoice Emitter Configuration
|
||||
INVOICE_COMPANY_NAME=AperoNight
|
||||
INVOICE_COMPANY_ADDRESS_LINE_1=123 Avenue des Événements
|
||||
INVOICE_COMPANY_ADDRESS_LINE_2=75000 Paris, France
|
||||
INVOICE_COMPANY_EMAIL=contact@apero-night.fr
|
||||
INVOICE_COMPANY_PHONE=
|
||||
INVOICE_COMPANY_WEBSITE=
|
||||
INVOICE_COMPANY_VAT_NUMBER=
|
||||
INVOICE_COMPANY_SIRET=
|
||||
|
||||
# Application variables
|
||||
STRIPE_PUBLISHABLE_KEY=pk_test_51S1M7BJWx6G2LLIXYpTvi0hxMpZ4tZSxkmr2Wbp1dQ73MKNp4Tyu4xFJBqLXK5nn4E0nEf2tdgJqEwWZLosO3QGn00kMvjXWGW
|
||||
STRIPE_SECRET_KEY=sk_test_51S1M7BJWx6G2LLIXK2pdLpRKb9Mgd3sZ30N4ueVjHepgxQKbWgMVJoa4v4ESzHQ6u6zJjO4jUvgLYPU1QLyAiFTN00sGz2ortW
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
class OnboardingController < ApplicationController
|
||||
before_action :authenticate_user!
|
||||
before_action :redirect_if_onboarding_complete, except: [:complete]
|
||||
before_action :redirect_if_onboarding_complete, except: [ :complete ]
|
||||
|
||||
def index
|
||||
# Display the onboarding form
|
||||
@@ -10,7 +10,7 @@ class OnboardingController < ApplicationController
|
||||
if onboarding_params_valid?
|
||||
current_user.update!(onboarding_params)
|
||||
current_user.complete_onboarding!
|
||||
|
||||
|
||||
flash[:notice] = "Bienvenue sur #{Rails.application.config.app_name} ! Votre profil a été configuré avec succès."
|
||||
redirect_to dashboard_path
|
||||
else
|
||||
@@ -26,7 +26,7 @@ class OnboardingController < ApplicationController
|
||||
end
|
||||
|
||||
def onboarding_params_valid?
|
||||
onboarding_params[:first_name].present? &&
|
||||
onboarding_params[:first_name].present? &&
|
||||
onboarding_params[:last_name].present?
|
||||
end
|
||||
|
||||
|
||||
@@ -9,19 +9,19 @@ class PagesController < ApplicationController
|
||||
def home
|
||||
# Featured events for the main grid (6-9 events like Shotgun)
|
||||
@featured_events = Event.published.featured.includes(:ticket_types).limit(9)
|
||||
|
||||
|
||||
# If no featured events, show latest published events
|
||||
if @featured_events.empty?
|
||||
@featured_events = Event.published.includes(:ticket_types).order(created_at: :desc).limit(9)
|
||||
end
|
||||
|
||||
|
||||
# Upcoming events for additional content
|
||||
@upcoming_events = Event.published.upcoming.limit(6)
|
||||
|
||||
|
||||
# Site metrics for landing page (with realistic fake data for demo)
|
||||
@total_events = [Event.published.count, 50].max # At least 50 events for demo
|
||||
@total_users = [User.count, 2500].max # At least 2500 users for demo
|
||||
@events_this_month = [Event.published.where(created_at: 1.month.ago..Time.current).count, 12].max # At least 12 this month
|
||||
@total_events = [ Event.published.count, 50 ].max # At least 50 events for demo
|
||||
@total_users = [ User.count, 2500 ].max # At least 2500 users for demo
|
||||
@events_this_month = [ Event.published.where(created_at: 1.month.ago..Time.current).count, 12 ].max # At least 12 this month
|
||||
@active_cities = 5 # Fixed number for demo
|
||||
end
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ class StripeInvoiceService
|
||||
name: customer_name,
|
||||
metadata: {
|
||||
user_id: @order.user.id,
|
||||
created_by: "aperonight_system"
|
||||
created_by: "#{ENV.fetch('INVOICE_COMPANY_NAME', 'aperonight').downcase}_system"
|
||||
}
|
||||
})
|
||||
|
||||
@@ -133,7 +133,7 @@ class StripeInvoiceService
|
||||
order_id: @order.id,
|
||||
user_id: @order.user.id,
|
||||
event_name: @order.event.name,
|
||||
created_by: "aperonight_system",
|
||||
created_by: "#{ENV.fetch('INVOICE_COMPANY_NAME', 'aperonight').downcase}_system",
|
||||
payment_method: "checkout_session"
|
||||
},
|
||||
description: "Invoice for #{@order.event.name} - Order ##{@order.id}",
|
||||
|
||||
@@ -31,11 +31,26 @@
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold text-gray-900 mb-3">Émis par</h3>
|
||||
<div class="bg-purple-50 rounded-lg p-4 border border-purple-200">
|
||||
<h4 class="font-semibold text-purple-900">AperoNight</h4>
|
||||
<h4 class="font-semibold text-purple-900"><%= ENV.fetch("INVOICE_COMPANY_NAME", "AperoNight") %></h4>
|
||||
<div class="mt-2 space-y-1 text-sm text-purple-700">
|
||||
<p>123 Avenue des Événements</p>
|
||||
<p>75000 Paris, France</p>
|
||||
<p>contact@apero-night.fr</p>
|
||||
<% if ENV["INVOICE_COMPANY_ADDRESS_LINE_1"].present? %>
|
||||
<p><%= ENV["INVOICE_COMPANY_ADDRESS_LINE_1"] %></p>
|
||||
<% end %>
|
||||
<% if ENV["INVOICE_COMPANY_ADDRESS_LINE_2"].present? %>
|
||||
<p><%= ENV["INVOICE_COMPANY_ADDRESS_LINE_2"] %></p>
|
||||
<% end %>
|
||||
<% if ENV["INVOICE_COMPANY_EMAIL"].present? %>
|
||||
<p><%= ENV["INVOICE_COMPANY_EMAIL"] %></p>
|
||||
<% end %>
|
||||
<% if ENV["INVOICE_COMPANY_PHONE"].present? %>
|
||||
<p><%= ENV["INVOICE_COMPANY_PHONE"] %></p>
|
||||
<% end %>
|
||||
<% if ENV["INVOICE_COMPANY_VAT_NUMBER"].present? %>
|
||||
<p>TVA: <%= ENV["INVOICE_COMPANY_VAT_NUMBER"] %></p>
|
||||
<% end %>
|
||||
<% if ENV["INVOICE_COMPANY_SIRET"].present? %>
|
||||
<p>SIRET: <%= ENV["INVOICE_COMPANY_SIRET"] %></p>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,37 +1,11 @@
|
||||
<div class="min-h-screen bg-gradient-to-br from-gray-50 to-gray-100">
|
||||
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||
<!-- Breadcrumb -->
|
||||
<nav class="flex mb-6" aria-label="Breadcrumb">
|
||||
<ol class="inline-flex items-center space-x-1 md:space-x-2 rounded-lg bg-white px-4 py-2 shadow-sm">
|
||||
<li class="inline-flex items-center">
|
||||
<%= link_to "Accueil", root_path, class: "inline-flex items-center text-sm font-medium text-gray-700 hover:text-purple-600" %>
|
||||
</li>
|
||||
<li>
|
||||
<div class="flex items-center">
|
||||
<svg class="w-4 h-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<%= link_to "Événements", events_path, class: "ml-1 text-sm font-medium text-gray-700 hover:text-purple-600 md:ml-2" %>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="flex items-center">
|
||||
<svg class="w-4 h-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<%= link_to @event.name, event_path(@event.slug, @event), class: "ml-1 text-sm font-medium text-gray-700 hover:text-purple-600 md:ml-2" %>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="flex items-center">
|
||||
<svg class="w-4 h-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<span class="ml-1 text-sm font-medium text-purple-600 md:ml-2">Nouvelle commande</span>
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
<%= render 'components/breadcrumb', crumbs: [
|
||||
{ name: 'Accueil', path: root_path },
|
||||
{ name: 'Événements', path: events_path },
|
||||
{ name: @event.name, path: event_path(@event.slug, @event) },
|
||||
{ name: 'Nouvelle commande', path: nil }
|
||||
] %>
|
||||
|
||||
<!-- Page Header -->
|
||||
<div class="mb-8">
|
||||
|
||||
@@ -4,7 +4,7 @@ class ApplicationControllerOnboardingTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
@user_without_onboarding = users(:one)
|
||||
@user_without_onboarding.update!(onboarding_completed: false)
|
||||
|
||||
|
||||
@user_with_onboarding = users(:two)
|
||||
@user_with_onboarding.update!(onboarding_completed: true, first_name: "John", last_name: "Doe")
|
||||
end
|
||||
@@ -54,4 +54,4 @@ class ApplicationControllerOnboardingTest < ActionDispatch::IntegrationTest
|
||||
get onboarding_path
|
||||
assert_response :success
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,7 +4,7 @@ class OnboardingControllerTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
@user_without_onboarding = users(:one)
|
||||
@user_without_onboarding.update!(onboarding_completed: false)
|
||||
|
||||
|
||||
@user_with_onboarding = users(:two)
|
||||
@user_with_onboarding.update!(onboarding_completed: true, first_name: "John", last_name: "Doe")
|
||||
end
|
||||
@@ -30,20 +30,20 @@ class OnboardingControllerTest < ActionDispatch::IntegrationTest
|
||||
|
||||
test "should complete onboarding with valid data" do
|
||||
sign_in @user_without_onboarding
|
||||
|
||||
|
||||
assert_not @user_without_onboarding.onboarding_completed?
|
||||
|
||||
|
||||
post complete_onboarding_path, params: {
|
||||
user: {
|
||||
first_name: "Jane",
|
||||
last_name: "Smith"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
assert_redirected_to dashboard_path
|
||||
follow_redirect!
|
||||
assert_select ".notification", /Bienvenue sur Aperonight/
|
||||
|
||||
|
||||
@user_without_onboarding.reload
|
||||
assert @user_without_onboarding.onboarding_completed?
|
||||
assert_equal "Jane", @user_without_onboarding.first_name
|
||||
@@ -52,34 +52,34 @@ class OnboardingControllerTest < ActionDispatch::IntegrationTest
|
||||
|
||||
test "should not complete onboarding without required fields" do
|
||||
sign_in @user_without_onboarding
|
||||
|
||||
|
||||
post complete_onboarding_path, params: {
|
||||
user: {
|
||||
first_name: "",
|
||||
last_name: "Smith"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
assert_response :success
|
||||
assert_select ".notification", /Veuillez remplir tous les champs requis/
|
||||
|
||||
|
||||
@user_without_onboarding.reload
|
||||
assert_not @user_without_onboarding.onboarding_completed?
|
||||
end
|
||||
|
||||
test "should not complete onboarding without last name" do
|
||||
sign_in @user_without_onboarding
|
||||
|
||||
|
||||
post complete_onboarding_path, params: {
|
||||
user: {
|
||||
first_name: "Jane",
|
||||
last_name: ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
assert_response :success
|
||||
assert_select ".notification", /Veuillez remplir tous les champs requis/
|
||||
|
||||
|
||||
@user_without_onboarding.reload
|
||||
assert_not @user_without_onboarding.onboarding_completed?
|
||||
end
|
||||
|
||||
@@ -24,7 +24,7 @@ class TicketMailerTest < ActionMailer::TestCase
|
||||
assert_equal [ "no-reply@aperonight.fr" ], email.from
|
||||
assert_equal [ @user.email ], email.to
|
||||
assert_equal "Confirmation d'achat - #{@event.name}", email.subject
|
||||
|
||||
|
||||
# Check if we have any content
|
||||
content = ""
|
||||
if email.html_part
|
||||
@@ -34,7 +34,7 @@ class TicketMailerTest < ActionMailer::TestCase
|
||||
else
|
||||
content = email.body.to_s
|
||||
end
|
||||
|
||||
|
||||
# If still empty, try to get content from parts
|
||||
if content.empty? && email.parts.any?
|
||||
email.parts.each do |part|
|
||||
@@ -44,7 +44,7 @@ class TicketMailerTest < ActionMailer::TestCase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Instead of strict matching, just check that content exists
|
||||
assert content.length > 0, "Email body should not be empty"
|
||||
assert_match @event.name, content
|
||||
@@ -64,7 +64,7 @@ class TicketMailerTest < ActionMailer::TestCase
|
||||
assert_equal [ "no-reply@aperonight.fr" ], email.from
|
||||
assert_equal [ @ticket.user.email ], email.to
|
||||
assert_equal "Confirmation d'achat - #{@ticket.event.name}", email.subject
|
||||
|
||||
|
||||
# Check if we have any content
|
||||
content = ""
|
||||
if email.html_part
|
||||
@@ -74,7 +74,7 @@ class TicketMailerTest < ActionMailer::TestCase
|
||||
else
|
||||
content = email.body.to_s
|
||||
end
|
||||
|
||||
|
||||
# If still empty, try to get content from parts
|
||||
if content.empty? && email.parts.any?
|
||||
email.parts.each do |part|
|
||||
@@ -84,7 +84,7 @@ class TicketMailerTest < ActionMailer::TestCase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Instead of strict matching, just check that content exists
|
||||
assert content.length > 0, "Email body should not be empty"
|
||||
assert_match @ticket.event.name, content
|
||||
@@ -105,7 +105,7 @@ class TicketMailerTest < ActionMailer::TestCase
|
||||
assert_equal [ "no-reply@aperonight.fr" ], email.from
|
||||
assert_equal [ @user.email ], email.to
|
||||
assert_equal "Rappel : #{@event.name} dans une semaine", email.subject
|
||||
|
||||
|
||||
# Check content properly
|
||||
content = ""
|
||||
if email.html_part
|
||||
@@ -115,7 +115,7 @@ class TicketMailerTest < ActionMailer::TestCase
|
||||
else
|
||||
content = email.body.to_s
|
||||
end
|
||||
|
||||
|
||||
assert content.length > 0, "Email body should not be empty"
|
||||
assert_match /une semaine/, content
|
||||
assert_match @event.name, content
|
||||
@@ -136,7 +136,7 @@ class TicketMailerTest < ActionMailer::TestCase
|
||||
end
|
||||
|
||||
assert_equal "Rappel : #{@event.name} demain", email.subject
|
||||
|
||||
|
||||
# Check content properly
|
||||
content = ""
|
||||
if email.html_part
|
||||
@@ -146,7 +146,7 @@ class TicketMailerTest < ActionMailer::TestCase
|
||||
else
|
||||
content = email.body.to_s
|
||||
end
|
||||
|
||||
|
||||
assert content.length > 0, "Email body should not be empty"
|
||||
assert_match /demain/, content
|
||||
end
|
||||
@@ -161,7 +161,7 @@ class TicketMailerTest < ActionMailer::TestCase
|
||||
end
|
||||
|
||||
assert_equal "C'est aujourd'hui : #{@event.name}", email.subject
|
||||
|
||||
|
||||
# Check content properly
|
||||
content = ""
|
||||
if email.html_part
|
||||
@@ -171,7 +171,7 @@ class TicketMailerTest < ActionMailer::TestCase
|
||||
else
|
||||
content = email.body.to_s
|
||||
end
|
||||
|
||||
|
||||
assert content.length > 0, "Email body should not be empty"
|
||||
assert_match /aujourd'hui/, content
|
||||
end
|
||||
@@ -186,7 +186,7 @@ class TicketMailerTest < ActionMailer::TestCase
|
||||
end
|
||||
|
||||
assert_equal "Rappel : #{@event.name} dans 3 jours", email.subject
|
||||
|
||||
|
||||
# Check content properly
|
||||
content = ""
|
||||
if email.html_part
|
||||
@@ -196,7 +196,7 @@ class TicketMailerTest < ActionMailer::TestCase
|
||||
else
|
||||
content = email.body.to_s
|
||||
end
|
||||
|
||||
|
||||
assert content.length > 0, "Email body should not be empty"
|
||||
assert_match /3 jours/, content
|
||||
end
|
||||
|
||||
@@ -74,21 +74,21 @@ class UserTest < ActiveSupport::TestCase
|
||||
test "should complete onboarding" do
|
||||
user = users(:one)
|
||||
user.update!(onboarding_completed: false)
|
||||
|
||||
|
||||
assert user.needs_onboarding?, "User should need onboarding initially"
|
||||
|
||||
|
||||
user.complete_onboarding!
|
||||
|
||||
|
||||
assert_not user.needs_onboarding?, "User should not need onboarding after completion"
|
||||
assert user.onboarding_completed?, "User should have completed onboarding"
|
||||
end
|
||||
|
||||
test "needs_onboarding? should return correct value" do
|
||||
user = users(:one)
|
||||
|
||||
|
||||
user.update!(onboarding_completed: false)
|
||||
assert user.needs_onboarding?, "User with false onboarding_completed should need onboarding"
|
||||
|
||||
|
||||
user.update!(onboarding_completed: true)
|
||||
assert_not user.needs_onboarding?, "User with true onboarding_completed should not need onboarding"
|
||||
end
|
||||
|
||||
@@ -17,7 +17,7 @@ module ActiveSupport
|
||||
fixtures :all
|
||||
|
||||
# Add more helper methods to be used by all tests here...
|
||||
|
||||
|
||||
# Helper to create users with completed onboarding by default for tests
|
||||
def create_test_user(attributes = {})
|
||||
User.create!({
|
||||
|
||||
Reference in New Issue
Block a user