var/cache/dev/twig/c0/c0d1f3a332cda846da3924c2128d24e9.php line 46

Open in your IDE?
  1. <?php
  2. use Twig\Environment;
  3. use Twig\Error\LoaderError;
  4. use Twig\Error\RuntimeError;
  5. use Twig\Extension\CoreExtension;
  6. use Twig\Extension\SandboxExtension;
  7. use Twig\Markup;
  8. use Twig\Sandbox\SecurityError;
  9. use Twig\Sandbox\SecurityNotAllowedTagError;
  10. use Twig\Sandbox\SecurityNotAllowedFilterError;
  11. use Twig\Sandbox\SecurityNotAllowedFunctionError;
  12. use Twig\Source;
  13. use Twig\Template;
  14. use Twig\TemplateWrapper;
  15. /* home/cart.html.twig */
  16. class __TwigTemplate_0219938fbd6025d98cba8e952062cfef extends Template
  17. {
  18.     private Source $source;
  19.     /**
  20.      * @var array<string, Template>
  21.      */
  22.     private array $macros = [];
  23.     public function __construct(Environment $env)
  24.     {
  25.         parent::__construct($env);
  26.         $this->source $this->getSourceContext();
  27.         $this->blocks = [
  28.             'title' => [$this'block_title'],
  29.             'body' => [$this'block_body'],
  30.             'stylesheets' => [$this'block_stylesheets'],
  31.             'javascripts' => [$this'block_javascripts'],
  32.         ];
  33.     }
  34.     protected function doGetParent(array $context): bool|string|Template|TemplateWrapper
  35.     {
  36.         // line 1
  37.         return "base_home.html.twig";
  38.     }
  39.     protected function doDisplay(array $context, array $blocks = []): iterable
  40.     {
  41.         $macros $this->macros;
  42.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  43.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "template""home/cart.html.twig"));
  44.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  45.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "template""home/cart.html.twig"));
  46.         $this->parent $this->load("base_home.html.twig"1);
  47.         yield from $this->parent->unwrap()->yield($contextarray_merge($this->blocks$blocks));
  48.         
  49.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  50.         
  51.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  52.     }
  53.     // line 3
  54.     /**
  55.      * @return iterable<null|scalar|\Stringable>
  56.      */
  57.     public function block_title(array $context, array $blocks = []): iterable
  58.     {
  59.         $macros $this->macros;
  60.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  61.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""title"));
  62.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  63.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""title"));
  64.         yield "Panier | MaketOu";
  65.         
  66.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  67.         
  68.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  69.         yield from [];
  70.     }
  71.     // line 5
  72.     /**
  73.      * @return iterable<null|scalar|\Stringable>
  74.      */
  75.     public function block_body(array $context, array $blocks = []): iterable
  76.     {
  77.         $macros $this->macros;
  78.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  79.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""body"));
  80.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  81.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""body"));
  82.         // line 6
  83.         yield "    <!-- Start Banner Area -->
  84.     <section class=\"banner-area organic-breadcrumb\">
  85.         <div class=\"container\">
  86.             <div class=\"breadcrumb-banner d-flex flex-wrap align-items-center justify-content-end\">
  87.                 <div class=\"col-first\">
  88.                     <h1>Panier</h1>
  89.                     <nav class=\"d-flex align-items-center\">
  90.                         <a href=\"";
  91.         // line 13
  92.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("ui_home");
  93.         yield "\">Accueil<span class=\"lnr lnr-arrow-right\"></span></a>
  94.                         <a href=\"javascript:void(0)\">Panier</a>
  95.                     </nav>
  96.                 </div>
  97.             </div>
  98.         </div>
  99.     </section>
  100.     <!-- End Banner Area -->
  101.     <!--================Cart Area =================-->
  102.     <section class=\"cart_area\">
  103.         <div class=\"container\">
  104.             <div class=\"row\">
  105.                 <div class=\"col-lg-8\">
  106.                     <div class=\"cart_inner\">
  107.                         <div class=\"table-responsive\">
  108.                             <table class=\"table\">
  109.                                 <thead>
  110.                                     <tr>
  111.                                         <th scope=\"col\">Produit</th>
  112.                                         <th scope=\"col\">Prix</th>
  113.                                         <th scope=\"col\">Quantité</th>
  114.                                         <th scope=\"col\">Total</th>
  115.                                         <th scope=\"col\">Action</th>
  116.                                     </tr>
  117.                                 </thead>
  118.                                 <tbody>
  119.                                     ";
  120.         // line 40
  121.         $context['_parent'] = $context;
  122.         $context['_seq'] = CoreExtension::ensureTraversable(($context["items"] ?? null));
  123.         $context['_iterated'] = false;
  124.         foreach ($context['_seq'] as $context["_key"] => $context["item"]) {
  125.             // line 41
  126.             yield "                                    <tr>
  127.                                         <td data-label=\"Produit\">
  128.                                             <div class=\"cart-item\">
  129.                                                 ";
  130.             // line 44
  131.             $context["image"] = (((CoreExtension::getAttribute($this->env$this->source$context["item"], "image", [], "any"truetruefalse44) && (Twig\Extension\CoreExtension::length($this->env->getCharset(), CoreExtension::getAttribute($this->env$this->source$context["item"], "image", [], "any"falsefalsefalse44)) > 0))) ? (CoreExtension::getAttribute($this->env$this->source$context["item"], "image", [], "any"falsefalsefalse44)) : ($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl("ui/img/category/s-p1.jpg")));
  132.             // line 45
  133.             yield "                                                <img src=\"";
  134.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(($context["image"] ?? null), "html"nulltrue);
  135.             yield "\" alt=\"";
  136.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["item"], "name", [], "any"falsefalsefalse45), "html"nulltrue);
  137.             yield "\" class=\"cart-item-image\">
  138.                                                 <div class=\"cart-item-info\">
  139.                                                     <a href=\"";
  140.             // line 47
  141.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("ui_product_show", ["slug" => CoreExtension::getAttribute($this->env$this->source$context["item"], "slug", [], "any"falsefalsefalse47)]), "html"nulltrue);
  142.             yield "\" class=\"cart-item-name\">";
  143.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["item"], "name", [], "any"falsefalsefalse47), "html"nulltrue);
  144.             yield "</a>
  145.                                                 </div>
  146.                                             </div>
  147.                                         </td>
  148.                                         <td data-label=\"Prix\">
  149.                                             <span class=\"cart-item-price\">";
  150.             // line 52
  151.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(CoreExtension::getAttribute($this->env$this->source$context["item"], "price", [], "any"falsefalsefalse52), 2"."" "), "html"nulltrue);
  152.             yield " HTG</span>
  153.                                         </td>
  154.                                         <td data-label=\"Quantité\">
  155.                                             <div class=\"quantity-controls\">
  156.                                                 <button class=\"quantity-btn\" onclick=\"changeQuantity(";
  157.             // line 56
  158.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["item"], "id", [], "any"falsefalsefalse56), "html"nulltrue);
  159.             yield ", -1)\">-</button>
  160.                                                 <input type=\"text\" value=\"";
  161.             // line 57
  162.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["item"], "qty", [], "any"falsefalsefalse57), "html"nulltrue);
  163.             yield "\" class=\"quantity-input\" id=\"qty-";
  164.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["item"], "id", [], "any"falsefalsefalse57), "html"nulltrue);
  165.             yield "\" onchange=\"updateQuantity(";
  166.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["item"], "id", [], "any"falsefalsefalse57), "html"nulltrue);
  167.             yield ", this.value)\">
  168.                                                 <button class=\"quantity-btn\" onclick=\"changeQuantity(";
  169.             // line 58
  170.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["item"], "id", [], "any"falsefalsefalse58), "html"nulltrue);
  171.             yield ", 1)\">+</button>
  172.                                             </div>
  173.                                         </td>
  174.                                         <td data-label=\"Total\">
  175.                                             <span class=\"cart-item-total\" id=\"total-";
  176.             // line 62
  177.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["item"], "id", [], "any"falsefalsefalse62), "html"nulltrue);
  178.             yield "\">";
  179.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber((CoreExtension::getAttribute($this->env$this->source$context["item"], "price", [], "any"falsefalsefalse62) * CoreExtension::getAttribute($this->env$this->source$context["item"], "qty", [], "any"falsefalsefalse62)), 2"."" "), "html"nulltrue);
  180.             yield " HTG</span>
  181.                                         </td>
  182.                                         <td data-label=\"Action\">
  183.                                             <button class=\"remove-btn\" onclick=\"removeFromCart(";
  184.             // line 65
  185.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["item"], "id", [], "any"falsefalsefalse65), "html"nulltrue);
  186.             yield ")\">Supprimer</button>
  187.                                         </td>
  188.                                     </tr>
  189.                                     ";
  190.             $context['_iterated'] = true;
  191.         }
  192.         // line 68
  193.         if (!$context['_iterated']) {
  194.             // line 69
  195.             yield "                                        <tr>
  196.                                             <td colspan=\"5\" style=\"text-align: center; padding: 50px;\">
  197.                                                 Votre panier est vide.
  198.                                                 <br>
  199.                                                 <a href=\"";
  200.             // line 73
  201.             yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("ui_listing");
  202.             yield "\" style=\"color: #007185;\">Continuer vos achats</a>
  203.                                             </td>
  204.                                         </tr>
  205.                                     ";
  206.         }
  207.         $_parent $context['_parent'];
  208.         unset($context['_seq'], $context['_key'], $context['item'], $context['_parent'], $context['_iterated']);
  209.         $context array_intersect_key($context$_parent) + $_parent;
  210.         // line 77
  211.         yield "                                </tbody>
  212.                             </table>
  213.                         </div>
  214.                     </div>
  215.                 </div>
  216.                 <div class=\"col-lg-4\">
  217.                     <div class=\"cart-summary\">
  218.                         <h3>Résumé de la commande</h3>
  219.                         <div class=\"cart-subtotal\">
  220.                             <span id=\"cart-subtotal-label\">Sous-total (<span id=\"cart-item-count\">";
  221.         // line 86
  222.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::length($this->env->getCharset(), ($context["items"] ?? null)), "html"nulltrue);
  223.         yield "</span> article";
  224.         yield (((Twig\Extension\CoreExtension::length($this->env->getCharset(), ($context["items"] ?? null)) > 1)) ? ("s") : (""));
  225.         yield ")</span>
  226.                             <span id=\"cart-subtotal\">";
  227.         // line 87
  228.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(($context["subtotal"] ?? null), 2"."" "), "html"nulltrue);
  229.         yield " HTG</span>
  230.                         </div>
  231.                         <div class=\"cart-total\">
  232.                             <span>Total</span>
  233.                             <span id=\"cart-total\">";
  234.         // line 91
  235.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(($context["subtotal"] ?? null), 2"."" "), "html"nulltrue);
  236.         yield " HTG</span>
  237.                         </div>
  238.                         <button class=\"checkout-btn mt-3\" onclick=\"proceedToCheckout()\">Passer la commande</button>
  239.                         <button class=\"continue-shopping\" onclick=\"window.location.href='";
  240.         // line 94
  241.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("ui_listing");
  242.         yield "'\">Continuer vos achats</button>
  243.                     </div>
  244.                 </div>
  245.             </div>
  246.         </div>
  247.     </section>
  248.     <!--================End Cart Area =================-->
  249.     <!-- Modal personnalisé -->
  250.     <div id=\"customModal\" class=\"custom-modal\">
  251.         <div class=\"custom-modal-overlay\"></div>
  252.         <div class=\"custom-modal-content\">
  253.             <div class=\"custom-modal-header\">
  254.                 <h3 class=\"custom-modal-title\" id=\"modalTitle\">Titre</h3>
  255.                 <button class=\"custom-modal-close\" onclick=\"closeCustomModal()\" aria-label=\"Fermer\">
  256.                     <span>&times;</span>
  257.                 </button>
  258.             </div>
  259.             <div class=\"custom-modal-body\" id=\"modalBody\">
  260.                 <p id=\"modalMessage\">Message</p>
  261.             </div>
  262.             <div class=\"custom-modal-footer\" id=\"modalFooter\">
  263.                 <button class=\"custom-modal-btn custom-modal-btn-primary\" id=\"modalConfirmBtn\" onclick=\"confirmModalAction()\">Confirmer</button>
  264.                 <button class=\"custom-modal-btn custom-modal-btn-secondary\" id=\"modalCancelBtn\" onclick=\"closeCustomModal()\">Annuler</button>
  265.             </div>
  266.         </div>
  267.     </div>
  268. ";
  269.         
  270.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  271.         
  272.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  273.         yield from [];
  274.     }
  275.     // line 124
  276.     /**
  277.      * @return iterable<null|scalar|\Stringable>
  278.      */
  279.     public function block_stylesheets(array $context, array $blocks = []): iterable
  280.     {
  281.         $macros $this->macros;
  282.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  283.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""stylesheets"));
  284.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  285.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""stylesheets"));
  286.         // line 125
  287.         yield "<style>
  288. .cart_area {
  289.     background-color: #f8f8f8;
  290.     padding: 20px 0;
  291. }
  292. .cart_inner {
  293.     background: white;
  294.     border-radius: 8px;
  295.     box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  296.     overflow: hidden;
  297. }
  298. .table th {
  299.     background-color: #f3f3f3;
  300.     border-bottom: 2px solid #ddd;
  301.     font-weight: 600;
  302.     color: #333;
  303.     padding: 15px;
  304. }
  305. .table td {
  306.     vertical-align: middle;
  307.     padding: 15px;
  308. }
  309. .cart-item {
  310.     display: flex;
  311.     align-items: center;
  312. }
  313. .cart-item-image {
  314.     width: 80px;
  315.     height: 80px;
  316.     object-fit: cover;
  317.     border-radius: 8px;
  318.     margin-right: 15px;
  319. }
  320. .cart-item-info {
  321.     flex-grow: 1;
  322. }
  323. .cart-item-name {
  324.     font-weight: 500;
  325.     color: #007185;
  326.     text-decoration: none;
  327.     margin-bottom: 5px;
  328. }
  329. .cart-item-name:hover {
  330.     text-decoration: underline;
  331. }
  332. .cart-item-price {
  333.     color: #333;
  334.     font-size: 18px;
  335.     font-weight: 700;
  336. }
  337. .quantity-controls {
  338.     display: flex !important;
  339.     align-items: center !important;
  340.     justify-content: center !important;
  341.     border: 1px solid #ddd !important;
  342.     border-radius: 4px !important;
  343.     width: 120px !important;
  344.     height: 40px !important;
  345.     position: relative !important;
  346.     background: white !important;
  347.     overflow: hidden !important;
  348. }
  349. .quantity-controls .quantity-btn {
  350.     background: #f8f8f8 !important;
  351.     border: none !important;
  352.     width: 35px !important;
  353.     height: 100% !important;
  354.     min-width: 35px !important;
  355.     cursor: pointer !important;
  356.     font-size: 18px !important;
  357.     font-weight: 600 !important;
  358.     color: #333 !important;
  359.     display: flex !important;
  360.     align-items: center !important;
  361.     justify-content: center !important;
  362.     padding: 0 !important;
  363.     margin: 0 !important;
  364.     line-height: 1 !important;
  365.     transition: background-color 0.2s ease !important;
  366.     position: relative !important;
  367.     z-index: 1 !important;
  368. }
  369. .quantity-controls .quantity-btn:first-child {
  370.     border-right: 1px solid #ddd !important;
  371. }
  372. .quantity-controls .quantity-btn:last-child {
  373.     border-left: 1px solid #ddd !important;
  374. }
  375. .quantity-controls .quantity-btn:hover {
  376.     background: #e7e7e7 !important;
  377.     color: #000 !important;
  378. }
  379. .quantity-controls .quantity-btn:active {
  380.     background: #d0d0d0 !important;
  381. }
  382. .quantity-controls .quantity-input {
  383.     border: none !important;
  384.     width: 50px !important;
  385.     min-width: 50px !important;
  386.     height: 100% !important;
  387.     text-align: center !important;
  388.     font-size: 15px !important;
  389.     font-weight: 500 !important;
  390.     padding: 0 !important;
  391.     margin: 0 !important;
  392.     background: white !important;
  393.     color: #333 !important;
  394.     outline: none !important;
  395.     box-shadow: none !important;
  396.     -moz-appearance: textfield !important;
  397.     position: relative !important;
  398.     z-index: 1 !important;
  399. }
  400. .quantity-controls .quantity-input::-webkit-outer-spin-button,
  401. .quantity-controls .quantity-input::-webkit-inner-spin-button {
  402.     -webkit-appearance: none !important;
  403.     margin: 0 !important;
  404. }
  405. /* Surcharger les styles externes qui pourraient interférer */
  406. .cart_inner .table tbody tr td .quantity-controls,
  407. .cart_inner .table tbody tr td .quantity-controls .quantity-btn,
  408. .cart_inner .table tbody tr td .quantity-controls .quantity-input {
  409.     position: relative !important;
  410. }
  411. .cart_inner .table tbody tr td .quantity-controls .quantity-btn:before,
  412. .cart_inner .table tbody tr td .quantity-controls .quantity-btn:after {
  413.     display: none !important;
  414.     content: none !important;
  415. }
  416. .cart-item-total {
  417.     font-size: 18px;
  418.     font-weight: 700;
  419.     color: #333;
  420. }
  421. /* Responsive Styles */
  422. @media (max-width: 991.98px) {
  423.     .cart_area {
  424.         padding: 15px 0;
  425.     }
  426.     
  427.     .cart-summary {
  428.         margin-top: 2rem;
  429.     }
  430. }
  431. @media (max-width: 767.98px) {
  432.     .cart_inner {
  433.         border-radius: 0;
  434.     }
  435.     
  436.     .table {
  437.         font-size: 0.875rem;
  438.     }
  439.     
  440.     .table th {
  441.         padding: 10px 8px;
  442.         font-size: 0.8rem;
  443.     }
  444.     
  445.     .table td {
  446.         padding: 10px 8px;
  447.     }
  448.     
  449.     .cart-item {
  450.         flex-direction: column;
  451.         align-items: flex-start;
  452.     }
  453.     
  454.     .cart-item-image {
  455.         width: 60px;
  456.         height: 60px;
  457.         margin-right: 0;
  458.         margin-bottom: 10px;
  459.     }
  460.     
  461.     .cart-item-name {
  462.         font-size: 0.9rem;
  463.     }
  464.     
  465.     .cart-item-price,
  466.     .cart-item-total {
  467.         font-size: 1rem;
  468.     }
  469.     
  470.     .quantity-controls {
  471.         width: 110px !important;
  472.         height: 38px !important;
  473.     }
  474.     
  475.     .quantity-controls .quantity-btn {
  476.         width: 32px !important;
  477.         font-size: 16px !important;
  478.     }
  479.     
  480.     .quantity-controls .quantity-input {
  481.         width: 46px !important;
  482.         font-size: 14px !important;
  483.     }
  484.     
  485.     .cart-summary {
  486.         margin-top: 1.5rem;
  487.         padding: 1.5rem;
  488.     }
  489.     
  490.     .checkout-btn,
  491.     .continue-shopping {
  492.         width: 100%;
  493.         margin-bottom: 0.5rem;
  494.     }
  495. }
  496. @media (max-width: 575.98px) {
  497.     .table thead {
  498.         display: none;
  499.     }
  500.     
  501.     .table tbody tr {
  502.         display: block;
  503.         margin-bottom: 1rem;
  504.         border: 1px solid #dee2e6;
  505.         border-radius: 8px;
  506.         padding: 1rem;
  507.     }
  508.     
  509.     .table tbody td {
  510.         display: flex;
  511.         justify-content: space-between;
  512.         align-items: center;
  513.         padding: 0.5rem 0;
  514.         border: none;
  515.         text-align: right;
  516.     }
  517.     
  518.     .table tbody td::before {
  519.         content: attr(data-label);
  520.         font-weight: bold;
  521.         text-align: left;
  522.         margin-right: 1rem;
  523.     }
  524.     
  525.     .table tbody td:first-child {
  526.         flex-direction: column;
  527.         align-items: flex-start;
  528.     }
  529.     
  530.     .cart-item-image {
  531.         width: 100%;
  532.         height: 200px;
  533.         margin-bottom: 1rem;
  534.     }
  535.     
  536.     .cart-item-name {
  537.         font-size: 1rem;
  538.         margin-bottom: 0.5rem;
  539.     }
  540.     
  541.     .quantity-controls {
  542.         width: 100% !important;
  543.         max-width: 150px !important;
  544.         margin: 0 auto !important;
  545.         justify-content: center !important;
  546.         height: 40px !important;
  547.     }
  548.     
  549.     .quantity-controls .quantity-btn {
  550.         width: 40px !important;
  551.         font-size: 18px !important;
  552.     }
  553.     
  554.     .quantity-controls .quantity-input {
  555.         width: 60px !important;
  556.         font-size: 16px !important;
  557.     }
  558.     
  559.     .remove-btn {
  560.         width: 100%;
  561.         margin-top: 0.5rem;
  562.     }
  563. }
  564. .remove-btn {
  565.     background: #ff9900;
  566.     color: white;
  567.     border: none;
  568.     padding: 8px 16px;
  569.     border-radius: 4px;
  570.     cursor: pointer;
  571.     font-size: 12px;
  572. }
  573. .remove-btn:hover {
  574.     background: #e68900;
  575. }
  576. .cart-summary {
  577.     background: white;
  578.     border-radius: 8px;
  579.     box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  580.     padding: 20px;
  581.     height: fit-content;
  582. }
  583. .cart-subtotal {
  584.     display: flex;
  585.     justify-content: space-between;
  586.     padding: 10px 0;
  587.     border-bottom: 1px solid #ddd;
  588.     margin-bottom: 15px;
  589. }
  590. .cart-total {
  591.     font-size: 20px;
  592.     font-weight: 700;
  593.     color: #333;
  594. }
  595. .checkout-btn {
  596.     background: #ffa200;
  597.     color: white;
  598.     border: none;
  599.     padding: 12px 24px;
  600.     border-radius: 4px;
  601.     cursor: pointer;
  602.     width: 100%;
  603.     font-size: 16px;
  604.     font-weight: 600;
  605. }
  606. .checkout-btn:hover {
  607.     background: #e68900;
  608. }
  609. .continue-shopping {
  610.     background: #095ad3;
  611.     color: #ffffff;
  612.     border: none;
  613.     padding: 12px 24px;
  614.     border-radius: 4px;
  615.     cursor: pointer;
  616.     width: 100%;
  617.     font-size: 16px;
  618.     font-weight: 600;
  619.     margin-top: 10px;
  620. }
  621. .continue-shopping:hover {
  622.     background: #e68900;
  623.     color: #ffffff
  624. }
  625. /* ============================================
  626.    MODAL PERSONNALISÉ
  627.    ============================================ */
  628. .custom-modal {
  629.     display: none;
  630.     position: fixed;
  631.     top: 0;
  632.     left: 0;
  633.     width: 100%;
  634.     height: 100%;
  635.     z-index: 10000;
  636.     opacity: 0;
  637.     transition: opacity 0.3s ease;
  638. }
  639. .custom-modal.show {
  640.     display: flex;
  641.     align-items: center;
  642.     justify-content: center;
  643.     opacity: 1;
  644. }
  645. .custom-modal-overlay {
  646.     position: absolute;
  647.     top: 0;
  648.     left: 0;
  649.     width: 100%;
  650.     height: 100%;
  651.     background: rgba(0, 0, 0, 0.5);
  652.     backdrop-filter: blur(4px);
  653.     -webkit-backdrop-filter: blur(4px);
  654. }
  655. .custom-modal-content {
  656.     position: relative;
  657.     background: white;
  658.     border-radius: 12px;
  659.     box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
  660.     max-width: 500px;
  661.     width: 90%;
  662.     max-height: 90vh;
  663.     overflow: hidden;
  664.     transform: scale(0.9) translateY(-20px);
  665.     transition: transform 0.3s ease;
  666.     z-index: 10001;
  667. }
  668. .custom-modal.show .custom-modal-content {
  669.     transform: scale(1) translateY(0);
  670. }
  671. .custom-modal-header {
  672.     display: flex;
  673.     align-items: center;
  674.     justify-content: space-between;
  675.     padding: 20px 24px;
  676.     border-bottom: 1px solid #e0e0e0;
  677.     background: linear-gradient(135deg, #ffa200 0%, #ff9900 100%);
  678. }
  679. .custom-modal-header.error {
  680.     background: linear-gradient(135deg, #dc3545 0%, #c82333 100%);
  681. }
  682. .custom-modal-header.success {
  683.     background: linear-gradient(135deg, #28a745 0%, #218838 100%);
  684. }
  685. .custom-modal-header.warning {
  686.     background: linear-gradient(135deg, #ffc107 0%, #e0a800 100%);
  687. }
  688. .custom-modal-header.info {
  689.     background: linear-gradient(135deg, #17a2b8 0%, #138496 100%);
  690. }
  691. .custom-modal-title {
  692.     margin: 0;
  693.     font-size: 20px;
  694.     font-weight: 600;
  695.     color: white;
  696.     display: flex;
  697.     align-items: center;
  698.     gap: 10px;
  699. }
  700. .custom-modal-title::before {
  701.     content: '';
  702.     width: 24px;
  703.     height: 24px;
  704.     display: inline-block;
  705.     background-size: contain;
  706.     background-repeat: no-repeat;
  707.     background-position: center;
  708. }
  709. .custom-modal-title.success::before {
  710.     content: '✓';
  711.     font-size: 20px;
  712.     font-weight: bold;
  713. }
  714. .custom-modal-title.error::before {
  715.     content: '✕';
  716.     font-size: 20px;
  717.     font-weight: bold;
  718. }
  719. .custom-modal-title.warning::before {
  720.     content: '⚠';
  721.     font-size: 20px;
  722.     font-weight: bold;
  723. }
  724. .custom-modal-title.info::before {
  725.     content: 'ℹ';
  726.     font-size: 20px;
  727.     font-weight: bold;
  728. }
  729. .custom-modal-close {
  730.     background: rgba(255, 255, 255, 0.15);
  731.     border: 2px solid rgba(255, 255, 255, 0.3);
  732.     color: white;
  733.     font-size: 22px;
  734.     font-weight: 300;
  735.     line-height: 1;
  736.     width: 36px;
  737.     height: 36px;
  738.     border-radius: 50%;
  739.     cursor: pointer;
  740.     display: flex;
  741.     align-items: center;
  742.     justify-content: center;
  743.     transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  744.     padding: 0;
  745.     margin: 0;
  746.     position: relative;
  747.     overflow: hidden;
  748. }
  749. .custom-modal-close::before {
  750.     content: '';
  751.     position: absolute;
  752.     top: 50%;
  753.     left: 50%;
  754.     width: 0;
  755.     height: 0;
  756.     border-radius: 50%;
  757.     background: rgba(255, 255, 255, 0.2);
  758.     transform: translate(-50%, -50%);
  759.     transition: width 0.3s ease, height 0.3s ease;
  760. }
  761. .custom-modal-close:hover {
  762.     background: rgba(255, 255, 255, 0.25);
  763.     border-color: rgba(255, 255, 255, 0.5);
  764.     transform: rotate(90deg) scale(1.1);
  765.     box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  766. }
  767. .custom-modal-close:hover::before {
  768.     width: 100%;
  769.     height: 100%;
  770. }
  771. .custom-modal-close:active {
  772.     transform: rotate(90deg) scale(0.95);
  773.     background: rgba(255, 255, 255, 0.3);
  774. }
  775. .custom-modal-close span {
  776.     position: relative;
  777.     z-index: 1;
  778.     display: block;
  779.     line-height: 1;
  780. }
  781. .custom-modal-body {
  782.     padding: 24px;
  783.     font-size: 16px;
  784.     line-height: 1.6;
  785.     color: #333;
  786.     max-height: 60vh;
  787.     overflow-y: auto;
  788. }
  789. .custom-modal-body p {
  790.     margin: 0;
  791. }
  792. .custom-modal-footer {
  793.     display: flex;
  794.     gap: 12px;
  795.     justify-content: flex-end;
  796.     padding: 16px 24px;
  797.     border-top: 1px solid #e0e0e0;
  798.     background: #f8f9fa;
  799. }
  800. .custom-modal-footer.single-button {
  801.     justify-content: center;
  802. }
  803. .custom-modal-btn {
  804.     padding: 10px 24px;
  805.     border: none;
  806.     border-radius: 6px;
  807.     font-size: 15px;
  808.     font-weight: 500;
  809.     cursor: pointer;
  810.     transition: all 0.2s ease;
  811.     min-width: 100px;
  812. }
  813. .custom-modal-btn-primary {
  814.     background: #ffa200;
  815.     color: white;
  816. }
  817. .custom-modal-btn-primary:hover {
  818.     background: #e68900;
  819.     transform: translateY(-1px);
  820.     box-shadow: 0 4px 8px rgba(255, 162, 0, 0.3);
  821. }
  822. .custom-modal-btn-secondary {
  823.     background: #6c757d;
  824.     color: white;
  825. }
  826. .custom-modal-btn-secondary:hover {
  827.     background: #5a6268;
  828.     transform: translateY(-1px);
  829.     box-shadow: 0 4px 8px rgba(108, 117, 125, 0.3);
  830. }
  831. .custom-modal-btn-success {
  832.     background: #28a745;
  833.     color: white;
  834. }
  835. .custom-modal-btn-success:hover {
  836.     background: #218838;
  837.     transform: translateY(-1px);
  838.     box-shadow: 0 4px 8px rgba(40, 167, 69, 0.3);
  839. }
  840. .custom-modal-btn-danger {
  841.     background: #dc3545;
  842.     color: white;
  843. }
  844. .custom-modal-btn-danger:hover {
  845.     background: #c82333;
  846.     transform: translateY(-1px);
  847.     box-shadow: 0 4px 8px rgba(220, 53, 69, 0.3);
  848. }
  849. /* Animation pour les modals */
  850. @keyframes modalFadeIn {
  851.     from {
  852.         opacity: 0;
  853.     }
  854.     to {
  855.         opacity: 1;
  856.     }
  857. }
  858. @keyframes modalSlideIn {
  859.     from {
  860.         transform: scale(0.9) translateY(-20px);
  861.         opacity: 0;
  862.     }
  863.     to {
  864.         transform: scale(1) translateY(0);
  865.         opacity: 1;
  866.     }
  867. }
  868. .custom-modal.show .custom-modal-overlay {
  869.     animation: modalFadeIn 0.3s ease;
  870. }
  871. .custom-modal.show .custom-modal-content {
  872.     animation: modalSlideIn 0.3s ease;
  873. }
  874. /* Responsive */
  875. @media (max-width: 575.98px) {
  876.     .custom-modal-content {
  877.         width: 95%;
  878.         margin: 20px;
  879.     }
  880.     
  881.     .custom-modal-header {
  882.         padding: 16px 20px;
  883.     }
  884.     
  885.     .custom-modal-title {
  886.         font-size: 18px;
  887.     }
  888.     
  889.     .custom-modal-body {
  890.         padding: 20px;
  891.         font-size: 15px;
  892.     }
  893.     
  894.     .custom-modal-footer {
  895.         flex-direction: column;
  896.         padding: 16px 20px;
  897.     }
  898.     
  899.     .custom-modal-btn {
  900.         width: 100%;
  901.     }
  902. }
  903. </style>
  904. ";
  905.         
  906.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  907.         
  908.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  909.         yield from [];
  910.     }
  911.     // line 816
  912.     /**
  913.      * @return iterable<null|scalar|\Stringable>
  914.      */
  915.     public function block_javascripts(array $context, array $blocks = []): iterable
  916.     {
  917.         $macros $this->macros;
  918.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  919.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""javascripts"));
  920.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  921.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""javascripts"));
  922.         // line 817
  923.         yield "<script>
  924. // Variables globales pour le modal
  925. let modalConfirmCallback = null;
  926. let modalCancelCallback = null;
  927. // Fonctions pour gérer le modal personnalisé
  928. function showCustomModal(options) {
  929.     const modal = document.getElementById('customModal');
  930.     const title = document.getElementById('modalTitle');
  931.     const message = document.getElementById('modalMessage');
  932.     const footer = document.getElementById('modalFooter');
  933.     const confirmBtn = document.getElementById('modalConfirmBtn');
  934.     const cancelBtn = document.getElementById('modalCancelBtn');
  935.     const header = modal.querySelector('.custom-modal-header');
  936.     
  937.     // Réinitialiser les classes
  938.     header.className = 'custom-modal-header';
  939.     title.className = 'custom-modal-title';
  940.     footer.className = 'custom-modal-footer';
  941.     
  942.     // Définir le titre et le message
  943.     title.textContent = options.title || 'Information';
  944.     message.textContent = options.message || '';
  945.     
  946.     // Définir le type (success, error, warning, info)
  947.     const type = options.type || 'info';
  948.     header.classList.add(type);
  949.     title.classList.add(type);
  950.     
  951.     // Configurer les boutons
  952.     if (options.showCancel !== false) {
  953.         cancelBtn.style.display = 'block';
  954.         footer.classList.remove('single-button');
  955.     } else {
  956.         cancelBtn.style.display = 'none';
  957.         footer.classList.add('single-button');
  958.     }
  959.     
  960.     // Configurer le bouton de confirmation
  961.     if (options.confirmText) {
  962.         confirmBtn.textContent = options.confirmText;
  963.     }
  964.     
  965.     if (options.confirmClass) {
  966.         confirmBtn.className = 'custom-modal-btn ' + options.confirmClass;
  967.     } else {
  968.         confirmBtn.className = 'custom-modal-btn custom-modal-btn-primary';
  969.     }
  970.     
  971.     // Stocker les callbacks
  972.     modalConfirmCallback = options.onConfirm || null;
  973.     modalCancelCallback = options.onCancel || null;
  974.     
  975.     // Afficher le modal
  976.     modal.classList.add('show');
  977.     document.body.style.overflow = 'hidden';
  978. }
  979. function closeCustomModal() {
  980.     const modal = document.getElementById('customModal');
  981.     const cancelCallback = modalCancelCallback; // Sauvegarder avant réinitialisation
  982.     
  983.     modal.classList.remove('show');
  984.     document.body.style.overflow = '';
  985.     
  986.     // Réinitialiser les callbacks
  987.     modalConfirmCallback = null;
  988.     modalCancelCallback = null;
  989.     
  990.     // Appeler le callback d'annulation si présent
  991.     if (cancelCallback) {
  992.         cancelCallback();
  993.     }
  994. }
  995. function confirmModalAction() {
  996.     if (modalConfirmCallback) {
  997.         modalConfirmCallback();
  998.     }
  999.     closeCustomModal();
  1000. }
  1001. // Fermer le modal en cliquant sur l'overlay
  1002. document.addEventListener('DOMContentLoaded', function() {
  1003.     const modal = document.getElementById('customModal');
  1004.     const overlay = modal.querySelector('.custom-modal-overlay');
  1005.     
  1006.     overlay.addEventListener('click', function() {
  1007.         closeCustomModal();
  1008.     });
  1009.     
  1010.     // Fermer avec la touche Escape
  1011.     document.addEventListener('keydown', function(e) {
  1012.         if (e.key === 'Escape' && modal.classList.contains('show')) {
  1013.             closeCustomModal();
  1014.         }
  1015.     });
  1016. });
  1017. // Fonctions utilitaires pour différents types de modals
  1018. function showAlert(title, message, type = 'info') {
  1019.     showCustomModal({
  1020.         title: title,
  1021.         message: message,
  1022.         type: type,
  1023.         showCancel: false,
  1024.         confirmText: 'OK'
  1025.     });
  1026. }
  1027. function showConfirm(title, message, onConfirm, onCancel = null, type = 'warning') {
  1028.     showCustomModal({
  1029.         title: title,
  1030.         message: message,
  1031.         type: type,
  1032.         showCancel: true,
  1033.         confirmText: 'Confirmer',
  1034.         cancelText: 'Annuler',
  1035.         onConfirm: onConfirm,
  1036.         onCancel: onCancel
  1037.     });
  1038. }
  1039. function proceedToCheckout() {
  1040.     // Vérifier qu'il y a des articles dans le panier
  1041.     if (Object.keys(cartData).length === 0) {
  1042.         showAlert('Panier vide', 'Votre panier est vide. Veuillez ajouter des articles avant de continuer.', 'warning');
  1043.         return;
  1044.     }
  1045.     
  1046.     // Rediriger vers la page de checkout
  1047.     window.location.href = '";
  1048.         // line 948
  1049.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("ui_checkout");
  1050.         yield "';
  1051. }
  1052. function changeQuantity(productId, delta) {
  1053.     const qtyInput = document.getElementById('qty-' + productId);
  1054.     if (!qtyInput) return;
  1055.     
  1056.     const currentQty = parseInt(qtyInput.value) || 0;
  1057.     const newQty = Math.max(0, currentQty + delta);
  1058.     
  1059.     updateQuantity(productId, newQty);
  1060. }
  1061. let cartData = {}; // Stocker les données du panier côté client
  1062. // Initialiser les données du panier
  1063. ";
  1064.         // line 963
  1065.         $context['_parent'] = $context;
  1066.         $context['_seq'] = CoreExtension::ensureTraversable(($context["items"] ?? null));
  1067.         foreach ($context['_seq'] as $context["_key"] => $context["item"]) {
  1068.             // line 964
  1069.             yield "    ";
  1070.             $context["image"] = (((CoreExtension::getAttribute($this->env$this->source$context["item"], "images", [], "any"truetruefalse964) && (Twig\Extension\CoreExtension::length($this->env->getCharset(), CoreExtension::getAttribute($this->env$this->source$context["item"], "images", [], "any"falsefalsefalse964)) > 0))) ? ((($_v0 CoreExtension::getAttribute($this->env$this->source$context["item"], "images", [], "any"falsefalsefalse964)) && is_array($_v0) || $_v0 instanceof ArrayAccess ? ($_v0[0] ?? null) : null)) : ($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl("ui/img/category/s-p1.jpg")));
  1071.             // line 965
  1072.             yield "
  1073. cartData[";
  1074.             // line 966
  1075.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["item"], "id", [], "any"falsefalsefalse966), "html"nulltrue);
  1076.             yield "] = {
  1077.     id: ";
  1078.             // line 967
  1079.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["item"], "id", [], "any"falsefalsefalse967), "html"nulltrue);
  1080.             yield ",
  1081.     name: '";
  1082.             // line 968
  1083.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["item"], "name", [], "any"falsefalsefalse968), "html"nulltrue);
  1084.             yield "',
  1085.     price: ";
  1086.             // line 969
  1087.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["item"], "price", [], "any"falsefalsefalse969), "html"nulltrue);
  1088.             yield ",
  1089.     qty: ";
  1090.             // line 970
  1091.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["item"], "qty", [], "any"falsefalsefalse970), "html"nulltrue);
  1092.             yield ",
  1093.     image: '";
  1094.             // line 971
  1095.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(($context["image"] ?? null), "html"nulltrue);
  1096.             yield "',
  1097.     slug: '";
  1098.             // line 972
  1099.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["item"], "slug", [], "any"falsefalsefalse972), "html"nulltrue);
  1100.             yield "'
  1101. };
  1102. ";
  1103.         }
  1104.         $_parent $context['_parent'];
  1105.         unset($context['_seq'], $context['_key'], $context['item'], $context['_parent']);
  1106.         $context array_intersect_key($context$_parent) + $_parent;
  1107.         // line 975
  1108.         yield "
  1109. function updateQuantity(productId, newQty) {
  1110.     const item = cartData[productId];
  1111.     
  1112.     if (!item) {
  1113.         console.error('Produit non trouvé:', productId);
  1114.         return;
  1115.     }
  1116.     
  1117.     // Validation de la quantité
  1118.     newQty = Math.max(0, parseInt(newQty) || 0);
  1119.     
  1120.     if (newQty === 0) {
  1121.         removeFromCart(productId);
  1122.         return;
  1123.     }
  1124.     
  1125.     if (newQty > 99) {
  1126.         showAlert('Quantité maximale', 'La quantité maximale est de 99 articles.', 'warning');
  1127.         return;
  1128.     }
  1129.     
  1130.     // Mettre à jour l'interface immédiatement (optimistic update)
  1131.     updateCartDisplay(productId, newQty);
  1132.     
  1133.     // Envoyer la requête au serveur
  1134.     fetch('";
  1135.         // line 1001
  1136.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("ui_cart_update");
  1137.         yield "', {
  1138.         method: 'POST',
  1139.         headers: { 
  1140.             'Content-Type': 'application/x-www-form-urlencoded',
  1141.             'X-Requested-With': 'XMLHttpRequest'
  1142.         },
  1143.         body: 'productId=' + productId + '&qty=' + newQty
  1144.     })
  1145.     .then(response => response.json())
  1146.     .then(data => {
  1147.         if (data.ok) {
  1148.             // Les données serveur confirment la mise à jour
  1149.             // cartData est déjà à jour depuis l'optimistic update
  1150.             console.log('Panier mis à jour avec succès');
  1151.         } else {
  1152.             // En cas d'erreur, restaurer la valeur précédente
  1153.             const oldQty = item.qty;
  1154.             updateCartDisplay(productId, oldQty);
  1155.             showAlert('Erreur', data.message || 'Erreur lors de la mise à jour du panier.', 'error');
  1156.         }
  1157.     })
  1158.     .catch(error => {
  1159.         console.error('Erreur:', error);
  1160.         // Restaurer la valeur précédente en cas d'erreur réseau
  1161.         const oldQty = item.qty;
  1162.         updateCartDisplay(productId, oldQty);
  1163.         showAlert('Erreur de connexion', 'Une erreur de connexion est survenue. Veuillez réessayer.', 'error');
  1164.     });
  1165. }
  1166. function updateCartDisplay(productId, qty) {
  1167.     const item = cartData[productId];
  1168.     if (!item) return;
  1169.     
  1170.     // Mettre à jour les données locales
  1171.     item.qty = qty;
  1172.     
  1173.     // Mettre à jour la quantité dans l'input
  1174.     const qtyInput = document.getElementById('qty-' + productId);
  1175.     if (qtyInput) {
  1176.         qtyInput.value = qty;
  1177.     }
  1178.     
  1179.     // Mettre à jour le total du produit
  1180.     const totalElement = document.getElementById('total-' + productId);
  1181.     if (totalElement) {
  1182.         const itemTotal = (item.price * qty);
  1183.         totalElement.textContent = itemTotal.toLocaleString('fr-FR', {
  1184.             minimumFractionDigits: 2,
  1185.             maximumFractionDigits: 2
  1186.         }) + ' HTG';
  1187.     }
  1188.     
  1189.     // Mettre à jour les totaux généraux
  1190.     updateCartSummary();
  1191. }
  1192. function updateCartTotals(data) {
  1193.     // Mettre à jour le sous-total depuis les données serveur
  1194.     const subtotalElement = document.getElementById('cart-subtotal');
  1195.     const totalElement = document.getElementById('cart-total');
  1196.     
  1197.     if (subtotalElement) {
  1198.         subtotalElement.textContent = parseFloat(data.subtotal).toLocaleString('fr-FR', {
  1199.             minimumFractionDigits: 2,
  1200.             maximumFractionDigits: 2
  1201.         }) + ' HTG';
  1202.     }
  1203.     
  1204.     if (totalElement) {
  1205.         totalElement.textContent = parseFloat(data.subtotal).toLocaleString('fr-FR', {
  1206.             minimumFractionDigits: 2,
  1207.             maximumFractionDigits: 2
  1208.         }) + ' HTG';
  1209.     }
  1210.     
  1211.     // Mettre à jour le compteur d'articles
  1212.     const itemCountElement = document.querySelector('.cart-subtotal span');
  1213.     if (itemCountElement) {
  1214.         const totalItems = Object.values(cartData).reduce((sum, item) => sum + item.qty, 0);
  1215.         const itemText = totalItems + ' article' + (totalItems > 1 ? 's' : '');
  1216.         itemCountElement.textContent = itemText;
  1217.     }
  1218. }
  1219. function updateCartSummary() {
  1220.     // Calculer les totaux côté client depuis cartData
  1221.     let subtotal = 0;
  1222.     let totalItems = 0;
  1223.     
  1224.     Object.values(cartData).forEach(item => {
  1225.         subtotal += item.price * item.qty;
  1226.         totalItems += item.qty;
  1227.     });
  1228.     
  1229.     // Mettre à jour l'affichage du sous-total
  1230.     const subtotalElement = document.getElementById('cart-subtotal');
  1231.     if (subtotalElement) {
  1232.         subtotalElement.textContent = subtotal.toLocaleString('fr-FR', {
  1233.             minimumFractionDigits: 2,
  1234.             maximumFractionDigits: 2
  1235.         }) + ' HTG';
  1236.     }
  1237.     
  1238.     // Mettre à jour l'affichage du total
  1239.     const totalElement = document.getElementById('cart-total');
  1240.     if (totalElement) {
  1241.         totalElement.textContent = subtotal.toLocaleString('fr-FR', {
  1242.             minimumFractionDigits: 2,
  1243.             maximumFractionDigits: 2
  1244.         }) + ' HTG';
  1245.     }
  1246.     
  1247.     // Mettre à jour le compteur d'articles
  1248.     const itemCountElement = document.getElementById('cart-item-count');
  1249.     if (itemCountElement) {
  1250.         itemCountElement.textContent = totalItems;
  1251.     }
  1252.     
  1253.     // Mettre à jour le label du sous-total
  1254.     const subtotalLabel = document.getElementById('cart-subtotal-label');
  1255.     if (subtotalLabel) {
  1256.         const itemText = totalItems + ' article' + (totalItems > 1 ? 's' : '');
  1257.         subtotalLabel.innerHTML = 'Sous-total (<span id=\"cart-item-count\">' + totalItems + '</span> ' + (totalItems > 1 ? 'articles' : 'article') + ')';
  1258.     }
  1259. }
  1260. function removeFromCart(productId) {
  1261.     const item = cartData[productId];
  1262.     const itemName = item ? item.name : 'cet article';
  1263.     
  1264.     showConfirm(
  1265.         'Supprimer l\\'article',
  1266.         `Êtes-vous sûr de vouloir supprimer \"\${itemName}\" de votre panier ?`,
  1267.         function() {
  1268.             // Mettre à jour l'interface immédiatement
  1269.             const row = document.querySelector(`tr:has(#qty-\${productId})`);
  1270.             if (row) {
  1271.                 row.style.opacity = '0.5';
  1272.                 row.style.pointerEvents = 'none';
  1273.             }
  1274.             
  1275.             performRemoveFromCart(productId, row);
  1276.         },
  1277.         null,
  1278.         'warning'
  1279.     );
  1280. }
  1281. function performRemoveFromCart(productId, row) {
  1282.     
  1283.     fetch('";
  1284.         // line 1152
  1285.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("ui_cart_remove");
  1286.         yield "', {
  1287.         method: 'POST',
  1288.         headers: { 
  1289.             'Content-Type': 'application/x-www-form-urlencoded',
  1290.             'X-Requested-With': 'XMLHttpRequest'
  1291.         },
  1292.         body: 'productId=' + productId
  1293.     })
  1294.     .then(response => response.json())
  1295.     .then(data => {
  1296.         if (data.ok) {
  1297.             // Supprimer des données locales
  1298.             delete cartData[productId];
  1299.             
  1300.             // Supprimer la ligne du DOM
  1301.             const row = document.querySelector(`tr:has(#qty-\${productId})`);
  1302.             if (row) {
  1303.                 row.remove();
  1304.             }
  1305.             
  1306.             // Mettre à jour les totaux
  1307.             updateCartTotals(data);
  1308.             
  1309.             // Mettre à jour le résumé du panier
  1310.             updateCartSummary();
  1311.             
  1312.             // Afficher un message de succès
  1313.             showAlert('Article supprimé', 'L\\'article a été supprimé de votre panier avec succès.', 'success');
  1314.             
  1315.             // Vérifier si le panier est vide
  1316.             if (Object.keys(cartData).length === 0) {
  1317.                 setTimeout(function() {
  1318.                     location.reload();
  1319.                 }, 1500);
  1320.             }
  1321.         } else {
  1322.             // Restaurer l'affichage en cas d'erreur
  1323.             if (row) {
  1324.                 row.style.opacity = '1';
  1325.                 row.style.pointerEvents = 'auto';
  1326.             }
  1327.             showAlert('Erreur', data.message || 'Erreur lors de la suppression de l\\'article.', 'error');
  1328.         }
  1329.     })
  1330.     .catch(error => {
  1331.         console.error('Erreur:', error);
  1332.         // Restaurer l'affichage en cas d'erreur réseau
  1333.         if (row) {
  1334.             row.style.opacity = '1';
  1335.             row.style.pointerEvents = 'auto';
  1336.         }
  1337.         showAlert('Erreur de connexion', 'Une erreur de connexion est survenue. Veuillez réessayer.', 'error');
  1338.     });
  1339. }
  1340. // Script pour forcer l'application des styles des boutons de quantité
  1341. document.addEventListener('DOMContentLoaded', function() {
  1342.     const quantityControls = document.querySelectorAll('.quantity-controls');
  1343.     quantityControls.forEach(function(control) {
  1344.         if (control) {
  1345.             // Forcer les styles sur le conteneur
  1346.             control.style.display = 'flex';
  1347.             control.style.alignItems = 'center';
  1348.             control.style.justifyContent = 'center';
  1349.             control.style.border = '1px solid #ddd';
  1350.             control.style.borderRadius = '4px';
  1351.             control.style.width = '120px';
  1352.             control.style.height = '40px';
  1353.             control.style.position = 'relative';
  1354.             control.style.background = 'white';
  1355.             control.style.overflow = 'hidden';
  1356.             
  1357.             // Forcer les styles sur les boutons
  1358.             const buttons = control.querySelectorAll('.quantity-btn');
  1359.             buttons.forEach(function(btn, index) {
  1360.                 btn.style.background = '#f8f8f8';
  1361.                 btn.style.border = 'none';
  1362.                 btn.style.width = '35px';
  1363.                 btn.style.height = '100%';
  1364.                 btn.style.cursor = 'pointer';
  1365.                 btn.style.fontSize = '18px';
  1366.                 btn.style.fontWeight = '600';
  1367.                 btn.style.color = '#333';
  1368.                 btn.style.display = 'flex';
  1369.                 btn.style.alignItems = 'center';
  1370.                 btn.style.justifyContent = 'center';
  1371.                 btn.style.padding = '0';
  1372.                 btn.style.margin = '0';
  1373.                 btn.style.lineHeight = '1';
  1374.                 btn.style.position = 'relative';
  1375.                 btn.style.zIndex = '1';
  1376.                 
  1377.                 // Ajouter les bordures entre les boutons
  1378.                 if (index === 0) {
  1379.                     btn.style.borderRight = '1px solid #ddd';
  1380.                 } else if (index === buttons.length - 1) {
  1381.                     btn.style.borderLeft = '1px solid #ddd';
  1382.                 }
  1383.             });
  1384.             
  1385.             // Forcer les styles sur l'input
  1386.             const input = control.querySelector('.quantity-input');
  1387.             if (input) {
  1388.                 input.style.border = 'none';
  1389.                 input.style.width = '50px';
  1390.                 input.style.height = '100%';
  1391.                 input.style.textAlign = 'center';
  1392.                 input.style.fontSize = '15px';
  1393.                 input.style.fontWeight = '500';
  1394.                 input.style.padding = '0';
  1395.                 input.style.margin = '0';
  1396.                 input.style.background = 'white';
  1397.                 input.style.color = '#333';
  1398.                 input.style.outline = 'none';
  1399.                 input.style.boxShadow = 'none';
  1400.                 input.style.position = 'relative';
  1401.                 input.style.zIndex = '1';
  1402.             }
  1403.         }
  1404.     });
  1405. });
  1406. </script>
  1407. ";
  1408.         
  1409.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  1410.         
  1411.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  1412.         yield from [];
  1413.     }
  1414.     /**
  1415.      * @codeCoverageIgnore
  1416.      */
  1417.     public function getTemplateName(): string
  1418.     {
  1419.         return "home/cart.html.twig";
  1420.     }
  1421.     /**
  1422.      * @codeCoverageIgnore
  1423.      */
  1424.     public function isTraitable(): bool
  1425.     {
  1426.         return false;
  1427.     }
  1428.     /**
  1429.      * @codeCoverageIgnore
  1430.      */
  1431.     public function getDebugInfo(): array
  1432.     {
  1433.         return array (  1403 => 1152,  1249 => 1001,  1221 => 975,  1212 => 972,  1208 => 971,  1204 => 970,  1200 => 969,  1196 => 968,  1192 => 967,  1188 => 966,  1185 => 965,  1182 => 964,  1178 => 963,  1160 => 948,  1027 => 817,  1014 => 816,  314 => 125,  301 => 124,  261 => 94,  255 => 91,  248 => 87,  242 => 86,  231 => 77,  221 => 73,  215 => 69,  213 => 68,  205 => 65,  197 => 62,  190 => 58,  182 => 57,  178 => 56,  171 => 52,  161 => 47,  153 => 45,  151 => 44,  146 => 41,  141 => 40,  111 => 13,  102 => 6,  89 => 5,  66 => 3,  43 => 1,);
  1434.     }
  1435.     public function getSourceContext(): Source
  1436.     {
  1437.         return new Source("{% extends 'base_home.html.twig' %}
  1438. {% block title %}Panier | MaketOu{% endblock %}
  1439. {% block body %}
  1440.     <!-- Start Banner Area -->
  1441.     <section class=\"banner-area organic-breadcrumb\">
  1442.         <div class=\"container\">
  1443.             <div class=\"breadcrumb-banner d-flex flex-wrap align-items-center justify-content-end\">
  1444.                 <div class=\"col-first\">
  1445.                     <h1>Panier</h1>
  1446.                     <nav class=\"d-flex align-items-center\">
  1447.                         <a href=\"{{ path('ui_home') }}\">Accueil<span class=\"lnr lnr-arrow-right\"></span></a>
  1448.                         <a href=\"javascript:void(0)\">Panier</a>
  1449.                     </nav>
  1450.                 </div>
  1451.             </div>
  1452.         </div>
  1453.     </section>
  1454.     <!-- End Banner Area -->
  1455.     <!--================Cart Area =================-->
  1456.     <section class=\"cart_area\">
  1457.         <div class=\"container\">
  1458.             <div class=\"row\">
  1459.                 <div class=\"col-lg-8\">
  1460.                     <div class=\"cart_inner\">
  1461.                         <div class=\"table-responsive\">
  1462.                             <table class=\"table\">
  1463.                                 <thead>
  1464.                                     <tr>
  1465.                                         <th scope=\"col\">Produit</th>
  1466.                                         <th scope=\"col\">Prix</th>
  1467.                                         <th scope=\"col\">Quantité</th>
  1468.                                         <th scope=\"col\">Total</th>
  1469.                                         <th scope=\"col\">Action</th>
  1470.                                     </tr>
  1471.                                 </thead>
  1472.                                 <tbody>
  1473.                                     {% for item in items %}
  1474.                                     <tr>
  1475.                                         <td data-label=\"Produit\">
  1476.                                             <div class=\"cart-item\">
  1477.                                                 {% set image = (item.image is defined and item.image|length > 0) ? item.image : asset('ui/img/category/s-p1.jpg') %}
  1478.                                                 <img src=\"{{ image }}\" alt=\"{{ item.name }}\" class=\"cart-item-image\">
  1479.                                                 <div class=\"cart-item-info\">
  1480.                                                     <a href=\"{{ path('ui_product_show', { slug: item.slug }) }}\" class=\"cart-item-name\">{{ item.name }}</a>
  1481.                                                 </div>
  1482.                                             </div>
  1483.                                         </td>
  1484.                                         <td data-label=\"Prix\">
  1485.                                             <span class=\"cart-item-price\">{{ item.price|number_format(2, '.', ' ') }} HTG</span>
  1486.                                         </td>
  1487.                                         <td data-label=\"Quantité\">
  1488.                                             <div class=\"quantity-controls\">
  1489.                                                 <button class=\"quantity-btn\" onclick=\"changeQuantity({{ item.id }}, -1)\">-</button>
  1490.                                                 <input type=\"text\" value=\"{{ item.qty }}\" class=\"quantity-input\" id=\"qty-{{ item.id }}\" onchange=\"updateQuantity({{ item.id }}, this.value)\">
  1491.                                                 <button class=\"quantity-btn\" onclick=\"changeQuantity({{ item.id }}, 1)\">+</button>
  1492.                                             </div>
  1493.                                         </td>
  1494.                                         <td data-label=\"Total\">
  1495.                                             <span class=\"cart-item-total\" id=\"total-{{ item.id }}\">{{ (item.price * item.qty)|number_format(2, '.', ' ') }} HTG</span>
  1496.                                         </td>
  1497.                                         <td data-label=\"Action\">
  1498.                                             <button class=\"remove-btn\" onclick=\"removeFromCart({{ item.id }})\">Supprimer</button>
  1499.                                         </td>
  1500.                                     </tr>
  1501.                                     {% else %}
  1502.                                         <tr>
  1503.                                             <td colspan=\"5\" style=\"text-align: center; padding: 50px;\">
  1504.                                                 Votre panier est vide.
  1505.                                                 <br>
  1506.                                                 <a href=\"{{ path('ui_listing') }}\" style=\"color: #007185;\">Continuer vos achats</a>
  1507.                                             </td>
  1508.                                         </tr>
  1509.                                     {% endfor %}
  1510.                                 </tbody>
  1511.                             </table>
  1512.                         </div>
  1513.                     </div>
  1514.                 </div>
  1515.                 <div class=\"col-lg-4\">
  1516.                     <div class=\"cart-summary\">
  1517.                         <h3>Résumé de la commande</h3>
  1518.                         <div class=\"cart-subtotal\">
  1519.                             <span id=\"cart-subtotal-label\">Sous-total (<span id=\"cart-item-count\">{{ items|length }}</span> article{{ items|length > 1 ? 's' : '' }})</span>
  1520.                             <span id=\"cart-subtotal\">{{ subtotal|number_format(2, '.', ' ') }} HTG</span>
  1521.                         </div>
  1522.                         <div class=\"cart-total\">
  1523.                             <span>Total</span>
  1524.                             <span id=\"cart-total\">{{ subtotal|number_format(2, '.', ' ') }} HTG</span>
  1525.                         </div>
  1526.                         <button class=\"checkout-btn mt-3\" onclick=\"proceedToCheckout()\">Passer la commande</button>
  1527.                         <button class=\"continue-shopping\" onclick=\"window.location.href='{{ path('ui_listing') }}'\">Continuer vos achats</button>
  1528.                     </div>
  1529.                 </div>
  1530.             </div>
  1531.         </div>
  1532.     </section>
  1533.     <!--================End Cart Area =================-->
  1534.     <!-- Modal personnalisé -->
  1535.     <div id=\"customModal\" class=\"custom-modal\">
  1536.         <div class=\"custom-modal-overlay\"></div>
  1537.         <div class=\"custom-modal-content\">
  1538.             <div class=\"custom-modal-header\">
  1539.                 <h3 class=\"custom-modal-title\" id=\"modalTitle\">Titre</h3>
  1540.                 <button class=\"custom-modal-close\" onclick=\"closeCustomModal()\" aria-label=\"Fermer\">
  1541.                     <span>&times;</span>
  1542.                 </button>
  1543.             </div>
  1544.             <div class=\"custom-modal-body\" id=\"modalBody\">
  1545.                 <p id=\"modalMessage\">Message</p>
  1546.             </div>
  1547.             <div class=\"custom-modal-footer\" id=\"modalFooter\">
  1548.                 <button class=\"custom-modal-btn custom-modal-btn-primary\" id=\"modalConfirmBtn\" onclick=\"confirmModalAction()\">Confirmer</button>
  1549.                 <button class=\"custom-modal-btn custom-modal-btn-secondary\" id=\"modalCancelBtn\" onclick=\"closeCustomModal()\">Annuler</button>
  1550.             </div>
  1551.         </div>
  1552.     </div>
  1553. {% endblock %}
  1554. {% block stylesheets %}
  1555. <style>
  1556. .cart_area {
  1557.     background-color: #f8f8f8;
  1558.     padding: 20px 0;
  1559. }
  1560. .cart_inner {
  1561.     background: white;
  1562.     border-radius: 8px;
  1563.     box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  1564.     overflow: hidden;
  1565. }
  1566. .table th {
  1567.     background-color: #f3f3f3;
  1568.     border-bottom: 2px solid #ddd;
  1569.     font-weight: 600;
  1570.     color: #333;
  1571.     padding: 15px;
  1572. }
  1573. .table td {
  1574.     vertical-align: middle;
  1575.     padding: 15px;
  1576. }
  1577. .cart-item {
  1578.     display: flex;
  1579.     align-items: center;
  1580. }
  1581. .cart-item-image {
  1582.     width: 80px;
  1583.     height: 80px;
  1584.     object-fit: cover;
  1585.     border-radius: 8px;
  1586.     margin-right: 15px;
  1587. }
  1588. .cart-item-info {
  1589.     flex-grow: 1;
  1590. }
  1591. .cart-item-name {
  1592.     font-weight: 500;
  1593.     color: #007185;
  1594.     text-decoration: none;
  1595.     margin-bottom: 5px;
  1596. }
  1597. .cart-item-name:hover {
  1598.     text-decoration: underline;
  1599. }
  1600. .cart-item-price {
  1601.     color: #333;
  1602.     font-size: 18px;
  1603.     font-weight: 700;
  1604. }
  1605. .quantity-controls {
  1606.     display: flex !important;
  1607.     align-items: center !important;
  1608.     justify-content: center !important;
  1609.     border: 1px solid #ddd !important;
  1610.     border-radius: 4px !important;
  1611.     width: 120px !important;
  1612.     height: 40px !important;
  1613.     position: relative !important;
  1614.     background: white !important;
  1615.     overflow: hidden !important;
  1616. }
  1617. .quantity-controls .quantity-btn {
  1618.     background: #f8f8f8 !important;
  1619.     border: none !important;
  1620.     width: 35px !important;
  1621.     height: 100% !important;
  1622.     min-width: 35px !important;
  1623.     cursor: pointer !important;
  1624.     font-size: 18px !important;
  1625.     font-weight: 600 !important;
  1626.     color: #333 !important;
  1627.     display: flex !important;
  1628.     align-items: center !important;
  1629.     justify-content: center !important;
  1630.     padding: 0 !important;
  1631.     margin: 0 !important;
  1632.     line-height: 1 !important;
  1633.     transition: background-color 0.2s ease !important;
  1634.     position: relative !important;
  1635.     z-index: 1 !important;
  1636. }
  1637. .quantity-controls .quantity-btn:first-child {
  1638.     border-right: 1px solid #ddd !important;
  1639. }
  1640. .quantity-controls .quantity-btn:last-child {
  1641.     border-left: 1px solid #ddd !important;
  1642. }
  1643. .quantity-controls .quantity-btn:hover {
  1644.     background: #e7e7e7 !important;
  1645.     color: #000 !important;
  1646. }
  1647. .quantity-controls .quantity-btn:active {
  1648.     background: #d0d0d0 !important;
  1649. }
  1650. .quantity-controls .quantity-input {
  1651.     border: none !important;
  1652.     width: 50px !important;
  1653.     min-width: 50px !important;
  1654.     height: 100% !important;
  1655.     text-align: center !important;
  1656.     font-size: 15px !important;
  1657.     font-weight: 500 !important;
  1658.     padding: 0 !important;
  1659.     margin: 0 !important;
  1660.     background: white !important;
  1661.     color: #333 !important;
  1662.     outline: none !important;
  1663.     box-shadow: none !important;
  1664.     -moz-appearance: textfield !important;
  1665.     position: relative !important;
  1666.     z-index: 1 !important;
  1667. }
  1668. .quantity-controls .quantity-input::-webkit-outer-spin-button,
  1669. .quantity-controls .quantity-input::-webkit-inner-spin-button {
  1670.     -webkit-appearance: none !important;
  1671.     margin: 0 !important;
  1672. }
  1673. /* Surcharger les styles externes qui pourraient interférer */
  1674. .cart_inner .table tbody tr td .quantity-controls,
  1675. .cart_inner .table tbody tr td .quantity-controls .quantity-btn,
  1676. .cart_inner .table tbody tr td .quantity-controls .quantity-input {
  1677.     position: relative !important;
  1678. }
  1679. .cart_inner .table tbody tr td .quantity-controls .quantity-btn:before,
  1680. .cart_inner .table tbody tr td .quantity-controls .quantity-btn:after {
  1681.     display: none !important;
  1682.     content: none !important;
  1683. }
  1684. .cart-item-total {
  1685.     font-size: 18px;
  1686.     font-weight: 700;
  1687.     color: #333;
  1688. }
  1689. /* Responsive Styles */
  1690. @media (max-width: 991.98px) {
  1691.     .cart_area {
  1692.         padding: 15px 0;
  1693.     }
  1694.     
  1695.     .cart-summary {
  1696.         margin-top: 2rem;
  1697.     }
  1698. }
  1699. @media (max-width: 767.98px) {
  1700.     .cart_inner {
  1701.         border-radius: 0;
  1702.     }
  1703.     
  1704.     .table {
  1705.         font-size: 0.875rem;
  1706.     }
  1707.     
  1708.     .table th {
  1709.         padding: 10px 8px;
  1710.         font-size: 0.8rem;
  1711.     }
  1712.     
  1713.     .table td {
  1714.         padding: 10px 8px;
  1715.     }
  1716.     
  1717.     .cart-item {
  1718.         flex-direction: column;
  1719.         align-items: flex-start;
  1720.     }
  1721.     
  1722.     .cart-item-image {
  1723.         width: 60px;
  1724.         height: 60px;
  1725.         margin-right: 0;
  1726.         margin-bottom: 10px;
  1727.     }
  1728.     
  1729.     .cart-item-name {
  1730.         font-size: 0.9rem;
  1731.     }
  1732.     
  1733.     .cart-item-price,
  1734.     .cart-item-total {
  1735.         font-size: 1rem;
  1736.     }
  1737.     
  1738.     .quantity-controls {
  1739.         width: 110px !important;
  1740.         height: 38px !important;
  1741.     }
  1742.     
  1743.     .quantity-controls .quantity-btn {
  1744.         width: 32px !important;
  1745.         font-size: 16px !important;
  1746.     }
  1747.     
  1748.     .quantity-controls .quantity-input {
  1749.         width: 46px !important;
  1750.         font-size: 14px !important;
  1751.     }
  1752.     
  1753.     .cart-summary {
  1754.         margin-top: 1.5rem;
  1755.         padding: 1.5rem;
  1756.     }
  1757.     
  1758.     .checkout-btn,
  1759.     .continue-shopping {
  1760.         width: 100%;
  1761.         margin-bottom: 0.5rem;
  1762.     }
  1763. }
  1764. @media (max-width: 575.98px) {
  1765.     .table thead {
  1766.         display: none;
  1767.     }
  1768.     
  1769.     .table tbody tr {
  1770.         display: block;
  1771.         margin-bottom: 1rem;
  1772.         border: 1px solid #dee2e6;
  1773.         border-radius: 8px;
  1774.         padding: 1rem;
  1775.     }
  1776.     
  1777.     .table tbody td {
  1778.         display: flex;
  1779.         justify-content: space-between;
  1780.         align-items: center;
  1781.         padding: 0.5rem 0;
  1782.         border: none;
  1783.         text-align: right;
  1784.     }
  1785.     
  1786.     .table tbody td::before {
  1787.         content: attr(data-label);
  1788.         font-weight: bold;
  1789.         text-align: left;
  1790.         margin-right: 1rem;
  1791.     }
  1792.     
  1793.     .table tbody td:first-child {
  1794.         flex-direction: column;
  1795.         align-items: flex-start;
  1796.     }
  1797.     
  1798.     .cart-item-image {
  1799.         width: 100%;
  1800.         height: 200px;
  1801.         margin-bottom: 1rem;
  1802.     }
  1803.     
  1804.     .cart-item-name {
  1805.         font-size: 1rem;
  1806.         margin-bottom: 0.5rem;
  1807.     }
  1808.     
  1809.     .quantity-controls {
  1810.         width: 100% !important;
  1811.         max-width: 150px !important;
  1812.         margin: 0 auto !important;
  1813.         justify-content: center !important;
  1814.         height: 40px !important;
  1815.     }
  1816.     
  1817.     .quantity-controls .quantity-btn {
  1818.         width: 40px !important;
  1819.         font-size: 18px !important;
  1820.     }
  1821.     
  1822.     .quantity-controls .quantity-input {
  1823.         width: 60px !important;
  1824.         font-size: 16px !important;
  1825.     }
  1826.     
  1827.     .remove-btn {
  1828.         width: 100%;
  1829.         margin-top: 0.5rem;
  1830.     }
  1831. }
  1832. .remove-btn {
  1833.     background: #ff9900;
  1834.     color: white;
  1835.     border: none;
  1836.     padding: 8px 16px;
  1837.     border-radius: 4px;
  1838.     cursor: pointer;
  1839.     font-size: 12px;
  1840. }
  1841. .remove-btn:hover {
  1842.     background: #e68900;
  1843. }
  1844. .cart-summary {
  1845.     background: white;
  1846.     border-radius: 8px;
  1847.     box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  1848.     padding: 20px;
  1849.     height: fit-content;
  1850. }
  1851. .cart-subtotal {
  1852.     display: flex;
  1853.     justify-content: space-between;
  1854.     padding: 10px 0;
  1855.     border-bottom: 1px solid #ddd;
  1856.     margin-bottom: 15px;
  1857. }
  1858. .cart-total {
  1859.     font-size: 20px;
  1860.     font-weight: 700;
  1861.     color: #333;
  1862. }
  1863. .checkout-btn {
  1864.     background: #ffa200;
  1865.     color: white;
  1866.     border: none;
  1867.     padding: 12px 24px;
  1868.     border-radius: 4px;
  1869.     cursor: pointer;
  1870.     width: 100%;
  1871.     font-size: 16px;
  1872.     font-weight: 600;
  1873. }
  1874. .checkout-btn:hover {
  1875.     background: #e68900;
  1876. }
  1877. .continue-shopping {
  1878.     background: #095ad3;
  1879.     color: #ffffff;
  1880.     border: none;
  1881.     padding: 12px 24px;
  1882.     border-radius: 4px;
  1883.     cursor: pointer;
  1884.     width: 100%;
  1885.     font-size: 16px;
  1886.     font-weight: 600;
  1887.     margin-top: 10px;
  1888. }
  1889. .continue-shopping:hover {
  1890.     background: #e68900;
  1891.     color: #ffffff
  1892. }
  1893. /* ============================================
  1894.    MODAL PERSONNALISÉ
  1895.    ============================================ */
  1896. .custom-modal {
  1897.     display: none;
  1898.     position: fixed;
  1899.     top: 0;
  1900.     left: 0;
  1901.     width: 100%;
  1902.     height: 100%;
  1903.     z-index: 10000;
  1904.     opacity: 0;
  1905.     transition: opacity 0.3s ease;
  1906. }
  1907. .custom-modal.show {
  1908.     display: flex;
  1909.     align-items: center;
  1910.     justify-content: center;
  1911.     opacity: 1;
  1912. }
  1913. .custom-modal-overlay {
  1914.     position: absolute;
  1915.     top: 0;
  1916.     left: 0;
  1917.     width: 100%;
  1918.     height: 100%;
  1919.     background: rgba(0, 0, 0, 0.5);
  1920.     backdrop-filter: blur(4px);
  1921.     -webkit-backdrop-filter: blur(4px);
  1922. }
  1923. .custom-modal-content {
  1924.     position: relative;
  1925.     background: white;
  1926.     border-radius: 12px;
  1927.     box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
  1928.     max-width: 500px;
  1929.     width: 90%;
  1930.     max-height: 90vh;
  1931.     overflow: hidden;
  1932.     transform: scale(0.9) translateY(-20px);
  1933.     transition: transform 0.3s ease;
  1934.     z-index: 10001;
  1935. }
  1936. .custom-modal.show .custom-modal-content {
  1937.     transform: scale(1) translateY(0);
  1938. }
  1939. .custom-modal-header {
  1940.     display: flex;
  1941.     align-items: center;
  1942.     justify-content: space-between;
  1943.     padding: 20px 24px;
  1944.     border-bottom: 1px solid #e0e0e0;
  1945.     background: linear-gradient(135deg, #ffa200 0%, #ff9900 100%);
  1946. }
  1947. .custom-modal-header.error {
  1948.     background: linear-gradient(135deg, #dc3545 0%, #c82333 100%);
  1949. }
  1950. .custom-modal-header.success {
  1951.     background: linear-gradient(135deg, #28a745 0%, #218838 100%);
  1952. }
  1953. .custom-modal-header.warning {
  1954.     background: linear-gradient(135deg, #ffc107 0%, #e0a800 100%);
  1955. }
  1956. .custom-modal-header.info {
  1957.     background: linear-gradient(135deg, #17a2b8 0%, #138496 100%);
  1958. }
  1959. .custom-modal-title {
  1960.     margin: 0;
  1961.     font-size: 20px;
  1962.     font-weight: 600;
  1963.     color: white;
  1964.     display: flex;
  1965.     align-items: center;
  1966.     gap: 10px;
  1967. }
  1968. .custom-modal-title::before {
  1969.     content: '';
  1970.     width: 24px;
  1971.     height: 24px;
  1972.     display: inline-block;
  1973.     background-size: contain;
  1974.     background-repeat: no-repeat;
  1975.     background-position: center;
  1976. }
  1977. .custom-modal-title.success::before {
  1978.     content: '✓';
  1979.     font-size: 20px;
  1980.     font-weight: bold;
  1981. }
  1982. .custom-modal-title.error::before {
  1983.     content: '✕';
  1984.     font-size: 20px;
  1985.     font-weight: bold;
  1986. }
  1987. .custom-modal-title.warning::before {
  1988.     content: '⚠';
  1989.     font-size: 20px;
  1990.     font-weight: bold;
  1991. }
  1992. .custom-modal-title.info::before {
  1993.     content: 'ℹ';
  1994.     font-size: 20px;
  1995.     font-weight: bold;
  1996. }
  1997. .custom-modal-close {
  1998.     background: rgba(255, 255, 255, 0.15);
  1999.     border: 2px solid rgba(255, 255, 255, 0.3);
  2000.     color: white;
  2001.     font-size: 22px;
  2002.     font-weight: 300;
  2003.     line-height: 1;
  2004.     width: 36px;
  2005.     height: 36px;
  2006.     border-radius: 50%;
  2007.     cursor: pointer;
  2008.     display: flex;
  2009.     align-items: center;
  2010.     justify-content: center;
  2011.     transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  2012.     padding: 0;
  2013.     margin: 0;
  2014.     position: relative;
  2015.     overflow: hidden;
  2016. }
  2017. .custom-modal-close::before {
  2018.     content: '';
  2019.     position: absolute;
  2020.     top: 50%;
  2021.     left: 50%;
  2022.     width: 0;
  2023.     height: 0;
  2024.     border-radius: 50%;
  2025.     background: rgba(255, 255, 255, 0.2);
  2026.     transform: translate(-50%, -50%);
  2027.     transition: width 0.3s ease, height 0.3s ease;
  2028. }
  2029. .custom-modal-close:hover {
  2030.     background: rgba(255, 255, 255, 0.25);
  2031.     border-color: rgba(255, 255, 255, 0.5);
  2032.     transform: rotate(90deg) scale(1.1);
  2033.     box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  2034. }
  2035. .custom-modal-close:hover::before {
  2036.     width: 100%;
  2037.     height: 100%;
  2038. }
  2039. .custom-modal-close:active {
  2040.     transform: rotate(90deg) scale(0.95);
  2041.     background: rgba(255, 255, 255, 0.3);
  2042. }
  2043. .custom-modal-close span {
  2044.     position: relative;
  2045.     z-index: 1;
  2046.     display: block;
  2047.     line-height: 1;
  2048. }
  2049. .custom-modal-body {
  2050.     padding: 24px;
  2051.     font-size: 16px;
  2052.     line-height: 1.6;
  2053.     color: #333;
  2054.     max-height: 60vh;
  2055.     overflow-y: auto;
  2056. }
  2057. .custom-modal-body p {
  2058.     margin: 0;
  2059. }
  2060. .custom-modal-footer {
  2061.     display: flex;
  2062.     gap: 12px;
  2063.     justify-content: flex-end;
  2064.     padding: 16px 24px;
  2065.     border-top: 1px solid #e0e0e0;
  2066.     background: #f8f9fa;
  2067. }
  2068. .custom-modal-footer.single-button {
  2069.     justify-content: center;
  2070. }
  2071. .custom-modal-btn {
  2072.     padding: 10px 24px;
  2073.     border: none;
  2074.     border-radius: 6px;
  2075.     font-size: 15px;
  2076.     font-weight: 500;
  2077.     cursor: pointer;
  2078.     transition: all 0.2s ease;
  2079.     min-width: 100px;
  2080. }
  2081. .custom-modal-btn-primary {
  2082.     background: #ffa200;
  2083.     color: white;
  2084. }
  2085. .custom-modal-btn-primary:hover {
  2086.     background: #e68900;
  2087.     transform: translateY(-1px);
  2088.     box-shadow: 0 4px 8px rgba(255, 162, 0, 0.3);
  2089. }
  2090. .custom-modal-btn-secondary {
  2091.     background: #6c757d;
  2092.     color: white;
  2093. }
  2094. .custom-modal-btn-secondary:hover {
  2095.     background: #5a6268;
  2096.     transform: translateY(-1px);
  2097.     box-shadow: 0 4px 8px rgba(108, 117, 125, 0.3);
  2098. }
  2099. .custom-modal-btn-success {
  2100.     background: #28a745;
  2101.     color: white;
  2102. }
  2103. .custom-modal-btn-success:hover {
  2104.     background: #218838;
  2105.     transform: translateY(-1px);
  2106.     box-shadow: 0 4px 8px rgba(40, 167, 69, 0.3);
  2107. }
  2108. .custom-modal-btn-danger {
  2109.     background: #dc3545;
  2110.     color: white;
  2111. }
  2112. .custom-modal-btn-danger:hover {
  2113.     background: #c82333;
  2114.     transform: translateY(-1px);
  2115.     box-shadow: 0 4px 8px rgba(220, 53, 69, 0.3);
  2116. }
  2117. /* Animation pour les modals */
  2118. @keyframes modalFadeIn {
  2119.     from {
  2120.         opacity: 0;
  2121.     }
  2122.     to {
  2123.         opacity: 1;
  2124.     }
  2125. }
  2126. @keyframes modalSlideIn {
  2127.     from {
  2128.         transform: scale(0.9) translateY(-20px);
  2129.         opacity: 0;
  2130.     }
  2131.     to {
  2132.         transform: scale(1) translateY(0);
  2133.         opacity: 1;
  2134.     }
  2135. }
  2136. .custom-modal.show .custom-modal-overlay {
  2137.     animation: modalFadeIn 0.3s ease;
  2138. }
  2139. .custom-modal.show .custom-modal-content {
  2140.     animation: modalSlideIn 0.3s ease;
  2141. }
  2142. /* Responsive */
  2143. @media (max-width: 575.98px) {
  2144.     .custom-modal-content {
  2145.         width: 95%;
  2146.         margin: 20px;
  2147.     }
  2148.     
  2149.     .custom-modal-header {
  2150.         padding: 16px 20px;
  2151.     }
  2152.     
  2153.     .custom-modal-title {
  2154.         font-size: 18px;
  2155.     }
  2156.     
  2157.     .custom-modal-body {
  2158.         padding: 20px;
  2159.         font-size: 15px;
  2160.     }
  2161.     
  2162.     .custom-modal-footer {
  2163.         flex-direction: column;
  2164.         padding: 16px 20px;
  2165.     }
  2166.     
  2167.     .custom-modal-btn {
  2168.         width: 100%;
  2169.     }
  2170. }
  2171. </style>
  2172. {% endblock %}
  2173. {% block javascripts %}
  2174. <script>
  2175. // Variables globales pour le modal
  2176. let modalConfirmCallback = null;
  2177. let modalCancelCallback = null;
  2178. // Fonctions pour gérer le modal personnalisé
  2179. function showCustomModal(options) {
  2180.     const modal = document.getElementById('customModal');
  2181.     const title = document.getElementById('modalTitle');
  2182.     const message = document.getElementById('modalMessage');
  2183.     const footer = document.getElementById('modalFooter');
  2184.     const confirmBtn = document.getElementById('modalConfirmBtn');
  2185.     const cancelBtn = document.getElementById('modalCancelBtn');
  2186.     const header = modal.querySelector('.custom-modal-header');
  2187.     
  2188.     // Réinitialiser les classes
  2189.     header.className = 'custom-modal-header';
  2190.     title.className = 'custom-modal-title';
  2191.     footer.className = 'custom-modal-footer';
  2192.     
  2193.     // Définir le titre et le message
  2194.     title.textContent = options.title || 'Information';
  2195.     message.textContent = options.message || '';
  2196.     
  2197.     // Définir le type (success, error, warning, info)
  2198.     const type = options.type || 'info';
  2199.     header.classList.add(type);
  2200.     title.classList.add(type);
  2201.     
  2202.     // Configurer les boutons
  2203.     if (options.showCancel !== false) {
  2204.         cancelBtn.style.display = 'block';
  2205.         footer.classList.remove('single-button');
  2206.     } else {
  2207.         cancelBtn.style.display = 'none';
  2208.         footer.classList.add('single-button');
  2209.     }
  2210.     
  2211.     // Configurer le bouton de confirmation
  2212.     if (options.confirmText) {
  2213.         confirmBtn.textContent = options.confirmText;
  2214.     }
  2215.     
  2216.     if (options.confirmClass) {
  2217.         confirmBtn.className = 'custom-modal-btn ' + options.confirmClass;
  2218.     } else {
  2219.         confirmBtn.className = 'custom-modal-btn custom-modal-btn-primary';
  2220.     }
  2221.     
  2222.     // Stocker les callbacks
  2223.     modalConfirmCallback = options.onConfirm || null;
  2224.     modalCancelCallback = options.onCancel || null;
  2225.     
  2226.     // Afficher le modal
  2227.     modal.classList.add('show');
  2228.     document.body.style.overflow = 'hidden';
  2229. }
  2230. function closeCustomModal() {
  2231.     const modal = document.getElementById('customModal');
  2232.     const cancelCallback = modalCancelCallback; // Sauvegarder avant réinitialisation
  2233.     
  2234.     modal.classList.remove('show');
  2235.     document.body.style.overflow = '';
  2236.     
  2237.     // Réinitialiser les callbacks
  2238.     modalConfirmCallback = null;
  2239.     modalCancelCallback = null;
  2240.     
  2241.     // Appeler le callback d'annulation si présent
  2242.     if (cancelCallback) {
  2243.         cancelCallback();
  2244.     }
  2245. }
  2246. function confirmModalAction() {
  2247.     if (modalConfirmCallback) {
  2248.         modalConfirmCallback();
  2249.     }
  2250.     closeCustomModal();
  2251. }
  2252. // Fermer le modal en cliquant sur l'overlay
  2253. document.addEventListener('DOMContentLoaded', function() {
  2254.     const modal = document.getElementById('customModal');
  2255.     const overlay = modal.querySelector('.custom-modal-overlay');
  2256.     
  2257.     overlay.addEventListener('click', function() {
  2258.         closeCustomModal();
  2259.     });
  2260.     
  2261.     // Fermer avec la touche Escape
  2262.     document.addEventListener('keydown', function(e) {
  2263.         if (e.key === 'Escape' && modal.classList.contains('show')) {
  2264.             closeCustomModal();
  2265.         }
  2266.     });
  2267. });
  2268. // Fonctions utilitaires pour différents types de modals
  2269. function showAlert(title, message, type = 'info') {
  2270.     showCustomModal({
  2271.         title: title,
  2272.         message: message,
  2273.         type: type,
  2274.         showCancel: false,
  2275.         confirmText: 'OK'
  2276.     });
  2277. }
  2278. function showConfirm(title, message, onConfirm, onCancel = null, type = 'warning') {
  2279.     showCustomModal({
  2280.         title: title,
  2281.         message: message,
  2282.         type: type,
  2283.         showCancel: true,
  2284.         confirmText: 'Confirmer',
  2285.         cancelText: 'Annuler',
  2286.         onConfirm: onConfirm,
  2287.         onCancel: onCancel
  2288.     });
  2289. }
  2290. function proceedToCheckout() {
  2291.     // Vérifier qu'il y a des articles dans le panier
  2292.     if (Object.keys(cartData).length === 0) {
  2293.         showAlert('Panier vide', 'Votre panier est vide. Veuillez ajouter des articles avant de continuer.', 'warning');
  2294.         return;
  2295.     }
  2296.     
  2297.     // Rediriger vers la page de checkout
  2298.     window.location.href = '{{ path('ui_checkout') }}';
  2299. }
  2300. function changeQuantity(productId, delta) {
  2301.     const qtyInput = document.getElementById('qty-' + productId);
  2302.     if (!qtyInput) return;
  2303.     
  2304.     const currentQty = parseInt(qtyInput.value) || 0;
  2305.     const newQty = Math.max(0, currentQty + delta);
  2306.     
  2307.     updateQuantity(productId, newQty);
  2308. }
  2309. let cartData = {}; // Stocker les données du panier côté client
  2310. // Initialiser les données du panier
  2311. {% for item in items %}
  2312.     {% set image = (item.images is defined and item.images|length > 0) ? item.images[0] : asset('ui/img/category/s-p1.jpg') %}
  2313. cartData[{{ item.id }}] = {
  2314.     id: {{ item.id }},
  2315.     name: '{{ item.name }}',
  2316.     price: {{ item.price }},
  2317.     qty: {{ item.qty }},
  2318.     image: '{{ image }}',
  2319.     slug: '{{ item.slug }}'
  2320. };
  2321. {% endfor %}
  2322. function updateQuantity(productId, newQty) {
  2323.     const item = cartData[productId];
  2324.     
  2325.     if (!item) {
  2326.         console.error('Produit non trouvé:', productId);
  2327.         return;
  2328.     }
  2329.     
  2330.     // Validation de la quantité
  2331.     newQty = Math.max(0, parseInt(newQty) || 0);
  2332.     
  2333.     if (newQty === 0) {
  2334.         removeFromCart(productId);
  2335.         return;
  2336.     }
  2337.     
  2338.     if (newQty > 99) {
  2339.         showAlert('Quantité maximale', 'La quantité maximale est de 99 articles.', 'warning');
  2340.         return;
  2341.     }
  2342.     
  2343.     // Mettre à jour l'interface immédiatement (optimistic update)
  2344.     updateCartDisplay(productId, newQty);
  2345.     
  2346.     // Envoyer la requête au serveur
  2347.     fetch('{{ path(\"ui_cart_update\") }}', {
  2348.         method: 'POST',
  2349.         headers: { 
  2350.             'Content-Type': 'application/x-www-form-urlencoded',
  2351.             'X-Requested-With': 'XMLHttpRequest'
  2352.         },
  2353.         body: 'productId=' + productId + '&qty=' + newQty
  2354.     })
  2355.     .then(response => response.json())
  2356.     .then(data => {
  2357.         if (data.ok) {
  2358.             // Les données serveur confirment la mise à jour
  2359.             // cartData est déjà à jour depuis l'optimistic update
  2360.             console.log('Panier mis à jour avec succès');
  2361.         } else {
  2362.             // En cas d'erreur, restaurer la valeur précédente
  2363.             const oldQty = item.qty;
  2364.             updateCartDisplay(productId, oldQty);
  2365.             showAlert('Erreur', data.message || 'Erreur lors de la mise à jour du panier.', 'error');
  2366.         }
  2367.     })
  2368.     .catch(error => {
  2369.         console.error('Erreur:', error);
  2370.         // Restaurer la valeur précédente en cas d'erreur réseau
  2371.         const oldQty = item.qty;
  2372.         updateCartDisplay(productId, oldQty);
  2373.         showAlert('Erreur de connexion', 'Une erreur de connexion est survenue. Veuillez réessayer.', 'error');
  2374.     });
  2375. }
  2376. function updateCartDisplay(productId, qty) {
  2377.     const item = cartData[productId];
  2378.     if (!item) return;
  2379.     
  2380.     // Mettre à jour les données locales
  2381.     item.qty = qty;
  2382.     
  2383.     // Mettre à jour la quantité dans l'input
  2384.     const qtyInput = document.getElementById('qty-' + productId);
  2385.     if (qtyInput) {
  2386.         qtyInput.value = qty;
  2387.     }
  2388.     
  2389.     // Mettre à jour le total du produit
  2390.     const totalElement = document.getElementById('total-' + productId);
  2391.     if (totalElement) {
  2392.         const itemTotal = (item.price * qty);
  2393.         totalElement.textContent = itemTotal.toLocaleString('fr-FR', {
  2394.             minimumFractionDigits: 2,
  2395.             maximumFractionDigits: 2
  2396.         }) + ' HTG';
  2397.     }
  2398.     
  2399.     // Mettre à jour les totaux généraux
  2400.     updateCartSummary();
  2401. }
  2402. function updateCartTotals(data) {
  2403.     // Mettre à jour le sous-total depuis les données serveur
  2404.     const subtotalElement = document.getElementById('cart-subtotal');
  2405.     const totalElement = document.getElementById('cart-total');
  2406.     
  2407.     if (subtotalElement) {
  2408.         subtotalElement.textContent = parseFloat(data.subtotal).toLocaleString('fr-FR', {
  2409.             minimumFractionDigits: 2,
  2410.             maximumFractionDigits: 2
  2411.         }) + ' HTG';
  2412.     }
  2413.     
  2414.     if (totalElement) {
  2415.         totalElement.textContent = parseFloat(data.subtotal).toLocaleString('fr-FR', {
  2416.             minimumFractionDigits: 2,
  2417.             maximumFractionDigits: 2
  2418.         }) + ' HTG';
  2419.     }
  2420.     
  2421.     // Mettre à jour le compteur d'articles
  2422.     const itemCountElement = document.querySelector('.cart-subtotal span');
  2423.     if (itemCountElement) {
  2424.         const totalItems = Object.values(cartData).reduce((sum, item) => sum + item.qty, 0);
  2425.         const itemText = totalItems + ' article' + (totalItems > 1 ? 's' : '');
  2426.         itemCountElement.textContent = itemText;
  2427.     }
  2428. }
  2429. function updateCartSummary() {
  2430.     // Calculer les totaux côté client depuis cartData
  2431.     let subtotal = 0;
  2432.     let totalItems = 0;
  2433.     
  2434.     Object.values(cartData).forEach(item => {
  2435.         subtotal += item.price * item.qty;
  2436.         totalItems += item.qty;
  2437.     });
  2438.     
  2439.     // Mettre à jour l'affichage du sous-total
  2440.     const subtotalElement = document.getElementById('cart-subtotal');
  2441.     if (subtotalElement) {
  2442.         subtotalElement.textContent = subtotal.toLocaleString('fr-FR', {
  2443.             minimumFractionDigits: 2,
  2444.             maximumFractionDigits: 2
  2445.         }) + ' HTG';
  2446.     }
  2447.     
  2448.     // Mettre à jour l'affichage du total
  2449.     const totalElement = document.getElementById('cart-total');
  2450.     if (totalElement) {
  2451.         totalElement.textContent = subtotal.toLocaleString('fr-FR', {
  2452.             minimumFractionDigits: 2,
  2453.             maximumFractionDigits: 2
  2454.         }) + ' HTG';
  2455.     }
  2456.     
  2457.     // Mettre à jour le compteur d'articles
  2458.     const itemCountElement = document.getElementById('cart-item-count');
  2459.     if (itemCountElement) {
  2460.         itemCountElement.textContent = totalItems;
  2461.     }
  2462.     
  2463.     // Mettre à jour le label du sous-total
  2464.     const subtotalLabel = document.getElementById('cart-subtotal-label');
  2465.     if (subtotalLabel) {
  2466.         const itemText = totalItems + ' article' + (totalItems > 1 ? 's' : '');
  2467.         subtotalLabel.innerHTML = 'Sous-total (<span id=\"cart-item-count\">' + totalItems + '</span> ' + (totalItems > 1 ? 'articles' : 'article') + ')';
  2468.     }
  2469. }
  2470. function removeFromCart(productId) {
  2471.     const item = cartData[productId];
  2472.     const itemName = item ? item.name : 'cet article';
  2473.     
  2474.     showConfirm(
  2475.         'Supprimer l\\'article',
  2476.         `Êtes-vous sûr de vouloir supprimer \"\${itemName}\" de votre panier ?`,
  2477.         function() {
  2478.             // Mettre à jour l'interface immédiatement
  2479.             const row = document.querySelector(`tr:has(#qty-\${productId})`);
  2480.             if (row) {
  2481.                 row.style.opacity = '0.5';
  2482.                 row.style.pointerEvents = 'none';
  2483.             }
  2484.             
  2485.             performRemoveFromCart(productId, row);
  2486.         },
  2487.         null,
  2488.         'warning'
  2489.     );
  2490. }
  2491. function performRemoveFromCart(productId, row) {
  2492.     
  2493.     fetch('{{ path(\"ui_cart_remove\") }}', {
  2494.         method: 'POST',
  2495.         headers: { 
  2496.             'Content-Type': 'application/x-www-form-urlencoded',
  2497.             'X-Requested-With': 'XMLHttpRequest'
  2498.         },
  2499.         body: 'productId=' + productId
  2500.     })
  2501.     .then(response => response.json())
  2502.     .then(data => {
  2503.         if (data.ok) {
  2504.             // Supprimer des données locales
  2505.             delete cartData[productId];
  2506.             
  2507.             // Supprimer la ligne du DOM
  2508.             const row = document.querySelector(`tr:has(#qty-\${productId})`);
  2509.             if (row) {
  2510.                 row.remove();
  2511.             }
  2512.             
  2513.             // Mettre à jour les totaux
  2514.             updateCartTotals(data);
  2515.             
  2516.             // Mettre à jour le résumé du panier
  2517.             updateCartSummary();
  2518.             
  2519.             // Afficher un message de succès
  2520.             showAlert('Article supprimé', 'L\\'article a été supprimé de votre panier avec succès.', 'success');
  2521.             
  2522.             // Vérifier si le panier est vide
  2523.             if (Object.keys(cartData).length === 0) {
  2524.                 setTimeout(function() {
  2525.                     location.reload();
  2526.                 }, 1500);
  2527.             }
  2528.         } else {
  2529.             // Restaurer l'affichage en cas d'erreur
  2530.             if (row) {
  2531.                 row.style.opacity = '1';
  2532.                 row.style.pointerEvents = 'auto';
  2533.             }
  2534.             showAlert('Erreur', data.message || 'Erreur lors de la suppression de l\\'article.', 'error');
  2535.         }
  2536.     })
  2537.     .catch(error => {
  2538.         console.error('Erreur:', error);
  2539.         // Restaurer l'affichage en cas d'erreur réseau
  2540.         if (row) {
  2541.             row.style.opacity = '1';
  2542.             row.style.pointerEvents = 'auto';
  2543.         }
  2544.         showAlert('Erreur de connexion', 'Une erreur de connexion est survenue. Veuillez réessayer.', 'error');
  2545.     });
  2546. }
  2547. // Script pour forcer l'application des styles des boutons de quantité
  2548. document.addEventListener('DOMContentLoaded', function() {
  2549.     const quantityControls = document.querySelectorAll('.quantity-controls');
  2550.     quantityControls.forEach(function(control) {
  2551.         if (control) {
  2552.             // Forcer les styles sur le conteneur
  2553.             control.style.display = 'flex';
  2554.             control.style.alignItems = 'center';
  2555.             control.style.justifyContent = 'center';
  2556.             control.style.border = '1px solid #ddd';
  2557.             control.style.borderRadius = '4px';
  2558.             control.style.width = '120px';
  2559.             control.style.height = '40px';
  2560.             control.style.position = 'relative';
  2561.             control.style.background = 'white';
  2562.             control.style.overflow = 'hidden';
  2563.             
  2564.             // Forcer les styles sur les boutons
  2565.             const buttons = control.querySelectorAll('.quantity-btn');
  2566.             buttons.forEach(function(btn, index) {
  2567.                 btn.style.background = '#f8f8f8';
  2568.                 btn.style.border = 'none';
  2569.                 btn.style.width = '35px';
  2570.                 btn.style.height = '100%';
  2571.                 btn.style.cursor = 'pointer';
  2572.                 btn.style.fontSize = '18px';
  2573.                 btn.style.fontWeight = '600';
  2574.                 btn.style.color = '#333';
  2575.                 btn.style.display = 'flex';
  2576.                 btn.style.alignItems = 'center';
  2577.                 btn.style.justifyContent = 'center';
  2578.                 btn.style.padding = '0';
  2579.                 btn.style.margin = '0';
  2580.                 btn.style.lineHeight = '1';
  2581.                 btn.style.position = 'relative';
  2582.                 btn.style.zIndex = '1';
  2583.                 
  2584.                 // Ajouter les bordures entre les boutons
  2585.                 if (index === 0) {
  2586.                     btn.style.borderRight = '1px solid #ddd';
  2587.                 } else if (index === buttons.length - 1) {
  2588.                     btn.style.borderLeft = '1px solid #ddd';
  2589.                 }
  2590.             });
  2591.             
  2592.             // Forcer les styles sur l'input
  2593.             const input = control.querySelector('.quantity-input');
  2594.             if (input) {
  2595.                 input.style.border = 'none';
  2596.                 input.style.width = '50px';
  2597.                 input.style.height = '100%';
  2598.                 input.style.textAlign = 'center';
  2599.                 input.style.fontSize = '15px';
  2600.                 input.style.fontWeight = '500';
  2601.                 input.style.padding = '0';
  2602.                 input.style.margin = '0';
  2603.                 input.style.background = 'white';
  2604.                 input.style.color = '#333';
  2605.                 input.style.outline = 'none';
  2606.                 input.style.boxShadow = 'none';
  2607.                 input.style.position = 'relative';
  2608.                 input.style.zIndex = '1';
  2609.             }
  2610.         }
  2611.     });
  2612. });
  2613. </script>
  2614. {% endblock %}""home/cart.html.twig""/home/u540977899/domains/maketou-ht.com/public_html/templates/home/cart.html.twig");
  2615.     }
  2616. }