Files
ludikevent_crm/templates/dashboard/contrats/list.twig
Serreau Jovann afa6133907 ```
 feat(Product.php): Ajoute ProductDoc pour gérer les documents.
 feat(Contrats.php): Gère les fichiers du contrat via VichUploader.
 feat(templates): Crée template mail signature contrat.
 feat(SignatureController): Ajoute la signature du contrat.
 feat(ContratsController): Crée contrat depuis devis et liste contrats.
 feat(Client): Crée soumission contrat Docuseal.
 feat(DevisPdfService): Corrige l'assurance RC Pro.
 feat(.env): Ajoute CONTRAT_BASEURL.
 feat(ProductDocType): Crée formulaire pour les documents produit.
 feat(contrats/list.twig): Liste et actions pour les contrats.
 feat(UtmEvent.js): Track click document produit.
 feat(ContratEvent.php): Crée event pour envoi contrat.
 feat(admin.js): Initialise la recherche dynamique des contrats.
 feat(ContratPdfService): Génère le PDF du contrat DocuSeal.
 feat(products/add.twig): Ajoute gestion des documents produits.
 feat(ContratController): Crée controlleur contrat.
 feat(ContratSubscriber.php): Envoi du contrat par email.
 feat(reservation/produit.twig): Affiche les documents produit.
 feat(ProductController.php): Refactorisation et ajout des documents.
```
2026-01-22 15:58:57 +01:00

123 lines
10 KiB
Twig

{% extends 'dashboard/base.twig' %}
{% block title %}Contrats de locations{% endblock %}
{% block title_header %}Contrats de locations{% endblock %}
{% block body %}
<div class="space-y-6 pb-20">
{# --- BARRE DE RECHERCHE --- #}
<div class="relative group mb-12">
<div class="absolute inset-y-0 left-0 pl-6 flex items-center pointer-events-none">
<svg class="w-5 h-5 text-slate-500 group-focus-within:text-blue-500 transition-colors" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
</svg>
</div>
<input type="text"
id="searchContrat"
placeholder="Rechercher un contrat (Nom, N° ou Ville)..."
class="w-full bg-white/5 border border-white/10 backdrop-blur-xl text-white text-sm rounded-[1.5rem] pl-14 pr-6 py-5 focus:outline-none focus:ring-2 focus:ring-blue-500/50 focus:border-blue-500 transition-all placeholder:text-slate-500 font-medium">
</div>
<div id="contratsList" class="space-y-6">
{% for contrat in contrats %}
<div class="contrat-card bg-white/5 border border-white/10 backdrop-blur-md rounded-[2rem] overflow-hidden hover:border-blue-500/40 transition-all group">
<div class="grid grid-cols-1 lg:grid-cols-12">
{# --- COLONNE 1 : NUMÉRO & STATUS --- #}
<div class="lg:col-span-2 p-8 bg-white/[0.02] flex flex-col justify-center border-r border-white/5">
<span class="text-[9px] font-black text-blue-500 uppercase tracking-widest mb-2 block text-search">Référence</span>
<h3 class="text-white font-black italic text-lg tracking-tighter text-search">{{ contrat.numReservation }}</h3>
<div class="mt-4">
{% if contrat.isSigned %}
<span class="px-3 py-1 bg-emerald-500/10 text-emerald-500 text-[8px] font-black uppercase rounded-lg border border-emerald-500/20 inline-flex items-center gap-1">
<svg class="w-2 h-2" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path></svg>
Signé
</span>
{% else %}
<span class="px-3 py-1 bg-amber-500/10 text-amber-500 text-[8px] font-black uppercase rounded-lg border border-amber-500/20 inline-flex items-center gap-1">
<svg class="w-2 h-2" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z" clip-rule="evenodd"></path></svg>
En attente
</span>
{% endif %}
</div>
</div>
{# --- COLONNE 2 : CLIENT --- #}
<div class="lg:col-span-4 p-8 border-r border-white/5">
<div class="flex items-start gap-4">
<div class="w-10 h-10 bg-blue-600/10 rounded-xl flex items-center justify-center text-blue-500 shrink-0">
<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="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>
<div>
<span class="text-[9px] font-black text-slate-500 uppercase tracking-widest mb-1 block">Locataire</span>
<p class="text-white font-bold text-lg uppercase italic text-search">{{ contrat.customer.surname }} {{ contrat.customer.name }}</p>
<div class="mt-2 space-y-1">
<p class="text-slate-400 text-xs flex items-center gap-2">
<svg class="w-3 h-3 text-blue-500/50" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"></path></svg>
{{ contrat.customer.email }}
</p>
<p class="text-slate-400 text-xs flex items-center gap-2">
<svg class="w-3 h-3 text-blue-500/50" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z"></path></svg>
{{ contrat.customer.phone }}
</p>
</div>
</div>
</div>
</div>
{# --- COLONNE 3 : ÉVÉNEMENT --- #}
<div class="lg:col-span-4 p-8 border-r border-white/5">
<div class="flex items-start gap-4">
<div class="w-10 h-10 bg-amber-500/10 rounded-xl flex items-center justify-center text-amber-500 shrink-0">
<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="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>
<div>
<span class="text-[9px] font-black text-slate-500 uppercase tracking-widest mb-1 block">Lieu de l'événement</span>
<p class="text-white font-medium text-sm leading-relaxed">
{{ contrat.addressEvent }}<br>
<span class="text-amber-500 font-bold tracking-wider text-search">{{ contrat.zipCodeEvent }}</span>
<span class="text-white font-black uppercase italic text-search">{{ contrat.townEvent }}</span>
</p>
</div>
</div>
</div>
{# --- COLONNE 4 : ACTIONS (2/12) --- #}
<div class="lg:col-span-2 p-6 flex flex-row lg:flex-col justify-center gap-2">
{# VOIR #}
<a href="{{ path('app_crm_contrats', {id: contrat.id}) }}"
title="Voir les 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 group/btn border border-white/5 shadow-lg shadow-black/20">
<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>
{# TÉLÉCHARGER #}
<a download="contrat N°{{ contrat.numReservation }}"
href="{{ vich_uploader_asset(contrat,'devisFile') }}"
title="Télécharger le PDF"
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 shadow-lg shadow-black/20">
<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>
{# ENVOYER PAR EMAIL #}
<a href="{{ path('app_crm_contrats', {idSend: contrat.id}) }}"
title="Envoyer le contrat au client"
onclick="return confirm('Souhaitez-vous envoyer ce contrat par email à {{ 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 shadow-lg shadow-black/20">
<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>
</a>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
{{ knp_pagination_render(contrats) }}
{# --- JS SIMPLE POUR LA RECHERCHE INSTANTANÉE --- #}
{% endblock %}