Compare commits
5 Commits
28eddb22ab
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 580b24bbed | |||
| a8d3bc12ae | |||
|
|
b228d5a174 | ||
|
|
61ad8c64d4 | ||
|
|
4e06f91acb |
@@ -1,27 +1,23 @@
|
|||||||
import { Controller } from "@hotwired/stimulus"
|
import { Controller } from "@hotwired/stimulus"
|
||||||
|
|
||||||
export default class extends Controller {
|
export default class extends Controller {
|
||||||
static targets = ["modal", "cloneTicketTypes"]
|
static targets = ["cloneTicketTypes"]
|
||||||
static values = {
|
static values = {
|
||||||
duplicateUrl: String
|
duplicateUrl: String
|
||||||
}
|
}
|
||||||
|
|
||||||
connect() {
|
connect() {
|
||||||
// Close modal when clicking outside
|
// Get modal element from the document
|
||||||
this.modalTarget.addEventListener('click', (event) => {
|
this.modalElement = document.querySelector('[data-event-duplication-target="modal"]')
|
||||||
if (event.target === this.modalTarget) {
|
|
||||||
this.close()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
open() {
|
open() {
|
||||||
this.modalTarget.classList.remove('hidden')
|
this.modalElement.classList.remove('hidden')
|
||||||
document.body.classList.add('overflow-hidden')
|
document.body.classList.add('overflow-hidden')
|
||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
this.modalTarget.classList.add('hidden')
|
this.modalElement.classList.add('hidden')
|
||||||
document.body.classList.remove('overflow-hidden')
|
document.body.classList.remove('overflow-hidden')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -107,22 +107,6 @@
|
|||||||
<div class="w-5 h-5 border-2 border-purple-200 border-t-purple-600 rounded-full animate-spin"></div>
|
<div class="w-5 h-5 border-2 border-purple-200 border-t-purple-600 rounded-full animate-spin"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Location Actions -->
|
|
||||||
<div class="flex flex-wrap gap-2">
|
|
||||||
<button type="button" data-action="click->event-form#getCurrentLocation" data-event-form-target="getCurrentLocationBtn" class="inline-flex items-center px-3 py-2 text-xs font-medium text-white bg-green-600 rounded-lg hover:bg-green-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed">
|
|
||||||
<span data-event-form-target="getCurrentLocationIcon">
|
|
||||||
<i data-lucide="map-pin" class="w-3 h-3 mr-1"></i>
|
|
||||||
</span>
|
|
||||||
<span data-event-form-target="getCurrentLocationText">Ma position</span>
|
|
||||||
</button>
|
|
||||||
<button type="button" data-action="click->event-form#previewLocation" data-event-form-target="previewLocationBtn" class="inline-flex items-center px-3 py-2 text-xs font-medium text-purple-700 bg-purple-50 border border-purple-200 rounded-lg hover:bg-purple-100 transition-colors disabled:opacity-50 disabled:cursor-not-allowed">
|
|
||||||
<span data-event-form-target="previewLocationIcon">
|
|
||||||
<i data-lucide="map" class="w-3 h-3 mr-1"></i>
|
|
||||||
</span>
|
|
||||||
<span data-event-form-target="previewLocationText">Prévisualiser</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="mt-2 text-sm text-gray-500">
|
<p class="mt-2 text-sm text-gray-500">
|
||||||
@@ -144,11 +128,24 @@
|
|||||||
<div class="bg-white rounded-lg border border-gray-200 p-6">
|
<div class="bg-white rounded-lg border border-gray-200 p-6">
|
||||||
<h3 class="text-lg font-semibold text-gray-900 mb-6">Options</h3>
|
<h3 class="text-lg font-semibold text-gray-900 mb-6">Options</h3>
|
||||||
|
|
||||||
<div class="flex items-center">
|
<div class="space-y-4">
|
||||||
<%= form.check_box :featured, class: "h-4 w-4 text-purple-600 border-gray-300 rounded focus:ring-purple-500" %>
|
<div class="flex items-center">
|
||||||
<%= form.label :featured, "Mettre en avant sur la page d'accueil", class: "ml-2 text-sm text-gray-700" %>
|
<%= form.check_box :featured, class: "h-4 w-4 text-purple-600 border-gray-300 rounded focus:ring-purple-500" %>
|
||||||
|
<%= form.label :featured, "Mettre en avant sur la page d'accueil", class: "ml-2 text-sm text-gray-700" %>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-gray-500">Les événements mis en avant apparaissent en premier sur la page d'accueil.</p>
|
||||||
|
|
||||||
|
<div class="flex items-start">
|
||||||
|
<%= form.check_box :allow_booking_during_event, class: "h-4 w-4 text-purple-600 border-gray-300 rounded focus:ring-purple-500 mt-1" %>
|
||||||
|
<div class="ml-2">
|
||||||
|
<%= form.label :allow_booking_during_event, "Autoriser la réservation pendant l'événement", class: "text-sm text-gray-700 font-medium" %>
|
||||||
|
<p class="text-sm text-gray-500 mt-1">
|
||||||
|
Si activé, les participants pourront acheter des billets même après le début de l'événement.
|
||||||
|
Si désactivé, la vente de billets s'arrêtera automatiquement à l'heure de début.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="mt-2 text-sm text-gray-500">Les événements mis en avant apparaissent en premier sur la page d'accueil.</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Actions -->
|
<!-- Actions -->
|
||||||
@@ -166,4 +163,3 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,52 +1,6 @@
|
|||||||
<% content_for(:title, @event.name) %>
|
<% content_for(:title, @event.name) %>
|
||||||
|
|
||||||
<div data-controller="event-duplication" data-event-duplication-duplicate-url-value="<%= duplicate_promoter_event_path(@event) %>">
|
<div data-controller="event-duplication" data-event-duplication-duplicate-url-value="<%= duplicate_promoter_event_path(@event) %>">
|
||||||
<!-- Modal -->
|
|
||||||
<div data-event-duplication-target="modal" class="fixed inset-0 z-50 hidden overflow-y-auto">
|
|
||||||
<div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
|
|
||||||
<!-- Background overlay -->
|
|
||||||
<div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" aria-hidden="true"></div>
|
|
||||||
|
|
||||||
<!-- Modal container -->
|
|
||||||
<div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full">
|
|
||||||
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
|
|
||||||
<div class="sm:flex sm:items-start">
|
|
||||||
<div class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10">
|
|
||||||
<i data-lucide="copy" class="h-6 w-6 text-blue-600"></i>
|
|
||||||
</div>
|
|
||||||
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
|
||||||
<h3 class="text-lg leading-6 font-medium text-gray-900" id="modal-title">
|
|
||||||
Dupliquer l'événement
|
|
||||||
</h3>
|
|
||||||
<div class="mt-2">
|
|
||||||
<p class="text-sm text-gray-500">
|
|
||||||
Choisissez les options de duplication pour "<%= @event.name %>".
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div class="mt-4">
|
|
||||||
<div class="flex items-center">
|
|
||||||
<input data-event-duplication-target="cloneTicketTypes" id="cloneTicketTypes" type="checkbox" class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" checked>
|
|
||||||
<label for="cloneTicketTypes" class="ml-2 block text-sm text-gray-900">
|
|
||||||
Dupliquer également les types de billets (<%= @event.ticket_types.count %> type(s))
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
|
|
||||||
<button type="button" data-action="click->event-duplication#duplicate" class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm">
|
|
||||||
Dupliquer
|
|
||||||
</button>
|
|
||||||
<button type="button" data-action="click->event-duplication#close" class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm">
|
|
||||||
Annuler
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
<div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||||
|
|
||||||
<!-- Breadcrumb -->
|
<!-- Breadcrumb -->
|
||||||
@@ -159,7 +113,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex-shrink-0">
|
<div class="flex-shrink-0">
|
||||||
<%= link_to event_path(@event.slug, @event), target: "_blank", class: "text-green-600 hover:text-green-800 font-medium text-sm whitespace-nowrap" do %>
|
<%= link_to event_path(@event.slug, @event), target: "_blank", class: "text-green-600 hover:text-green-800 font-medium text-sm whitespace-nowrap" do %>
|
||||||
Voir publiquement <i data-lucide="external-link" class="w-4 h-4 inline ml-1"></i>
|
Voir la fiche publique <i data-lucide="external-link" class="w-4 h-4 inline ml-1"></i>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -334,4 +288,52 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal -->
|
||||||
|
<div data-event-duplication-target="modal" class="hidden relative z-50" aria-labelledby="modal-title" role="dialog" aria-modal="true">
|
||||||
|
<!-- Background backdrop, show/hide based on modal state -->
|
||||||
|
<div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity"></div>
|
||||||
|
|
||||||
|
<div class="fixed inset-0 z-50 overflow-y-auto">
|
||||||
|
<div class="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
|
||||||
|
<!-- Modal container -->
|
||||||
|
<div class="relative transform overflow-hidden rounded-lg bg-white text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg">
|
||||||
|
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
|
||||||
|
<div class="sm:flex sm:items-start">
|
||||||
|
<div class="mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10">
|
||||||
|
<i data-lucide="copy" class="h-6 w-6 text-blue-600"></i>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
||||||
|
<h3 class="text-lg font-medium leading-6 text-gray-900" id="modal-title">
|
||||||
|
Dupliquer l'événement
|
||||||
|
</h3>
|
||||||
|
<div class="mt-2">
|
||||||
|
<p class="text-sm text-gray-500">
|
||||||
|
Choisissez les options de duplication pour "<%= @event.name %>".
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="mt-4">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<input data-event-duplication-target="cloneTicketTypes" id="cloneTicketTypes" type="checkbox" class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" checked>
|
||||||
|
<label for="cloneTicketTypes" class="ml-2 block text-sm text-gray-900">
|
||||||
|
Dupliquer également les types de billets (<%= @event.ticket_types.count %> type(s))
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50 px-4 py-3 sm:flex sm:flex-row-reverse sm:px-6">
|
||||||
|
<button type="button" data-action="click->event-duplication#duplicate" class="inline-flex w-full justify-center rounded-md border border-transparent bg-blue-600 px-4 py-2 text-base font-medium text-white shadow-sm hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 sm:ml-3 sm:w-auto sm:text-sm">
|
||||||
|
Dupliquer
|
||||||
|
</button>
|
||||||
|
<button type="button" data-action="click->event-duplication#close" class="mt-3 inline-flex w-full justify-center rounded-md border border-gray-300 bg-white px-4 py-2 text-base font-medium text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm">
|
||||||
|
Annuler
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
<% content_for(:title, "#{@ticket_type.name} - #{@event.name}") %>
|
<% content_for(:title, "#{@ticket_type.name} - #{@event.name}") %>
|
||||||
|
|
||||||
<div class="container py-8">
|
<div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||||
|
<!-- Breadcrumb -->
|
||||||
|
<%= render 'components/breadcrumb', crumbs: [
|
||||||
|
{ name: 'Dashboard', path: dashboard_path },
|
||||||
|
{ name: 'Événements', path: promoter_events_path },
|
||||||
|
{ name: @event.name, path: promoter_event_path(@event) },
|
||||||
|
{ name: 'Types de billets', path: promoter_event_ticket_types_path(@event) },
|
||||||
|
{ name: @ticket_type.name, path: nil }
|
||||||
|
] %>
|
||||||
|
|
||||||
<!-- Header with actions -->
|
<!-- Header with actions -->
|
||||||
<div class="mb-8">
|
<div class="mb-8">
|
||||||
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
|
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ class Promoter::EventsControllerTest < ActionDispatch::IntegrationTest
|
|||||||
assert ticket_type2.valid?
|
assert ticket_type2.valid?
|
||||||
|
|
||||||
# Duplicate the event
|
# Duplicate the event
|
||||||
assert_difference('Event.count', 1) do
|
assert_difference("Event.count", 1) do
|
||||||
post duplicate_promoter_event_path(@event), params: { clone_ticket_types: "true" }
|
post duplicate_promoter_event_path(@event), params: { clone_ticket_types: "true" }
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ class Promoter::EventsControllerTest < ActionDispatch::IntegrationTest
|
|||||||
assert ticket_type2.valid?
|
assert ticket_type2.valid?
|
||||||
|
|
||||||
# Duplicate the event without ticket types
|
# Duplicate the event without ticket types
|
||||||
assert_difference('Event.count', 1) do
|
assert_difference("Event.count", 1) do
|
||||||
post duplicate_promoter_event_path(@event), params: { clone_ticket_types: "false" }
|
post duplicate_promoter_event_path(@event), params: { clone_ticket_types: "false" }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user