feat(EventsController): Affiche la liste des événements et les détails

Ajoute l'affichage des événements et de leurs détails. Ajoute aussi la gestion des affiches.
```
This commit is contained in:
Serreau Jovann
2025-12-02 21:48:03 +01:00
parent ae29a93d0b
commit 7e61371244
20 changed files with 1111 additions and 73 deletions

104
templates/admin/events.twig Normal file
View File

@@ -0,0 +1,104 @@
{% extends 'admin/base.twig' %}
{% block title 'Événement(s)' %}
{% block page_title 'Liste des Événements' %}
{% block body %}
<!-- Conteneur principal: utiliser bg-gray-900 pour l'arrière-plan du corps -->
<div class="bg-gray-900 text-gray-100 min-h-screen p-6">
<div class="flex justify-between items-center mb-6">
<!-- Titre en blanc -->
<h2 class="text-2xl font-semibold text-gray-100">Gestion des Événements</h2>
<!-- Bouton Créer un événement: le style reste contrasté -->
<a href="{{ path('admin_events_create') }}"
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium
rounded-lg shadow-md text-white bg-indigo-600 hover:bg-indigo-500 focus:outline-none focus:ring-2
focus:ring-offset-2 focus:ring-indigo-500 focus:ring-offset-gray-900 transition duration-150">
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path></svg>
Créer un événement
</a>
</div>
<!-- Tableau des événements -->
<!-- Fond du tableau en gris foncé, ombre conservée -->
<div class="bg-gray-800 shadow-xl overflow-hidden sm:rounded-lg">
{% if events is empty %}
<!-- Texte vide en gris clair -->
<div class="p-6 text-center text-gray-400">
Aucun événement trouvé. Commencez par en créer un !
</div>
{% else %}
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-700">
<!-- En-tête du tableau -->
<thead class="bg-gray-700">
<tr>
<!-- Texte de l'en-tête en gris clair/blanc -->
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-300 uppercase tracking-wider">
Titre
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-300 uppercase tracking-wider hidden sm:table-cell">
Lieu
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-300 uppercase tracking-wider hidden md:table-cell">
Organisateur
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-300 uppercase tracking-wider">
Début
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-300 uppercase tracking-wider hidden md:table-cell">
Fin
</th>
<th scope="col" class="relative px-6 py-3">
<span class="sr-only">Actions</span>
</th>
</tr>
</thead>
<!-- Corps du tableau -->
<tbody class="bg-gray-800 divide-y divide-gray-700">
{% for event in events %}
<!-- Ligne au survol en gris légèrement plus clair -->
<tr class="hover:bg-gray-700 transition duration-100">
<!-- Titre en blanc -->
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-100">
{{ event.title }}
</td>
<!-- Texte des cellules en gris clair -->
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-400 hidden sm:table-cell">
{{ event.location }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-400 hidden md:table-cell">
{{ event.organizer }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-400">
{{ event.startAt|date('d/m/Y') }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-400 hidden md:table-cell">
{{ event.endAt|date('d/m/Y') }}
</td>
<!-- Actions : lien Modifier en indigo, lien Supprimer en rouge -->
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<a href="{{ path('admin_events_edit', {id: event.id}) }}" class="text-indigo-400 hover:text-indigo-300 mr-3">
Modifier
</a>
<!-- Bouton de suppression -->
<form method="POST" action="{{ path('admin_events_delete', {id: event.id}) }}" class="inline-block" onsubmit="return confirm('Êtes-vous sûr de vouloir supprimer cet événement ? Cette action est irréversible.');">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ event.id) }}">
<button type="submit" class="text-red-400 hover:text-red-300 focus:outline-none">
Supprimer
</button>
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,171 @@
{% extends 'admin/base.twig' %}
{% block title %}Ajouter/Éditer un événement{% endblock %}
{% block page_title %}
{{ form.vars.value.id ? 'Éditer l\' événement: ' ~ form.vars.value.title : 'Créer un nouveau événement' }}
{% endblock %}
{% block body %}
{% form_theme form 'form_admin.twig' %}
<!-- Conteneur principal en mode sombre -->
<div class="bg-gray-900 min-h-screen p-6">
<div class="max-w-4xl mx-auto bg-gray-800 p-8 rounded-xl shadow-2xl">
<h1 class="text-3xl font-bold text-gray-100 mb-6"> {{ form.vars.value.id ? 'Éditer l\' événement: ' ~ form.vars.value.title : 'Créer un nouveau événement' }}</h1>
{{ form_start(form, {'attr': {'class': 'space-y-6'}}) }}
{% set event = form.vars.data %}
<!-- Style générique pour les form_row en dark mode -->
{% set input_classes = 'w-full px-4 py-3 border border-gray-600 rounded-lg bg-gray-700 text-gray-100 placeholder-gray-400 focus:ring-indigo-500 focus:border-indigo-500 transition duration-150' %}
{% set label_classes = 'text-white block text-sm font-medium text-gray-100 mb-1' %}
<!-- Champ Titre -->
<div class="form-group">
{{ form_row(form.title, {
'label_attr': {'class': label_classes},
'attr': {'class': input_classes}
}) }}
</div>
<!-- Champ Lieu -->
<div class="form-group">
{{ form_row(form.location, {
'label_attr': {'class': label_classes},
'attr': {'class': input_classes}
}) }}
</div>
<!-- Champs Date -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- Date de Début -->
<div class="form-group">
{{ form_row(form.startAt, {
'label_attr': {'class': label_classes},
'attr': {'class': input_classes}
}) }}
</div>
<!-- Date de Fin -->
<div class="form-group">
{{ form_row(form.endAt, {
'label_attr': {'class': label_classes},
'attr': {'class': input_classes}
}) }}
</div>
</div>
<!-- Champ Organisateur -->
<div class="form-group">
{{ form_row(form.organizer, {
'label_attr': {'class': label_classes},
'attr': {'class': input_classes}
}) }}
</div>
{# --- DÉBUT : CHAMP D'UPLOAD D'IMAGE STYLISÉ (Dark Mode) --- #}
{# --- SECTION IMAGE DE PROFIL / UPLOAD --- #}
<h3 class="text-2xl font-bold text-white border-b border-gray-700 pb-3 pt-6 mb-6">
Affiche
</h3>
<div class="flex items-center space-x-6">
{# Zone cliquable pour l'image existante, le placeholder ou la prévisualisation #}
<label for="{{ form.affiche.vars.id }}"
class="relative cursor-pointer bg-gray-700 rounded-full w-32 h-32
flex items-center justify-center border-2 border-dashed border-gray-600
hover:border-indigo-500 transition duration-300 overflow-hidden shadow-lg"
id="preview-container">
{% set currentImageUrl = event.eventsFileName ? asset(vich_uploader_asset(event, 'affiche')) : '' %}
{# Image de prévisualisation ou Image actuelle #}
<img id="profile-preview-img"
src="{{ currentImageUrl }}"
alt="Photo de profil"
class="w-full h-full object-cover {{ currentImageUrl ? '' : 'hidden' }}">
{# Icône par défaut (visible seulement si aucune image actuelle) #}
<svg id="default-user-icon"
class="h-12 w-12 text-gray-500 {{ currentImageUrl ? 'hidden' : '' }}"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path>
</svg>
{# Overlay pour indiquer que c'est cliquable (s'applique à l'ensemble du label) #}
<div class="absolute inset-0 bg-black bg-opacity-40 flex items-center justify-center
opacity-0 hover:opacity-100 transition duration-300 text-white font-bold text-xs p-2 text-center">
Cliquer pour changer
</div>
</label>
{# Champ de fichier réel (caché) #}
{{ form_widget(form.affiche, {'attr': {'class': 'sr-only'}}) }}
<div class="flex-1">
<p class="text-sm text-gray-400">
Sélectionnez une nouvelle affiche. Le fichier actuel sera remplacé. (Max 2Mo).
</p>
{# Affichage des erreurs spécifiques au champ image #}
{{ form_errors(form.affiche) }}
</div>
</div>
{# --- FIN : CHAMP D'UPLOAD D'IMAGE STYLISÉ --- #}
<!-- Bouton de soumission -->
<div class="pt-4">
<button type="submit"
class="inline-flex justify-center w-full px-4 py-3 border border-transparent text-lg font-medium rounded-lg shadow-sm text-white bg-indigo-600 hover:bg-indigo-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 focus:ring-offset-gray-800 transition duration-150">
Enregistrer l'événement
</button>
</div>
{{ form_end(form) }}
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
// Récupère l'ID réel du champ de fichier généré par Symfony
const fileInput = document.getElementById('{{ form.affiche.vars.id }}');
const previewImg = document.getElementById('profile-preview-img');
const defaultIcon = document.getElementById('default-user-icon');
if (fileInput) {
fileInput.addEventListener('change', function() {
// Vérifie si un fichier a été sélectionné
if (this.files && this.files[0]) {
const reader = new FileReader();
reader.onload = function(e) {
// 1. Met à jour l'attribut src de l'image avec la data URL du fichier
previewImg.src = e.target.result;
// 2. Assure que l'image est visible
previewImg.classList.remove('hidden');
// 3. Cache l'icône par défaut si elle est là
if (defaultIcon) {
defaultIcon.classList.add('hidden');
}
}
// Lit le contenu du fichier
reader.readAsDataURL(this.files[0]);
}
});
}
});
</script>
{% endblock %}

View File

@@ -7,23 +7,23 @@
{% block breadcrumb_schema %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "{{ 'breadcrumb.home'|trans }}",
"item": "{{ app.request.schemeAndHttpHost }}"
},
{
"@type": "ListItem",
"position": 2,
"name": "{{ 'breadcrumb.events'|trans }}",
"item": "{{ app.request.schemeAndHttpHost }}{{ app.request.pathInfo }}"
}
]
}
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "{{ 'breadcrumb.home'|trans }}",
"item": "{{ app.request.schemeAndHttpHost }}"
},
{
"@type": "ListItem",
"position": 2,
"name": "{{ 'breadcrumb.events'|trans }}",
"item": "{{ app.request.schemeAndHttpHost }}{{ app.request.pathInfo }}"
}
]
}
</script>
{% endblock %}
@@ -38,53 +38,73 @@
{% if events is defined and events is not empty %}
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 max-w-6xl mx-auto">
{% for event in events %}
<div class="bg-white rounded-xl shadow-lg border border-gray-100 p-6 flex flex-col justify-between transition duration-300 hover:shadow-xl hover:border-indigo-200">
<div>
{# Event Title #}
<h2 class="text-2xl font-bold text-indigo-700 mb-4">{{ event.title }}</h2>
<div class="bg-white rounded-xl shadow-lg border border-gray-100 flex flex-col justify-between transition duration-300 hover:shadow-xl hover:border-indigo-200 overflow-hidden">
<div class="space-y-3 text-gray-600">
{# --- AJOUT DE L'AFFICHE (IMAGE) --- #}
{% set imageUrl = event.eventsFileName ? vich_uploader_asset(event, 'affiche') : null %}
{# Date Block (Start Date / End Date) #}
<p class="flex items-start text-sm">
<svg class="w-4 h-4 mt-1 mr-2 flex-shrink-0 text-indigo-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path></svg>
<div>
<span class="font-medium text-gray-800">{{ 'events.list.date_label'|trans|default('Date') }}:</span>
<div class="text-xs mt-0.5">
{{ event.start_date|date('d/m/Y H:i') }}
{% if event.start_date|date('Ymd') != event.end_date|date('Ymd') %}
- {{ event.end_date|date('d/m/Y H:i') }}
{% else %}
- {{ event.end_date|date('H:i') }}
{% endif %}
</div>
</div>
</p>
{# Location Block #}
<p class="flex items-start text-sm">
<svg class="w-4 h-4 mt-0.5 mr-2 flex-shrink-0 text-indigo-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"></path></svg>
<div>
<span class="font-medium text-gray-800">{{ 'events.list.location_label'|trans|default('Location') }}:</span>
<div class="text-xs mt-0.5">{{ event.location }}</div>
</div>
</p>
{# Organizer Block #}
<p class="flex items-start text-sm">
<svg class="w-4 h-4 mt-0.5 mr-2 flex-shrink-0 text-indigo-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path></svg>
<div>
<span class="font-medium text-gray-800">{{ 'events.list.organizer_label'|trans|default('Organizer') }}:</span>
<div class="text-xs mt-0.5">{{ event.organizer }}</div>
</div>
</p>
{% if imageUrl %}
<div class="h-48 bg-gray-200 overflow-hidden">
<img src="{{ asset(imageUrl) | imagine_filter('webp') }}"
alt="Affiche de l'événement {{ event.title }}"
class="w-full h-full object-cover">
</div>
</div>
{% else %}
{# Placeholder si aucune image n'est disponible #}
<div class="h-48 flex items-center justify-center bg-gray-100 text-gray-400">
<svg class="w-12 h-12" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 18m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"></path></svg>
</div>
{% endif %}
{# --- FIN AJOUT DE L'AFFICHE --- #}
{# Details Link (assuming an 'id' or slug is available) #}
<a href="{{ url('app_event_details', {id: event.id|default(loop.index)}) }}" class="mt-6 text-center w-full py-2 bg-indigo-50 hover:bg-indigo-100 text-indigo-600 font-semibold rounded-md text-sm transition duration-300 border border-indigo-100">
{{ 'events.list.details_button'|trans|default('View Details') }}
</a>
<div class="p-6 flex flex-col justify-between flex-grow">
<div>
{# Event Title #}
<h2 class="text-2xl font-bold text-indigo-700 mb-4">{{ event.title }}</h2>
<div class="space-y-3 text-gray-600">
{# Date Block (Start Date / End Date) #}
<p class="flex items-start text-sm">
<svg class="w-4 h-4 mt-1 mr-2 flex-shrink-0 text-indigo-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path></svg>
<div>
<span class="font-medium text-gray-800">{{ 'events.list.date_label'|trans|default('Date') }}:</span>
<div class="text-xs mt-0.5">
{{ event.startAt|date('d/m/Y H:i') }}
{% if event.startAt|date('Ymd') != event.endAt|date('Ymd') %}
- {{ event.endAt|date('d/m/Y H:i') }}
{% else %}
- {{ event.endAt|date('H:i') }}
{% endif %}
</div>
</div>
</p>
{# Location Block #}
<p class="flex items-start text-sm">
<svg class="w-4 h-4 mt-0.5 mr-2 flex-shrink-0 text-indigo-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"></path></svg>
<div>
<span class="font-medium text-gray-800">{{ 'events.list.location_label'|trans|default('Location') }}:</span>
<div class="text-xs mt-0.5">{{ event.location }}</div>
</div>
</p>
{# Organizer Block #}
<p class="flex items-start text-sm">
<svg class="w-4 h-4 mt-0.5 mr-2 flex-shrink-0 text-indigo-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path></svg>
<div>
<span class="font-medium text-gray-800">{{ 'events.list.organizer_label'|trans|default('Organizer') }}:</span>
<div class="text-xs mt-0.5">{{ event.organizer }}</div>
</div>
</p>
</div>
</div>
{# Details Link (assuming an 'id' or slug is available) #}
<a href="{{ url('app_event_details', {id: event.id|default(loop.index)}) }}" class="mt-6 text-center w-full py-2 bg-indigo-50 hover:bg-indigo-100 text-indigo-600 font-semibold rounded-md text-sm transition duration-300 border border-indigo-100">
{{ 'events.list.details_button'|trans|default('View Details') }}
</a>
</div>
</div>
{% endfor %}
</div>
@@ -92,10 +112,10 @@
{# Fallback if no events are found (repurposing the original styling) #}
<div class="max-w-3xl mx-auto text-center py-16 md:py-24 bg-white rounded-xl shadow-lg border border-gray-100">
<span class="text-6xl text-gray-400 mb-4 inline-block">
{# Icon: Calendar with an X #}
<svg class="lucide lucide-calendar-x" xmlns="http://www.w3.org/2000/svg" width="60" height="60" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="4" rx="2" ry="2"/><line x1="16" x2="16" y1="2" y2="6"/><line x1="8" x2="8" y1="2" y2="6"/><line x1="3" x2="21" y1="10" y2="10"/><path d="m14.5 12.5-5 5"/><path d="m9.5 12.5 5 5"/></svg>
</span>
<span class="text-6xl text-gray-400 mb-4 inline-block">
{# Icon: Calendar with an X #}
<svg class="lucide lucide-calendar-x" xmlns="http://www.w3.org/2000/svg" width="60" height="60" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="4" rx="2" ry="2"/><line x1="16" x2="16" y1="2" y2="6"/><line x1="8" x2="8" y1="2" y2="6"/><line x1="3" x2="21" y1="10" y2="10"/><path d="m14.5 12.5-5 5"/><path d="m9.5 12.5 5 5"/></svg>
</span>
<h2 class="text-4xl font-extrabold text-gray-800 mt-4 mb-3">
{{ 'events.no_events_title'|trans|default('No Upcoming Events') }}
@@ -113,4 +133,6 @@
{% endif %}
</div>
{% endblock %}

116
templates/event_view.twig Normal file
View File

@@ -0,0 +1,116 @@
{% extends 'base.twig' %}
{% block title %}{{ event.title }}{% endblock %}
{% block meta_description %}{{ event.title }}{% endblock %}
{% block canonical_url %}<link rel="canonical" href="{{ url('app_event_details',{id:event.id}) }}" />{% endblock %}
{% block breadcrumb_schema %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "{{ 'breadcrumb.home'|trans }}",
"item": "{{ app.request.schemeAndHttpHost }}"
},
{
"@type": "ListItem",
"position": 2,
"name": "{{ 'breadcrumb.events'|trans }}",
"item": "{{ url('app_events') }}"
},
{
"@type": "ListItem",
"position": 3,
"name": "{{ event.title }}",
"item": "{{ app.request.schemeAndHttpHost }}{{ path('app_event_details',{id:event.id}) }}"
}
]
}
</script>
{% endblock %}
{% block body %}
<div class="container mx-auto p-4 md:p-8 pt-12">
<div class="max-w-4xl mx-auto bg-white rounded-2xl shadow-2xl overflow-hidden">
{% set imageUrl = event.eventsFileName ? vich_uploader_asset(event, 'affiche') : null %}
{# Image / Affiche de l'événement #}
{% if imageUrl %}
<div class="h-64 sm:h-96 w-full overflow-hidden">
<img src="{{ asset(imageUrl) }}"
alt="Affiche de l'événement {{ event.title }}"
class="w-full h-full object-cover">
</div>
{% endif %}
<div class="p-6 sm:p-10">
{# Titre principal #}
<h1 class="text-4xl font-extrabold text-gray-900 mb-6 border-b pb-4">
{{ event.title }}
</h1>
{# Détails clés (Date, Lieu, Organisateur) #}
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8 border-b pb-6">
{# Date Block #}
<div class="flex items-start">
<svg class="w-6 h-6 mr-3 flex-shrink-0 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path></svg>
<div>
<p class="text-sm font-semibold text-indigo-600">{{ 'events.details.date'|trans|default('Date') }}</p>
<p class="text-lg font-medium text-gray-800">
{{ event.startAt|date('d/m/Y') }}
{% if event.startAt|date('Ymd') != event.endAt|date('Ymd') %}
- {{ event.endAt|date('d/m/Y') }}
{% else %}
- {{ event.endAt|date('H:i') }}
{% endif %}
</p>
</div>
</div>
{# Location Block #}
<div class="flex items-start">
<svg class="w-6 h-6 mr-3 flex-shrink-0 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"></path></svg>
<div>
<p class="text-sm font-semibold text-indigo-600">{{ 'events.details.location'|trans|default('Lieu') }}</p>
<p class="text-lg font-medium text-gray-800">{{ event.location }}</p>
</div>
</div>
{# Organizer Block #}
<div class="flex items-start">
<svg class="w-6 h-6 mr-3 flex-shrink-0 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path></svg>
<div>
<p class="text-sm font-semibold text-indigo-600">{{ 'events.details.organizer'|trans|default('Organisateur') }}</p>
<p class="text-lg font-medium text-gray-800">{{ event.organizer }}</p>
</div>
</div>
</div>
{# Description #}
{% if event.description is defined and event.description is not empty %}
<h2 class="text-2xl font-bold text-gray-800 mb-4">
{{ 'events.details.description_title'|trans|default('Description') }}
</h2>
<div class="prose max-w-none text-gray-600 leading-relaxed mb-10">
{{ event.description|raw }} {# Assuming description is HTML/Markdown content #}
</div>
{% endif %}
{# Bouton de retour #}
<a href="{{ url('app_events') }}" class="inline-flex items-center text-indigo-600 hover:text-indigo-800 transition duration-150 font-medium mt-4">
<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>
{{ 'events.details.back_to_list'|trans|default('Retour à la liste des événements') }}
</a>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,75 @@
{% extends 'mails/base.twig' %}
{% block subject %}
Nouveaux événement : {{ datas.event.title }}
{% endblock %}
{% block content %}
<mj-section background-color="#ffffff" padding-top="30px" padding-bottom="20px">
<mj-column>
<mj-text font-size="20px" color="#1F2937" font-weight="bold" line-height="28px">
Découvrez notre nouvel événement !
</mj-text>
<mj-text font-size="16px" color="#4B5563" padding-top="10px">
Nous sommes ravis de vous annoncer la création d'un nouvel événement. Voici les détails :
</mj-text>
</mj-column>
</mj-section>
{# Détails de l'événement #}
<mj-section background-color="#F3F4F6" padding="20px">
<mj-column>
<mj-text font-size="14px" color="#6B7280" padding-bottom="5px">
Titre de l'événement :
</mj-text>
<mj-text font-size="18px" color="#1F2937" font-weight="600" padding-bottom="15px">
{{ datas.event.title }}
</mj-text>
<mj-divider border-color="#D1D5DB" border-width="1px" padding="0 0 15px 0" />
{# Organisateur #}
<mj-text font-size="14px" color="#6B7280" padding-bottom="5px">
Organisateur :
</mj-text>
<mj-text font-size="16px" color="#1F2937" padding-bottom="15px">
{{ datas.event.organizer }}
</mj-text>
{# Lieu #}
<mj-text font-size="14px" color="#6B7280" padding-bottom="5px">
Lieu :
</mj-text>
<mj-text font-size="16px" color="#1F2937" padding-bottom="15px">
{{ datas.event.location }}
</mj-text>
{# Dates #}
<mj-table padding-bottom="15px">
<tr>
<td style="width: 50%; padding-right: 10px;">
<span style="font-size: 14px; color: #6B7280;">Début :</span><br />
<span style="font-size: 16px; color: #1F2937;">{{ datas.event.startAt|date('d/m/Y') }}</span>
</td>
<td style="width: 50%; padding-left: 10px;">
<span style="font-size: 14px; color: #6B7280;">Fin :</span><br />
<span style="font-size: 16px; color: #1F2937;">{{ datas.event.endAt|date('d/m/Y') }}</span>
</td>
</tr>
</mj-table>
<mj-divider border-color="#D1D5DB" border-width="1px" padding="10px 0 20px 0" />
{# Appel à l'action (CTA) vers l'URL publique #}
<mj-button background-color="#4F46E5" color="#ffffff" border-radius="8px"
href="{{ datas.url }}"
padding="10px 25px" font-size="16px">
Voir les détails de l'événement
</mj-button>
</mj-column>
</mj-section>
{% endblock %}

View File

@@ -0,0 +1,17 @@
Nouveaux événement : {{ datas.event.title }}
Découvrez notre nouvel événement !
Nous sommes ravis de vous annoncer la création d'un nouvel événement. Voici les détails :
Titre de l'événement : {{ datas.event.title }}
Organisateur : {{ datas.event.organizer }}
Lieu : {{ datas.event.location }}
Début : {{ datas.event.startAt|date('d/m/Y') }}
Fin : {{ datas.event.endAt|date('d/m/Y') }}
Voir les détails de l'événement :
{{ datas.url }}
À très vite,
L'équipe [Nom de votre organisation]