Files
ludikevent_crm/templates/dashboard/products/add.twig
Serreau Jovann d993a545d9 ```
 feat(Product): Ajoute la publication des produits et les périodes bloquées

Ajoute la possibilité de publier ou masquer un produit.
Permet de bloquer des périodes pour un produit.
Corrige des bugs liés à la suppression des produits du panier.
Mise à jour de l'affichage du calendrier pour les blocages.
```
2026-02-03 14:53:11 +01:00

540 lines
41 KiB
Twig

{% extends 'dashboard/base.twig' %}
{% block title %}Fiche Produit{% endblock %}
{% block title_header %}Gestion du <span class="text-blue-500">Matériel</span>{% endblock %}
{% block actions %}
<div class="flex items-center gap-4">
{% if product is defined and product is not null and product.id %}
<div class="flex items-center">
{% if not product.isPublish %}
<div class="flex items-center bg-white/5 backdrop-blur-xl border border-rose-500/30 rounded-2xl overflow-hidden shadow-xl">
<div class="flex items-center px-5 py-3 space-x-3 bg-rose-500/5">
<div class="w-2 h-2 rounded-full bg-rose-500 shadow-[0_0_8px_rgba(244,63,94,0.8)]"></div>
<span class="text-[10px] font-black text-rose-500 uppercase tracking-widest">Hors ligne</span>
</div>
<a data-turbo="false" href="{{ path('app_crm_product_edit', {id: product.id, act: 'togglePublish', 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">
Publier
</a>
</div>
{% else %}
<div class="flex items-center bg-white/5 backdrop-blur-xl border border-emerald-500/30 rounded-2xl overflow-hidden shadow-xl">
<div class="flex items-center px-5 py-3 space-x-3 bg-emerald-500/5">
<div class="w-2 h-2 rounded-full bg-emerald-400 shadow-[0_0_8px_rgba(52,211,153,0.8)] animate-pulse"></div>
<span class="text-[10px] font-black text-emerald-400 uppercase tracking-widest">En ligne</span>
</div>
<a data-turbo="false" href="{{ path('app_crm_product_edit', {id: product.id, act: 'togglePublish', status: 'false'}) }}"
onclick="return confirm('Voulez-vous vraiment masquer ce produit ?')"
class="px-6 py-3 bg-white/5 hover:bg-rose-600 text-slate-400 hover:text-white text-[10px] font-black uppercase tracking-widest transition-all active:scale-95 border-l border-white/10">
Désactiver
</a>
</div>
{% endif %}
</div>
{% endif %}
{% if product.slug != "" %}
<a target="_blank" rel="nofollow"
href="https://reservation.ludikevent.fr{{ path('reservation_product_show', {id: product.slug}) }}"
class="flex items-center px-6 py-3 bg-white/5 hover:bg-white/10 border border-white/10 hover:border-blue-500/50 text-white text-[10px] font-black uppercase tracking-[0.2em] rounded-2xl transition-all group shadow-xl backdrop-blur-md">
<svg class="w-4 h-4 mr-2.5 text-blue-500 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="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>
Voir sur le site
<svg class="w-3 h-3 ml-2 text-slate-300 group-hover:translate-x-1 group-hover:-translate-y-1 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"/>
</svg>
</a>
{% endif %}
</div>
{% endblock %}
{% block body %}
<div class="max-w-6xl mx-auto animate-in fade-in slide-in-from-bottom-4 duration-700">
{{ form_start(form) }}
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
{# --- COLONNE GAUCHE --- #}
<div class="lg:col-span-2 space-y-8">
{# 00. IMAGE DU PRODUIT #}
<div class="backdrop-blur-xl bg-[#1e293b]/40 border border-white/5 rounded-[2.5rem] p-8 shadow-2xl">
<h3 class="text-lg font-bold text-white mb-6 flex items-center">
<span class="w-8 h-8 bg-purple-600/20 text-purple-500 rounded-lg flex items-center justify-center mr-3 text-[10px] font-black">00</span>
Image du Produit
</h3>
<div class="flex flex-col md:flex-row items-center gap-8">
{# Preview Image #}
<div class="relative flex-shrink-0">
<div class="w-48 h-48 rounded-[2rem] overflow-hidden border-2 border-white/10 bg-slate-900/50 flex items-center justify-center">
<img id="product-image-preview"
src="{{ product.imageName ? vich_uploader_asset(product, 'imageFile') | imagine_filter('webp') : '#' }}"
class="w-full h-full object-cover {{ product.imageName ? '' : 'hidden' }}">
<svg id="product-image-placeholder"
class="w-12 h-12 text-slate-700 {{ product.imageName ? 'hidden' : '' }}"
fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
</div>
</div>
{# Input File #}
<div class="flex-1 w-full">
{{ form_label(form.imageFile, 'Sélectionner un fichier', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-widest mb-2 block'}}) }}
{{ form_widget(form.imageFile, {
'id': 'product_image_input',
'attr': {
'class': 'block w-full text-xs text-slate-400 file:mr-4 file:py-2.5 file:px-4 file:rounded-xl file:border-0 file:text-[10px] file:font-black file:uppercase file:tracking-widest file:bg-blue-600/10 file:text-blue-500 hover:file:bg-blue-600/20 transition-all cursor-pointer'
}
}) }}
</div>
</div>
</div>
{# 01. INFORMATIONS GÉNÉRALES #}
<div class="backdrop-blur-xl bg-[#1e293b]/40 border border-white/5 rounded-[2.5rem] p-8 shadow-2xl">
<h3 class="text-lg font-bold text-white mb-6 flex items-center">
<span class="w-8 h-8 bg-blue-600/20 text-blue-500 rounded-lg flex items-center justify-center mr-3 text-[10px] font-black">01</span>
Détails du Catalogue
</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="md:col-span-2">
{{ form_label(form.name, 'Désignation Commerciale', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
{{ form_widget(form.name, {'attr': {'placeholder': 'Ex: Château Gonflable Jungle', 'class': 'w-full bg-slate-900/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.category, 'Catégorie', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
{{ form_widget(form.category, {'attr': {'class': 'w-full bg-slate-900/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.ref, 'Référence Interne (SKU)', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
{{ form_widget(form.ref, {'attr': {'placeholder': 'REF-000', 'class': 'w-full bg-slate-900/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 class="md:col-span-2 mt-2">
{{ form_label(form.description, 'Description détaillée', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
{{ form_widget(form.description, {
'attr': {
'is':'crm-editor',
'class': 'w-full bg-slate-900/50 border-white/5 rounded-2xl text-white focus:ring-blue-500/20 focus:border-blue-500 transition-all py-3.5 px-5 min-h-[150px]',
'placeholder': 'Décrivez les dimensions, la capacité, les points forts...'
}
}) }}
{% if form_errors(form.description) %}
<div class="text-rose-500 text-[10px] font-bold mt-2 ml-2 uppercase tracking-widest">
{{ form_errors(form.description) }}
</div>
{% endif %}
</div>
</div>
</div>
{# 02. DIMENSIONS DU PRODUIT #}
<div class="backdrop-blur-xl bg-[#1e293b]/40 border border-white/5 rounded-[2.5rem] p-8 shadow-2xl">
<h3 class="text-lg font-bold text-white mb-6 flex items-center">
<span class="w-8 h-8 bg-blue-600/20 text-blue-500 rounded-lg flex items-center justify-center mr-3 text-[10px] font-black">02</span>
Dimensions de la Structure
</h3>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
{# Largeur #}
<div class="relative group">
{{ form_label(form.dimW, 'Largeur (m)', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
<div class="relative">
<div class="absolute inset-y-0 left-0 pl-4 flex items-center pointer-events-none">
<span class="text-slate-500 text-[10px] font-bold italic">W</span>
</div>
{{ form_widget(form.dimW, {'attr': {'placeholder': '0.00', 'class': 'w-full bg-slate-900/50 border-white/5 rounded-2xl text-white font-mono focus:ring-blue-500/20 focus:border-blue-500 transition-all py-3.5 pl-10 pr-5'}}) }}
</div>
</div>
{# Longueur #}
<div class="relative group">
{{ form_label(form.dimP, 'Longueur (m)', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
<div class="relative">
<div class="absolute inset-y-0 left-0 pl-4 flex items-center pointer-events-none">
<span class="text-slate-500 text-[10px] font-bold italic">L</span>
</div>
{{ form_widget(form.dimP, {'attr': {'placeholder': '0.00', 'class': 'w-full bg-slate-900/50 border-white/5 rounded-2xl text-white font-mono focus:ring-blue-500/20 focus:border-blue-500 transition-all py-3.5 pl-10 pr-5'}}) }}
</div>
</div>
{# Hauteur #}
<div class="relative group">
{{ form_label(form.dimH, 'Hauteur (m)', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
<div class="relative">
<div class="absolute inset-y-0 left-0 pl-4 flex items-center pointer-events-none">
<span class="text-slate-500 text-[10px] font-bold italic">H</span>
</div>
{{ form_widget(form.dimH, {'attr': {'placeholder': '0.00', 'class': 'w-full bg-slate-900/50 border-white/5 rounded-2xl text-white font-mono focus:ring-blue-500/20 focus:border-blue-500 transition-all py-3.5 pl-10 pr-5'}}) }}
</div>
</div>
</div>
</div>
</div>
{# --- COLONNE DROITE --- #}
<div class="lg:col-span-1 space-y-8">
{# 03. FINANCES & TARIFS #}
<div class="backdrop-blur-xl bg-[#1e293b]/40 border border-white/5 rounded-[2.5rem] p-8 shadow-2xl h-full border-l-emerald-500/10 border-l-2">
<h3 class="text-lg font-bold text-white mb-8 flex items-center">
<span class="w-8 h-8 bg-emerald-600/20 text-emerald-500 rounded-lg flex items-center justify-center mr-3 text-[10px] font-black">03</span>
Finances & Tarifs
</h3>
<div class="space-y-6">
<div is="stripe-commission-calculator">
{{ form_label(form.priceDay, 'Tarif 1er Jour (€)', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-widest ml-1 mb-2 block'}}) }}
<p class="text-[9px] text-slate-500 italic mb-2 -mt-1">Ou tarif weekend pour les barnums</p>
<div class="relative">
{{ form_widget(form.priceDay, {'attr': {'class': 'w-full bg-slate-900/50 border-white/5 rounded-2xl text-emerald-400 font-black text-xl focus:ring-emerald-500/20 focus:border-emerald-500 transition-all py-4 px-5'}}) }}
<span class="absolute right-5 top-1/2 -translate-y-1/2 text-slate-600 font-bold">€HT</span>
</div>
<div class="flex justify-between items-center mt-1 px-1 {{ form.priceDay.vars.value ? '' : 'hidden' }}">
<p class="text-[9px] text-slate-500 italic" title="Pour les cartes standard de l'Espace économique européen">Com. Stripe (EEE) : 1,5% + 0,25€</p>
<p class="text-[10px] font-bold text-slate-400 commission-display">
~ {{ ((form.priceDay.vars.value|default(0) * 0.015) + 0.25)|number_format(2, ',', ' ') }}
</p>
</div>
</div>
<div is="stripe-commission-calculator">
{{ form_label(form.priceSup, 'Tarif Jour Sup. (€)', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-widest ml-1 mb-2 block'}}) }}
<div class="relative">
{{ form_widget(form.priceSup, {'attr': {'class': 'w-full bg-slate-900/50 border-white/5 rounded-2xl text-blue-400 font-black text-xl focus:ring-blue-500/20 focus:border-blue-500 transition-all py-4 px-5'}}) }}
<span class="absolute right-5 top-1/2 -translate-y-1/2 text-slate-600 font-bold">€HT</span>
</div>
<div class="flex justify-between items-center mt-1 px-1 {{ form.priceSup.vars.value ? '' : 'hidden' }}">
<p class="text-[9px] text-slate-500 italic" title="Pour les cartes standard de l'Espace économique européen">Com. Stripe (EEE) : 1,5% + 0,25€</p>
<p class="text-[10px] font-bold text-slate-400 commission-display">
~ {{ ((form.priceSup.vars.value|default(0) * 0.015) + 0.25)|number_format(2, ',', ' ') }}
</p>
</div>
</div>
</div>
<hr class="mt-8 border-white/5"/>
<div class="pt-8">
{{ form_label(form.caution, 'Montant de la Caution (€)', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-widest ml-1 mb-2 block'}}) }}
<div class="relative">
{{ form_widget(form.caution, {'attr': {'class': 'w-full bg-slate-900/50 border-white/5 rounded-2xl text-white font-mono focus:ring-blue-500/20 focus:border-blue-500 transition-all py-3 px-5 text-center'}}) }}
</div>
<div class="mt-4 p-4 rounded-2xl bg-white/5 border border-white/10 backdrop-blur-md shadow-xl">
<div class="flex gap-3">
<div class="flex-shrink-0">
<svg class="w-5 h-5 text-blue-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
</div>
<p class="text-[11px] leading-relaxed text-slate-300">
<strong class="text-white block mb-1 uppercase tracking-wider">Information importante</strong>
Cette somme sera prélevée sur le compte bancaire du client. Conformément aux politiques de <span class="text-blue-400">Stripe</span>, les fonds peuvent être bloqués pour un maximum de <span class="font-bold text-white">4 jours</span>.
</p>
</div>
</div>
</div>
</div>
</div>
</div>
{# FOOTER ACTIONS #}
<div class="mt-12 mb-20 flex items-center justify-between backdrop-blur-xl bg-slate-900/40 p-6 rounded-[2rem] border border-white/5 shadow-xl">
<button type="submit" class="relative overflow-hidden group px-12 py-4 bg-blue-600 hover:bg-blue-500 text-white text-[10px] font-black uppercase tracking-[0.2em] rounded-2xl transition-all shadow-lg shadow-blue-600/30">
<span class="relative z-10 flex items-center">
<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="3" d="M5 13l4 4L19 7" /></svg>
Enregistrer la fiche
</span>
<div class="absolute inset-0 bg-gradient-to-r from-transparent via-white/10 to-transparent -translate-x-full group-hover:translate-x-full transition-transform duration-1000"></div>
</button>
</div>
{{ form_end(form) }}
{# 04. DOCUMENTS TECHNIQUES (PDF) #}
{% if formDoc is defined %}
<div class="backdrop-blur-xl bg-[#1e293b]/40 border border-white/5 rounded-[2.5rem] p-8 shadow-2xl mt-8">
<h3 class="text-lg font-bold text-white mb-6 flex items-center">
<span class="w-8 h-8 bg-amber-600/20 text-amber-500 rounded-lg flex items-center justify-center mr-3 text-[10px] font-black">04</span>
Documents & Notices
</h3>
{# LISTE DES DOCUMENTS #}
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-10">
{% for doc in product.productDocs %}
<div class="flex items-center justify-between p-4 bg-white/5 border border-white/5 rounded-2xl group hover:bg-white/10 transition-all">
<div class="flex items-center gap-4">
<div class="w-10 h-10 bg-red-500/20 text-red-500 rounded-xl flex items-center justify-center">
<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="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"/></svg>
</div>
<div>
<div class="text-xs font-black text-white uppercase tracking-wider">{{ doc.name }}</div>
<div class="text-[9px] font-bold {{ doc.isPublic ? 'text-emerald-500' : 'text-slate-500' }} uppercase tracking-tighter">
{{ doc.isPublic ? '● Public' : '○ Privé (Interne)' }}
</div>
</div>
</div>
<div class="flex gap-2">
<a href="{{ vich_uploader_asset(doc, 'docProduct') }}" target="_blank" class="p-2 text-slate-400 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="M4 16v1a2 2 0 002 2h12a2 2 0 002-2v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/></svg>
</a>
<form data-turbo="false" method="post" action="{{ path('app_crm_product_edit', {'id': product.id, act:'deleted', idDoc: doc.id}) }}"
onsubmit="return confirm('Confirmer la suppression ?');"
class="inline-block">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ doc.id) }}">
<button type="submit" class="p-2 text-slate-400 hover:text-rose-500 transition-colors" title="Supprimer">
<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="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>
</form>
</div>
</div>
{% else %}
<div class="md:col-span-2 py-8 text-center border-2 border-dashed border-white/5 rounded-3xl">
<p class="text-[10px] font-black text-slate-600 uppercase tracking-[0.2em]">Aucun document attaché</p>
</div>
{% endfor %}
</div>
<div class="h-px bg-white/5 w-full mb-10"></div>
{# FORMULAIRE D'AJOUT DOC #}
{{ form_start(formDoc) }}
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 items-end">
<div>
{{ form_label(formDoc.name, 'Nom du document', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
{{ form_widget(formDoc.name, {'attr': {'placeholder': 'Ex: Notice technique PDF', 'class': 'w-full bg-slate-900/50 border-white/5 rounded-2xl text-white focus:ring-amber-500/20 focus:border-amber-500 transition-all py-4 px-5 font-bold text-sm'}}) }}
</div>
<div>
{{ form_label(formDoc.isPublic, 'Visibilité Client', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
{{ form_widget(formDoc.isPublic, {'attr': {'class': 'w-full bg-slate-900/50 border-white/5 rounded-2xl text-white focus:ring-blue-500/20 focus:border-blue-500 transition-all py-4 px-5 font-bold text-sm cursor-pointer'}}) }}
</div>
<div class="md:col-span-2 bg-slate-950/40 p-6 rounded-[2rem] border border-dashed border-white/10 group hover:border-amber-500/30 transition-all">
{{ form_label(formDoc.docProduct, 'Fichier PDF (Notice, Certificat...)', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-widest mb-4 block text-center'}}) }}
{{ form_widget(formDoc.docProduct, {
'attr': {
'class': 'block w-full text-xs text-slate-400 file:mr-4 file:py-3 file:px-6 file:rounded-xl file:border-0 file:text-[10px] file:font-black file:uppercase file:tracking-widest file:bg-amber-600 file:text-white hover:file:bg-amber-500 transition-all cursor-pointer'
}
}) }}
</div>
</div>
<div class="mt-8 flex justify-end">
<button type="submit" class="group px-8 py-4 bg-amber-600/10 hover:bg-amber-600 text-amber-500 hover:text-white text-[10px] font-black uppercase tracking-widest rounded-2xl transition-all border border-amber-500/20 flex items-center">
<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="3" d="M12 4v16m8-8H4"/></svg>
Ajouter au dossier
</button>
</div>
{{ form_end(formDoc) }}
</div>
{% endif %}
{# 05. VIDEOS #}
{% if formVideo is defined %}
<div class="backdrop-blur-xl bg-[#1e293b]/40 border border-white/5 rounded-[2.5rem] p-8 shadow-2xl mt-8">
<h3 class="text-lg font-bold text-white mb-6 flex items-center">
<span class="w-8 h-8 bg-rose-600/20 text-rose-500 rounded-lg flex items-center justify-center mr-3 text-[10px] font-black">05</span>
Vidéos
</h3>
{# LISTE DES VIDÉOS #}
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-10">
{% for video in product.productVideos %}
<div class="relative group rounded-2xl overflow-hidden border border-white/5 bg-black/50 aspect-video shadow-lg">
<video controls class="w-full h-full object-cover">
<source src="{{ vich_uploader_asset(video, 'imageFile') }}" type="video/mp4">
Votre navigateur ne supporte pas la vidéo.
</video>
{# DELETE BUTTON VIDEO #}
<div class="absolute top-3 right-3 opacity-0 group-hover:opacity-100 transition-all z-20">
<form data-turbo="false" method="post" action="{{ path('app_crm_product_edit', {'id': product.id, act:'deleteVideo', idVideo: video.id}) }}"
onsubmit="return confirm('Supprimer cette vidéo ?');" class="inline-block">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ video.id) }}">
<button type="submit" class="p-2.5 bg-black/60 hover:bg-rose-600 text-white rounded-xl backdrop-blur-md transition-all shadow-lg hover:scale-105">
<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="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>
</form>
</div>
</div>
{% else %}
<div class="md:col-span-2 py-8 text-center border-2 border-dashed border-white/5 rounded-3xl">
<p class="text-[10px] font-black text-slate-600 uppercase tracking-[0.2em]">Aucune vidéo</p>
</div>
{% endfor %}
</div>
<div class="h-px bg-white/5 w-full mb-10"></div>
{# FORMULAIRE D'AJOUT VIDEO #}
{{ form_start(formVideo) }}
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 items-end">
<div class="md:col-span-2 bg-slate-950/40 p-6 rounded-[2rem] border border-dashed border-white/10 group hover:border-rose-500/30 transition-all">
{{ form_label(formVideo.imageFile, 'Fichier Vidéo (MP4, WebM...)', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-widest mb-4 block text-center'}}) }}
{{ form_widget(formVideo.imageFile, {
'attr': {
'class': 'block w-full text-xs text-slate-400 file:mr-4 file:py-3 file:px-6 file:rounded-xl file:border-0 file:text-[10px] file:font-black file:uppercase file:tracking-widest file:bg-rose-600 file:text-white hover:file:bg-rose-500 transition-all cursor-pointer'
}
}) }}
</div>
</div>
<div class="mt-8 flex justify-end">
<button type="submit" class="group px-8 py-4 bg-rose-600/10 hover:bg-rose-600 text-rose-500 hover:text-white text-[10px] font-black uppercase tracking-widest rounded-2xl transition-all border border-rose-500/20 flex items-center">
<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="3" d="M12 4v16m8-8H4"/></svg>
Ajouter la vidéo
</button>
</div>
{{ form_end(formVideo) }}
</div>
{% endif %}
{# 06. PHOTOS #}
{% if formPhoto is defined %}
<div class="backdrop-blur-xl bg-[#1e293b]/40 border border-white/5 rounded-[2.5rem] p-8 shadow-2xl mt-8">
<h3 class="text-lg font-bold text-white mb-6 flex items-center">
<span class="w-8 h-8 bg-cyan-600/20 text-cyan-500 rounded-lg flex items-center justify-center mr-3 text-[10px] font-black">06</span>
Photos Supplémentaires
</h3>
{# LISTE DES PHOTOS #}
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6 mb-10">
{% for photo in product.productPhotos %}
<div class="relative group rounded-2xl overflow-hidden border border-white/5 aspect-square shadow-lg">
<img src="{{ vich_uploader_asset(photo, 'imageFile') }}" class="w-full h-full object-cover transform group-hover:scale-110 transition-transform duration-700">
{# DELETE BUTTON PHOTO #}
<div class="absolute top-3 right-3 opacity-0 group-hover:opacity-100 transition-all z-20">
<form data-turbo="false" method="post" action="{{ path('app_crm_product_edit', {'id': product.id, act:'deletePhoto', idPhoto: photo.id}) }}"
onsubmit="return confirm('Supprimer cette photo ?');" class="inline-block">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ photo.id) }}">
<button type="submit" class="p-2.5 bg-black/60 hover:bg-rose-600 text-white rounded-xl backdrop-blur-md transition-all shadow-lg hover:scale-105">
<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="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>
</form>
</div>
</div>
{% else %}
<div class="col-span-full py-8 text-center border-2 border-dashed border-white/5 rounded-3xl">
<p class="text-[10px] font-black text-slate-600 uppercase tracking-[0.2em]">Aucune photo</p>
</div>
{% endfor %}
</div>
<div class="h-px bg-white/5 w-full mb-10"></div>
{# FORMULAIRE D'AJOUT PHOTO #}
{{ form_start(formPhoto) }}
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 items-end">
<div class="md:col-span-2 bg-slate-950/40 p-6 rounded-[2rem] border border-dashed border-white/10 group hover:border-cyan-500/30 transition-all">
{{ form_label(formPhoto.imageFile, 'Fichier Image (JPG, PNG...)', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-widest mb-4 block text-center'}}) }}
{{ form_widget(formPhoto.imageFile, {
'attr': {
'class': 'block w-full text-xs text-slate-400 file:mr-4 file:py-3 file:px-6 file:rounded-xl file:border-0 file:text-[10px] file:font-black file:uppercase file:tracking-widest file:bg-cyan-600 file:text-white hover:file:bg-cyan-500 transition-all cursor-pointer'
}
}) }}
</div>
</div>
<div class="mt-8 flex justify-end">
<button type="submit" class="group px-8 py-4 bg-cyan-600/10 hover:bg-cyan-600 text-cyan-500 hover:text-white text-[10px] font-black uppercase tracking-widest rounded-2xl transition-all border border-cyan-500/20 flex items-center">
<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="3" d="M12 4v16m8-8H4"/></svg>
Ajouter la photo
</button>
</div>
{{ form_end(formPhoto) }}
</div>
{% endif %}
{# 07. PÉRIODES BLOQUÉES #}
{% if formBlocked is defined %}
<div class="backdrop-blur-xl bg-[#1e293b]/40 border border-white/5 rounded-[2.5rem] p-8 shadow-2xl mt-8">
<h3 class="text-lg font-bold text-white mb-6 flex items-center">
<span class="w-8 h-8 bg-rose-600/20 text-rose-500 rounded-lg flex items-center justify-center mr-3 text-[10px] font-black">07</span>
Indisponibilités & Blocages
</h3>
{# LISTE DES BLOCAGES #}
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-10">
{% for blocked in product.productBlockeds %}
<div class="relative group p-6 rounded-2xl border border-white/5 bg-white/5 hover:bg-white/10 transition-all flex flex-col justify-between">
<div>
<div class="flex items-center gap-3 mb-4">
<div class="w-8 h-8 rounded-lg bg-rose-500/20 text-rose-500 flex items-center justify-center">
<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 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
</div>
<span class="text-[10px] font-black uppercase tracking-widest text-white">Indisponible</span>
</div>
<div class="space-y-1">
<p class="text-xs text-slate-400">Du <strong class="text-white">{{ blocked.dateStart|date('d/m/Y H:i') }}</strong></p>
<p class="text-xs text-slate-400">Au <strong class="text-white">{{ blocked.dateEnd|date('d/m/Y H:i') }}</strong></p>
</div>
{% if blocked.reason %}
<p class="mt-4 text-[10px] text-slate-500 italic border-l-2 border-slate-700 pl-3">
{{ blocked.reason }}
</p>
{% endif %}
</div>
{# DELETE BUTTON BLOCKED #}
<div class="absolute top-3 right-3 opacity-0 group-hover:opacity-100 transition-all">
<form data-turbo="false" method="post" action="{{ path('app_crm_product_edit', {'id': product.id, act:'deleteBlocked', idBlocked: blocked.id}) }}"
onsubmit="return confirm('Supprimer ce blocage ?');" class="inline-block">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ blocked.id) }}">
<button type="submit" class="p-2 text-slate-400 hover:text-rose-500 transition-colors" title="Supprimer">
<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="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>
</form>
</div>
</div>
{% else %}
<div class="col-span-full py-8 text-center border-2 border-dashed border-white/5 rounded-3xl">
<p class="text-[10px] font-black text-slate-600 uppercase tracking-[0.2em]">Aucune période bloquée</p>
</div>
{% endfor %}
</div>
<div class="h-px bg-white/5 w-full mb-10"></div>
{# FORMULAIRE D'AJOUT BLOCAGE #}
{{ form_start(formBlocked) }}
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 items-start">
<div>
{{ form_label(formBlocked.dateStart, 'Début du blocage', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
{{ form_widget(formBlocked.dateStart, {'attr': {'class': 'w-full bg-slate-900/50 border-white/5 rounded-2xl text-white focus:ring-rose-500/20 focus:border-rose-500 transition-all py-4 px-5 font-bold text-sm'}}) }}
</div>
<div>
{{ form_label(formBlocked.dateEnd, 'Fin du blocage', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
{{ form_widget(formBlocked.dateEnd, {'attr': {'class': 'w-full bg-slate-900/50 border-white/5 rounded-2xl text-white focus:ring-rose-500/20 focus:border-rose-500 transition-all py-4 px-5 font-bold text-sm'}}) }}
</div>
<div class="md:col-span-2">
{{ form_label(formBlocked.reason, 'Raison (Optionnel)', {'label_attr': {'class': 'text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
{{ form_widget(formBlocked.reason, {'attr': {'placeholder': 'Ex: Maintenance annuelle, Réparation...', 'class': 'w-full bg-slate-900/50 border-white/5 rounded-2xl text-white focus:ring-rose-500/20 focus:border-rose-500 transition-all py-4 px-5 font-medium text-sm min-h-[100px]'}}) }}
</div>
</div>
<div class="mt-8 flex justify-end">
<button type="submit" class="group px-8 py-4 bg-rose-600/10 hover:bg-rose-600 text-rose-500 hover:text-white text-[10px] font-black uppercase tracking-widest rounded-2xl transition-all border border-rose-500/20 flex items-center">
<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="3" d="M12 4v16m8-8H4"/></svg>
Bloquer cette période
</button>
</div>
{{ form_end(formBlocked) }}
</div>
{% endif %}
</div>
{% endblock %}