templates/panier/index.html.twig line 1

Open in your IDE?
  1. {% extends 'backfront.html.twig' %}
  2. {% block title %}SIP-ACADEMY - Mon Panier{% endblock %}
  3. {% block meta_description %}
  4.     Consultez votre panier d'achat SIP Academy. Gérez vos formations et packs, et finalisez votre commande en toute sécurité.
  5. {% endblock %}
  6. {% block body %}
  7.     <style>
  8.         /* ===== COULEURS ET VARIABLES ===== */
  9.         :root {
  10.             --gold: #FFAE27;
  11.             --gold-dark: #e09500;
  12.             --gold-light: #fff8e6;
  13.             --navy: #1F3971;
  14.             --navy-dark: #162d5a;
  15.             --navy-light: #e8edf8;
  16.             --text-dark: #1a2a3a;
  17.             --text-muted: #6c757d;
  18.             --border-light: #eef2f6;
  19.             --success: #28a745;
  20.             --danger: #dc3545;
  21.         }
  22.         /* ===== BREADCRUMB ===== */
  23.         .breadcrumb-area {
  24.             background: linear-gradient(135deg, var(--navy) 0%, var(--navy-dark) 100%);
  25.             padding: 80px 0 60px;
  26.             position: relative;
  27.         }
  28.         .breadcrumb-title h1 {
  29.             color: #fff;
  30.             font-size: 42px;
  31.             font-weight: 700;
  32.             margin-bottom: 10px;
  33.         }
  34.         .breadcrumb-list {
  35.             list-style: none;
  36.             padding: 0;
  37.             margin: 0;
  38.             display: flex;
  39.             justify-content: center;
  40.             gap: 15px;
  41.         }
  42.         .breadcrumb-list li, .breadcrumb-list li a {
  43.             color: rgba(255,255,255,0.7);
  44.             text-decoration: none;
  45.         }
  46.         .breadcrumb-list li.active {
  47.             color: var(--gold);
  48.         }
  49.         /* ===== PANIER ===== */
  50.         .cart-section {
  51.             padding: 60px 0;
  52.             background: #f8fafc;
  53.         }
  54.         /* Titre principal */
  55.         .cart-header {
  56.             margin-bottom: 30px;
  57.         }
  58.         .cart-title {
  59.             font-size: 28px;
  60.             font-weight: 700;
  61.             color: var(--text-dark);
  62.             margin-bottom: 8px;
  63.         }
  64.         .cart-subtitle {
  65.             color: var(--text-muted);
  66.             font-size: 14px;
  67.         }
  68.         /* Tableau */
  69.         .cart-table {
  70.             background: #fff;
  71.             border-radius: 20px;
  72.             overflow: hidden;
  73.             box-shadow: 0 5px 25px rgba(0,0,0,0.05);
  74.             border: 1px solid var(--border-light);
  75.         }
  76.         .cart-table thead th {
  77.             background: var(--navy-light);
  78.             padding: 15px 20px;
  79.             font-weight: 600;
  80.             color: var(--navy);
  81.             border-bottom: 2px solid var(--border-light);
  82.         }
  83.         .cart-table tbody td {
  84.             padding: 20px;
  85.             vertical-align: middle;
  86.             border-bottom: 1px solid var(--border-light);
  87.         }
  88.         /* Carte produit */
  89.         .product-card {
  90.             display: flex;
  91.             align-items: center;
  92.             gap: 15px;
  93.         }
  94.         .product-image {
  95.             width: 80px;
  96.             height: 80px;
  97.             border-radius: 12px;
  98.             overflow: hidden;
  99.             background: linear-gradient(135deg, #f8faff 0%, #fff 100%);
  100.             display: flex;
  101.             align-items: center;
  102.             justify-content: center;
  103.             flex-shrink: 0;
  104.         }
  105.         .product-image img {
  106.             width: auto;
  107.             height: auto;
  108.             max-width: 100%;
  109.             max-height: 100%;
  110.             object-fit: contain;
  111.         }
  112.         .product-info {
  113.             flex: 1;
  114.         }
  115.         .product-title {
  116.             font-size: 16px;
  117.             font-weight: 700;
  118.             color: var(--text-dark);
  119.             margin-bottom: 4px;
  120.         }
  121.         .product-title a {
  122.             color: inherit;
  123.             text-decoration: none;
  124.             transition: color 0.2s;
  125.         }
  126.         .product-title a:hover {
  127.             color: var(--gold);
  128.         }
  129.         .product-meta {
  130.             font-size: 12px;
  131.             color: var(--text-muted);
  132.         }
  133.         /* Badges */
  134.         .badge-custom {
  135.             display: inline-flex;
  136.             align-items: center;
  137.             gap: 6px;
  138.             padding: 6px 14px;
  139.             border-radius: 30px;
  140.             font-size: 12px;
  141.             font-weight: 600;
  142.         }
  143.         .badge-formation {
  144.             background: linear-gradient(135deg, #0d6efd, #0a58ca);
  145.             color: white;
  146.         }
  147.         .badge-pack {
  148.             background: linear-gradient(135deg, #28a745, #1e7e34);
  149.             color: white;
  150.         }
  151.         /* Prix */
  152.         .price-current {
  153.             font-size: 18px;
  154.             font-weight: 700;
  155.             color: var(--gold-dark);
  156.         }
  157.         .price-old {
  158.             font-size: 13px;
  159.             color: var(--text-muted);
  160.             text-decoration: line-through;
  161.             margin-left: 8px;
  162.         }
  163.         /* Bouton supprimer */
  164.         .btn-remove {
  165.             width: 36px;
  166.             height: 36px;
  167.             border-radius: 50%;
  168.             background: #f8f9fa;
  169.             border: 1px solid var(--border-light);
  170.             color: var(--danger);
  171.             display: flex;
  172.             align-items: center;
  173.             justify-content: center;
  174.             transition: all 0.3s ease;
  175.             cursor: pointer;
  176.         }
  177.         .btn-remove:hover {
  178.             background: var(--danger);
  179.             color: white;
  180.             transform: scale(1.05);
  181.         }
  182.         /* Panier vide */
  183.         /* Panier vide - centré parfaitement */
  184.         .empty-cart {
  185.             text-align: center;
  186.             padding: 60px 40px;
  187.             background: #fff;
  188.             border-radius: 24px;
  189.             border: 1px solid var(--border-light);
  190.             box-shadow: 0 10px 30px rgba(0,0,0,0.05);
  191.             max-width: 550px;
  192.             margin: 0 auto;  /* Centrage horizontal */
  193.             width: 100%;
  194.         }
  195.         .empty-cart-icon {
  196.             font-size: 80px;
  197.             color: var(--gold);
  198.             margin-bottom: 20px;
  199.         }
  200.         .empty-cart h3 {
  201.             font-size: 24px;
  202.             font-weight: 700;
  203.             color: var(--text-dark);
  204.             margin-bottom: 12px;
  205.         }
  206.         .empty-cart p {
  207.             color: var(--text-muted);
  208.             margin-bottom: 30px;
  209.             font-size: 15px;
  210.         }
  211.         .btn-continue {
  212.             display: inline-flex;
  213.             align-items: center;
  214.             justify-content: center;
  215.             gap: 10px;
  216.             background: linear-gradient(135deg, var(--navy), var(--navy-dark));
  217.             color: #fff;
  218.             padding: 12px 32px;
  219.             border-radius: 40px;
  220.             text-decoration: none;
  221.             font-weight: 600;
  222.             transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
  223.         }
  224.         .btn-continue:hover {
  225.             background: linear-gradient(135deg, var(--gold), var(--gold-dark));
  226.             color: var(--navy);
  227.             transform: translateY(-3px);
  228.             box-shadow: 0 10px 25px rgba(255,174,39,0.3);
  229.         }
  230.         .btn-continue i {
  231.             transition: transform 0.3s;
  232.         }
  233.         .btn-continue:hover i {
  234.             transform: translateX(-5px);
  235.         }
  236.         /* Résumé commande */
  237.         .summary-card {
  238.             background: #fff;
  239.             border-radius: 20px;
  240.             padding: 25px;
  241.             box-shadow: 0 5px 25px rgba(0,0,0,0.05);
  242.             border: 1px solid var(--border-light);
  243.             position: sticky;
  244.             top: 20px;
  245.         }
  246.         .summary-title {
  247.             font-size: 20px;
  248.             font-weight: 700;
  249.             color: var(--text-dark);
  250.             margin-bottom: 20px;
  251.             padding-bottom: 15px;
  252.             border-bottom: 2px solid var(--border-light);
  253.         }
  254.         .summary-row {
  255.             display: flex;
  256.             justify-content: space-between;
  257.             padding: 10px 0;
  258.             font-size: 14px;
  259.         }
  260.         .summary-row.total {
  261.             border-top: 2px solid var(--border-light);
  262.             margin-top: 10px;
  263.             padding-top: 15px;
  264.             font-size: 18px;
  265.             font-weight: 700;
  266.             color: var(--text-dark);
  267.         }
  268.         .summary-row.total .summary-value {
  269.             color: var(--gold-dark);
  270.             font-size: 22px;
  271.         }
  272.         .summary-divider {
  273.             height: 1px;
  274.             background: var(--border-light);
  275.             margin: 15px 0;
  276.         }
  277.         .btn-checkout {
  278.             width: 100%;
  279.             background: linear-gradient(135deg, var(--navy), var(--navy-dark));
  280.             color: #fff;
  281.             border: none;
  282.             padding: 14px;
  283.             border-radius: 40px;
  284.             font-weight: 700;
  285.             font-size: 16px;
  286.             transition: all 0.3s ease;
  287.             margin-top: 20px;
  288.             cursor: pointer;
  289.         }
  290.         .btn-checkout:hover {
  291.             background: linear-gradient(135deg, var(--gold), var(--gold-dark));
  292.             color: var(--navy);
  293.             transform: translateY(-2px);
  294.             box-shadow: 0 8px 20px rgba(255,174,39,0.3);
  295.         }
  296.         .payment-icons {
  297.             display: flex;
  298.             justify-content: center;
  299.             gap: 15px;
  300.             margin-top: 20px;
  301.             padding-top: 15px;
  302.             border-top: 1px solid var(--border-light);
  303.         }
  304.         .payment-icons i {
  305.             font-size: 24px;
  306.             color: #adb5bd;
  307.             transition: color 0.3s;
  308.         }
  309.         .payment-icons i:hover {
  310.             color: var(--gold);
  311.         }
  312.         /* Responsive */
  313.         @media (max-width: 768px) {
  314.             .cart-table thead {
  315.                 display: none;
  316.             }
  317.             .cart-table tbody tr {
  318.                 display: block;
  319.                 margin-bottom: 15px;
  320.                 border: 1px solid var(--border-light);
  321.                 border-radius: 16px;
  322.             }
  323.             .cart-table tbody td {
  324.                 display: flex;
  325.                 justify-content: space-between;
  326.                 align-items: center;
  327.                 padding: 12px 15px;
  328.                 border-bottom: 1px solid var(--border-light);
  329.             }
  330.             .cart-table tbody td:last-child {
  331.                 border-bottom: none;
  332.             }
  333.             .cart-table tbody td::before {
  334.                 content: attr(data-label);
  335.                 font-weight: 600;
  336.                 color: var(--navy);
  337.             }
  338.             .product-card {
  339.                 flex-direction: column;
  340.                 text-align: center;
  341.             }
  342.             .summary-card {
  343.                 margin-top: 20px;
  344.                 position: static;
  345.             }
  346.         }
  347.     </style>
  348.     <!-- BREADCRUMB -->
  349.     <div class="breadcrumb-area">
  350.         <div class="container">
  351.             <div class="row">
  352.                 <div class="col-md-12">
  353.                     <div class="breadcrumb-title text-center">
  354.                         <h1>Mon Panier</h1>
  355.                         <ul class="breadcrumb-list">
  356.                             <li><a href="{{ path('app_home') }}">Accueil</a></li>
  357.                             <li class="active">Panier</li>
  358.                         </ul>
  359.                     </div>
  360.                 </div>
  361.             </div>
  362.         </div>
  363.     </div>
  364.     <!-- SECTION PANIER -->
  365.     <!-- SECTION PANIER -->
  366.     <div class="cart-section">
  367.         <div class="container">
  368.             {% if items|length > 0 %}
  369.                 <!-- Affichage quand le panier n'est pas vide -->
  370.                 <div class="row">
  371.                     <div class="col-lg-8">
  372.                         <div class="cart-header">
  373.                             <h2 class="cart-title">Mon Panier</h2>
  374.                             <p class="cart-subtitle">{{ items|length }} élément(s) dans votre panier</p>
  375.                         </div>
  376.                         <div class="cart-table">
  377.                             <table class="table mb-0">
  378.                                 <thead>
  379.                                 <tr>
  380.                                     <th>Produit</th>
  381.                                     <th>Type</th>
  382.                                     <th class="text-end">Prix</th>
  383.                                     <th class="text-center">Action</th>
  384.                                 </tr>
  385.                                 </thead>
  386.                                 <tbody>
  387.                                 {% set totalPanier = 0 %}
  388.                                 {% for item in items %}
  389.                                     {% set quantite = 1 %}
  390.                                     {% set prix = item.prix %}
  391.                                     {% set sousTotal = prix * quantite %}
  392.                                     {% set totalPanier = totalPanier + sousTotal %}
  393.                                     <tr>
  394.                                         <td data-label="Produit">
  395.                                             <div class="product-card">
  396.                                                 <div class="product-image">
  397.                                                     {% if item.type == 'formation' %}
  398.                                                         <img src="{{ asset('uploads/formation/' ~ item.item.affiche) }}" alt="{{ item.item.titre }}">
  399.                                                     {% else %}
  400.                                                         <img src="{{ asset('uploads/formation/' ~ item.item.image) }}" alt="{{ item.item.libelle }}">
  401.                                                     {% endif %}
  402.                                                 </div>
  403.                                                 <div class="product-info">
  404.                                                     <h5 class="product-title">
  405.                                                         <a href="{% if item.type == 'formation' %}{{ path('app_formation_detailsfront', {'slug': item.item.slug}) }}{% else %}#{% endif %}">
  406.                                                             {% if item.type == 'formation' %}
  407.                                                                 {{ item.item.titre }}
  408.                                                             {% else %}
  409.                                                                 {{ item.item.libelle }}
  410.                                                             {% endif %}
  411.                                                         </a>
  412.                                                     </h5>
  413.                                                     <div class="product-meta">
  414.                                                         {% if item.type == 'formation' and item.item.formateur %}
  415.                                                             Par {{ item.item.formateur.prenom }} {{ item.item.formateur.nom }}
  416.                                                         {% elseif item.type == 'pack' %}
  417.                                                             Pack de formations
  418.                                                         {% endif %}
  419.                                                     </div>
  420.                                                 </div>
  421.                                             </div>
  422.                                         </td>
  423.                                         <td data-label="Type">
  424.                                             {% if item.type == 'formation' %}
  425.                                                 <span class="badge-custom badge-formation">
  426.                                                 <i class="fa fa-graduation-cap"></i> Formation
  427.                                             </span>
  428.                                             {% else %}
  429.                                                 <span class="badge-custom badge-pack">
  430.                                                 <i class="fa fa-cubes"></i> Pack
  431.                                             </span>
  432.                                             {% endif %}
  433.                                         </td>
  434.                                         <td data-label="Prix" class="text-end">
  435.                                             <span class="price-current">{{ sousTotal }} DT</span>
  436.                                             {% if item.type == 'formation' and item.item.isPromo %}
  437.                                                 <div class="price-old"><del>{{ item.item.prixPromo }} DT</del></div>
  438.                                             {% endif %}
  439.                                         </td>
  440.                                         <td data-label="Action" class="text-center">
  441.                                             <button class="btn-remove"
  442.                                                     data-id="{{ item.item.id }}"
  443.                                                     data-type="{{ item.type }}">
  444.                                                 <i class="fa fa-trash-o"></i>
  445.                                             </button>
  446.                                         </td>
  447.                                     </tr>
  448.                                 {% endfor %}
  449.                                 </tbody>
  450.                             </table>
  451.                         </div>
  452.                     </div>
  453.                     <div class="col-lg-4">
  454.                         <div class="summary-card">
  455.                             <h4 class="summary-title">Résumé de la commande</h4>
  456.                             <div class="summary-row">
  457.                                 <span class="summary-label">Sous-total</span>
  458.                                 <span class="summary-value">{{ totalPanier|number_format(2, '.', ',') }} DT</span>
  459.                             </div>
  460.                             {% set tva = totalPanier * 0.19 %}
  461.                             <div class="summary-row">
  462.                                 <span class="summary-label">TVA (19%)</span>
  463.                                 <span class="summary-value">{{ tva|number_format(2, '.', ',') }} DT</span>
  464.                             </div>
  465.                             <div class="summary-row">
  466.                                 <span class="summary-label">Timbre fiscal</span>
  467.                                 <span class="summary-value">1.00 DT</span>
  468.                             </div>
  469.                             {% set totalAvecTvaEtTimbre = totalPanier + tva + 1 %}
  470.                             <div class="summary-row total">
  471.                                 <span class="summary-label">Total à payer</span>
  472.                                 <span class="summary-value">{{ totalAvecTvaEtTimbre|number_format(2, '.', ',') }} DT</span>
  473.                             </div>
  474.                             <button id="btn-payer" class="btn-checkout">
  475.                                 <i class="fa fa-lock"></i>
  476.                                 Valider la commande
  477.                             </button>
  478.                         </div>
  479.                     </div>
  480.                 </div>
  481.             {% else %}
  482.                 <!-- Panier vide - centré -->
  483.                 <div class="row">
  484.                     <div class="col-12">
  485.                         <div class="empty-cart">
  486.                             <div class="empty-cart-icon">
  487.                                 <i class="fa fa-shopping-cart"></i>
  488.                             </div>
  489.                             <h3>Votre panier est vide</h3>
  490.                             <p>Découvrez nos formations et packs pour commencer votre apprentissage</p>
  491.                             <a href="{{ path('app_formation_elearning_front') }}" class="btn-continue">
  492.                                 <i class="fa fa-arrow-left"></i>
  493.                                 Découvrir nos formations
  494.                             </a>
  495.                         </div>
  496.                     </div>
  497.                 </div>
  498.             {% endif %}
  499.         </div>
  500.     </div>
  501.     <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
  502.     <script>
  503.         document.addEventListener('DOMContentLoaded', () => {
  504.             // Gestion de la suppression
  505.             document.querySelectorAll('.btn-remove').forEach(btn => {
  506.                 btn.addEventListener('click', async (e) => {
  507.                     e.preventDefault();
  508.                     const id = btn.dataset.id;
  509.                     const type = btn.dataset.type;
  510.                     const result = await Swal.fire({
  511.                         title: 'Confirmation',
  512.                         text: 'Voulez-vous vraiment supprimer cet élément du panier ?',
  513.                         icon: 'warning',
  514.                         showCancelButton: true,
  515.                         confirmButtonColor: '#dc3545',
  516.                         cancelButtonColor: '#6c757d',
  517.                         confirmButtonText: 'Oui, supprimer',
  518.                         cancelButtonText: 'Annuler'
  519.                     });
  520.                     if (result.isConfirmed) {
  521.                         try {
  522.                             const response = await fetch(`/panier/supprimer/${id}?type=${type}`, {
  523.                                 method: 'POST',
  524.                                 headers: { 'X-Requested-With': 'XMLHttpRequest' }
  525.                             });
  526.                             if (response.ok) {
  527.                                 Swal.fire({
  528.                                     icon: 'success',
  529.                                     title: 'Supprimé !',
  530.                                     text: 'L\'élément a été supprimé de votre panier.',
  531.                                     timer: 1500,
  532.                                     showConfirmButton: false
  533.                                 }).then(() => location.reload());
  534.                             }
  535.                         } catch (err) {
  536.                             console.error(err);
  537.                         }
  538.                     }
  539.                 });
  540.             });
  541.             // Gestion du paiement
  542.             const btnPayer = document.getElementById('btn-payer');
  543.             const isAuthenticated = {{ isAuthenticated ? 'true' : 'false' }};
  544.             if (btnPayer) {
  545.                 btnPayer.addEventListener('click', (event) => {
  546.                     event.preventDefault();
  547.                     if (!isAuthenticated) {
  548.                         Swal.fire({
  549.                             icon: 'info',
  550.                             title: 'Connexion requise',
  551.                             text: 'Vous devez être connecté pour finaliser votre commande.',
  552.                             showCancelButton: true,
  553.                             confirmButtonText: 'Se connecter',
  554.                             cancelButtonText: 'Annuler',
  555.                             confirmButtonColor: '#1F3971'
  556.                         }).then((result) => {
  557.                             if (result.isConfirmed) {
  558.                                 // Rediriger vers login avec l'URL de retour vers le panier
  559.                                 window.location.href = '{{ path('app_login') }}?redirect={{ path('panier_voir')|url_encode }}';
  560.                             }
  561.                         });
  562.                     }
  563.                     else {
  564.                         Swal.fire({
  565.                             icon: 'question',
  566.                             title: 'Confirmation',
  567.                             html: 'Voulez-vous confirmer cette commande ?<br><small>Le paiement s\'effectuera à la livraison</small>',
  568.                             showCancelButton: true,
  569.                             confirmButtonText: 'Oui, confirmer',
  570.                             cancelButtonText: 'Annuler',
  571.                             confirmButtonColor: '#28a745'
  572.                         }).then((result) => {
  573.                             if (result.isConfirmed) {
  574.                                 window.location.href = '{{ path('panier_confirmer') }}';
  575.                             }
  576.                         });
  577.                     }
  578.                 });
  579.             }
  580.         });
  581.     </script>
  582. {% endblock %}