templates/tracking/_Tab_track_container.html.twig line 1

Open in your IDE?
  1. {# templates/tracking/_Tab_track_container.html.twig #}
  2. <style>
  3.     :root {
  4.         --afi-primary: #006E51;
  5.         --afi-success: #28a745;
  6.         --afi-danger: #e53e3e;
  7.         --afi-border: #edf2f7;
  8.     }
  9.     /* Conteneur Zigzag */
  10.     .timeline-zigzag {
  11.         position: relative;
  12.         padding: 20px 0;
  13.         margin-top: 30px;
  14.     }
  15.     .timeline-zigzag::before {
  16.         content: '';
  17.         position: absolute;
  18.         left: 50%; width: 3px; height: 100%;
  19.         background: linear-gradient(to bottom, var(--afi-success), #e9ecef);
  20.         transform: translateX(-50%);
  21.     }
  22.     .zigzag-item {
  23.         position: relative;
  24.         width: 50%;
  25.         padding: 10px 40px;
  26.         box-sizing: border-box;
  27.     }
  28.     .zigzag-item.left { left: 0; text-align: right; }
  29.     .zigzag-item.right { left: 50%; text-align: left; }
  30.     /* Points centraux */
  31.     .zigzag-dot {
  32.         position: absolute;
  33.         top: 20px;
  34.         width: 18px; height: 18px;
  35.         background: #fff;
  36.         border: 4px solid var(--afi-success);
  37.         border-radius: 50%;
  38.         z-index: 10;
  39.     }
  40.     .left .zigzag-dot { right: -10px; }
  41.     .right .zigzag-dot { left: -10px; }
  42.     /* Cartes */
  43.     .timeline-content {
  44.         background: #fff;
  45.         padding: 20px;
  46.         border-radius: 18px;
  47.         box-shadow: 0 10px 25px rgba(0,0,0,0.05);
  48.         border: 1px solid var(--afi-border);
  49.         transition: 0.3s ease;
  50.         display: inline-block;
  51.         width: 100%;
  52.         text-align: left;
  53.     }
  54.     /* Style pour la DERNIÈRE sous-étape globale */
  55.     .latest-status-marker {
  56.         border: 2px solid var(--afi-success) !important;
  57.         background: rgba(40, 167, 69, 0.03);
  58.         animation: pulse-border 2s infinite;
  59.     }
  60.     @keyframes pulse-border {
  61.         0% { box-shadow: 0 0 0 0 rgba(40, 167, 69, 0.4); }
  62.         70% { box-shadow: 0 0 0 10px rgba(40, 167, 69, 0); }
  63.         100% { box-shadow: 0 0 0 0 rgba(40, 167, 69, 0); }
  64.     }
  65.     .sub-tracking-list {
  66.         padding-left: 15px;
  67.         border-left: 2px solid #f1f5f9;
  68.         margin-top: 12px;
  69.     }
  70.     .afi-comment {
  71.         font-size: 0.75rem;
  72.         color: var(--afi-danger);
  73.         font-weight: 600;
  74.         background: rgba(229, 62, 62, 0.05);
  75.         padding: 5px 10px;
  76.         border-radius: 6px;
  77.         margin-top: 5px;
  78.         display: inline-block;
  79.         font-style: italic;
  80.     }
  81.     /* Mobile Responsive */
  82.     @media (max-width: 768px) {
  83.         .timeline-zigzag::before { left: 20px; }
  84.         .zigzag-item { width: 100%; left: 0 !important; padding-left: 45px; padding-right: 10px; text-align: left !important; }
  85.         .zigzag-dot { left: 11px !important; }
  86.     }
  87. </style>
  88. <div class="container mt-4">
  89.     <div class="text-center mb-5">
  90.         <h1 class="font-weight-bold" style="color: #1a202c;">{{ programme_contenaire.numeroContenaire }}</h1>
  91.         {# Identification des derniers états pour le header[cite: 1, 2] #}
  92.         {% set sortedSuivis = programme_contenaire.suiviContenaires|sort((a, b) => a.dateOperation <=> b.dateOperation) %}
  93.         {% set lastBase = sortedSuivis|last %}
  94.         {# On cherche la sous-étape la plus récente de TOUT le projet #}
  95.         {% set allSubSuivis = [] %}
  96.         {% for ct in programme_contenaire.suiviContenaires %}
  97.             {% for ss in ct.getSousSuivis %}
  98.                 {% set allSubSuivis = allSubSuivis|merge([ss]) %}
  99.             {% endfor %}
  100.         {% endfor %}
  101.         {% set globalLatestSub = (allSubSuivis|sort((a, b) => a.createdAt <=> b.createdAt))|last %}
  102.         <div class="d-flex flex-column align-items-center">
  103.             <span class="badge badge-pill shadow-sm px-4 py-2 mb-2" style="background: #fff; border: 1px solid var(--afi-border);">
  104.                 <i class="fa fa-map-marker-alt text-primary mr-2"></i>
  105.                 {% if lastBase %}{{ lastBase.lieu }}{% else %}Origin Port{% endif %}
  106.             </span>
  107.             {% if globalLatestSub %}
  108.                 <div class="status-badge-hero px-3 py-1" style="background: var(--afi-primary); color: white; border-radius: 20px; font-size: 0.8rem; font-weight: bold;">
  109.                     CURRENT STATUS: {{ globalLatestSub.sousPosition.libelle|upper }}
  110.                 </div>
  111.             {% endif %}
  112.         </div>
  113.     </div>
  114.     <div class="timeline-zigzag">
  115.         {% for ct in programme_contenaire.suiviContenaires|sort((a, b) => b.dateOperation <=> a.dateOperation) %}
  116.             <div class="zigzag-item {{ loop.index0 is even ? 'left' : 'right' }}">
  117.                 <div class="zigzag-dot"></div>
  118.                 <div class="timeline-content">
  119.                     <div class="d-flex justify-content-between align-items-center mb-2">
  120.                         <strong class="text-uppercase" style="color: #1a202c;">{{ ct.lieu }}</strong>
  121.                         <small class="text-muted"><i class="far fa-calendar-alt"></i> {{ ct.dateOperation|date('M d, Y') }}</small>
  122.                     </div>
  123.                     <div class="sub-tracking-list">
  124.                         {% for ss in ct.getSousSuivis|sort((a, b) => b.createdAt <=> a.createdAt) %}
  125.                             <div class="sub-tracking-item py-1 {{ (globalLatestSub and ss.id == globalLatestSub.id) ? 'latest-status-marker p-2 rounded' : '' }}">
  126.                                 <div class="d-flex justify-content-between align-items-center">
  127.                                     <span style="font-size: 0.85rem; font-weight: 700;">
  128.                                         <i class="fa {{ (globalLatestSub and ss.id == globalLatestSub.id) ? 'fa-sync-alt fa-spin text-primary' : 'fa-check-circle text-success' }} mr-2"></i>
  129.                                         {{ ss.sousPosition.libelle }}
  130.                                     </span>
  131.                                     <small class="text-muted" style="font-size: 0.7rem;">{{ ss.createdAt|date('H:i') }}</small>
  132.                                 </div>
  133.                                 {% if ss.commentaire is defined and ss.commentaire %}
  134.                                     <div class="afi-comment">
  135.                                         <i class="fa fa-info-circle mr-1"></i> {{ ss.commentaire }}
  136.                                     </div>
  137.                                 {% endif %}
  138.                             </div>
  139.                         {% endfor %}
  140.                     </div>
  141.                 </div>
  142.             </div>
  143.         {% else %}
  144.             <div class="text-center py-5">
  145.                 <p class="text-muted italic">No tracking history found for this container.</p>
  146.             </div>
  147.         {% endfor %}
  148.     </div>
  149. </div>