Files
ludikevent_crm/templates/dashboard/contrats/add.twig
Serreau Jovann e644dc4b85 ```
 feat(templates): Améliore la lisibilité et l'esthétique de l'interface

Ce commit met à jour les couleurs et les styles de texte dans plusieurs
templates pour améliorer la lisibilité et l'esthétique globale de
l'interface utilisateur.  Les couleurs de texte secondaires sont
ajustées pour un meilleur contraste.
```
2026-01-29 18:20:22 +01:00

281 lines
23 KiB
Twig

{% extends 'dashboard/base.twig' %}
{% block title %}Création Contrat de location{% endblock %}
{% block title_header %}Nouveau <span class="text-blue-500">Contrat de location</span>{% endblock %}
{% block actions %}
<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>
Annuler
</a>
{% endblock %}
{% block body %}
<div class=" mx-auto animate-in fade-in slide-in-from-bottom-4 duration-700 pb-24">
{{ form_start(form) }}
<div class="grid grid-cols-1 md:grid-cols-12 gap-8">
{# --- BLOC 01 : CLIENT & VIGILANCE --- #}
<div class="md:col-span-4 flex flex-col gap-8">
<div class="backdrop-blur-xl bg-slate-900/40 border border-white/5 rounded-[2.5rem] p-8 shadow-2xl flex-grow">
<h3 class="text-sm font-black text-blue-500 uppercase tracking-widest mb-8 flex items-center">
<span class="w-6 h-6 bg-blue-600/20 rounded-lg flex items-center justify-center mr-3 text-[10px]">01</span>
Client & Type
</h3>
<div class="space-y-6">
<div>
{{ form_label(form.customer, 'Client', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
{{ form_widget(form.customer, {'attr': {'class': 'w-full bg-slate-950/50 border-white/5 rounded-2xl text-white focus:ring-blue-500/20 focus:border-blue-500 transition-all py-3.5 px-5'}}) }}
</div>
<div>
{{ form_label(form.type, 'Type de contrat', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
{{ form_widget(form.type, {'attr': {'class': 'w-full bg-slate-950/50 border-white/5 rounded-2xl text-white focus:ring-blue-500/20 focus:border-blue-500 transition-all py-3.5 px-5'}}) }}
</div>
<div class="pt-6 border-t border-white/5">
{{ form_label(form.notes, 'Notes de vigilance', {'label_attr': {'class': 'text-[10px] font-black text-rose-500 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
<div class="relative group">
{{ form_widget(form.notes, {
'attr': {
'class': 'w-full bg-rose-500/5 border border-rose-500/10 rounded-2xl text-rose-100 placeholder:text-rose-500/30 focus:ring-rose-500/20 focus:border-rose-500/40 transition-all py-3.5 px-5 text-xs italic',
'placeholder': 'Client exigeant, chien, accès compliqué...',
'rows': '6'
}
}) }}
<div class="absolute top-4 right-4 text-rose-500/30">
<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 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" /></svg>
</div>
</div>
</div>
</div>
</div>
</div>
{# --- BLOC 02 & 03 : ADRESSE & TECHNIQUE --- #}
<div class="md:col-span-8 flex flex-col gap-8">
{# LIEU DE L'ÉVÉNEMENT (Tous les champs d'adresse) #}
<div class="backdrop-blur-xl bg-slate-900/40 border border-white/5 rounded-[2.5rem] p-8 shadow-2xl">
<h3 class="text-sm font-black text-emerald-500 uppercase tracking-widest mb-8 flex items-center">
<span class="w-6 h-6 bg-emerald-600/20 rounded-lg flex items-center justify-center mr-3 text-[10px]">02</span>
Lieu de l'événement
</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-6 gap-y-5">
<div class="md:col-span-2">
{{ form_label(form.addressEvent, 'Adresse principale', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
{{ form_widget(form.addressEvent, {'attr': {'class': 'w-full bg-slate-950/50 border-white/5 rounded-2xl text-white focus:ring-blue-500/20 focus:border-blue-500 transition-all py-3.5 px-5'}}) }}
</div>
<div>
{{ form_label(form.address2Event, 'Complément d\'adresse 1', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
{{ form_widget(form.address2Event, {'attr': {'class': 'w-full bg-slate-950/50 border-white/5 rounded-2xl text-white focus:ring-blue-500/20 focus:border-blue-500 transition-all py-3.5 px-5', 'placeholder': 'Bâtiment, étage...'}}) }}
</div>
<div>
{{ form_label(form.address3Event, 'Complément d\'adresse 2', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
{{ form_widget(form.address3Event, {'attr': {'class': 'w-full bg-slate-950/50 border-white/5 rounded-2xl text-white focus:ring-blue-500/20 focus:border-blue-500 transition-all py-3.5 px-5', 'placeholder': 'Code, interphone...'}}) }}
</div>
<div>
{{ form_label(form.zipCodeEvent, 'Code Postal', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
{{ form_widget(form.zipCodeEvent, {'attr': {'class': 'w-full bg-slate-950/50 border-white/5 rounded-2xl text-white font-mono focus:ring-blue-500/20 focus:border-blue-500 transition-all py-3.5 px-5'}}) }}
</div>
<div>
{{ form_label(form.townEvent, 'Ville', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
{{ form_widget(form.townEvent, {'attr': {'class': 'w-full bg-slate-950/50 border-white/5 rounded-2xl text-white focus:ring-blue-500/20 focus:border-blue-500 transition-all py-3.5 px-5'}}) }}
</div>
<div class="md:col-span-2">
{{ form_label(form.details, 'Précisions de livraison / Notes d\'accès', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
{{ form_widget(form.details, {'attr': {'class': 'w-full bg-slate-950/50 border-white/5 rounded-2xl text-white focus:ring-blue-500/20 focus:border-blue-500 transition-all py-3.5 px-5', 'rows': '2', 'placeholder': 'Ex: Portail étroit, se garer dans la cour...'}}) }}
</div>
</div>
</div>
{# TECHNIQUE (Bloc 03) #}
<div class="backdrop-blur-xl bg-slate-900/60 border border-amber-500/10 rounded-[2.5rem] p-8 shadow-2xl">
<h3 class="text-sm font-black text-amber-500 uppercase tracking-widest mb-8 flex items-center">
<span class="w-6 h-6 bg-amber-600/20 rounded-lg flex items-center justify-center mr-3 text-[10px]">03</span>
Contraintes Techniques
</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
{{ form_label(form.typeSol, 'Nature du sol', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
{{ form_widget(form.typeSol, {'attr': {'class': 'w-full bg-slate-950/50 border-white/5 rounded-2xl text-white focus:ring-amber-500/20 focus:border-amber-500 transition-all py-3.5 px-5'}}) }}
</div>
<div>
{{ form_label(form.pente, 'Pente / Dénivelé', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
{{ form_widget(form.pente, {'attr': {'class': 'w-full bg-slate-950/50 border-white/5 rounded-2xl text-white focus:ring-amber-500/20 focus:border-amber-500 transition-all py-3.5 px-5'}}) }}
</div>
<div>
{{ form_label(form.access, 'Accès Camion', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
{{ form_widget(form.access, {'attr': {'class': 'w-full bg-slate-950/50 border-white/5 rounded-2xl text-white focus:ring-amber-500/20 focus:border-amber-500 transition-all py-3.5 px-5'}}) }}
</div>
<div>
{{ form_label(form.distancePower, 'Distance Point électrique', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
{{ form_widget(form.distancePower, {'attr': {'class': 'w-full bg-slate-950/50 border-white/5 rounded-2xl text-white focus:ring-amber-500/20 focus:border-amber-500 transition-all py-3.5 px-5'}}) }}
</div>
</div>
</div>
</div>
</div>
{# --- BLOC 04 : PÉRIODE --- #}
<div class="mt-8 backdrop-blur-xl bg-blue-600/5 border border-blue-500/10 rounded-[2.5rem] p-8 shadow-2xl">
<h3 class="text-sm font-black text-blue-400 uppercase tracking-widest mb-8 flex items-center justify-center">
<span class="w-6 h-6 bg-blue-600/20 rounded-lg flex items-center justify-center mr-3 text-[10px]">04</span>
Période de location
</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 max-w-4xl mx-auto">
<div>
{{ form_label(form.dateAt, 'Début de l\'événement', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] ml-1 mb-2 block text-center'}}) }}
{{ form_widget(form.dateAt, {'attr': {'class': 'w-full bg-slate-950/50 border-white/5 rounded-2xl text-white text-center focus:ring-blue-500/40 focus:border-blue-500 transition-all py-4 px-5 font-black'}}) }}
</div>
<div>
{{ form_label(form.endAt, 'Fin de l\'événement', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] ml-1 mb-2 block text-center'}}) }}
{{ form_widget(form.endAt, {'attr': {'class': 'w-full bg-slate-950/50 border-white/5 rounded-2xl text-white text-center focus:ring-blue-500/40 focus:border-blue-500 transition-all py-4 px-5 font-black'}}) }}
</div>
</div>
</div>
{# --- BLOC 05 : REPEATER PRESTATIONS --- #}
<div class="form-repeater mt-12" data-component="repeater" is="repeat-line">
<div class="flex items-center justify-between mb-8 px-8">
<h3 class="text-sm font-black text-purple-500 uppercase tracking-widest flex items-center">
<span class="w-6 h-6 bg-purple-600/20 rounded-lg flex items-center justify-center mr-3 text-[10px]">05</span>
Détail des prestations
</h3>
</div>
<ol class="form-repeater__rows space-y-6" data-ref="rows">
{% for key, line in lines %}
<li class="form-repeater__row group animate-in slide-in-from-right-5 duration-300">
<input type="hidden" value="{{ line.id }}" name="lines[{{ key }}][id]">
<fieldset class="backdrop-blur-md bg-white/5 border border-white/10 rounded-[2.5rem] p-8 hover:border-purple-500/30 transition-all shadow-xl">
<div class="grid grid-cols-1 lg:grid-cols-12 gap-6 items-end">
{# 1. PRODUIT AVEC BOUTON RECHERCHE #}
<div class="lg:col-span-4">
<label class="text-[9px] font-black text-slate-300 uppercase tracking-widest ml-1 mb-2 block">Produit / Prestation</label>
<div class="relative flex items-center">
<input type="text" name="lines[{{ key }}][name]" value="{{ line.name }}" required class="w-full bg-slate-950/50 border-white/5 rounded-2xl text-white focus:ring-purple-500/20 focus:border-purple-500 transition-all py-3 pl-5 pr-12 text-sm">
{# BOUTON RECHERCHER #}
<button is="search-product" type="button" class="absolute right-2 p-2 bg-purple-500/10 hover:bg-purple-500 text-purple-400 hover:text-white rounded-xl transition-all duration-300 group/search" title="Rechercher un produit">
Rechercher un produit
</button>
</div>
</div>
{# 2. PRIX 1J #}
<div class="lg:col-span-2">
<label class="text-[9px] font-black text-slate-300 uppercase tracking-widest ml-1 mb-2 block">Prix 1J HT</label>
<input type="text" name="lines[{{ key }}][priceHt1Day]" value="{{ line.priceHt1Day }}" required class="w-full bg-slate-950/50 border-white/5 rounded-2xl text-white focus:ring-purple-500/20 focus:border-purple-500 transition-all py-3 px-5 text-sm font-mono">
</div>
{# 3. PRIX SUP #}
<div class="lg:col-span-2">
<label class="text-[9px] font-black text-slate-300 uppercase tracking-widest ml-1 mb-2 block">Prix J Sup. HT</label>
<input type="text" name="lines[{{ key }}][priceHtSupDay]" value="{{ line.priceHtSupDay }}" required class="w-full bg-slate-950/50 border-white/5 rounded-2xl text-white focus:ring-purple-500/20 focus:border-purple-500 transition-all py-3 px-5 text-sm font-mono">
</div>
{# 4. CAUTION #}
<div class="lg:col-span-3">
<label class="text-[9px] font-black text-slate-300 uppercase tracking-widest ml-1 mb-2 block">Caution (€)</label>
<input type="text" name="lines[{{ key }}][caution]" value="{{ line.caution }}" required class="w-full bg-slate-950/50 border-white/5 rounded-2xl text-white focus:ring-purple-500/20 focus:border-purple-500 transition-all py-3 px-5 text-sm font-mono">
</div>
{# 5. SUPPRIMER #}
<div class="lg:col-span-1 flex justify-end">
<button type="button" data-ref="removeButton" class="w-12 h-12 flex items-center justify-center bg-red-500/10 hover:bg-red-500 text-red-500 hover:text-white rounded-xl transition-all shadow-lg group/del">
<svg class="w-5 h-5 group-hover/del:scale-110 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
</svg>
</button>
</div>
</div>
</fieldset>
</li>
{% endfor %}
</ol>
<div class="mt-8 px-4">
<button type="button" data-ref="addButton" class="w-full py-5 border-2 border-dashed border-white/10 hover:border-purple-500/50 bg-white/5 hover:bg-purple-500/10 rounded-3xl text-purple-400 text-[10px] font-black uppercase tracking-[0.4em] transition-all flex items-center justify-center space-x-4 group">
<span class="text-2xl group-hover:rotate-180 transition-transform duration-500">+</span>
<span>Ajouter une prestation</span>
</button>
</div>
</div>
<div class="form-repeater mt-12" data-component="repeater2" is="repeat-line">
<div class="flex items-center justify-between mb-8 px-8">
<h3 class="text-sm font-black text-purple-500 uppercase tracking-widest flex items-center">
<span class="w-6 h-6 bg-purple-600/20 rounded-lg flex items-center justify-center mr-3 text-[10px]">05</span>
Détail des options
</h3>
</div>
<ol class="form-repeater__rows space-y-6" data-ref="rows">
{% for key, line in options %}
<li class="form-repeater__row group animate-in slide-in-from-right-5 duration-300">
<input type="hidden" value="{{ line.id }}" name="options[{{ key }}][id]">
<fieldset class="backdrop-blur-md bg-white/5 border border-white/10 rounded-[2.5rem] p-8 hover:border-purple-500/30 transition-all shadow-xl">
<div class="grid grid-cols-1 lg:grid-cols-12 gap-6 items-end">
{# 1. PRODUIT AVEC BOUTON RECHERCHE #}
<div class="lg:col-span-6">
<label class="text-[9px] font-black text-slate-300 uppercase tracking-widest ml-1 mb-2 block">Produit / Prestation</label>
<div class="relative flex items-center">
<input type="text" name="options[{{ key }}][name]" value="{{ line.name }}" required class="w-full bg-slate-950/50 border-white/5 rounded-2xl text-white focus:ring-purple-500/20 focus:border-purple-500 transition-all py-3 pl-5 pr-12 text-sm">
{# BOUTON RECHERCHER #}
<button is="search-options" type="button" class="absolute right-2 p-2 bg-purple-500/10 hover:bg-purple-500 text-purple-400 hover:text-white rounded-xl transition-all duration-300 group/search" title="Rechercher un produit">
Rechercher une options
</button>
</div>
</div>
<div class="lg:col-span-2">
<label class="text-[9px] font-black text-slate-300 uppercase tracking-widest ml-1 mb-2 block">Détails</label>
<input type="text" name="options[{{ key }}][details]" value="{{ line.details }}" required class="w-full bg-slate-950/50 border-white/5 rounded-2xl text-white focus:ring-purple-500/20 focus:border-purple-500 transition-all py-3 px-5 text-sm font-mono">
</div>
{# 2. PRIX 1J #}
<div class="lg:col-span-3">
<label class="text-[9px] font-black text-slate-300 uppercase tracking-widest ml-1 mb-2 block">Prix 1J HT</label>
<input type="text" name="options[{{ key }}][priceHt]" value="{{ line.priceHt }}" required class="w-full bg-slate-950/50 border-white/5 rounded-2xl text-white focus:ring-purple-500/20 focus:border-purple-500 transition-all py-3 px-5 text-sm font-mono">
</div>
{# 5. SUPPRIMER #}
<div class="lg:col-span-1 flex justify-end">
<button type="button" data-ref="removeButton" class="w-12 h-12 flex items-center justify-center bg-red-500/10 hover:bg-red-500 text-red-500 hover:text-white rounded-xl transition-all shadow-lg group/del">
<svg class="w-5 h-5 group-hover/del:scale-110 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
</svg>
</button>
</div>
</div>
</fieldset>
</li>
{% endfor %}
</ol>
<div class="mt-8 px-4">
<button type="button" data-ref="addButton" class="w-full py-5 border-2 border-dashed border-white/10 hover:border-purple-500/50 bg-white/5 hover:bg-purple-500/10 rounded-3xl text-purple-400 text-[10px] font-black uppercase tracking-[0.4em] transition-all flex items-center justify-center space-x-4 group">
<span class="text-2xl group-hover:rotate-180 transition-transform duration-500">+</span>
<span>Ajouter une prestation</span>
</button>
</div>
</div>
{# --- BARRE D'ACTIONS FINALE --- #}
<div class="mt-16 flex items-center justify-end backdrop-blur-xl bg-slate-900/40 p-6 rounded-[3rem] border border-white/5 shadow-xl">
<button type="submit" class="group px-16 py-5 bg-blue-600 hover:bg-blue-500 text-white text-[11px] font-black uppercase tracking-[0.3em] rounded-[2rem] transition-all shadow-lg shadow-blue-600/30 flex items-center hover:scale-[1.02] active:scale-95">
Valider et Créer le contrat
<svg class="w-5 h-5 ml-4 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="3" d="M14 5l7 7m0 0l-7 7m7-7H3"/></svg>
</button>
</div>
{{ form_end(form) }}
</div>
{% endblock %}