wip: OrdersController#new
This commit is contained in:
@@ -1,8 +1,7 @@
|
|||||||
# Project Backlog
|
# Project Backlog
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 📋 Todo
|
## 📋 Todo
|
||||||
|
|
||||||
- [ ] Set up project infrastructure
|
- [ ] Set up project infrastructure
|
||||||
- [ ] Design user interface mockups
|
- [ ] Design user interface mockups
|
||||||
- [ ] Create user dashboard
|
- [ ] Create user dashboard
|
||||||
@@ -20,11 +19,11 @@
|
|||||||
- [ ] Deploy to production
|
- [ ] Deploy to production
|
||||||
|
|
||||||
## 🚧 Doing
|
## 🚧 Doing
|
||||||
- [x] Add login functionality
|
|
||||||
|
|
||||||
|
|
||||||
|
- [ ] refactor: Moving checkout to OrdersController
|
||||||
|
|
||||||
## ✅ Done
|
## ✅ Done
|
||||||
|
|
||||||
- [x] Initialize git repository
|
- [x] Initialize git repository
|
||||||
- [x] Set up development environment
|
- [x] Set up development environment
|
||||||
- [x] Create project structure
|
- [x] Create project structure
|
||||||
@@ -42,3 +41,4 @@
|
|||||||
- [x] Configure environment variables
|
- [x] Configure environment variables
|
||||||
- [x] Create authentication system
|
- [x] Create authentication system
|
||||||
- [x] Implement user registration
|
- [x] Implement user registration
|
||||||
|
- [x] Add login functionality
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ module Api
|
|||||||
def store_cart
|
def store_cart
|
||||||
cart_data = params[:cart] || {}
|
cart_data = params[:cart] || {}
|
||||||
session[:pending_cart] = cart_data
|
session[:pending_cart] = cart_data
|
||||||
|
session[:event_id] = @event.id
|
||||||
|
|
||||||
render json: { status: "success", message: "Cart stored successfully" }
|
render json: { status: "success", message: "Cart stored successfully" }
|
||||||
rescue => e
|
rescue => e
|
||||||
|
|||||||
@@ -6,7 +6,31 @@ class OrdersController < ApplicationController
|
|||||||
before_action :authenticate_user!
|
before_action :authenticate_user!
|
||||||
before_action :set_order, only: [:show, :checkout, :retry_payment, :increment_payment_attempt]
|
before_action :set_order, only: [:show, :checkout, :retry_payment, :increment_payment_attempt]
|
||||||
|
|
||||||
|
# Display new order form
|
||||||
|
#
|
||||||
|
# On this page user can complete the tickets details (first name and last name),
|
||||||
|
# add a comment on the order.
|
||||||
|
def new
|
||||||
|
@cart_data = session[:pending_cart] || {}
|
||||||
|
|
||||||
|
if @cart_data.empty?
|
||||||
|
redirect_to root_path, alert: "Veuillez d'abord sélectionner vos billets"
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# Build order preview from cart data
|
||||||
|
@event_id = session[:event_id]
|
||||||
|
if @event_id.present?
|
||||||
|
@event = Event.includes(:ticket_types).find_by(id: @event_id)
|
||||||
|
redirect_to root_path, alert: "Événement non trouvé" unless @event
|
||||||
|
else
|
||||||
|
redirect_to root_path, alert: "Informations manquantes"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Display order summary
|
# Display order summary
|
||||||
|
#
|
||||||
|
#
|
||||||
def show
|
def show
|
||||||
@tickets = @order.tickets.includes(:ticket_type)
|
@tickets = @order.tickets.includes(:ticket_type)
|
||||||
end
|
end
|
||||||
@@ -115,7 +139,7 @@ class OrdersController < ApplicationController
|
|||||||
|
|
||||||
if order_id.present?
|
if order_id.present?
|
||||||
order = current_user.orders.find_by(id: order_id, status: "draft")
|
order = current_user.orders.find_by(id: order_id, status: "draft")
|
||||||
|
|
||||||
if order&.can_retry_payment?
|
if order&.can_retry_payment?
|
||||||
redirect_to order_checkout_path(order),
|
redirect_to order_checkout_path(order),
|
||||||
alert: "Le paiement a été annulé. Vous pouvez réessayer."
|
alert: "Le paiement a été annulé. Vous pouvez réessayer."
|
||||||
@@ -163,4 +187,4 @@ class OrdersController < ApplicationController
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
# Controller for static pages and user dashboard
|
# Controller for static pages and user dashboard
|
||||||
# Handles basic page rendering and user-specific content
|
# Handles basic page rendering and user-specific content
|
||||||
class PagesController < ApplicationController
|
class PagesController < ApplicationController
|
||||||
# Skip authentication for public pages
|
|
||||||
# skip_before_action :authenticate_user!, only: [ :home ]
|
|
||||||
before_action :authenticate_user!, only: [ :dashboard ]
|
before_action :authenticate_user!, only: [ :dashboard ]
|
||||||
|
|
||||||
# Homepage showing featured events
|
# Homepage showing featured events
|
||||||
|
#
|
||||||
|
# Display homepage with featured events and incoming ones
|
||||||
def home
|
def home
|
||||||
@events = Event.published.featured.limit(3)
|
@featured_events = Event.published.featured.limit(3)
|
||||||
|
|
||||||
if user_signed_in?
|
if user_signed_in?
|
||||||
redirect_to(dashboard_path)
|
redirect_to(dashboard_path)
|
||||||
|
|||||||
@@ -2,32 +2,25 @@
|
|||||||
// Run that command whenever you add a new controller or create them with
|
// Run that command whenever you add a new controller or create them with
|
||||||
// ./bin/rails generate stimulus controllerName
|
// ./bin/rails generate stimulus controllerName
|
||||||
|
|
||||||
import { application } from "./application"
|
import { application } from "./application";
|
||||||
|
|
||||||
import LogoutController from "./logout_controller";
|
import LogoutController from "./logout_controller";
|
||||||
application.register("logout", LogoutController);
|
application.register("logout", LogoutController);
|
||||||
|
|
||||||
import CounterController from "./counter_controller"
|
import CounterController from "./counter_controller";
|
||||||
application.register("counter", CounterController);
|
application.register("counter", CounterController);
|
||||||
|
|
||||||
import FlashMessageController from "./flash_message_controller"
|
import FlashMessageController from "./flash_message_controller";
|
||||||
application.register("flash-message", FlashMessageController);
|
application.register("flash-message", FlashMessageController);
|
||||||
|
|
||||||
import TicketSelectionController from "./ticket_selection_controller"
|
import TicketSelectionController from "./ticket_selection_controller";
|
||||||
application.register("ticket-selection", TicketSelectionController);
|
// application.register("ticket-selection", TicketSelectionController);
|
||||||
|
|
||||||
import HeaderController from "./header_controller"
|
import HeaderController from "./header_controller";
|
||||||
application.register("header", HeaderController);
|
application.register("header", HeaderController);
|
||||||
|
|
||||||
import EventFormController from "./event_form_controller"
|
import EventFormController from "./event_form_controller";
|
||||||
application.register("event-form", EventFormController);
|
application.register("event-form", EventFormController);
|
||||||
|
|
||||||
import TicketTypeFormController from "./ticket_type_form_controller"
|
import TicketTypeFormController from "./ticket_type_form_controller";
|
||||||
application.register("ticket-type-form", TicketTypeFormController);
|
application.register("ticket-type-form", TicketTypeFormController);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,150 +1,169 @@
|
|||||||
import { Controller } from "@hotwired/stimulus"
|
import { Controller } from "@hotwired/stimulus";
|
||||||
|
|
||||||
// Controller for handling ticket selection on the event show page
|
// Controller for handling ticket selection on the event show page
|
||||||
// Manages quantity inputs, calculates totals, and enables/disables the checkout button
|
// Manages quantity inputs, calculates totals, and enables/disables the checkout button
|
||||||
export default class extends Controller {
|
export default class extends Controller {
|
||||||
static targets = ["quantityInput", "totalQuantity", "totalAmount", "checkoutButton", "form"]
|
static targets = [
|
||||||
static values = { eventSlug: String, eventId: String }
|
"quantityInput",
|
||||||
|
"totalQuantity",
|
||||||
|
"totalAmount",
|
||||||
|
"checkoutButton",
|
||||||
|
"form",
|
||||||
|
];
|
||||||
|
static values = { eventSlug: String, eventId: String };
|
||||||
|
|
||||||
// Initialize the controller and update the cart summary
|
// Initialize the controller and update the cart summary
|
||||||
connect() {
|
connect() {
|
||||||
this.updateCartSummary()
|
this.updateCartSummary();
|
||||||
this.bindFormSubmission()
|
this.bindFormSubmission();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind form submission to handle cart storage
|
// Bind form submission to handle cart storage
|
||||||
bindFormSubmission() {
|
bindFormSubmission() {
|
||||||
if (this.hasFormTarget) {
|
if (this.hasFormTarget) {
|
||||||
this.formTarget.addEventListener('submit', this.submitCart.bind(this))
|
this.formTarget.addEventListener("submit", this.submitCart.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increment the quantity for a specific ticket type
|
// Increment the quantity for a specific ticket type
|
||||||
increment(event) {
|
increment(event) {
|
||||||
const ticketTypeId = event.currentTarget.dataset.target
|
const ticketTypeId = event.currentTarget.dataset.target;
|
||||||
const input = this.quantityInputTargets.find(input => input.dataset.target === ticketTypeId)
|
const input = this.quantityInputTargets.find(
|
||||||
const value = parseInt(input.value) || 0
|
(input) => input.dataset.target === ticketTypeId,
|
||||||
const max = parseInt(input.max) || 0
|
);
|
||||||
|
const value = parseInt(input.value) || 0;
|
||||||
|
const max = parseInt(input.max) || 0;
|
||||||
|
|
||||||
if (value < max) {
|
if (value < max) {
|
||||||
input.value = value + 1
|
input.value = value + 1;
|
||||||
this.updateCartSummary()
|
this.updateCartSummary();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrement the quantity for a specific ticket type
|
// Decrement the quantity for a specific ticket type
|
||||||
decrement(event) {
|
decrement(event) {
|
||||||
const ticketTypeId = event.currentTarget.dataset.target
|
const ticketTypeId = event.currentTarget.dataset.target;
|
||||||
const input = this.quantityInputTargets.find(input => input.dataset.target === ticketTypeId)
|
const input = this.quantityInputTargets.find(
|
||||||
const value = parseInt(input.value) || 0
|
(input) => input.dataset.target === ticketTypeId,
|
||||||
|
);
|
||||||
|
const value = parseInt(input.value) || 0;
|
||||||
|
|
||||||
if (value > 0) {
|
if (value > 0) {
|
||||||
input.value = value - 1
|
input.value = value - 1;
|
||||||
this.updateCartSummary()
|
this.updateCartSummary();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update quantity when directly edited in the input field
|
// Update quantity when directly edited in the input field
|
||||||
updateQuantity(event) {
|
updateQuantity(event) {
|
||||||
const input = event.currentTarget
|
const input = event.currentTarget;
|
||||||
let value = parseInt(input.value) || 0
|
let value = parseInt(input.value) || 0;
|
||||||
const max = parseInt(input.max) || 0
|
const max = parseInt(input.max) || 0;
|
||||||
|
|
||||||
// Ensure value is within valid range (0 to max available)
|
// Ensure value is within valid range (0 to max available)
|
||||||
if (value < 0) value = 0
|
if (value < 0) value = 0;
|
||||||
if (value > max) value = max
|
if (value > max) value = max;
|
||||||
|
|
||||||
input.value = value
|
input.value = value;
|
||||||
this.updateCartSummary()
|
this.updateCartSummary();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate and update the cart summary (total quantity and amount)
|
// Calculate and update the cart summary (total quantity and amount)
|
||||||
updateCartSummary() {
|
updateCartSummary() {
|
||||||
let totalQuantity = 0
|
let totalQuantity = 0;
|
||||||
let totalAmount = 0
|
let totalAmount = 0;
|
||||||
|
|
||||||
// Sum up quantities and calculate total amount
|
// Sum up quantities and calculate total amount
|
||||||
this.quantityInputTargets.forEach(input => {
|
this.quantityInputTargets.forEach((input) => {
|
||||||
const quantity = parseInt(input.value) || 0
|
const quantity = parseInt(input.value) || 0;
|
||||||
const price = parseInt(input.dataset.price) || 0
|
const price = parseInt(input.dataset.price) || 0;
|
||||||
|
|
||||||
totalQuantity += quantity
|
totalQuantity += quantity;
|
||||||
totalAmount += quantity * price
|
totalAmount += quantity * price;
|
||||||
})
|
});
|
||||||
|
|
||||||
// Update the displayed total quantity and amount
|
// Update the displayed total quantity and amount
|
||||||
this.totalQuantityTarget.textContent = totalQuantity
|
this.totalQuantityTarget.textContent = totalQuantity;
|
||||||
this.totalAmountTarget.textContent = `€${(totalAmount / 100).toFixed(2)}`
|
this.totalAmountTarget.textContent = `€${(totalAmount / 100).toFixed(2)}`;
|
||||||
|
|
||||||
// Enable/disable checkout button based on whether any tickets are selected
|
// Enable/disable checkout button based on whether any tickets are selected
|
||||||
if (totalQuantity > 0) {
|
if (totalQuantity > 0) {
|
||||||
this.checkoutButtonTarget.classList.remove('opacity-50', 'cursor-not-allowed')
|
this.checkoutButtonTarget.classList.remove(
|
||||||
this.checkoutButtonTarget.disabled = false
|
"opacity-50",
|
||||||
|
"cursor-not-allowed",
|
||||||
|
);
|
||||||
|
this.checkoutButtonTarget.disabled = false;
|
||||||
} else {
|
} else {
|
||||||
this.checkoutButtonTarget.classList.add('opacity-50', 'cursor-not-allowed')
|
this.checkoutButtonTarget.classList.add(
|
||||||
this.checkoutButtonTarget.disabled = true
|
"opacity-50",
|
||||||
|
"cursor-not-allowed",
|
||||||
|
);
|
||||||
|
this.checkoutButtonTarget.disabled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle form submission - store cart in session before proceeding
|
// Handle form submission - store cart in session before proceeding
|
||||||
async submitCart(event) {
|
async submitCart(event) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
|
|
||||||
const cartData = this.buildCartData()
|
const cartData = this.buildCartData();
|
||||||
|
|
||||||
if (Object.keys(cartData).length === 0) {
|
if (Object.keys(cartData).length === 0) {
|
||||||
alert('Veuillez sélectionner au moins un billet')
|
alert("Veuillez sélectionner au moins un billet");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Store cart data in session
|
// Store cart data in session
|
||||||
await this.storeCartInSession(cartData)
|
await this.storeCartInSession(cartData);
|
||||||
|
|
||||||
// Redirect to tickets/new page
|
|
||||||
const ticketNewUrl = `/events/${this.eventSlugValue}.${this.eventIdValue}/tickets/new`
|
|
||||||
window.location.href = ticketNewUrl
|
|
||||||
|
|
||||||
|
// Redirect to orders/new page
|
||||||
|
const OrderNewUrl = `/orders/new`;
|
||||||
|
window.location.href = OrderNewUrl;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error storing cart:', error)
|
console.error("Error storing cart:", error);
|
||||||
alert('Une erreur est survenue. Veuillez réessayer.')
|
alert("Une erreur est survenue. Veuillez réessayer.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build cart data from current form state
|
// Build cart data from current form state
|
||||||
buildCartData() {
|
buildCartData() {
|
||||||
const cartData = {}
|
const cartData = {};
|
||||||
|
|
||||||
this.quantityInputTargets.forEach(input => {
|
this.quantityInputTargets.forEach((input) => {
|
||||||
const quantity = parseInt(input.value) || 0
|
const quantity = parseInt(input.value) || 0;
|
||||||
if (quantity > 0) {
|
if (quantity > 0) {
|
||||||
const ticketTypeId = input.dataset.target
|
const ticketTypeId = input.dataset.target;
|
||||||
cartData[ticketTypeId] = {
|
cartData[ticketTypeId] = {
|
||||||
quantity: quantity
|
quantity: quantity,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
return cartData
|
return cartData;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store cart data in session via AJAX
|
// Store cart data in session via AJAX
|
||||||
async storeCartInSession(cartData) {
|
async storeCartInSession(cartData) {
|
||||||
const storeCartUrl = `/api/v1/events/${this.eventIdValue}/store_cart`
|
const storeCartUrl = `/api/v1/events/${this.eventIdValue}/store_cart`;
|
||||||
|
|
||||||
const response = await fetch(storeCartUrl, {
|
const response = await fetch(storeCartUrl, {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
"Content-Type": "application/json",
|
||||||
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
|
"X-CSRF-Token": document
|
||||||
|
.querySelector('meta[name="csrf-token"]')
|
||||||
|
.getAttribute("content"),
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ cart: cartData })
|
body: JSON.stringify({ cart: cartData }),
|
||||||
})
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`Failed to store cart data: ${response.status} ${response.statusText}`)
|
throw new Error(
|
||||||
|
`Failed to store cart data: ${response.status} ${response.statusText}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.json()
|
return response.json();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -208,7 +208,7 @@
|
|||||||
|
|
||||||
<!-- Right Column: Ticket Selection -->
|
<!-- Right Column: Ticket Selection -->
|
||||||
<div class="lg:col-span-1">
|
<div class="lg:col-span-1">
|
||||||
<%= form_with url: "#", method: :post, id: "checkout_form", local: true, data: {
|
<%= form_with url: order_new_path, method: :get, id: "checkout_form", local: true, data: {
|
||||||
controller: "ticket-selection",
|
controller: "ticket-selection",
|
||||||
ticket_selection_target: "form",
|
ticket_selection_target: "form",
|
||||||
ticket_selection_event_slug_value: @event.slug,
|
ticket_selection_event_slug_value: @event.slug,
|
||||||
|
|||||||
71
app/views/orders/new.html.erb
Normal file
71
app/views/orders/new.html.erb
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
<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">
|
||||||
|
<!-- Page Header -->
|
||||||
|
<div class="mb-8">
|
||||||
|
<h1 class="text-3xl font-bold text-gray-900 mb-2">Nouvelle Commande</h1>
|
||||||
|
<p class="text-gray-600">Vérifiez vos billets avant de continuer vers le paiement</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Order Summary -->
|
||||||
|
<div class="bg-white rounded-2xl shadow-sm border border-gray-200 p-6">
|
||||||
|
<h2 class="text-xl font-semibold text-gray-900 mb-4">Résumé de votre commande</h2>
|
||||||
|
|
||||||
|
<% if @event %>
|
||||||
|
<div class="mb-6">
|
||||||
|
<h3 class="text-lg font-medium text-gray-800"><%= @event.name %></h3>
|
||||||
|
<p class="text-gray-600"><%= @event.venue_name %></p>
|
||||||
|
<% if @event.starts_at %>
|
||||||
|
<p class="text-sm text-gray-500">
|
||||||
|
<%= @event.starts_at.strftime("%d/%m/%Y à %H:%M") %>
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Cart Items -->
|
||||||
|
<div class="space-y-4 mb-6">
|
||||||
|
<% @cart_data.each do |ticket_type_id, item| %>
|
||||||
|
<% ticket_type = @event.ticket_types.find_by(id: ticket_type_id) %>
|
||||||
|
<% if ticket_type && item["quantity"].to_i > 0 %>
|
||||||
|
<div class="flex justify-between items-center py-3 border-b border-gray-100">
|
||||||
|
<div>
|
||||||
|
<h4 class="font-medium text-gray-900"><%= ticket_type.name %></h4>
|
||||||
|
<p class="text-sm text-gray-600"><%= ticket_type.description if ticket_type.description.present? %></p>
|
||||||
|
</div>
|
||||||
|
<div class="text-right">
|
||||||
|
<p class="font-medium">Quantité: <%= item["quantity"] %></p>
|
||||||
|
<p class="text-lg font-semibold text-purple-700">
|
||||||
|
<%= number_to_currency(ticket_type.price_cents * item["quantity"].to_i / 100.0, unit: "€", separator: ",", delimiter: " ") %>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Continue to Tickets -->
|
||||||
|
<div class="flex justify-end">
|
||||||
|
<%= link_to ticket_new_path,
|
||||||
|
class: "inline-flex items-center px-6 py-3 border border-transparent text-base font-medium rounded-xl text-white bg-gradient-to-r from-purple-600 to-indigo-600 hover:from-purple-700 hover:to-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-purple-500 transition-all duration-200" do %>
|
||||||
|
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7l5 5m0 0l-5 5m5-5H6"></path>
|
||||||
|
</svg>
|
||||||
|
Continuer vers les détails
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Back to Event -->
|
||||||
|
<div class="mt-6">
|
||||||
|
<% if @event %>
|
||||||
|
<%= link_to event_path(@event.slug, @event),
|
||||||
|
class: "inline-flex items-center text-purple-600 hover:text-purple-700 font-medium transition-colors" do %>
|
||||||
|
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path>
|
||||||
|
</svg>
|
||||||
|
Retour à l'événement
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="featured-events-grid" data-controller="featured-event">
|
<div class="featured-events-grid" data-controller="featured-event">
|
||||||
<% @events.each do |event| %>
|
<% @featured_events.each do |event| %>
|
||||||
<div class="featured-event-card" data-featured-event-target="card">
|
<div class="featured-event-card" data-featured-event-target="card">
|
||||||
<%= link_to event_path(event.slug, event) do %>
|
<%= link_to event_path(event.slug, event) do %>
|
||||||
<img src="<%= event.image %>" alt="<%= event.name %>" class="featured-event-image" data-featured-event-target="animated">
|
<img src="<%= event.image %>" alt="<%= event.name %>" class="featured-event-image" data-featured-event-target="animated">
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
<span class="badge badge-featured">★ En vedette</span>
|
<span class="badge badge-featured">★ En vedette</span>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if event.ticket_types.any? { |ticket_type| ticket_type.available_quantity > 0 } %>
|
<% if event.ticket_types.any? { |ticket_type| ticket_type.available_quantity > 0 } %>
|
||||||
<span class="badge badge-available">Disponible</span>
|
<!--<span class="badge badge-available">Disponible</span>-->
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="featured-event-title"><%= event.name %></h3>
|
<h3 class="featured-event-title"><%= event.name %></h3>
|
||||||
@@ -154,4 +154,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ Rails.application.routes.draw do
|
|||||||
get "events/:slug.:id", to: "events#show", as: "event"
|
get "events/:slug.:id", to: "events#show", as: "event"
|
||||||
|
|
||||||
# === Orders ===
|
# === Orders ===
|
||||||
|
|
||||||
|
get "orders/new", to: "orders#new", as: "order_new"
|
||||||
|
|
||||||
resources :orders, only: [:show] do
|
resources :orders, only: [:show] do
|
||||||
member do
|
member do
|
||||||
get :checkout
|
get :checkout
|
||||||
@@ -47,13 +50,12 @@ Rails.application.routes.draw do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Order payment routes
|
|
||||||
get "orders/payments/success", to: "orders#payment_success", as: "order_payment_success"
|
get "orders/payments/success", to: "orders#payment_success", as: "order_payment_success"
|
||||||
get "orders/payments/cancel", to: "orders#payment_cancel", as: "order_payment_cancel"
|
get "orders/payments/cancel", to: "orders#payment_cancel", as: "order_payment_cancel"
|
||||||
|
|
||||||
# === Tickets ===
|
# === Tickets ===
|
||||||
get "events/:slug.:id/tickets/new", to: "tickets#new", as: "ticket_new"
|
get "tickets/new", to: "tickets#new", as: "ticket_new"
|
||||||
post "events/:slug.:id/tickets/create", to: "tickets#create", as: "ticket_create"
|
post "tickets/create", to: "tickets#create", as: "ticket_create"
|
||||||
|
|
||||||
# Keep these for now but they redirect to order system
|
# Keep these for now but they redirect to order system
|
||||||
get "events/:slug.:id/tickets/checkout", to: "tickets#checkout", as: "ticket_checkout"
|
get "events/:slug.:id/tickets/checkout", to: "tickets#checkout", as: "ticket_checkout"
|
||||||
|
|||||||
Reference in New Issue
Block a user