feat(ReserverController): Ordonne les formules par position
🎨 style(formule/show.twig): Simplifie le texte de tarification
♻️ refactor(FormulesController): Permet de réordonner les formules
🐛 fix(SortableReorder.js): Corrige l'attribut URL de tbody
 feat(formules/view.twig): Ajoute un sélecteur de type de formule
🐛 fix(formules.twig): Correction de l'ordre d'affichage
🐛 fix(revervation.twig): Correction de la description SEO
```
This commit is contained in:
Serreau Jovann
2026-01-30 10:35:02 +01:00
parent b2928d896b
commit c5a0e41803
7 changed files with 31 additions and 14 deletions

View File

@@ -17,8 +17,7 @@ export class SortableReorder extends HTMLTableElement {
init() {
const tbody = this.querySelector('tbody');
const url = this.getAttribute('url');
const url = tbody.getAttribute('url');
if (!tbody || !url) {
console.warn('SortableReorder: <tbody> ou attribut "url" manquant.');
return;

View File

@@ -33,13 +33,24 @@ class FormulesController extends AbstractController
{
// --- JSON ENDPOINTS ---
#[Route(path: '/crm/formules', name: 'app_crm_formules', methods: ['GET'])]
public function formules(PaginatorInterface $paginator,AppLogger $appLogger,Request $request,FormulesRepository $formulesRepository): Response
#[Route(path: '/crm/formules', name: 'app_crm_formules', methods: ['GET','POST'])]
public function formules(PaginatorInterface $paginator,EntityManagerInterface $entityManager,AppLogger $appLogger,Request $request,FormulesRepository $formulesRepository): Response
{
if($request->isMethod('POST')) {
$items = $request->getContent();
$items = json_decode($items, true)['items'];
foreach ($items as $key => $item) {
$fv = $formulesRepository->find($item);
$fv->setPos($key);
$entityManager->persist($fv);
}
$entityManager->flush();
return $this->json([]);
}
$appLogger->record('VIEW', 'Consultation des formules');
return $this->render('dashboard/formules.twig', [
'formules' => $paginator->paginate($formulesRepository->findBy([],['id'=>'asc']), $request->query->getInt('page', 1), 10),
'formules' => $paginator->paginate($formulesRepository->findBy([],['pos'=>'asc']), $request->query->getInt('page', 1), 10),
]);
}
#[Route(path: '/crm/formules/delete/{id}', name: 'app_crm_formules_delete', methods: ['POST', 'GET'])]
@@ -116,11 +127,13 @@ class FormulesController extends AbstractController
#[Route(path: '/crm/formules/{id}', name: 'app_crm_formules_view', methods: ['GET', 'POST'])]
public function formulesView(?Formules $formules,FormulesProductInclusRepository $formulesProductInclusRepository,ProductRepository $productRepository, Request $request, EntityManagerInterface $entityManager, AppLogger $appLogger): Response
{
if (!$formules instanceof Formules) {
$this->addFlash('error', 'Formule introuvable.');
return $this->redirectToRoute('app_crm_formules');
}
if($request->query->has('type'))
$formules->setType($request->get('type',"pack"));
// 1. GESTION DU STATUT (Toggle Publish)
if ($request->get('act') === 'togglePublish') {
$status = $request->get('status') === 'true';

View File

@@ -151,7 +151,7 @@ class ReserverController extends AbstractController
{
return $this->render('revervation/formules.twig',[
'formules' => $formulesRepository->findBy(['isPublish'=>true],['updatedAt' => 'DESC']),
'formules' => $formulesRepository->findBy(['isPublish'=>true],['pos' => 'ASC']),
'tvaEnabled' => isset($_ENV['TVA_ENABLED']) && $_ENV['TVA_ENABLED'] === "true",
]);

View File

@@ -33,9 +33,9 @@
<th class="px-6 py-5 text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] text-right">Actions</th>
</tr>
</thead>
<tbody class="divide-y divide-white/5">
<tbody class="divide-y divide-white/5" url="{{ path('app_crm_formules') }}">
{% for formule in formules %}
<tr class="group hover:bg-white/[0.02] transition-colors">
<tr class="group hover:bg-white/[0.02] transition-colors" data-id="{{ formule.id }}">
{# MOVE ICON #}
<td class="px-6 py-4 text-center">
<div class="cursor-move text-slate-600 group-hover:text-blue-500 transition-colors p-2 rounded-xl hover:bg-blue-500/10 inline-flex">

View File

@@ -3,6 +3,7 @@
{% block title %}Modifier : {{ formule.name }}{% endblock %}
{% block actions %}
<div class="flex items-center space-x-4">
{# SYSTÈME DE STATUT TYPE 'ADMIN' ADAPTÉ AUX FORMULES #}
<div class="flex items-center">
@@ -50,7 +51,12 @@
<p class="text-[10px] font-bold text-blue-500 uppercase tracking-[0.3em]">{{ type|default('PACK')|upper }}</p>
</div>
</div>
<div class="w-full max-w-4xl mb-8 flex flex-col md:flex-row justify-center items-center gap-6">
<div class="flex gap-2 p-1 bg-white/5 backdrop-blur-xl border border-white/10 rounded-2xl">
<a href="{{ path('app_crm_formules_view',{type:"pack",id:formule.id}) }}" class="px-6 py-2 rounded-xl text-sm font-bold transition-all {% if type == 'pack' %}bg-blue-600 text-white shadow-lg shadow-blue-600/20{% else %}text-slate-400 hover:text-white{% endif %}">Mode Pack</a>
<a href="{{ path('app_crm_formules_view',{type:"free",id:formule.id}) }}" class="px-6 py-2 rounded-xl text-sm font-bold transition-all {% if type == 'free' %}bg-blue-600 text-white shadow-lg shadow-blue-600/20{% else %}text-slate-400 hover:text-white{% endif %}">Mode Libre</a>
</div>
</div>
<div class="w-full space-y-6">
{{ form_start(form, {'attr': {'class': 'space-y-6'}}) }}
@@ -143,7 +149,7 @@
{# Badge de rappel du type #}
<span class="text-[9px] font-boldtext-slate-300 uppercase px-3 py-1 bg-white/5 rounded-lg border border-white/10 italic">
Tarification dégressive
Tarification
</span>
</div>

View File

@@ -57,7 +57,7 @@
{# BOX TARIFS DÉGRESSIFS #}
<div class="bg-slate-50 border-4 border-slate-900 rounded-[2.5rem] p-8 mb-8 relative">
<div class="absolute -top-4 left-6 bg-white border-2 border-slate-900 px-4 py-1 rounded-full text-[10px] font-black uppercase text-[#f39e36]">Tarification Dégressive</div>
<div class="absolute -top-4 left-6 bg-white border-2 border-slate-900 px-4 py-1 rounded-full text-[10px] font-black uppercase text-[#f39e36]">Tarification</div>
<div class="grid grid-cols-3 gap-4">
<div class="text-center">

View File

@@ -2,7 +2,7 @@
{# --- SEO OPTIMISÉ --- #}
{% block title %}Nos Formules Location | Packs Gonflables & Événements - Ludik Event{% endblock %}
{% block description %}Découvrez nos packs événementiels clés en main. Location de châteaux gonflables, machines gourmandes et animations regroupés dans nos formules exclusives à prix dégressifs.{% endblock %}
{% block description %}Découvrez nos packs événementiels clés en main. Location de châteaux gonflables, machines gourmandes et animations regroupés dans nos formules exclusives.{% endblock %}
{% block breadcrumb_json %}
,{
@@ -60,7 +60,6 @@
{# Tags / Avantages #}
<div class="flex flex-wrap gap-2 mt-4">
<span class="text-[9px] font-black bg-blue-50 text-blue-600 px-3 py-1 rounded-lg border border-blue-100">Profitez de la livraison offerte dans un rayon de 50 à 70 km autour de Saint-Quentin.</span>
<span class="text-[9px] font-black bg-amber-50 text-amber-600 px-3 py-1 rounded-lg border border-amber-100">TARIF DÉGRESSIF</span>
</div>
{# Grille de Tarifs Dégressifs #}