templates/partials/_document_upload.html.twig line 1

  1. {% set input_class = input_class|default('w-full px-4 py-2 rounded-lg border border-slate-200 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent transition') %}
  2. <div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
  3.     {% for field, config in document_labels %}
  4.         {# Récupération du nom du fichier via le getter #}
  5.         {% set fileName = attribute(candidature, field) %}
  6.         {% set fileExists = fileName is not null and fileName != '' %}
  7.         {% set isImage = fileName matches '/\\.(jpg|jpeg|png|gif|webp|svg)$/i' %}
  8.         {# Déterminer l'URL du fichier existant - à adapter selon votre configuration #}
  9.         {% set fileUrl = asset('media/' ~ candidature.numero ~ '/' ~ fileName) %}
  10.         
  11.         <div class="transform transition-all duration-300 hover:-translate-y-1">
  12.             <div class="bg-white rounded-xl p-5 border-2 border-dashed border-slate-200 hover:border-indigo-400 hover:bg-indigo-50/30 transition-all group cursor-pointer upload-area" data-field="{{ field }}">
  13.                 <div class="flex flex-col items-center text-center">
  14.                     <!-- Cadre d'aperçu (toujours visible) -->
  15.                     <div class="w-full mb-3 bg-slate-50 rounded-lg border border-slate-200 overflow-hidden" style="height: 120px;">
  16.                         <div class="w-full h-full flex items-center justify-center preview-container" id="preview-{{ field }}">
  17.                             {% if fileExists and isImage %}
  18.                                 <img src="{{ fileUrl }}" 
  19.                                      alt="Aperçu {{ config.text }}" 
  20.                                      class="w-full h-full object-contain p-1"
  21.                                      onerror="this.parentElement.innerHTML = '<i class=\'fas fa-exclamation-triangle text-red-500 text-2xl\'></i><span class=\'text-xs text-red-500 ml-1\'>Erreur</span>'">
  22.                             {% elseif fileExists and not isImage %}
  23.                                 {# Pour les PDF, afficher une icône avec lien #}
  24.                                 <div class="flex flex-col items-center justify-center text-slate-400">
  25.                                     <i class="fas fa-file-pdf text-4xl text-red-500 mb-1"></i>
  26.                                     <span class="text-xs">PDF</span>
  27.                                 </div>
  28.                             {% else %}
  29.                                 <div class="flex flex-col items-center justify-center text-slate-400">
  30.                                     <i class="fas fa-{{ config.icon }} text-3xl mb-1"></i>
  31.                                     <span class="text-xs">Aucun fichier</span>
  32.                                 </div>
  33.                             {% endif %}
  34.                         </div>
  35.                     </div>
  36.                     
  37.                 {{ form_widget(attribute(form, field), {'attr': {
  38.                     'class': 'hidden file-input',
  39.                     'data-field': field,
  40.                     'accept': config.accept,
  41.                     'data-max-size': '10485760',
  42.                     'data-current-file': fileName ?? ''
  43.                 }}) }}
  44.                 {# 10 Mo (à ajuster selon votre limite) #}
  45.                     
  46.                     <label class="block text-sm font-semibold text-slate-700 mb-1">
  47.                         {{ config.text }}
  48.                         <span class="text-xs font-normal text-slate-500 ml-1">({{ config.formats }})</span>
  49.                     </label>
  50.                     {# Lien de téléchargement pour le fichier existant (si PDF ou autre) #}
  51.                     {% if fileExists %}
  52.                         <div class="mt-4 w-full">
  53.                             <a href="{{ fileUrl }}" target="_blank" class="inline-flex items-center justify-center w-full sm:w-auto px-4 py-2.5 rounded-lg bg-indigo-600 text-white text-sm font-semibold hover:bg-indigo-700 transition shadow-sm hover:shadow focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2">
  54.                                 <i class="fas fa-download mr-2"></i> Télécharger
  55.                             </a>
  56.                         </div>
  57.                     {% endif %}
  58.                 </div>
  59.             </div>
  60.         </div>
  61.     {% endfor %}
  62. </div>
  63. <script>
  64. document.addEventListener('DOMContentLoaded', function() {
  65.     // Gestion du clic sur la zone d'upload
  66.     document.querySelectorAll('.upload-area').forEach(area => {
  67.         area.addEventListener('click', function(e) {
  68.             // Ne pas déclencher si on clique sur un lien (comme le téléchargement)
  69.             if (e.target.tagName === 'A' || e.target.closest('a')) {
  70.                 return;
  71.             }
  72.             
  73.             const field = this.dataset.field;
  74.             const fileInput = document.querySelector(`.file-input[data-field="${field}"]`);
  75.             if (fileInput) {
  76.                 fileInput.click();
  77.             }
  78.         });
  79.     });
  80.     // Gestion du changement de fichier
  81.     document.querySelectorAll('.file-input').forEach(input => {
  82.         input.addEventListener('change', function(e) {
  83.             const field = this.dataset.field;
  84.             const file = e.target.files[0];
  85.             
  86.             // Vérifier la taille du fichier
  87.             if (file && file.size > parseInt(this.dataset.maxSize)) {
  88.                 alert('Le fichier dépasse la limite de ' + (parseInt(this.dataset.maxSize) / 1048576) + ' Mo.');
  89.                 this.value = '';
  90.                 return;
  91.             }
  92.             
  93.             if (file) {
  94.                 // Mettre à jour l'aperçu
  95.                 const previewContainer = document.getElementById(`preview-${field}`);
  96.                 
  97.                 if (file.type.startsWith('image/')) {
  98.                     const reader = new FileReader();
  99.                     reader.onload = function(readerEvent) {
  100.                         previewContainer.innerHTML = `<img src="${readerEvent.target.result}" alt="Aperçu" class="w-full h-full object-contain p-1">`;
  101.                     }
  102.                     reader.readAsDataURL(file);
  103.                 } else {
  104.                     // Pour les PDF, afficher une icône PDF
  105.                     previewContainer.innerHTML = `
  106.                         <div class="flex flex-col items-center justify-center text-slate-400">
  107.                             <i class="fas fa-file-pdf text-4xl text-red-500 mb-1"></i>
  108.                             <span class="text-xs">PDF sélectionné</span>
  109.                         </div>
  110.                     `;
  111.                 }
  112.             }
  113.         });
  114.     });
  115. });
  116. </script>
  117. <style>
  118. .upload-area {
  119.     transition: all 0.3s ease;
  120.     cursor: pointer;
  121. }
  122. .upload-area:hover {
  123.     box-shadow: 0 10px 25px -5px rgba(79, 70, 229, 0.1);
  124. }
  125. .preview-container {
  126.     transition: all 0.2s ease;
  127. }
  128. .upload-area:hover .preview-container {
  129.     background-color: rgba(79, 70, 229, 0.05);
  130. }
  131. /* Style pour le cadre d'aperçu */
  132. .bg-slate-50 {
  133.     background-color: #f8fafc;
  134. }
  135. .object-contain {
  136.     object-fit: contain;
  137. }
  138. </style>