feat(all): Ajoute l'attribut `data-turbo="false"` sur les liens.
🐛 fix(security): Corrige le chemin d'accès de l'espace client.
```
This commit is contained in:
Serreau Jovann
2026-01-23 10:48:49 +01:00
parent 160240fe85
commit 881dd88d71
19 changed files with 53 additions and 53 deletions

View File

@@ -62,7 +62,7 @@ security:
access_control:
- { path: ^/2fa, roles: PUBLIC_ACCESS }
# Protection de l'espace client (Firewall customer_reservation)
- { path: ^/espace-contrat, roles: [ROLE_CUSTOMER] }
- { path: ^/gestion-contrat, roles: [ROLE_CUSTOMER] }
# Protection du CRM (Firewall main)
- { path: ^/crm, roles: [ROLE_ADMIN] }
- { path: ^/, roles: PUBLIC_ACCESS }

View File

@@ -42,7 +42,7 @@ use Vich\UploaderBundle\Templating\Helper\UploaderHelper;
class ContratController extends AbstractController
{
#[Route('/contrat/payment/cancel/{id}', name: 'gestion_contrat_cancel')]
#[Route('/reservation/contrat/payment/cancel/{id}', name: 'gestion_contrat_cancel')]
public function gestionContratCancel(
Contrats $contrat,
Request $request
@@ -54,7 +54,7 @@ class ContratController extends AbstractController
'contrat' => $contrat
]);
}
#[Route('/contrat/payment/success/{id}', name: 'gestion_contrat_success')]
#[Route('/reservation/contrat/payment/success/{id}', name: 'gestion_contrat_success')]
public function gestionContratSuccess(
Contrats $contrat,
Request $request,
@@ -130,7 +130,7 @@ class ContratController extends AbstractController
]);
}
#[Route('/gestion-contrat/{num}', name: 'gestion_contrat_view')]
#[Route('/reservation/gestion-contrat/{num}', name: 'gestion_contrat_view')]
public function gestionContratView(string $num,UploaderHelper $uploaderHelper,KernelInterface $kernel,\App\Service\Stripe\Client $stripeClient,Client $client,Mailer $mailer,EntityManagerInterface $entityManager, Request $request, ContratsRepository $contratsRepository): Response
{
$contrat = $contratsRepository->findOneBy(['numReservation' => $num]);
@@ -350,7 +350,7 @@ class ContratController extends AbstractController
]);
}
#[Route('/gestion-contrat/configuration', name: 'gestion_contrat_finish', priority: 5)]
#[Route('/reservation/gestion-contrat/configuration', name: 'gestion_contrat_finish', priority: 5)]
public function gestionContratConfig(
Request $request,
EntityManagerInterface $em,
@@ -393,7 +393,7 @@ class ContratController extends AbstractController
return $this->render('reservation/contrat/finish_config.twig', ['customer' => $customer]);
}
#[Route('/espace-contrat', name: 'gestion_contrat', priority: 5)]
#[Route('/reservation/espace-contrat', name: 'gestion_contrat', priority: 5)]
public function gestionContrat(
Request $request,
EntityManagerInterface $em,

View File

@@ -3,7 +3,7 @@
{% block title %}Administrateurs{% endblock %}
{% block actions %}
<a href="{{ path('app_crm_administrateur_add') }}"
<a data-turbo="false" href="{{ path('app_crm_administrateur_add') }}"
class="inline-flex items-center px-4 py-2 text-sm font-black uppercase tracking-widest text-white bg-indigo-600 rounded-xl hover:bg-indigo-700 shadow-lg shadow-indigo-500/20 transition-all active:scale-95">
<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="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
@@ -98,7 +98,7 @@
<td class="px-8 py-5 text-right whitespace-nowrap">
<div class="flex items-center justify-end space-x-3">
{# Bouton Gérer #}
<a href="{{ path('app_crm_administrateur_view', {id: admin.id}) }}"
<a data-turbo="false" href="{{ path('app_crm_administrateur_view', {id: admin.id}) }}"
class="flex items-center space-x-2 px-3 py-2 bg-slate-50 dark:bg-slate-800 text-slate-600 dark:text-slate-300 hover:bg-indigo-600 hover:text-white dark:hover:bg-indigo-600 dark:hover:text-white rounded-xl transition-all border border-slate-200 dark:border-slate-700 font-bold text-xs shadow-sm"
title="Paramètres de l'Administrateur">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path></svg>
@@ -107,7 +107,7 @@
{# Bouton Supprimer avec protection ROOT/CLIENT_MAIN #}
{% if 'ROLE_ROOT' not in admin.roles %}
<a href="{{ path('app_crm_administrateur_delete', {id: admin.id}) }}?_token={{ csrf_token('delete' ~ admin.id) }}"
<a data-turbo="false" href="{{ path('app_crm_administrateur_delete', {id: admin.id}) }}?_token={{ csrf_token('delete' ~ admin.id) }}"
data-turbo-method="post"
data-turbo-confirm="Confirmer la suppression définitive de l'Administrateur {{ admin.firstName }} {{ admin.name }} ?"
class="p-2.5 text-slate-400 hover:text-red-600 hover:bg-red-50 dark:hover:bg-red-500/10 rounded-xl transition-all border border-transparent hover:border-red-100 dark:hover:border-red-500/20"

View File

@@ -4,7 +4,7 @@
{% block actions %}
{# Bouton de retour vers la liste #}
<a href="{{ path('app_crm_administrateur') }}" class="inline-flex items-center px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 dark:bg-gray-800 dark:text-gray-300 dark:border-gray-600 dark:hover:bg-gray-700 transition-colors">
<a data-turbo="false" href="{{ path('app_crm_administrateur') }}" class="inline-flex items-center px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 dark:bg-gray-800 dark:text-gray-300 dark:border-gray-600 dark:hover:bg-gray-700 transition-colors">
<svg class="w-4 h-4 mr-2" 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>

View File

@@ -3,7 +3,7 @@
{% block title %}Administrateur : {{ admin.firstName }} {{ admin.name }}{% endblock %}
{% block actions %}
<a href="{{ path('app_crm_administrateur') }}" class="flex items-center space-x-2 px-4 py-2 text-slate-500 hover:text-slate-800 dark:hover:text-white transition-colors">
<a data-turbo="false" href="{{ path('app_crm_administrateur') }}" class="flex items-center space-x-2 px-4 py-2 text-slate-500 hover:text-slate-800 dark:hover:text-white transition-colors">
<svg class="w-5 h-5" 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"/></svg>
<span class="text-sm font-bold tracking-tight">Retour à la liste</span>
</a>
@@ -51,7 +51,7 @@
<div class="w-2 h-2 rounded-full bg-amber-500 shadow-[0_0_8px_rgba(245,158,11,0.8)]"></div>
<span class="text-[10px] font-black text-amber-500 uppercase tracking-widest">Compte non activé</span>
</div>
<a href="{{ path('app_crm_administrateur_view', {id: admin.id, act: 'updateStatut', status: 'true'}) }}"
<a data-turbo="false" href="{{ path('app_crm_administrateur_view', {id: admin.id, act: 'updateStatut', status: 'true'}) }}"
class="px-6 py-3 bg-emerald-600 hover:bg-emerald-500 text-white text-[10px] font-black uppercase tracking-widest transition-all active:scale-95 border-l border-white/5">
Activer
</a>
@@ -62,7 +62,7 @@
<div class="w-2 h-2 rounded-full bg-emerald-500 shadow-[0_0_8px_rgba(16,185,129,0.8)]"></div>
<span class="text-[10px] font-black text-emerald-500 uppercase tracking-widest">Accès en ligne</span>
</div>
<a href="{{ path('app_crm_administrateur_view', {id: admin.id, act: 'updateStatut', status: 'false'}) }}"
<a data-turbo="false" href="{{ path('app_crm_administrateur_view', {id: admin.id, act: 'updateStatut', status: 'false'}) }}"
onclick="return confirm('Voulez-vous vraiment désactiver cet accès ?')"
class="px-6 py-3 bg-slate-100 dark:bg-slate-800 hover:bg-red-600 text-slate-500 dark:text-slate-400 hover:text-white text-[10px] font-black uppercase tracking-widest transition-all active:scale-95 border-l border-slate-200 dark:border-white/5">
Désactiver
@@ -124,7 +124,7 @@
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" /></svg>
Sécurité et Mot de passe
</h3>
<a href="{{ path('app_crm_administrateur_view', {id: admin.id, act: 'sendResetLink'}) }}"
<a data-turbo="false" href="{{ path('app_crm_administrateur_view', {id: admin.id, act: 'sendResetLink'}) }}"
onclick="return confirm('Envoyer l\'email de réinitialisation ?')"
class="px-4 py-2 bg-slate-100 dark:bg-slate-800 hover:bg-indigo-500 hover:text-white text-slate-600 dark:text-slate-300 text-[10px] font-black uppercase rounded-xl transition-all border border-slate-200 dark:border-slate-700">
Envoyer un lien de réinitialisation
@@ -167,7 +167,7 @@
</p>
</div>
</div>
<a href="{{ path('app_crm_administrateur_view', {id: admin.id, act: admin.googleAuthenticatorSecret ? 'disable2fa' : 'sendLink2faenable'}) }}"
<a data-turbo="false" href="{{ path('app_crm_administrateur_view', {id: admin.id, act: admin.googleAuthenticatorSecret ? 'disable2fa' : 'sendLink2faenable'}) }}"
class="px-4 py-2 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 text-slate-700 dark:text-slate-200 text-xs font-bold rounded-xl hover:bg-indigo-500 hover:text-white transition-all shadow-sm">
<span>{{ admin.googleAuthenticatorSecret ? 'Désactiver' : 'Envoyer le lien' }}</span>
</a>

View File

@@ -7,7 +7,7 @@
{% block actions %}
<div class="flex items-center space-x-3">
{# Bouton Exporter XLSX #}
<a href="{{ path('app_crm_audit_logs', {extract: true, account: app.request.query.get('account')}) }}" target="_blank" class="flex items-center space-x-2 px-5 py-2.5 bg-emerald-600 hover:bg-emerald-700 text-white text-sm font-bold rounded-xl transition-all shadow-lg shadow-emerald-500/20 group">
<a data-turbo="false" href="{{ path('app_crm_audit_logs', {extract: true, account: app.request.query.get('account')}) }}" target="_blank" class="flex items-center space-x-2 px-5 py-2.5 bg-emerald-600 hover:bg-emerald-700 text-white text-sm font-bold rounded-xl transition-all shadow-lg shadow-emerald-500/20 group">
<svg class="w-5 h-5 group-hover:scale-110 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
@@ -55,7 +55,7 @@
{# 3. BOUTON RESET (Si un filtre est actif) #}
{% if app.request.query.get('account') %}
<div class="w-full md:w-auto">
<a href="{{ path('app_crm_audit_logs') }}" class="flex items-center justify-center px-4 py-3.5 text-slate-400 hover:text-rose-500 text-[10px] font-black uppercase tracking-widest transition-colors group">
<a data-turbo="false" href="{{ path('app_crm_audit_logs') }}" class="flex items-center justify-center px-4 py-3.5 text-slate-400 hover:text-rose-500 text-[10px] font-black uppercase tracking-widest transition-colors group">
<svg class="w-4 h-4 mr-2 group-hover:rotate-90 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
</svg>

View File

@@ -78,7 +78,7 @@
<td class="p-6 text-right">
<div class="flex items-center justify-end space-x-2">
{% if backup.status == 'SUCCESS' %}
<a href="{{ path('app_crm_backup_download', {id: backup.id}) }}"
<a data-turbo="false" href="{{ path('app_crm_backup_download', {id: backup.id}) }}"
download="sauvegarde.zip"
data-turbo="false"
class="inline-flex items-center px-4 py-2 bg-blue-600 text-white rounded-xl hover:bg-blue-700 transition-all shadow-lg shadow-blue-600/20 group/btn">
@@ -90,7 +90,7 @@
{% endif %}
{% if is_granted('ROLE_ROOT') %}
<a href="{{ path('app_crm_backup_delete', {id: backup.id}) }}"
<a data-turbo="false" href="{{ path('app_crm_backup_delete', {id: backup.id}) }}"
onclick="return confirm('Supprimer définitivement cette sauvegarde ?')"
class="inline-flex items-center justify-center w-10 h-10 bg-white/5 border border-white/10 rounded-xl text-slate-400 hover:bg-red-500 hover:text-white hover:border-red-500 transition-all">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">

View File

@@ -33,7 +33,7 @@
<div class="space-y-1">
{% macro nav_link(path, label, icon_svg, current_route) %}
{% set isActive = app.request.get('_route') == current_route %}
<a href="{{ path }}" class="flex items-center space-x-3 px-4 py-3 rounded-xl transition-all duration-200 group {{ isActive ? 'bg-blue-600 text-white shadow-lg shadow-blue-500/30' : 'hover:bg-slate-100 dark:hover:bg-slate-800 text-slate-600 dark:text-slate-400' }}">
<a data-turbo="false" href="{{ path }}" class="flex items-center space-x-3 px-4 py-3 rounded-xl transition-all duration-200 group {{ isActive ? 'bg-blue-600 text-white shadow-lg shadow-blue-500/30' : 'hover:bg-slate-100 dark:hover:bg-slate-800 text-slate-600 dark:text-slate-400' }}">
<svg class="w-5 h-5 {{ isActive ? 'text-white' : 'text-slate-400 group-hover:text-blue-500' }}" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">{{ icon_svg|raw }}</svg>
<span class="font-semibold text-sm">{{ label }}</span>
</a>
@@ -60,9 +60,9 @@
<svg class="w-4 h-4 transition-transform duration-300 arrow-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>
</summary>
<div class="mt-2 space-y-1">
<a href="{{ path('app_crm_administrateur') }}" class="block px-12 py-2 text-sm hover:text-blue-600 transition-colors">Gestion Admins</a>
<a href="{{ path('app_crm_audit_logs') }}" class="block px-12 py-2 text-sm hover:text-blue-600 transition-colors">Audit Logs</a>
<a href="{{ path('app_crm_backup') }}" class="block px-12 py-2 text-sm hover:text-blue-600 transition-colors">Sauvegarde</a>
<a data-turbo="false" href="{{ path('app_crm_administrateur') }}" class="block px-12 py-2 text-sm hover:text-blue-600 transition-colors">Gestion Admins</a>
<a data-turbo="false" href="{{ path('app_crm_audit_logs') }}" class="block px-12 py-2 text-sm hover:text-blue-600 transition-colors">Audit Logs</a>
<a data-turbo="false" href="{{ path('app_crm_backup') }}" class="block px-12 py-2 text-sm hover:text-blue-600 transition-colors">Sauvegarde</a>
</div>
</details>
</div>
@@ -94,7 +94,7 @@
{# Profil utilisateur #}
<div class="flex items-center gap-2">
{# Zone Profil cliquable #}
<a href="{{ path('app_crm_profils') }}"
<a data-turbo="false" href="{{ path('app_crm_profils') }}"
class="flex items-center space-x-3 px-4 py-2 bg-slate-50 dark:bg-slate-900/50 rounded-2xl border border-slate-200 dark:border-slate-700 shrink-0 hover:bg-slate-100 dark:hover:bg-slate-800 transition-all group">
<div class="w-8 h-8 rounded-full bg-blue-600 flex items-center justify-center text-white font-bold text-xs shadow-lg shadow-blue-500/20 group-hover:scale-105 transition-transform">
@@ -108,7 +108,7 @@
</a>
{# Bouton Déconnexion séparé #}
<a href="{{ path('app_logout') }}"
<a data-turbo="false" href="{{ path('app_logout') }}"
title="Déconnexion"
class="w-10 h-10 flex items-center justify-center bg-red-500/10 hover:bg-red-500 text-red-500 hover:text-white border border-red-500/20 rounded-xl transition-all duration-300">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">

View File

@@ -4,7 +4,7 @@
{% block title_header %}Nouveau <span class="text-blue-500">Contrat de location</span>{% endblock %}
{% block actions %}
<a href="{{ path('app_crm_contrats') }}" class="flex items-center px-4 py-2 text-[10px] font-black text-slate-400 hover:text-white uppercase tracking-widest transition-all group">
<a data-turbo="false" href="{{ path('app_crm_contrats') }}" class="flex items-center px-4 py-2 text-[10px] font-black text-slate-400 hover:text-white uppercase tracking-widest transition-all group">
<svg class="w-4 h-4 mr-2 transform group-hover:-translate-x-1 transition-transform" 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"/>
</svg>

View File

@@ -110,19 +110,19 @@
{# --- COLONNE 5 : ACTIONS (2/12) --- #}
<div class="lg:col-span-2 p-6 flex flex-row lg:flex-col justify-center gap-2">
<a href="{{ path('app_crm_contrats', {id: contrat.id}) }}"
<a data-turbo="false" href="{{ path('app_crm_contrats', {id: contrat.id}) }}"
title="Détails"
class="flex-1 lg:flex-none py-3 bg-white/5 hover:bg-blue-600 text-white rounded-xl flex items-center justify-center transition-all border border-white/5">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path></svg>
</a>
<a download="contrat-{{ contrat.numReservation }}"
<a data-turbo="false" download="contrat-{{ contrat.numReservation }}"
href="{{ vich_uploader_asset(contrat,'devisFile') }}"
class="flex-1 lg:flex-none py-3 bg-white/5 hover:bg-emerald-600 text-white rounded-xl flex items-center justify-center transition-all border border-white/5">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z"></path></svg>
</a>
<a href="{{ path('app_crm_contrats', {idSend: contrat.id}) }}"
<a data-turbo="false" href="{{ path('app_crm_contrats', {idSend: contrat.id}) }}"
onclick="return confirm('Envoyer à {{ contrat.customer.email }} ?')"
class="flex-1 lg:flex-none py-3 bg-white/5 hover:bg-indigo-500 text-white rounded-xl flex items-center justify-center transition-all border border-white/5">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"></path></svg>

View File

@@ -5,7 +5,7 @@
{% block actions %}
<div class="flex items-center space-x-3">
<a href="{{ path('app_crm_customer_add') }}" class="flex items-center space-x-2 px-6 py-3 bg-blue-600 hover:bg-blue-500 text-white text-[10px] font-black uppercase tracking-[0.2em] rounded-xl transition-all shadow-lg shadow-blue-600/20 group">
<a data-turbo="false" href="{{ path('app_crm_customer_add') }}" class="flex items-center space-x-2 px-6 py-3 bg-blue-600 hover:bg-blue-500 text-white text-[10px] font-black uppercase tracking-[0.2em] rounded-xl transition-all shadow-lg shadow-blue-600/20 group">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M12 4v16m8-8H4" />
</svg>
@@ -123,14 +123,14 @@
<td class="px-8 py-6 text-right">
<div class="flex items-center justify-end space-x-2">
{# Consulter / Modifier #}
<a href="{{ path('app_crm_customer_edit', {id: customer.id}) }}"
<a data-turbo="false" href="{{ path('app_crm_customer_edit', {id: customer.id}) }}"
class="p-2.5 text-slate-400 hover:text-blue-400 hover:bg-blue-400/10 rounded-xl transition-all border border-transparent hover:border-blue-500/20"
title="Consulter la fiche">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" /></svg>
</a>
{# Supprimer #}
<a href="{{ path('app_crm_customer_delete', {id: customer.id}) }}?_token={{ csrf_token('delete' ~ customer.id) }}"
<a data-turbo="false" href="{{ path('app_crm_customer_delete', {id: customer.id}) }}?_token={{ csrf_token('delete' ~ customer.id) }}"
data-turbo-method="post"
data-turbo-confirm="Confirmer la suppression définitive de {{ customer.surname }} {{ customer.name }} ?"
class="p-2.5 text-slate-400 hover:text-rose-500 hover:bg-rose-500/10 rounded-xl transition-all border border-transparent hover:border-rose-500/20"

View File

@@ -8,7 +8,7 @@
{# Navigation haute #}
<div class="mb-6 px-2">
<a href="{{ path('app_crm_customer') }}" class="inline-flex items-center text-[10px] font-black text-slate-500 hover:text-white uppercase tracking-[0.2em] transition-colors group">
<a data-turbo="false" href="{{ path('app_crm_customer') }}" class="inline-flex items-center text-[10px] font-black text-slate-500 hover:text-white uppercase tracking-[0.2em] transition-colors group">
<svg class="w-4 h-4 mr-2 group-hover:-translate-x-1 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
</svg>
@@ -111,7 +111,7 @@
{# ACTIONS : Boutons espacés #}
<div class="pt-10 border-t border-white/5 flex items-center justify-end">
<div class="flex items-center space-x-16"> {# Espace large entre les deux boutons #}
<a href="{{ path('app_crm_customer') }}" class="mr-2 text-[10px] font-black text-slate-500 hover:text-rose-500 uppercase tracking-widest transition-colors">
<a data-turbo="false" href="{{ path('app_crm_customer') }}" class="mr-2 text-[10px] font-black text-slate-500 hover:text-rose-500 uppercase tracking-widest transition-colors">
Annuler l'opération
</a>
<button type="submit" class="p-2 px-16 py-4 bg-blue-600 hover:bg-blue-500 text-white text-[10px] font-black uppercase tracking-[0.2em] rounded-2xl shadow-lg shadow-blue-600/20 transition-all hover:scale-105 active:scale-95">

View File

@@ -4,7 +4,7 @@
{% block title_header %}Fiche <span class="text-blue-500">Client</span>{% endblock %}
{% block actions %}
<a href="{{ path('app_crm_customer') }}" class="flex items-center px-4 py-2 text-[10px] font-black text-slate-400 hover:text-white uppercase tracking-widest transition-all group">
<a data-turbo="false" href="{{ path('app_crm_customer') }}" class="flex items-center px-4 py-2 text-[10px] font-black text-slate-400 hover:text-white uppercase tracking-widest transition-all group">
<svg class="w-4 h-4 mr-2 transform group-hover:-translate-x-1 transition-transform" 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"/></svg>
Retour au listing
</a>
@@ -89,7 +89,7 @@
<p class="text-[9px] text-slate-500 mb-6 leading-relaxed uppercase font-bold tracking-tight">
La suppression est définitive sur l'intranet et Stripe.
</p>
<a href="{{ path('app_crm_customer_delete', {id: customer.id}) }}?_token={{ csrf_token('delete' ~ customer.id) }}"
<a data-turbo="false" href="{{ path('app_crm_customer_delete', {id: customer.id}) }}?_token={{ csrf_token('delete' ~ customer.id) }}"
data-turbo-method="post"
data-turbo-confirm="Confirmer la suppression définitive ?"
class="flex items-center justify-center w-full py-3 border border-rose-500/20 hover:bg-rose-600 text-rose-500 hover:text-white text-[9px] font-black uppercase tracking-widest rounded-xl transition-all shadow-lg shadow-rose-500/5">
@@ -122,7 +122,7 @@
</p>
</div>
<div class="flex space-x-2">
<a href="{{ path('app_crm_customer_edit', {id: customer.id, idAddr: address.id}) }}" class="p-2 bg-blue-500/10 text-blue-400 rounded-lg hover:bg-blue-500 hover:text-white transition-all">
<a data-turbo="false" href="{{ path('app_crm_customer_edit', {id: customer.id, idAddr: address.id}) }}" class="p-2 bg-blue-500/10 text-blue-400 rounded-lg hover:bg-blue-500 hover:text-white transition-all">
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"/></svg>
</a>
</div>
@@ -163,7 +163,7 @@
</button>
{% if editingAddress %}
<a href="{{ path('app_crm_customer_edit', {id: customer.id}) }}" class="text-center py-2 text-[9px] font-black text-slate-500 uppercase tracking-widest hover:text-white transition-colors">
<a data-turbo="false" href="{{ path('app_crm_customer_edit', {id: customer.id}) }}" class="text-center py-2 text-[9px] font-black text-slate-500 uppercase tracking-widest hover:text-white transition-colors">
Annuler la modification
</a>
{% endif %}

View File

@@ -4,7 +4,7 @@
{% block title_header %}Nouveau <span class="text-blue-500">Devis</span>{% endblock %}
{% block actions %}
<a href="{{ path('app_crm_devis') }}" class="flex items-center px-4 py-2 text-[10px] font-black text-slate-400 hover:text-white uppercase tracking-widest transition-all group">
<a data-turbo="false" href="{{ path('app_crm_devis') }}" class="flex items-center px-4 py-2 text-[10px] font-black text-slate-400 hover:text-white uppercase tracking-widest transition-all group">
<svg class="w-4 h-4 mr-2 transform group-hover:-translate-x-1 transition-transform" 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"/>
</svg>

View File

@@ -5,7 +5,7 @@
{% block actions %}
<div class="flex items-center space-x-3">
<a href="{{ path('app_crm_devis_add') }}" class="flex items-center space-x-2 px-6 py-3 bg-blue-600 hover:bg-blue-500 text-white text-[10px] font-black uppercase tracking-[0.2em] rounded-xl transition-all shadow-lg shadow-blue-600/20 group">
<a data-turbo="false" href="{{ path('app_crm_devis_add') }}" class="flex items-center space-x-2 px-6 py-3 bg-blue-600 hover:bg-blue-500 text-white text-[10px] font-black uppercase tracking-[0.2em] rounded-xl transition-all shadow-lg shadow-blue-600/20 group">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M12 4v16m8-8H4" />
</svg>
@@ -103,7 +103,7 @@
{# Renvoyer lien de signature #}
{% if quote.state == "created_waitsign" %}
<a href="{{ path('app_crm_devis', {resend: quote.id}) }}"
<a data-turbo="false" href="{{ path('app_crm_devis', {resend: quote.id}) }}"
title="Renvoyer le lien de signature"
class="p-2 bg-indigo-600/10 hover:bg-indigo-600 text-indigo-500 hover:text-white rounded-xl transition-all border border-indigo-500/20 shadow-lg shadow-indigo-600/5">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -114,7 +114,7 @@
{# Modifier : Interdit si signé #}
{% if quote.state != "signed" and quote.state != "signée" %}
<a href="{{ path('app_crm_devis_edit', {id: quote.id}) }}" class="p-2 bg-blue-600/10 hover:bg-blue-600 text-blue-500 hover:text-white rounded-xl transition-all border border-blue-500/20 shadow-lg shadow-blue-600/5">
<a data-turbo="false" href="{{ path('app_crm_devis_edit', {id: quote.id}) }}" class="p-2 bg-blue-600/10 hover:bg-blue-600 text-blue-500 hover:text-white rounded-xl transition-all border border-blue-500/20 shadow-lg shadow-blue-600/5">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" /></svg>
</a>
{% endif %}
@@ -129,7 +129,7 @@
<a download="AUDIT_{{ quote.num }}.pdf" href="{{ vich_uploader_asset(quote, 'devisAuditFile') }}" title="Télécharger le certificat d'audit" target="_blank" class="p-2 bg-purple-600/10 hover:bg-purple-600 text-purple-500 hover:text-white rounded-xl transition-all border border-purple-500/20 shadow-lg shadow-purple-600/5">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
</a>
<a href="{{ path('app_crm_contrats_create', {idDevis: quote.id}) }}"
<a data-turbo="false" href="{{ path('app_crm_contrats_create', {idDevis: quote.id}) }}"
title="Générer le contrat de location"
class="flex items-center gap-2 px-4 py-2 bg-blue-600/10 hover:bg-blue-600 text-blue-500 hover:text-white rounded-xl transition-all border border-blue-500/20 shadow-lg shadow-blue-600/5 font-bold text-xs uppercase tracking-widest">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">

View File

@@ -80,7 +80,7 @@
{# FOOTER ACTIONS #}
<div class="mt-12 mb-20 flex items-center justify-between backdrop-blur-xl bg-slate-900/40 p-6 rounded-[2.5rem] border border-white/5 shadow-xl">
<a href="{{ path('app_crm_product') }}" class="px-8 py-4 text-[10px] font-black text-slate-400 hover:text-white uppercase tracking-widest transition-colors flex items-center group">
<a data-turbo="false" href="{{ path('app_crm_product') }}" class="px-8 py-4 text-[10px] font-black text-slate-400 hover:text-white uppercase tracking-widest transition-colors flex items-center group">
<svg class="w-4 h-4 mr-2 transform group-hover:-translate-x-1 transition-transform" 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" />
</svg>

View File

@@ -5,7 +5,7 @@
{% block actions %}
<div class="flex items-center space-x-3">
<a href="{{ path('app_crm_product_add') }}" class="flex items-center space-x-2 px-6 py-3 bg-blue-600 hover:bg-blue-500 text-white text-[10px] font-black uppercase tracking-[0.2em] rounded-xl transition-all shadow-lg shadow-blue-600/20 group">
<a data-turbo="false" href="{{ path('app_crm_product_add') }}" class="flex items-center space-x-2 px-6 py-3 bg-blue-600 hover:bg-blue-500 text-white text-[10px] font-black uppercase tracking-[0.2em] rounded-xl transition-all shadow-lg shadow-blue-600/20 group">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M12 4v16m8-8H4" />
</svg>
@@ -94,11 +94,11 @@
{# ACTIONS #}
<td class="px-6 py-4 text-right">
<div class="flex items-center justify-end space-x-2">
<a href="{{ path('app_crm_product_edit', {id: product.id}) }}" class="p-2 bg-blue-600/10 hover:bg-blue-600 text-blue-500 hover:text-white rounded-xl transition-all border border-blue-500/20 shadow-lg shadow-blue-600/5">
<a data-turbo="false" href="{{ path('app_crm_product_edit', {id: product.id}) }}" class="p-2 bg-blue-600/10 hover:bg-blue-600 text-blue-500 hover:text-white rounded-xl transition-all border border-blue-500/20 shadow-lg shadow-blue-600/5">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" /></svg>
</a>
<a href="{{ path('app_crm_product_delete', {id: product.id}) }}?_token={{ csrf_token('delete' ~ product.id) }}"
<a data-turbo="false" href="{{ path('app_crm_product_delete', {id: product.id}) }}?_token={{ csrf_token('delete' ~ product.id) }}"
data-turbo-method="post"
data-turbo-confirm="Confirmer la suppression définitive de '{{ product.name }}' ?"
class="p-2 bg-rose-500/10 hover:bg-rose-500 text-rose-500 hover:text-white rounded-xl transition-all border border-rose-500/20 shadow-lg shadow-rose-500/5">
@@ -135,7 +135,7 @@
</div>
<div class="flex items-center space-x-3">
<div class="flex items-center space-x-3">
<a href="{{ path('app_crm_product_options_add') }}" class="flex items-center space-x-2 px-6 py-3 bg-blue-600 hover:bg-blue-500 text-white text-[10px] font-black uppercase tracking-[0.2em] rounded-xl transition-all shadow-lg shadow-blue-600/20 group">
<a data-turbo="false" href="{{ path('app_crm_product_options_add') }}" class="flex items-center space-x-2 px-6 py-3 bg-blue-600 hover:bg-blue-500 text-white text-[10px] font-black uppercase tracking-[0.2em] rounded-xl transition-all shadow-lg shadow-blue-600/20 group">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M12 4v16m8-8H4"></path>
</svg>
@@ -201,11 +201,11 @@
{# ACTIONS #}
<td class="px-6 py-4 text-right">
<div class="flex items-center justify-end space-x-2">
<a href="{{ path('app_crm_product_options_edit', {id: option.id}) }}" class="p-2 bg-blue-600/10 hover:bg-blue-600 text-blue-500 hover:text-white rounded-xl transition-all border border-blue-500/20 shadow-lg shadow-blue-600/5">
<a data-turbo="false" href="{{ path('app_crm_product_options_edit', {id: option.id}) }}" class="p-2 bg-blue-600/10 hover:bg-blue-600 text-blue-500 hover:text-white rounded-xl transition-all border border-blue-500/20 shadow-lg shadow-blue-600/5">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" /></svg>
</a>
<a href="{{ path('app_crm_product_option_delete', {id: option.id}) }}?_token={{ csrf_token('delete' ~ option.id) }}"
<a data-turbo="false" href="{{ path('app_crm_product_option_delete', {id: option.id}) }}?_token={{ csrf_token('delete' ~ option.id) }}"
data-turbo-method="post"
data-turbo-confirm="Confirmer la suppression définitive de '{{ option.name }}' ?"
class="p-2 bg-rose-500/10 hover:bg-rose-500 text-rose-500 hover:text-white rounded-xl transition-all border border-rose-500/20 shadow-lg shadow-rose-500/5">

View File

@@ -113,7 +113,7 @@
Ajoutez une couche de protection en utilisant une application comme Google Authenticator pour valider vos connexions.
</p>
<a href="{{ path('app_crm_profils', {act: user.googleAuthenticatorSecret ? 'disable2fa' : 'sendLink2faenable'}) }}"
<a data-turbo="false" href="{{ path('app_crm_profils', {act: user.googleAuthenticatorSecret ? 'disable2fa' : 'sendLink2faenable'}) }}"
class="flex items-center justify-center w-full py-4 {% if user.googleAuthenticatorSecret %}bg-white/5 hover:bg-rose-600 text-slate-300 hover:text-white border-white/10 hover:border-rose-600{% else %}bg-indigo-600 hover:bg-indigo-700 text-white shadow-lg shadow-indigo-600/20 border-transparent{% endif %} border rounded-2xl text-[10px] font-black uppercase tracking-[0.3em] transition-all duration-300">
<span>{{ user.googleAuthenticatorSecret ? 'Désactiver la protection' : 'Envoyer le lien d\'activation' }}</span>
</a>
@@ -128,7 +128,7 @@
</div>
<h3 class="text-white font-bold text-lg mb-2">Session Intranet</h3>
<p class="text-slate-400 text-sm mb-6 leading-relaxed">Déconnectez-vous pour fermer vos accès sur cet appareil et sécuriser vos données.</p>
<a href="{{ path('app_logout') }}" class="block text-center w-full py-4 bg-rose-500/20 hover:bg-rose-600 text-rose-500 hover:text-white text-[10px] font-black uppercase tracking-[0.3em] rounded-2xl border border-rose-500/20 transition-all">
<a data-turbo="false" href="{{ path('app_logout') }}" class="block text-center w-full py-4 bg-rose-500/20 hover:bg-rose-600 text-rose-500 hover:text-white text-[10px] font-black uppercase tracking-[0.3em] rounded-2xl border border-rose-500/20 transition-all">
Se déconnecter
</a>
</div>

View File

@@ -67,7 +67,7 @@
<span class="text-[9px] font-bold text-slate-600 uppercase tracking-[0.2em]">Identifiant</span>
<span class="text-xs font-mono text-slate-400">#{{ item.id }}</span>
</div>
<a href="{{ item.link }}" class="flex items-center space-x-2 px-6 py-3 bg-white/5 hover:bg-blue-600 text-white border border-white/10 hover:border-blue-500 rounded-2xl text-[10px] font-black uppercase tracking-[0.2em] transition-all duration-300 shadow-lg">
<a data-turbo="false" href="{{ item.link }}" class="flex items-center space-x-2 px-6 py-3 bg-white/5 hover:bg-blue-600 text-white border border-white/10 hover:border-blue-500 rounded-2xl text-[10px] font-black uppercase tracking-[0.2em] transition-all duration-300 shadow-lg">
<span>Voir Fiche</span>
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M14 5l7 7m0 0l-7 7m7-7H3"/></svg>
</a>