<?php
use Twig\Environment;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Extension\CoreExtension;
use Twig\Extension\SandboxExtension;
use Twig\Markup;
use Twig\Sandbox\SecurityError;
use Twig\Sandbox\SecurityNotAllowedTagError;
use Twig\Sandbox\SecurityNotAllowedFilterError;
use Twig\Sandbox\SecurityNotAllowedFunctionError;
use Twig\Source;
use Twig\Template;
use Twig\TemplateWrapper;
/* home/listing.html.twig */
class __TwigTemplate_aa414e651db26efa98eb1f11d53e7f48 extends Template
{
private Source $source;
/**
* @var array<string, Template>
*/
private array $macros = [];
public function __construct(Environment $env)
{
parent::__construct($env);
$this->source = $this->getSourceContext();
$this->blocks = [
'body' => [$this, 'block_body'],
'title' => [$this, 'block_title'],
'stylesheets' => [$this, 'block_stylesheets'],
'javascripts' => [$this, 'block_javascripts'],
];
}
protected function doGetParent(array $context): bool|string|Template|TemplateWrapper
{
// line 1
return "base_home.html.twig";
}
protected function doDisplay(array $context, array $blocks = []): iterable
{
$macros = $this->macros;
$__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
$__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "template", "home/listing.html.twig"));
$__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
$__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "template", "home/listing.html.twig"));
$this->parent = $this->load("base_home.html.twig", 1);
yield from $this->parent->unwrap()->yield($context, array_merge($this->blocks, $blocks));
$__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
$__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
}
// line 3
/**
* @return iterable<null|scalar|\Stringable>
*/
public function block_body(array $context, array $blocks = []): iterable
{
$macros = $this->macros;
$__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
$__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "body"));
$__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
$__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "body"));
// line 4
yield "
\t<!-- Start Banner Area -->
\t<section class=\"banner-area organic-breadcrumb\">
\t\t<div class=\"container\">
\t\t\t<div class=\"breadcrumb-banner d-flex flex-wrap align-items-center justify-content-end\">
\t\t\t\t<div class=\"col-first\">
\t\t\t\t\t<h1>Page de listage de produit</h1>
\t\t\t\t\t<nav class=\"d-flex align-items-center\">
\t\t\t\t\t\t<a href=\"";
// line 12
yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("ui_home");
yield "\">Accueil<span class=\"lnr lnr-arrow-right\"></span>
\t\t\t\t\t\t</a>
\t\t\t\t\t\t<a href=\"javascript:void(0);\">Liste des produits</a>
\t\t\t\t\t</nav>
\t\t\t\t</div>
\t\t\t</div>
\t\t</div>
\t</section>
\t<!-- End Banner Area -->
\t<div class=\"container\">
\t\t<div class=\"row\">
\t\t\t<div class=\"col-xl-3 col-lg-4 col-md-5\">
\t\t\t\t<!-- Bouton toggle sidebar mobile -->
\t\t\t\t<button class=\"btn btn-outline-primary w-100 d-md-none mb-3 listing-sidebar-toggle\" type=\"button\" data-bs-toggle=\"collapse\" data-bs-target=\"#listingSidebarCollapse\" aria-expanded=\"false\" aria-controls=\"listingSidebarCollapse\">
\t\t\t\t\t<i class=\"lnr lnr-menu me-2\"></i>Filtres et catégories
\t\t\t\t\t<i class=\"lnr lnr-chevron-down ms-2 toggle-icon\"></i>
\t\t\t\t</button>
\t\t\t\t<!-- Sidebar avec collapse -->
\t\t\t\t<div class=\"collapse d-md-block\" id=\"listingSidebarCollapse\">
\t\t\t\t\t<div class=\"sidebar-categories\">
\t\t\t\t\t\t<div class=\"head\">Catégories</div>
\t\t\t\t\t\t<ul class=\"main-categories\">
\t\t\t\t\t\t\t<li class=\"main-nav-list\">
\t\t\t\t\t\t\t\t<a href=\"";
// line 37
yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("ui_listing");
yield "\" class=\"category-link ";
if ((($tmp = !($context["currentCategory"] ?? null)) && $tmp instanceof Markup ? (string) $tmp : $tmp)) {
yield "active";
}
yield "\">
\t\t\t\t\t\t\t\t\t<span class=\"lnr lnr-tag\"></span>Toutes les catégories
\t\t\t\t\t\t\t\t\t<span class=\"number\">(";
// line 39
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(($context["totalProducts"] ?? null), "html", null, true);
yield ")</span>
\t\t\t\t\t\t\t\t</a>
\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t";
// line 42
$context['_parent'] = $context;
$context['_seq'] = CoreExtension::ensureTraversable(($context["categories"] ?? null));
$context['_iterated'] = false;
foreach ($context['_seq'] as $context["_key"] => $context["category"]) {
// line 43
yield "\t\t\t\t\t\t\t\t<li class=\"main-nav-list\">
\t\t\t\t\t\t\t\t\t<a href=\"";
// line 44
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("ui_listing", ["category" => CoreExtension::getAttribute($this->env, $this->source, $context["category"], "slug", [], "any", false, false, false, 44)]), "html", null, true);
yield "\" class=\"category-link ";
if ((($context["currentCategory"] ?? null) == CoreExtension::getAttribute($this->env, $this->source, $context["category"], "slug", [], "any", false, false, false, 44))) {
yield "active";
}
yield "\" data-category=\"";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["category"], "slug", [], "any", false, false, false, 44), "html", null, true);
yield "\">
\t\t\t\t\t\t\t\t\t\t<span class=\"lnr lnr-tag\"></span>
\t\t\t\t\t\t\t\t\t\t";
// line 46
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["category"], "name", [], "any", false, false, false, 46), "html", null, true);
yield "
\t\t\t\t\t\t\t\t\t\t<span class=\"number\">(";
// line 47
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::length($this->env->getCharset(), CoreExtension::getAttribute($this->env, $this->source, $context["category"], "products", [], "any", false, false, false, 47)), "html", null, true);
yield ")</span>
\t\t\t\t\t\t\t\t\t</a>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t";
$context['_iterated'] = true;
}
// line 50
if (!$context['_iterated']) {
// line 51
yield "\t\t\t\t\t\t\t\t<li class=\"main-nav-list\">
\t\t\t\t\t\t\t\t\t<span>Aucune catégorie</span>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t";
}
$_parent = $context['_parent'];
unset($context['_seq'], $context['_key'], $context['category'], $context['_parent'], $context['_iterated']);
$context = array_intersect_key($context, $_parent) + $_parent;
// line 55
yield "\t\t\t\t\t\t</ul>
\t\t\t\t\t</div>
\t\t\t\t\t<div class=\"sidebar-filter mt-50\" id=\"brandsFilter\">
\t\t\t\t\t\t<div class=\"top-filter-head\">Filtres</div>
\t\t\t\t\t\t<div class=\"common-filter\">
\t\t\t\t\t\t\t<div class=\"head\">Marques</div>
\t\t\t\t\t\t\t<ul class=\"brand-list\" id=\"brandList\">
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"all-brands\" name=\"brand\" checked>
\t\t\t\t\t\t\t\t\t<label for=\"all-brands\">Toutes les marques</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t";
// line 66
$context['_parent'] = $context;
$context['_seq'] = CoreExtension::ensureTraversable(($context["brands"] ?? null));
foreach ($context['_seq'] as $context["_key"] => $context["brand"]) {
// line 67
yield "\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"brand-";
// line 68
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["brand"], "id", [], "any", false, false, false, 68), "html", null, true);
yield "\" name=\"brand\" value=\"";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["brand"], "slug", [], "any", false, false, false, 68), "html", null, true);
yield "\">
\t\t\t\t\t\t\t\t\t\t<label for=\"brand-";
// line 69
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["brand"], "id", [], "any", false, false, false, 69), "html", null, true);
yield "\">";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["brand"], "name", [], "any", false, false, false, 69), "html", null, true);
yield "<span>(";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["brand"], "getActiveProductsCount", [], "method", false, false, false, 69), "html", null, true);
yield ")</span>
\t\t\t\t\t\t\t\t\t\t</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t";
}
$_parent = $context['_parent'];
unset($context['_seq'], $context['_key'], $context['brand'], $context['_parent']);
$context = array_intersect_key($context, $_parent) + $_parent;
// line 73
yield "\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<!-- Filtres avancés -->
\t\t\t\t\t\t<div class=\"common-filter\">
\t\t\t\t\t\t\t<div class=\"head\">Boutiques</div>
\t\t\t\t\t\t\t<div id=\"shopsFilter\">
\t\t\t\t\t\t\t\t<form action=\"#\">
\t\t\t\t\t\t\t\t\t<ul
\t\t\t\t\t\t\t\t\t\tclass=\"shop-list\" id=\"shopList\"><!-- Les boutiques seront chargées dynamiquement -->
\t\t\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t\t\t</form>
\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<div class=\"common-filter\">
\t\t\t\t\t\t\t<div class=\"head\">Condition (";
// line 88
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::length($this->env->getCharset(), ($context["conditions"] ?? null)), "html", null, true);
yield ")</div>
\t\t\t\t\t\t\t<ul class=\"condition-list\" id=\"conditionList\">
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"all-conditions\" name=\"condition\" checked>
\t\t\t\t\t\t\t\t\t<label for=\"all-conditions\">Toutes les conditions</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t";
// line 94
$context['_parent'] = $context;
$context['_seq'] = CoreExtension::ensureTraversable(($context["conditions"] ?? null));
$context['_iterated'] = false;
foreach ($context['_seq'] as $context["_key"] => $context["condition"]) {
// line 95
yield "\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"condition-";
// line 96
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["condition"], "id", [], "any", false, false, false, 96), "html", null, true);
yield "\" name=\"condition\" value=\"";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["condition"], "slug", [], "any", false, false, false, 96), "html", null, true);
yield "\">
\t\t\t\t\t\t\t\t\t\t<label for=\"condition-";
// line 97
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["condition"], "id", [], "any", false, false, false, 97), "html", null, true);
yield "\">";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["condition"], "name", [], "any", false, false, false, 97), "html", null, true);
yield "<span>(";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["condition"], "getActiveProductsCount", [], "method", false, false, false, 97), "html", null, true);
yield ")</span>
\t\t\t\t\t\t\t\t\t\t</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t";
$context['_iterated'] = true;
}
// line 100
if (!$context['_iterated']) {
// line 101
yield "\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<span class=\"text-muted\">Aucune condition disponible</span>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t";
}
$_parent = $context['_parent'];
unset($context['_seq'], $context['_key'], $context['condition'], $context['_parent'], $context['_iterated']);
$context = array_intersect_key($context, $_parent) + $_parent;
// line 105
yield "\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<div class=\"common-filter\">
\t\t\t\t\t\t\t<div class=\"head\">Produits vedettes</div>
\t\t\t\t\t\t\t<form action=\"#\">
\t\t\t\t\t\t\t\t<ul>
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"featured-all\" name=\"featured\" checked>
\t\t\t\t\t\t\t\t\t\t<label for=\"featured-all\">Tous les produits</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"featured-only\" name=\"featured\" value=\"true\">
\t\t\t\t\t\t\t\t\t\t<label for=\"featured-only\">Produits vedettes uniquement</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t\t</form>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<div class=\"common-filter\">
\t\t\t\t\t\t\t<div class=\"head\">Type de produit</div>
\t\t\t\t\t\t\t<form action=\"#\">
\t\t\t\t\t\t\t\t<ul>
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"digital-all\" name=\"digital\" checked>
\t\t\t\t\t\t\t\t\t\t<label for=\"digital-all\">Tous les types</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"digital-physical\" name=\"digital\" value=\"false\">
\t\t\t\t\t\t\t\t\t\t<label for=\"digital-physical\">Produits physiques</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"digital-digital\" name=\"digital\" value=\"true\">
\t\t\t\t\t\t\t\t\t\t<label for=\"digital-digital\">Produits numériques</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t\t</form>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<div class=\"common-filter\">
\t\t\t\t\t\t\t<div class=\"head\">Disponibilité</div>
\t\t\t\t\t\t\t<form action=\"#\">
\t\t\t\t\t\t\t\t<ul>
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"availability-all\" name=\"availability\" checked>
\t\t\t\t\t\t\t\t\t\t<label for=\"availability-all\">Tous</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"availability-in-stock\" name=\"availability\" value=\"in_stock\">
\t\t\t\t\t\t\t\t\t\t<label for=\"availability-in-stock\">En stock</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"availability-low-stock\" name=\"availability\" value=\"low_stock\">
\t\t\t\t\t\t\t\t\t\t<label for=\"availability-low-stock\">Stock faible</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"availability-out-of-stock\" name=\"availability\" value=\"out_of_stock\">
\t\t\t\t\t\t\t\t\t\t<label for=\"availability-out-of-stock\">Rupture de stock</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t\t</form>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<div class=\"common-filter\">
\t\t\t\t\t\t\t<div class=\"head\">Note minimale</div>
\t\t\t\t\t\t\t<form action=\"#\">
\t\t\t\t\t\t\t\t<ul>
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"rating-all\" name=\"rating\" checked>
\t\t\t\t\t\t\t\t\t\t<label for=\"rating-all\">Toutes les notes</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"rating-4\" name=\"rating\" value=\"4\">
\t\t\t\t\t\t\t\t\t\t<label for=\"rating-4\">4 étoiles et plus</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"rating-3\" name=\"rating\" value=\"3\">
\t\t\t\t\t\t\t\t\t\t<label for=\"rating-3\">3 étoiles et plus</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"rating-2\" name=\"rating\" value=\"2\">
\t\t\t\t\t\t\t\t\t\t<label for=\"rating-2\">2 étoiles et plus</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t\t</form>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<div class=\"common-filter\">
\t\t\t\t\t\t\t<div class=\"head\">Poids</div>
\t\t\t\t\t\t\t<div class=\"weight-range-area\">
\t\t\t\t\t\t\t\t<div class=\"weight-inputs d-flex\">
\t\t\t\t\t\t\t\t\t<div class=\"weight-input\">
\t\t\t\t\t\t\t\t\t\t<label>Min (kg):</label>
\t\t\t\t\t\t\t\t\t\t<input type=\"number\" id=\"weightMin\" placeholder=\"0\" step=\"0.1\" min=\"0\">
\t\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t\t\t<div class=\"weight-input\">
\t\t\t\t\t\t\t\t\t\t<label>Max (kg):</label>
\t\t\t\t\t\t\t\t\t\t<input type=\"number\" id=\"weightMax\" placeholder=\"100\" step=\"0.1\" min=\"0\">
\t\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<div class=\"common-filter\">
\t\t\t\t\t\t\t<div class=\"head\">Couleur</div>
\t\t\t\t\t\t\t<div id=\"colorsFilter\">
\t\t\t\t\t\t\t\t<form action=\"#\">
\t\t\t\t\t\t\t\t\t<ul
\t\t\t\t\t\t\t\t\t\tclass=\"color-list\" id=\"colorList\"><!-- Les couleurs seront chargées dynamiquement -->
\t\t\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t\t\t</form>
\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<div class=\"common-filter\">
\t\t\t\t\t\t\t<div class=\"head\">Taille</div>
\t\t\t\t\t\t\t<div id=\"sizesFilter\">
\t\t\t\t\t\t\t\t<form action=\"#\">
\t\t\t\t\t\t\t\t\t<ul
\t\t\t\t\t\t\t\t\t\tclass=\"size-list\" id=\"sizeList\"><!-- Les tailles seront chargées dynamiquement -->
\t\t\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t\t\t</form>
\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<div class=\"common-filter\">
\t\t\t\t\t\t\t<div class=\"head\">Matériau</div>
\t\t\t\t\t\t\t<div id=\"materialsFilter\">
\t\t\t\t\t\t\t\t<form action=\"#\">
\t\t\t\t\t\t\t\t\t<ul
\t\t\t\t\t\t\t\t\t\tclass=\"material-list\" id=\"materialList\"><!-- Les matériaux seront chargés dynamiquement -->
\t\t\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t\t\t</form>
\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<div class=\"common-filter\">
\t\t\t\t\t\t\t<div class=\"head\">Prix</div>
\t\t\t\t\t\t\t<div class=\"price-range-area\">
\t\t\t\t\t\t\t\t<div id=\"price-range\"></div>
\t\t\t\t\t\t\t\t<div class=\"value-wrapper d-flex\">
\t\t\t\t\t\t\t\t\t<div class=\"price\">Prix:</div>
\t\t\t\t\t\t\t\t\t<span>\$</span>
\t\t\t\t\t\t\t\t\t<div id=\"lower-value\"></div>
\t\t\t\t\t\t\t\t\t<div class=\"to\">to</div>
\t\t\t\t\t\t\t\t\t<span>\$</span>
\t\t\t\t\t\t\t\t\t<div id=\"upper-value\"></div>
\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t</div>
\t\t\t\t\t</div>
\t\t\t\t</div>
\t\t\t\t<!-- Fin du collapse sidebar -->
\t\t\t</div>
\t\t\t<div class=\"col-xl-9 col-lg-8 col-md-7\">
\t\t\t<!-- Barre de tri et bouton de filtres -->
\t\t\t<div class=\"row mb-4\">
\t\t\t\t<div
\t\t\t\t\tclass=\"col-md-6 mb-3 mb-md-0\">
\t\t\t\t\t<!-- Bouton pour ouvrir le modal de filtres -->
\t\t\t\t\t<button type=\"button\" class=\"btn btn-lg d-flex align-items-center\" data-bs-toggle=\"modal\" data-bs-target=\"#filtersModal\" style=\"background: transparent; border: none; padding: 10px 16px; font-weight: 600; transition: all 0.3s ease;\">
\t\t\t\t\t\t<div class=\"filter-icon-circle d-flex align-items-center justify-content-center\" style=\"width: 42px; height: 42px; background: linear-gradient(135deg, #ffa200 0%, #ff8c00 100%); border-radius: 50%; border: 2px solid #ffa200; flex-shrink: 0; margin-right: 10px; box-shadow: 0 2px 8px rgba(255, 162, 0, 0.3);\">
\t\t\t\t\t\t\t<i class=\"lnr lnr-filter\" style=\"font-size: 1.3rem; color: white; font-weight: bold;\"></i>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<span style=\"font-size: 1.1rem; font-weight: 600; color: #333;\">Filtres</span>
\t\t\t\t\t\t<span class=\"badge bg-warning text-dark ms-2\" id=\"activeFiltersCount\" style=\"display: none; font-size: 0.85rem; padding: 4px 10px; border-radius: 12px; font-weight: 600;\">0</span>
\t\t\t\t\t</button>
\t\t\t\t</div>
\t\t\t\t<div class=\"col-md-6\">
\t\t\t\t\t<select class=\"form-select\" id=\"sortSelect\" onchange=\"applySorting()\">
\t\t\t\t\t\t<option value=\"newest\" ";
// line 276
if ((($context["currentSort"] ?? null) == "newest")) {
yield " selected ";
}
yield ">Plus récents</option>
\t\t\t\t\t\t<option value=\"price_asc\" ";
// line 277
if ((($context["currentSort"] ?? null) == "price_asc")) {
yield " selected ";
}
yield ">Prix croissant</option>
\t\t\t\t\t\t<option value=\"price_desc\" ";
// line 278
if ((($context["currentSort"] ?? null) == "price_desc")) {
yield " selected ";
}
yield ">Prix décroissant</option>
\t\t\t\t\t\t<option value=\"name_asc\" ";
// line 279
if ((($context["currentSort"] ?? null) == "name_asc")) {
yield " selected ";
}
yield ">Nom A-Z</option>
\t\t\t\t\t\t<option value=\"name_desc\" ";
// line 280
if ((($context["currentSort"] ?? null) == "name_desc")) {
yield " selected ";
}
yield ">Nom Z-A</option>
\t\t\t\t\t\t<option value=\"popular\" ";
// line 281
if ((($context["currentSort"] ?? null) == "popular")) {
yield " selected ";
}
yield ">Plus populaires</option>
\t\t\t\t\t</select>
\t\t\t\t</div>
\t\t\t</div>
\t\t\t<!-- Start Best Seller -->
\t\t\t<section class=\"lattest-product-area pb-40 category-list\">
\t\t\t\t<div class=\"row\" id=\"productsContainer\">
\t\t\t\t\t";
// line 289
$context['_parent'] = $context;
$context['_seq'] = CoreExtension::ensureTraversable(($context["products"] ?? null));
$context['_iterated'] = false;
foreach ($context['_seq'] as $context["_key"] => $context["product"]) {
// line 290
yield "\t\t\t\t\t\t<div class=\"col-lg-4 col-md-6\">
\t\t\t\t\t\t\t<div class=\"single-product\">
\t\t\t\t\t\t\t\t<div class=\"product-image-container mb-2\" onmouseenter=\"showImageNav(";
// line 292
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "id", [], "any", false, false, false, 292), "html", null, true);
yield ")\" onmouseleave=\"hideImageNav(";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "id", [], "any", false, false, false, 292), "html", null, true);
yield ")\">
\t\t\t\t\t\t\t\t\t<a href=\"";
// line 293
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["product"], "slug", [], "any", false, false, false, 293)]), "html", null, true);
yield "\">
\t\t\t\t\t\t\t\t\t\t";
// line 294
$context["allImages"] = ((CoreExtension::getAttribute($this->env, $this->source, $context["product"], "images", [], "any", true, true, false, 294)) ? (Twig\Extension\CoreExtension::default(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "images", [], "any", false, false, false, 294), [])) : ([]));
// line 295
yield "\t\t\t\t\t\t\t\t\t\t";
if (CoreExtension::getAttribute($this->env, $this->source, $context["product"], "variants", [], "any", true, true, false, 295)) {
// line 296
yield "\t\t\t\t\t\t\t\t\t\t\t";
$context['_parent'] = $context;
$context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "variants", [], "any", false, false, false, 296));
foreach ($context['_seq'] as $context["_key"] => $context["variant"]) {
// line 297
yield "\t\t\t\t\t\t\t\t\t\t\t\t";
if ((CoreExtension::getAttribute($this->env, $this->source, $context["variant"], "isActive", [], "any", false, false, false, 297) && CoreExtension::getAttribute($this->env, $this->source, $context["variant"], "images", [], "any", true, true, false, 297))) {
// line 298
yield "\t\t\t\t\t\t\t\t\t\t\t\t\t";
$context['_parent'] = $context;
$context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env, $this->source, $context["variant"], "images", [], "any", false, false, false, 298));
foreach ($context['_seq'] as $context["_key"] => $context["variantImg"]) {
// line 299
yield "\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
$context["allImages"] = Twig\Extension\CoreExtension::merge(($context["allImages"] ?? null), [$context["variantImg"]]);
// line 300
yield "\t\t\t\t\t\t\t\t\t\t\t\t\t";
}
$_parent = $context['_parent'];
unset($context['_seq'], $context['_key'], $context['variantImg'], $context['_parent']);
$context = array_intersect_key($context, $_parent) + $_parent;
// line 301
yield "\t\t\t\t\t\t\t\t\t\t\t\t";
}
// line 302
yield "\t\t\t\t\t\t\t\t\t\t\t";
}
$_parent = $context['_parent'];
unset($context['_seq'], $context['_key'], $context['variant'], $context['_parent']);
$context = array_intersect_key($context, $_parent) + $_parent;
// line 303
yield "\t\t\t\t\t\t\t\t\t\t";
}
// line 304
yield "\t\t\t\t\t\t\t\t\t\t";
if ((Twig\Extension\CoreExtension::length($this->env->getCharset(), ($context["allImages"] ?? null)) > 0)) {
// line 305
yield "\t\t\t\t\t\t\t\t\t\t\t<img class=\"img-fluid main-product-img\" id=\"main-img-";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "id", [], "any", false, false, false, 305), "html", null, true);
yield "\" src=\"";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl((($_v0 = ($context["allImages"] ?? null)) && is_array($_v0) || $_v0 instanceof ArrayAccess ? ($_v0[0] ?? null) : null)), "html", null, true);
yield "\" alt=\"";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "name", [], "any", false, false, false, 305), "html", null, true);
yield "\">
\t\t\t\t\t\t\t\t\t\t";
} else {
// line 307
yield "\t\t\t\t\t\t\t\t\t\t\t<img class=\"img-fluid main-product-img\" id=\"main-img-";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "id", [], "any", false, false, false, 307), "html", null, true);
yield "\" src=\"";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl("ui/img/product/p1.jpg"), "html", null, true);
yield "\" alt=\"";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "name", [], "any", false, false, false, 307), "html", null, true);
yield "\">
\t\t\t\t\t\t\t\t\t\t";
}
// line 309
yield "\t\t\t\t\t\t\t\t\t</a>
\t\t\t\t\t\t\t\t\t<!-- Boutons de navigation (visibles au survol) -->
\t\t\t\t\t\t\t\t\t";
// line 312
$context["allImages"] = ((CoreExtension::getAttribute($this->env, $this->source, $context["product"], "images", [], "any", true, true, false, 312)) ? (Twig\Extension\CoreExtension::default(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "images", [], "any", false, false, false, 312), [])) : ([]));
// line 313
yield "\t\t\t\t\t\t\t\t\t";
if (CoreExtension::getAttribute($this->env, $this->source, $context["product"], "variants", [], "any", true, true, false, 313)) {
// line 314
yield "\t\t\t\t\t\t\t\t\t\t";
$context['_parent'] = $context;
$context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "variants", [], "any", false, false, false, 314));
foreach ($context['_seq'] as $context["_key"] => $context["variant"]) {
// line 315
yield "\t\t\t\t\t\t\t\t\t\t\t";
if ((CoreExtension::getAttribute($this->env, $this->source, $context["variant"], "isActive", [], "any", false, false, false, 315) && CoreExtension::getAttribute($this->env, $this->source, $context["variant"], "images", [], "any", true, true, false, 315))) {
// line 316
yield "\t\t\t\t\t\t\t\t\t\t\t\t";
$context['_parent'] = $context;
$context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env, $this->source, $context["variant"], "images", [], "any", false, false, false, 316));
foreach ($context['_seq'] as $context["_key"] => $context["variantImg"]) {
// line 317
yield "\t\t\t\t\t\t\t\t\t\t\t\t\t";
$context["allImages"] = Twig\Extension\CoreExtension::merge(($context["allImages"] ?? null), [$context["variantImg"]]);
// line 318
yield "\t\t\t\t\t\t\t\t\t\t\t\t";
}
$_parent = $context['_parent'];
unset($context['_seq'], $context['_key'], $context['variantImg'], $context['_parent']);
$context = array_intersect_key($context, $_parent) + $_parent;
// line 319
yield "\t\t\t\t\t\t\t\t\t\t\t";
}
// line 320
yield "\t\t\t\t\t\t\t\t\t\t";
}
$_parent = $context['_parent'];
unset($context['_seq'], $context['_key'], $context['variant'], $context['_parent']);
$context = array_intersect_key($context, $_parent) + $_parent;
// line 321
yield "\t\t\t\t\t\t\t\t\t";
}
// line 322
yield "\t\t\t\t\t\t\t\t\t";
if ((Twig\Extension\CoreExtension::length($this->env->getCharset(), ($context["allImages"] ?? null)) > 1)) {
// line 323
yield "\t\t\t\t\t\t\t\t\t\t<button class=\"img-nav-btn img-nav-left\" id=\"img-left-";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "id", [], "any", false, false, false, 323), "html", null, true);
yield "\" onclick=\"prevImage(";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "id", [], "any", false, false, false, 323), "html", null, true);
yield ")\" style=\"display: none;\">
\t\t\t\t\t\t\t\t\t\t\t<span class=\"lnr lnr-chevron-left\"></span>
\t\t\t\t\t\t\t\t\t\t</button>
\t\t\t\t\t\t\t\t\t\t<button class=\"img-nav-btn img-nav-right\" id=\"img-right-";
// line 326
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "id", [], "any", false, false, false, 326), "html", null, true);
yield "\" onclick=\"nextImage(";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "id", [], "any", false, false, false, 326), "html", null, true);
yield ")\" style=\"display: none;\">
\t\t\t\t\t\t\t\t\t\t\t<span class=\"lnr lnr-chevron-right\"></span>
\t\t\t\t\t\t\t\t\t\t</button>
\t\t\t\t\t\t\t\t\t\t<!-- Indicateurs de position -->
\t\t\t\t\t\t\t\t\t\t<div class=\"img-indicators\" id=\"img-indicators-";
// line 331
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "id", [], "any", false, false, false, 331), "html", null, true);
yield "\" style=\"display: none;\">
\t\t\t\t\t\t\t\t\t\t\t";
// line 332
$context['_parent'] = $context;
$context['_seq'] = CoreExtension::ensureTraversable(($context["allImages"] ?? null));
$context['loop'] = [
'parent' => $context['_parent'],
'index0' => 0,
'index' => 1,
'first' => true,
];
if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof \Countable)) {
$length = count($context['_seq']);
$context['loop']['revindex0'] = $length - 1;
$context['loop']['revindex'] = $length;
$context['loop']['length'] = $length;
$context['loop']['last'] = 1 === $length;
}
foreach ($context['_seq'] as $context["_key"] => $context["img"]) {
// line 333
yield "\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"indicator\" id=\"indicator-";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "id", [], "any", false, false, false, 333), "html", null, true);
yield "-";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["loop"], "index0", [], "any", false, false, false, 333), "html", null, true);
yield "\" onclick=\"showImage(";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "id", [], "any", false, false, false, 333), "html", null, true);
yield ", ";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["loop"], "index0", [], "any", false, false, false, 333), "html", null, true);
yield ")\"></span>
\t\t\t\t\t\t\t\t\t\t\t";
++$context['loop']['index0'];
++$context['loop']['index'];
$context['loop']['first'] = false;
if (isset($context['loop']['revindex0'], $context['loop']['revindex'])) {
--$context['loop']['revindex0'];
--$context['loop']['revindex'];
$context['loop']['last'] = 0 === $context['loop']['revindex0'];
}
}
$_parent = $context['_parent'];
unset($context['_seq'], $context['_key'], $context['img'], $context['_parent'], $context['loop']);
$context = array_intersect_key($context, $_parent) + $_parent;
// line 335
yield "\t\t\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t\t\t";
}
// line 337
yield "\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t\t<div class=\"product-details\">
\t\t\t\t\t\t\t\t\t<a href=\"";
// line 340
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["product"], "slug", [], "any", false, false, false, 340)]), "html", null, true);
yield "\">
\t\t\t\t\t\t\t\t\t\t<h6>";
// line 341
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "name", [], "any", false, false, false, 341), "html", null, true);
yield "</h6>
\t\t\t\t\t\t\t\t\t</a>
\t\t\t\t\t\t\t\t\t<!-- Affichage de la boutique -->
\t\t\t\t\t\t\t\t\t<div class=\"shop-info\">
\t\t\t\t\t\t\t\t\t\t<small class=\"text-muted\">
\t\t\t\t\t\t\t\t\t\t\t<i class=\"lnr lnr-store\"></i>
\t\t\t\t\t\t\t\t\t\t\tVendu par :
\t\t\t\t\t\t\t\t\t\t\t";
// line 349
if ((CoreExtension::getAttribute($this->env, $this->source, $context["product"], "shop", [], "any", true, true, false, 349) && CoreExtension::getAttribute($this->env, $this->source, $context["product"], "shop", [], "any", false, false, false, 349))) {
// line 350
yield "\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("ui_shop_show", ["slug" => CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, $context["product"], "shop", [], "any", false, false, false, 350), "slug", [], "any", false, false, false, 350)]), "html", null, true);
yield "\" class=\"shop-link\">
\t\t\t\t\t\t\t\t\t\t\t\t\t";
// line 351
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, $context["product"], "shop", [], "any", false, false, false, 351), "name", [], "any", false, false, false, 351), "html", null, true);
yield "
\t\t\t\t\t\t\t\t\t\t\t\t</a>
\t\t\t\t\t\t\t\t\t\t\t";
} else {
// line 354
yield "\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"text-muted\">Boutique inconnue</span>
\t\t\t\t\t\t\t\t\t\t\t";
}
// line 356
yield "\t\t\t\t\t\t\t\t\t\t</small>
\t\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t\t\t<div class=\"price\">
\t\t\t\t\t\t\t\t\t\t<h6>";
// line 360
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "price", [], "any", false, false, false, 360), 2, ".", " "), "html", null, true);
yield "
\t\t\t\t\t\t\t\t\t\t\tHTG</h6>
\t\t\t\t\t\t\t\t\t\t";
// line 362
if ((($tmp = CoreExtension::getAttribute($this->env, $this->source, $context["product"], "compareAtPrice", [], "any", false, false, false, 362)) && $tmp instanceof Markup ? (string) $tmp : $tmp)) {
// line 363
yield "\t\t\t\t\t\t\t\t\t\t\t<h6 class=\"l-through\">";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "compareAtPrice", [], "any", false, false, false, 363), 2, ".", " "), "html", null, true);
yield "
\t\t\t\t\t\t\t\t\t\t\t\tHTG</h6>
\t\t\t\t\t\t\t\t\t\t";
}
// line 366
yield "\t\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t\t\t<div class=\"prd-bottom\">
\t\t\t\t\t\t\t\t\t\t<a href=\"javascript:void(0)\" class=\"social-info add-to-cart\" data-product-id=\"";
// line 368
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "id", [], "any", false, false, false, 368), "html", null, true);
yield "\" data-qty=\"1\">
\t\t\t\t\t\t\t\t\t\t\t<span class=\"ti-bag\"></span>
\t\t\t\t\t\t\t\t\t\t\t<p class=\"hover-text\">+ panier</p>
\t\t\t\t\t\t\t\t\t\t</a>
\t\t\t\t\t\t\t\t\t\t<a href=\"#\" class=\"social-info wishlist-btn\" data-product-id=\"";
// line 372
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "id", [], "any", false, false, false, 372), "html", null, true);
yield "\" ";
if ((($tmp = CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "user", [], "any", false, false, false, 372)) && $tmp instanceof Markup ? (string) $tmp : $tmp)) {
yield " onclick=\"toggleWishlist(";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "id", [], "any", false, false, false, 372), "html", null, true);
yield ", this); return false;\" ";
} else {
yield " onclick=\"alert('Vous devez être connecté pour ajouter aux favoris'); return false;\" ";
}
yield ">
\t\t\t\t\t\t\t\t\t\t\t<span class=\"lnr lnr-heart\"></span>
\t\t\t\t\t\t\t\t\t\t\t<p class=\"hover-text\">Favoris</p>
\t\t\t\t\t\t\t\t\t\t</a>
\t\t\t\t\t\t\t\t\t\t<a href=\"#\" class=\"social-info comparison-btn\" data-product-id=\"";
// line 376
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "id", [], "any", false, false, false, 376), "html", null, true);
yield "\" ";
if ((($tmp = CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "user", [], "any", false, false, false, 376)) && $tmp instanceof Markup ? (string) $tmp : $tmp)) {
yield " onclick=\"toggleComparison(";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "id", [], "any", false, false, false, 376), "html", null, true);
yield ", this); return false;\" ";
} else {
yield " onclick=\"alert('Vous devez être connecté pour comparer des produits'); return false;\" ";
}
yield ">
\t\t\t\t\t\t\t\t\t\t\t<span class=\"lnr lnr-sync\"></span>
\t\t\t\t\t\t\t\t\t\t\t<p class=\"hover-text\">Comparer</p>
\t\t\t\t\t\t\t\t\t\t</a>
\t\t\t\t\t\t\t\t\t\t<a href=\"";
// line 380
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["product"], "slug", [], "any", false, false, false, 380)]), "html", null, true);
yield "\" class=\"social-info\">
\t\t\t\t\t\t\t\t\t\t\t<span class=\"lnr lnr-move\"></span>
\t\t\t\t\t\t\t\t\t\t\t<p class=\"hover-text\">Voir plus</p>
\t\t\t\t\t\t\t\t\t\t</a>
\t\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t</div>
\t\t\t\t\t";
$context['_iterated'] = true;
}
// line 388
if (!$context['_iterated']) {
// line 389
yield "\t\t\t\t\t\t<div class=\"col-12\">
\t\t\t\t\t\t\t<p>Aucun produit disponible.</p>
\t\t\t\t\t\t</div>
\t\t\t\t\t";
}
$_parent = $context['_parent'];
unset($context['_seq'], $context['_key'], $context['product'], $context['_parent'], $context['_iterated']);
$context = array_intersect_key($context, $_parent) + $_parent;
// line 393
yield "\t\t\t\t</div>
\t\t\t\t<!-- Bouton Charger plus de produits -->
\t\t\t\t";
// line 396
if ((($context["totalPages"] ?? null) > ($context["currentPage"] ?? null))) {
// line 397
yield "\t\t\t\t\t<div class=\"text-center mt-4 mb-4\" id=\"loadMoreContainer\">
\t\t\t\t\t\t<button type=\"button\" class=\"btn btn-primary btn-lg\" id=\"loadMoreBtn\" onclick=\"loadMoreProducts()\">
\t\t\t\t\t\t\t<i class=\"lnr lnr-plus-circle me-2\"></i>Charger plus de produits
\t\t\t\t\t\t</button>
\t\t\t\t\t</div>
\t\t\t\t";
}
// line 403
yield "
\t\t\t\t<!-- Message de fin -->
\t\t\t\t<div id=\"noMoreProducts\" class=\"text-center py-4\" style=\"display: none;\">
\t\t\t\t\t<p class=\"text-muted\">
\t\t\t\t\t\t<i class=\"lnr lnr-checkmark-circle\"></i>
\t\t\t\t\t\tTous les produits ont été chargés</p>
\t\t\t\t</div>
\t\t\t</section>
\t\t\t<!-- End Best Seller -->
\t\t</div>
\t</div>
</div>";
$__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
$__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
yield from [];
}
// line 414
/**
* @return iterable<null|scalar|\Stringable>
*/
public function block_title(array $context, array $blocks = []): iterable
{
$macros = $this->macros;
$__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
$__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "title"));
$__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
$__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "title"));
yield "Liste des produits | MaketOu";
$__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
$__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
yield from [];
}
/**
* @return iterable<null|scalar|\Stringable>
*/
public function block_stylesheets(array $context, array $blocks = []): iterable
{
$macros = $this->macros;
$__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
$__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "stylesheets"));
$__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
$__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "stylesheets"));
// line 415
yield "<style>
\t/* Styles pour la navigation des images */
\t.product-image-container {
\t\tposition: relative;
\t\toverflow: hidden;
\t\tborder-radius: 8px;
\t}
\t.img-nav-btn {
\t\tposition: absolute;
\t\ttop: 50%;
\t\ttransform: translateY(-50%);
\t\tbackground: rgba(0, 0, 0, 0.6);
\t\tcolor: white;
\t\tborder: none;
\t\twidth: 35px;
\t\theight: 35px;
\t\tborder-radius: 50%;
\t\tdisplay: flex;
\t\talign-items: center;
\t\tjustify-content: center;
\t\tcursor: pointer;
\t\ttransition: all 0.3s ease;
\t\tz-index: 10;
\t}
\t.img-nav-btn:hover {
\t\tbackground: #095ad3;
\t\ttransform: translateY(-50%) scale(1.1);
\t}
\t.img-nav-left {
\t\tleft: 10px;
\t}
\t.img-nav-right {
\t\tright: 10px;
\t}
\t.img-indicators {
\t\tposition: absolute;
\t\tbottom: 10px;
\t\tleft: 50%;
\t\ttransform: translateX(-50%);
\t\tdisplay: flex;
\t\tgap: 5px;
\t\tz-index: 10;
\t}
\t.indicator {
\t\twidth: 8px;
\t\theight: 8px;
\t\tborder-radius: 50%;
\t\tbackground: rgba(255, 255, 255, 0.5);
\t\tcursor: pointer;
\t\tmargin-bottom: 10px;
\t\ttransition: all 0.3s ease;
\t\tborder: 1px solid rgba(255, 255, 255, 0.3);
\t}
\t.indicator.active {
\t\tbackground: #ffa200;
\t\tborder-color: #ffa200;
\t\ttransform: scale(1.2);
\t}
\t.indicator:hover {
\t\tbackground: rgba(255, 255, 255, 0.8);
\t}
\t/* Styles pour l'affichage de la boutique */
\t.shop-info {
\t\tmargin: 8px 0;
\t\tpadding: 5px 0;
\t\tborder-bottom: 1px solid #f0f0f0;
\t}
\t.shop-link {
\t\tcolor: #007bff;
\t\ttext-decoration: none;
\t\tfont-weight: 500;
\t}
\t.shop-link:hover {
\t\tcolor: #ffa200;
\t\ttext-decoration: underline;
\t}
\t/* Animation pour le survol */
\t.product-image-container:hover .main-product-img {
\t\ttransform: scale(1.05);
\t\ttransition: transform 0.3s ease;
\t}
\t.main-product-img {
\t\ttransition: transform 0.3s ease;
\t\twidth: 100%;
\t\theight: 100%;
\t\tobject-fit: cover; /* Recadre l'image pour remplir le conteneur */
\t\tobject-position: center; /* Centre l'image */
\t\tdisplay: block;
\t}
\t/* Styles pour les images des produits associés (Deals de la semaine) */
\t.related-product-img-container {
\t\tposition: relative;
\t\toverflow: hidden;
\t\tborder-radius: 8px;
\t\twidth: 100%;
\t\theight: 200px; /* Hauteur fixe pour les produits associés */
\t\tbackground: #f8f9fa; /* Fond au cas où l'image ne charge pas */
\t}
\t.related-product-img {
\t\twidth: 100%;
\t\theight: 100%;
\t\tobject-fit: cover; /* Recadre l'image pour remplir le conteneur */
\t\tobject-position: center; /* Centre l'image */
\t\tdisplay: block;
\t\ttransition: transform 0.3s ease;
\t}
\t.related-product-img-container:hover .related-product-img {
\t\ttransform: scale(1.05);
\t}
\t/* Styles pour l'image de catégorie dans les deals */
\t.category-banner-container {
\t\tdisplay: block;
\t\tposition: relative;
\t\toverflow: hidden;
\t\tborder-radius: 8px;
\t\twidth: 100%;
\t\theight: 400px; /* Hauteur fixe pour la bannière de catégorie */
\t\tbackground: #f8f9fa; /* Fond au cas où l'image ne charge pas */
\t}
\t.category-banner-img {
\t\twidth: 100%;
\t\theight: 100%;
\t\tobject-fit: cover; /* Recadre l'image pour remplir le conteneur */
\t\tobject-position: center; /* Centre l'image */
\t\tdisplay: block;
\t\ttransition: transform 0.3s ease;
\t}
\t.category-banner-container:hover .category-banner-img {
\t\ttransform: scale(1.05);
\t}
\t/* Styles pour les images de la modal Quick Product View */
\t.quick-view-carousel .item {
\t\twidth: 100%;
\t\theight: 400px; /* Hauteur fixe pour les images du carousel */
\t\tbackground-size: cover;
\t\tbackground-position: center;
\t\tbackground-repeat: no-repeat;
\t\tborder-radius: 8px;
\t}
\t/* Contraindre le conteneur d'image pour maintenir les proportions */
\t.product-image-container {
\t\tposition: relative;
\t\toverflow: hidden;
\t\tborder-radius: 8px;
\t\twidth: 200px;
\t\taspect-ratio: 1 / 1; /* Conteneur carré */
\t\tbackground: #f8f9fa; /* Fond au cas où l'image ne charge pas */
\t}
\t/* Styles pour le bouton de filtre amélioré */
\t.filter-icon-circle {
\t\ttransition: all 0.3s ease;
\t}
\tbutton[data-bs-target=\"#filtersModal\"]:hover .filter-icon-circle {
\t\tbackground: linear-gradient(135deg, #ff8c00 0%, #ff7700 100%) !important;
\t\ttransform: rotate(15deg) scale(1.1);
\t\tbox-shadow: 0 4px 15px rgba(255, 162, 0, 0.5);
\t}
\tbutton[data-bs-target=\"#filtersModal\"]:hover {
\t\ttransform: translateY(-2px);
\t}
\tbutton[data-bs-target=\"#filtersModal\"]:active {
\t\ttransform: translateY(0);
\t}
\tbutton[data-bs-target=\"#filtersModal\"]:hover span {
\t\tcolor: #ffa200 !important;
\t}
\t/* Styles pour le modal de filtres */
\t#filtersModal .modal-body {
\t\tpadding: 1.5rem;
\t}
\t#filtersModal .modal-body::-webkit-scrollbar {
\t\twidth: 8px;
\t}
\t#filtersModal .modal-body::-webkit-scrollbar-track {
\t\tbackground: #f1f1f1;
\t\tborder-radius: 4px;
\t}
\t#filtersModal .modal-body::-webkit-scrollbar-thumb {
\t\tbackground: #ffa200;
\t\tborder-radius: 4px;
\t}
\t#filtersModal .modal-body::-webkit-scrollbar-thumb:hover {
\t\tbackground: #e69100;
\t}
\t#filtersModal .modal-footer {
\t\tbox-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
\t}
\t/* Styles pour les filtres avancés */
\t.weight-range-area {
\t\tpadding: 15px 0;
\t}
\t.weight-inputs {
\t\tgap: 15px;
\t\talign-items: center;
\t}
\t.weight-input {
\t\tflex: 1;
\t}
\t.weight-input label {
\t\tdisplay: block;
\t\tmargin-bottom: 5px;
\t\tfont-weight: 500;
\t\tcolor: #333;
\t}
\t.weight-input input {
\t\twidth: 100%;
\t\tpadding: 8px 12px;
\t\tborder: 1px solid #ddd;
\t\tborder-radius: 4px;
\t\tfont-size: 14px;
\t}
\t.weight-input input:focus {
\t\toutline: none;
\t\tborder-color: #ffa200;
\t\tbox-shadow: 0 0 0 2px rgba(255, 162, 0, 0.2);
\t}
\t/* Styles pour les filtres dynamiques */
\t.shop-list,
\t.color-list,
\t.size-list,
\t.material-list,
\t.condition-list {
\t\tmax-height: 200px;
\t\toverflow-y: auto;
\t\tpadding-right: 5px;
\t}
\t.shop-list::-webkit-scrollbar,
\t.color-list::-webkit-scrollbar,
\t.size-list::-webkit-scrollbar,
\t.material-list::-webkit-scrollbar,
\t.condition-list::-webkit-scrollbar {
\t\twidth: 6px;
\t}
\t.shop-list::-webkit-scrollbar-track,
\t.color-list::-webkit-scrollbar-track,
\t.size-list::-webkit-scrollbar-track,
\t.material-list::-webkit-scrollbar-track,
\t.condition-list::-webkit-scrollbar-track {
\t\tbackground: #f1f1f1;
\t\tborder-radius: 3px;
\t}
\t.shop-list::-webkit-scrollbar-thumb,
\t.color-list::-webkit-scrollbar-thumb,
\t.size-list::-webkit-scrollbar-thumb,
\t.material-list::-webkit-scrollbar-thumb,
\t.condition-list::-webkit-scrollbar-thumb {
\t\tbackground: #ffa200;
\t\tborder-radius: 3px;
\t}
\t.shop-list::-webkit-scrollbar-thumb:hover,
\t.color-list::-webkit-scrollbar-thumb:hover,
\t.size-list::-webkit-scrollbar-thumb:hover,
\t.material-list::-webkit-scrollbar-thumb:hover,
\t.condition-list::-webkit-scrollbar-thumb:hover {
\t\tbackground: #e69100;
\t}
\t/* Animation pour les filtres qui apparaissent */
\t.common-filter {
\t\ttransition: all 0.3s ease;
\t}
\t.common-filter[style*=\"display: none\"] {
\t\topacity: 0;
\t\ttransform: translateY(-10px);
\t}
\t.common-filter[style*=\"display: block\"] {
\t\topacity: 1;
\t\ttransform: translateY(0);
\t}
\t/* Styles pour les indicateurs de chargement */
\t.loading-indicator {
\t\tdisplay: inline-block;
\t\twidth: 20px;
\t\theight: 20px;
\t\tborder: 3px solid #f3f3f3;
\t\tborder-top: 3px solid #ffa200;
\t\tborder-radius: 50%;
\t\tanimation: spin 1s linear infinite;
\t}
\t@keyframes spin {
\t\t0% {
\t\t\ttransform: rotate(0deg);
\t\t}
\t\t100% {
\t\t\ttransform: rotate(360deg);
\t\t}
\t}
\t/* Styles pour le loader de chargement infini */
\t.infinite-loader {
\t\tdisplay: flex;
\t\tflex-direction: column;
\t\talign-items: center;
\t\tjustify-content: center;
\t\tpadding: 20px;
\t}
\t.loader-spinner {
\t\twidth: 50px;
\t\theight: 50px;
\t\tborder: 4px solid #f3f3f3;
\t\tborder-top: 4px solid #ffa200;
\t\tborder-radius: 50%;
\t\tanimation: spin 1s linear infinite;
\t}
\t#infiniteScrollLoader {
\t\tmin-height: 100px;
\t}
\t#noMoreProducts {
\t\tmin-height: 60px;
\t\tcolor: #6c757d;
\t}
\t#noMoreProducts i {
\t\tfont-size: 24px;
\t\tcolor: #28a745;
\t\tmargin-right: 8px;
\t}
\t/* Responsive pour les filtres */
\t@media(max-width: 768px) {
\t\t.weight-inputs {
\t\t\tflex-direction: column;
\t\t\tgap: 10px;
\t\t}
\t\t.weight-input {
\t\t\twidth: 100%;
\t\t}
\t\t.common-filter {
\t\t\tmargin-bottom: 20px;
\t\t}
\t\t.shop-list,
\t\t.color-list,
\t\t.size-list,
\t\t.material-list,
\t\t.condition-list {
\t\t\tmax-height: 150px;
\t\t}
\t}
\t/* Bouton toggle sidebar mobile */
\t.listing-sidebar-toggle {
\t\tborder-radius: 0.5rem;
\t\tpadding: 0.75rem;
\t\tfont-weight: 500;
\t\tdisplay: flex;
\t\talign-items: center;
\t\tjustify-content: center;
\t}
\t.listing-sidebar-toggle .toggle-icon {
\t\ttransition: transform 0.3s ease;
\t\tdisplay: inline-block;
\t}
\t/* État fermé (par défaut) */
\t.listing-sidebar-toggle[aria-expanded=\"false\"] .toggle-icon,
\t.listing-sidebar-toggle.collapsed .toggle-icon {
\t\ttransform: rotate(0deg);
\t}
\t/* État ouvert */
\t.listing-sidebar-toggle[aria-expanded=\"true\"] .toggle-icon,
\t.listing-sidebar-toggle:not(.collapsed) .toggle-icon {
\t\ttransform: rotate(180deg);
\t}
\t/* Sidebar mobile */
\t@media(max-width: 767.98px) {
\t\t#listingSidebarCollapse {
\t\t\tmargin-bottom: 1rem;
\t\t}
\t}
</style>";
$__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
$__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
yield from [];
}
// line 839
/**
* @return iterable<null|scalar|\Stringable>
*/
public function block_javascripts(array $context, array $blocks = []): iterable
{
$macros = $this->macros;
$__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
$__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "javascripts"));
$__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
$__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "javascripts"));
// line 840
yield "<script>
// === Script isolé : chargement de plus de produits (comme les boutiques) ===
var currentPage = ";
// line 842
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(($context["currentPage"] ?? null), "html", null, true);
yield ";
var totalPages = ";
// line 843
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(($context["totalPages"] ?? null), "html", null, true);
yield ";
var isLoading = false;
function loadMoreProducts() {
if (isLoading || currentPage >= totalPages) return;
isLoading = true;
var btn = document.getElementById('loadMoreBtn');
var productsContainer = document.getElementById('productsContainer');
if (!btn || !productsContainer) {
isLoading = false;
return;
}
var originalText = btn.innerHTML;
btn.disabled = true;
btn.innerHTML = '<span class=\"spinner-border spinner-border-sm me-2\"></span>Chargement...';
currentPage++;
var url = new URL(window.location.href);
url.searchParams.set('page', currentPage);
fetch(url.toString(), {
headers: { 'X-Requested-With': 'XMLHttpRequest' }
})
.then(function(response) { return response.json(); })
.then(function(data) {
if (data.success && data.products) {
var tempDiv = document.createElement('div');
tempDiv.innerHTML = data.products;
var newProducts = tempDiv.querySelectorAll('.col-lg-4, .col-lg-3, [class*=\"col-lg\"]');
newProducts.forEach(function(product) {
productsContainer.appendChild(product);
});
currentPage = data.pagination.currentPage;
totalPages = data.pagination.totalPages;
// Initialiser les images et events pour les nouveaux produits
if (typeof initializeProductImages === 'function') initializeProductImages(tempDiv);
if (typeof initializeProductEventListeners === 'function') initializeProductEventListeners(tempDiv);
if (currentPage >= totalPages) {
document.getElementById('loadMoreContainer').style.display = 'none';
} else {
btn.disabled = false;
btn.innerHTML = originalText;
}
} else {
document.getElementById('loadMoreContainer').style.display = 'none';
}
isLoading = false;
})
.catch(function(error) {
btn.disabled = false;
btn.innerHTML = originalText;
isLoading = false;
});
}
</script>
<script>
\t// Variables globales pour la navigation des images
const productImages = {};
const currentImageIndex = {};
// Variables pour le chargement infini (utilise les var globales définies au-dessus)
let hasMoreProducts = totalPages > currentPage;
let currentFilters = {
category: '";
// line 915
yield (((array_key_exists("currentCategory", $context) && !(null === $context["currentCategory"]))) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($context["currentCategory"], "html", null, true)) : (""));
yield "',
brand: '";
// line 916
yield (((array_key_exists("currentBrand", $context) && !(null === $context["currentBrand"]))) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($context["currentBrand"], "html", null, true)) : (""));
yield "',
sort: '";
// line 917
yield (((array_key_exists("currentSort", $context) && !(null === $context["currentSort"]))) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($context["currentSort"], "html", null, true)) : ("newest"));
yield "',
priceMin: '";
// line 918
yield (((array_key_exists("priceMin", $context) && !(null === $context["priceMin"]))) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($context["priceMin"], "html", null, true)) : (""));
yield "',
priceMax: '";
// line 919
yield (((array_key_exists("priceMax", $context) && !(null === $context["priceMax"]))) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($context["priceMax"], "html", null, true)) : (""));
yield "'
};
// Modal style eBay pour remplacer les alertes - Définir AVANT son utilisation
function showEbayModal(message, type = 'info') {
const modalId = 'ebayAlertModal';
let existingModal = document.getElementById(modalId);
if (existingModal) {
existingModal.remove();
}
const modal = document.createElement('div');
modal.id = modalId;
modal.className = 'modal fade';
modal.setAttribute('tabindex', '-1');
modal.setAttribute('aria-labelledby', 'ebayAlertModalLabel');
modal.setAttribute('aria-hidden', 'true');
// Définir les couleurs et icônes selon le type
let iconClass = 'ti-info-alt';
let iconColor = '#0064D2';
let title = 'Information';
switch (type) {
case 'success': iconClass = 'ti-check-box';
iconColor = '#0A7C42';
title = 'Succès';
break;
case 'error':
case 'danger': iconClass = 'ti-alert';
iconColor = '#D32F2F';
title = 'Erreur';
break;
case 'warning': iconClass = 'ti-alert-triangle';
iconColor = '#F57C00';
title = 'Attention';
break;
default: iconClass = 'ti-info-alt';
iconColor = '#0064D2';
title = 'Information';
}
modal.innerHTML = `
<div class=\"modal-dialog modal-dialog-centered\">
<div class=\"modal-content\" style=\"border-radius: 8px; border: none; box-shadow: 0 4px 20px rgba(0,0,0,0.15);\">
<div class=\"modal-header\" style=\"border-bottom: 1px solid #e0e0e0; padding: 20px 24px;\">
<h5 class=\"modal-title\" id=\"ebayAlertModalLabel\" style=\"font-weight: 600; font-size: 18px; color: #333;\">
<i class=\"\${iconClass}\" style=\"color: \${iconColor}; margin-right: 8px;\"></i>\${title}
</h5>
<button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\" aria-label=\"Close\" style=\"margin: 0;\"></button>
</div>
<div class=\"modal-body\" style=\"padding: 24px; text-align: center;\">
<p style=\"margin: 0; font-size: 16px; color: #333; line-height: 1.5;\">\${message}</p>
</div>
<div class=\"modal-footer\" style=\"border-top: 1px solid #e0e0e0; padding: 16px 24px; justify-content: center;\">
<button type=\"button\" class=\"btn btn-primary\" data-bs-dismiss=\"modal\" style=\"min-width: 100px; background-color: \${iconColor}; border-color: \${iconColor}; border-radius: 4px; font-weight: 500;\">
OK
</button>
</div>
</div>
</div>
`;
document.body.appendChild(modal);
const bsModal = new bootstrap.Modal(modal);
bsModal.show();
// Supprimer le modal du DOM après fermeture
modal.addEventListener('hidden.bs.modal', function () {
modal.remove();
});
}
// Rendre la fonction globale
window.showEbayModal = showEbayModal;
document.addEventListener('DOMContentLoaded', function () { // Initialisation des données d'images pour chaque produit
";
// line 996
$context['_parent'] = $context;
$context['_seq'] = CoreExtension::ensureTraversable(($context["products"] ?? null));
foreach ($context['_seq'] as $context["_key"] => $context["product"]) {
// line 997
$context["allImages"] = ((CoreExtension::getAttribute($this->env, $this->source, $context["product"], "images", [], "any", true, true, false, 997)) ? (Twig\Extension\CoreExtension::default(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "images", [], "any", false, false, false, 997), [])) : ([]));
// line 998
if (CoreExtension::getAttribute($this->env, $this->source, $context["product"], "variants", [], "any", true, true, false, 998)) {
// line 999
yield "\t";
$context['_parent'] = $context;
$context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "variants", [], "any", false, false, false, 999));
foreach ($context['_seq'] as $context["_key"] => $context["variant"]) {
// line 1000
yield "\t\t";
if ((CoreExtension::getAttribute($this->env, $this->source, $context["variant"], "isActive", [], "any", false, false, false, 1000) && CoreExtension::getAttribute($this->env, $this->source, $context["variant"], "images", [], "any", true, true, false, 1000))) {
// line 1001
yield "\t\t\t";
$context['_parent'] = $context;
$context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env, $this->source, $context["variant"], "images", [], "any", false, false, false, 1001));
foreach ($context['_seq'] as $context["_key"] => $context["variantImg"]) {
// line 1002
yield "\t\t\t\t";
$context["allImages"] = Twig\Extension\CoreExtension::merge(($context["allImages"] ?? null), [$context["variantImg"]]);
// line 1003
yield "\t\t\t";
}
$_parent = $context['_parent'];
unset($context['_seq'], $context['_key'], $context['variantImg'], $context['_parent']);
$context = array_intersect_key($context, $_parent) + $_parent;
// line 1004
yield "\t\t";
}
// line 1005
yield "\t";
}
$_parent = $context['_parent'];
unset($context['_seq'], $context['_key'], $context['variant'], $context['_parent']);
$context = array_intersect_key($context, $_parent) + $_parent;
}
// line 1007
if ((Twig\Extension\CoreExtension::length($this->env->getCharset(), ($context["allImages"] ?? null)) > 0)) {
yield "productImages[";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "id", [], "any", false, false, false, 1007), "html", null, true);
yield "] = [";
$context['_parent'] = $context;
$context['_seq'] = CoreExtension::ensureTraversable(($context["allImages"] ?? null));
$context['loop'] = [
'parent' => $context['_parent'],
'index0' => 0,
'index' => 1,
'first' => true,
];
if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof \Countable)) {
$length = count($context['_seq']);
$context['loop']['revindex0'] = $length - 1;
$context['loop']['revindex'] = $length;
$context['loop']['length'] = $length;
$context['loop']['last'] = 1 === $length;
}
foreach ($context['_seq'] as $context["_key"] => $context["img"]) {
yield "'";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl($context["img"]), "html", null, true);
yield "'";
if ((($tmp = !CoreExtension::getAttribute($this->env, $this->source, $context["loop"], "last", [], "any", false, false, false, 1007)) && $tmp instanceof Markup ? (string) $tmp : $tmp)) {
yield ",";
}
++$context['loop']['index0'];
++$context['loop']['index'];
$context['loop']['first'] = false;
if (isset($context['loop']['revindex0'], $context['loop']['revindex'])) {
--$context['loop']['revindex0'];
--$context['loop']['revindex'];
$context['loop']['last'] = 0 === $context['loop']['revindex0'];
}
}
$_parent = $context['_parent'];
unset($context['_seq'], $context['_key'], $context['img'], $context['_parent'], $context['loop']);
$context = array_intersect_key($context, $_parent) + $_parent;
yield "];
currentImageIndex[";
// line 1008
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "id", [], "any", false, false, false, 1008), "html", null, true);
yield "] = 0;
console.log('Initialized product ";
// line 1009
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "id", [], "any", false, false, false, 1009), "html", null, true);
yield " with images:', productImages[";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["product"], "id", [], "any", false, false, false, 1009), "html", null, true);
yield "]);";
}
}
$_parent = $context['_parent'];
unset($context['_seq'], $context['_key'], $context['product'], $context['_parent']);
$context = array_intersect_key($context, $_parent) + $_parent;
// line 1010
yield "
// Gestion du panier
const cartButtons = document.querySelectorAll('.add-to-cart');
cartButtons.forEach(button => {
button.addEventListener('click', function () {
const productId = this.getAttribute('data-product-id');
const qty = this.getAttribute('data-qty');
fetch('";
// line 1018
yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("ui_cart_add");
yield "', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: 'productId=' + productId + '&qty=' + qty
}).then(response => response.json()).then(data => {
if (data.ok) {
showEbayModal('Produit ajouté au panier !', 'success');
// Mettre à jour le compteur du panier si présent
const cartBadge = document.querySelector('.cart-badge');
if (cartBadge) {
cartBadge.textContent = data.totalQty;
}
} else {
showEbayModal(data.message || 'Erreur lors de l\\'ajout au panier', 'error');
}
}).catch(error => {
console.error('Erreur:', error);
showEbayModal('Erreur lors de l\\'ajout au panier', 'error');
});
});
});
});
// Fonctions pour la navigation des images
window.showImageNav = function(productId) {
const leftBtn = document.getElementById('img-left-' + productId);
const rightBtn = document.getElementById('img-right-' + productId);
const indicators = document.getElementById('img-indicators-' + productId);
if (leftBtn) {
leftBtn.style.display = 'flex';
}
if (rightBtn) {
rightBtn.style.display = 'flex';
}
if (indicators) {
indicators.style.display = 'flex';
}
};
window.hideImageNav = function(productId) {
const leftBtn = document.getElementById('img-left-' + productId);
const rightBtn = document.getElementById('img-right-' + productId);
const indicators = document.getElementById('img-indicators-' + productId);
if (leftBtn) {
leftBtn.style.display = 'none';
}
if (rightBtn) {
rightBtn.style.display = 'none';
}
if (indicators) {
indicators.style.display = 'none';
}
};
window.showImage = function(productId, imageIndex) {
if (! productImages[productId] || ! productImages[productId][imageIndex]) {
console.log('Image not found for product', productId, 'index', imageIndex);
return;
}
const img = document.getElementById('main-img-' + productId);
if (img) {
console.log('Changing image to:', productImages[productId][imageIndex]);
// Force le rechargement de l'image
img.style.opacity = '0.5';
setTimeout(() => {
img.src = productImages[productId][imageIndex];
img.style.opacity = '1';
currentImageIndex[productId] = imageIndex;
updateIndicators(productId);
}, 100);
} else {
console.log('Image element not found:', 'main-img-' + productId);
}
};
window.nextImage = function(productId) {
if (! productImages[productId]) {
console.log('No images for product', productId);
return;
}
const nextIndex = (currentImageIndex[productId] + 1) % productImages[productId].length;
showImage(productId, nextIndex);
};
window.prevImage = function(productId) {
if (! productImages[productId]) {
console.log('No images for product', productId);
return;
}
const prevIndex = currentImageIndex[productId] === 0 ? productImages[productId].length - 1 : currentImageIndex[productId] - 1;
showImage(productId, prevIndex);
};
function updateIndicators(productId) {
const indicators = document.querySelectorAll('#img-indicators-' + productId + ' .indicator');
indicators.forEach((indicator, index) => {
indicator.classList.toggle('active', index === currentImageIndex[productId]);
});
}
// Fonction pour tracker la vue d'un produit
function trackProductView(productId) {
fetch (`/api/track-product-view/\${productId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
}
}).then(response => response.json()).then(data => {
if (data.success) {
console.log (`Vue enregistrée pour le produit \${productId}:`, data.viewCount);
}
}).catch(error => {
console.error('Erreur lors du tracking:', error);
});
}
// Fonction pour tracker la vue d'une boutique
function trackShopView(shopId) {
fetch (`/api/track-shop-view/\${shopId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
}
}).then(response => response.json()).then(data => {
if (data.success) {
console.log (`Vue enregistrée pour la boutique \${shopId}:`, data.viewCount);
}
}).catch(error => {
console.error('Erreur lors du tracking:', error);
});
}
// Ajouter le tracking aux événements existants
document.addEventListener('DOMContentLoaded', function () { // Tracking au survol des produits (avec délai)
const productCards = document.querySelectorAll('.single_product_item');
productCards.forEach(card => {
const productId = card.dataset.productId;
const shopId = card.dataset.shopId;
if (productId) {
let hoverTimeout;
card.addEventListener('mouseenter', () => { // Tracker la vue du produit après 2 secondes de survol
hoverTimeout = setTimeout(() => {
trackProductView(productId);
}, 2000);
});
card.addEventListener('mouseleave', () => {
clearTimeout(hoverTimeout);
});
// Tracking au clic sur le lien du produit
const productLink = card.querySelector('.product_img a');
if (productLink) {
productLink.addEventListener('click', () => {
trackProductView(productId);
});
}
}
// Tracking au clic sur le lien de la boutique
if (shopId) {
const shopLink = card.querySelector('.shop-link');
if (shopLink) {
shopLink.addEventListener('click', () => {
trackShopView(shopId);
});
}
}
});
});
</script>
<script>
\t// Système de filtrage AJAX avancé
// currentFilters est déjà déclaré plus haut, on met juste à jour les valeurs
if (typeof currentFilters !== 'undefined') { // Mettre à jour les valeurs existantes
currentFilters.category = '";
// line 1211
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(($context["currentCategory"] ?? null), "html", null, true);
yield "';
currentFilters.brand = '";
// line 1212
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(($context["currentBrand"] ?? null), "html", null, true);
yield "';
currentFilters.condition = '";
// line 1213
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(($context["currentCondition"] ?? null), "html", null, true);
yield "';
currentFilters.sort = '";
// line 1214
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(($context["currentSort"] ?? null), "html", null, true);
yield "';
currentFilters.priceMin = '";
// line 1215
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(($context["priceMin"] ?? null), "html", null, true);
yield "';
currentFilters.priceMax = '";
// line 1216
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(($context["priceMax"] ?? null), "html", null, true);
yield "';
currentFilters.page = ";
// line 1217
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(($context["currentPage"] ?? null), "html", null, true);
yield ";
currentFilters.q = currentFilters.q || '";
// line 1218
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1218), "query", [], "any", false, false, false, 1218), "get", ["q", ""], "method", false, false, false, 1218), "html", null, true);
yield "';
// Ajouter les nouveaux filtres depuis l'URL s'ils n'existent pas
if (! currentFilters.shop)
currentFilters.shop = '";
// line 1221
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1221), "query", [], "any", false, false, false, 1221), "get", ["shop", ""], "method", false, false, false, 1221), "html", null, true);
yield "';
if (! currentFilters.featured)
currentFilters.featured = '";
// line 1224
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1224), "query", [], "any", false, false, false, 1224), "get", ["featured", ""], "method", false, false, false, 1224), "html", null, true);
yield "';
if (! currentFilters.digital)
currentFilters.digital = '";
// line 1227
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1227), "query", [], "any", false, false, false, 1227), "get", ["digital", ""], "method", false, false, false, 1227), "html", null, true);
yield "';
if (! currentFilters.stockStatus)
currentFilters.stockStatus = '";
// line 1230
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1230), "query", [], "any", false, false, false, 1230), "get", ["stock_status", ""], "method", false, false, false, 1230), "html", null, true);
yield "';
if (! currentFilters.ratingMin)
currentFilters.ratingMin = '";
// line 1233
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1233), "query", [], "any", false, false, false, 1233), "get", ["rating_min", ""], "method", false, false, false, 1233), "html", null, true);
yield "';
if (! currentFilters.rating)
currentFilters.rating = '";
// line 1236
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1236), "query", [], "any", false, false, false, 1236), "get", ["rating_min", ""], "method", false, false, false, 1236), "html", null, true);
yield "';
if (! currentFilters.weightMin)
currentFilters.weightMin = '";
// line 1239
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1239), "query", [], "any", false, false, false, 1239), "get", ["weight_min", ""], "method", false, false, false, 1239), "html", null, true);
yield "';
if (! currentFilters.weightMax)
currentFilters.weightMax = '";
// line 1242
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1242), "query", [], "any", false, false, false, 1242), "get", ["weight_max", ""], "method", false, false, false, 1242), "html", null, true);
yield "';
if (! currentFilters.color)
currentFilters.color = '";
// line 1245
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1245), "query", [], "any", false, false, false, 1245), "get", ["color", ""], "method", false, false, false, 1245), "html", null, true);
yield "';
if (! currentFilters.size)
currentFilters.size = '";
// line 1248
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1248), "query", [], "any", false, false, false, 1248), "get", ["size", ""], "method", false, false, false, 1248), "html", null, true);
yield "';
if (! currentFilters.material)
currentFilters.material = '";
// line 1251
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1251), "query", [], "any", false, false, false, 1251), "get", ["material", ""], "method", false, false, false, 1251), "html", null, true);
yield "';
if (! currentFilters.condition)
currentFilters.condition = '";
// line 1254
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1254), "query", [], "any", false, false, false, 1254), "get", ["condition", ""], "method", false, false, false, 1254), "html", null, true);
yield "';
if (! currentFilters.availability)
currentFilters.availability = '";
// line 1257
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1257), "query", [], "any", false, false, false, 1257), "get", ["availability", ""], "method", false, false, false, 1257), "html", null, true);
yield "';
} else { // Si currentFilters n'existe pas, le créer avec les valeurs de l'URL
let currentFilters = {
category: '";
// line 1261
yield (((array_key_exists("currentCategory", $context) && !(null === $context["currentCategory"]))) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($context["currentCategory"], "html", null, true)) : (""));
yield "',
brand: '";
// line 1262
yield (((array_key_exists("currentBrand", $context) && !(null === $context["currentBrand"]))) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($context["currentBrand"], "html", null, true)) : (""));
yield "',
condition: '";
// line 1263
yield (((array_key_exists("currentCondition", $context) && !(null === $context["currentCondition"]))) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($context["currentCondition"], "html", null, true)) : (""));
yield "',
sort: '";
// line 1264
yield (((array_key_exists("currentSort", $context) && !(null === $context["currentSort"]))) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($context["currentSort"], "html", null, true)) : ("newest"));
yield "',
priceMin: '";
// line 1265
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1265), "query", [], "any", false, false, false, 1265), "get", ["price_min", ""], "method", false, false, false, 1265), "html", null, true);
yield "',
priceMax: '";
// line 1266
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1266), "query", [], "any", false, false, false, 1266), "get", ["price_max", ""], "method", false, false, false, 1266), "html", null, true);
yield "',
page: ";
// line 1267
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(($context["currentPage"] ?? null), "html", null, true);
yield ",
q: '";
// line 1268
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1268), "query", [], "any", false, false, false, 1268), "get", ["q", ""], "method", false, false, false, 1268), "html", null, true);
yield "',
// Nouveaux filtres depuis l'URL
shop: '";
// line 1270
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1270), "query", [], "any", false, false, false, 1270), "get", ["shop", ""], "method", false, false, false, 1270), "html", null, true);
yield "',
featured: '";
// line 1271
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1271), "query", [], "any", false, false, false, 1271), "get", ["featured", ""], "method", false, false, false, 1271), "html", null, true);
yield "',
digital: '";
// line 1272
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1272), "query", [], "any", false, false, false, 1272), "get", ["digital", ""], "method", false, false, false, 1272), "html", null, true);
yield "',
stockStatus: '";
// line 1273
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1273), "query", [], "any", false, false, false, 1273), "get", ["stock_status", ""], "method", false, false, false, 1273), "html", null, true);
yield "',
ratingMin: '";
// line 1274
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1274), "query", [], "any", false, false, false, 1274), "get", ["rating_min", ""], "method", false, false, false, 1274), "html", null, true);
yield "',
rating: '";
// line 1275
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1275), "query", [], "any", false, false, false, 1275), "get", ["rating_min", ""], "method", false, false, false, 1275), "html", null, true);
yield "',
weightMin: '";
// line 1276
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1276), "query", [], "any", false, false, false, 1276), "get", ["weight_min", ""], "method", false, false, false, 1276), "html", null, true);
yield "',
weightMax: '";
// line 1277
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1277), "query", [], "any", false, false, false, 1277), "get", ["weight_max", ""], "method", false, false, false, 1277), "html", null, true);
yield "',
color: '";
// line 1278
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1278), "query", [], "any", false, false, false, 1278), "get", ["color", ""], "method", false, false, false, 1278), "html", null, true);
yield "',
size: '";
// line 1279
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1279), "query", [], "any", false, false, false, 1279), "get", ["size", ""], "method", false, false, false, 1279), "html", null, true);
yield "',
material: '";
// line 1280
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1280), "query", [], "any", false, false, false, 1280), "get", ["material", ""], "method", false, false, false, 1280), "html", null, true);
yield "',
condition: '";
// line 1281
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1281), "query", [], "any", false, false, false, 1281), "get", ["condition", ""], "method", false, false, false, 1281), "html", null, true);
yield "',
availability: '";
// line 1282
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, ($context["app"] ?? null), "request", [], "any", false, false, false, 1282), "query", [], "any", false, false, false, 1282), "get", ["availability", ""], "method", false, false, false, 1282), "html", null, true);
yield "'
};
}
// Fonction pour appliquer les filtres
function applyFilters() {
const url = new URL('";
// line 1288
yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("ui_api_products_filter");
yield "', window.location.origin);
// Ajouter les paramètres
Object.keys(currentFilters).forEach(key => {
if (currentFilters[key] && currentFilters[key] !== '') { // Mapper les clés pour l'API
let apiKey = key;
if (key === 'priceMin') {
apiKey = 'price_min';
} else if (key === 'priceMax') {
apiKey = 'price_max';
} else if (key === 'ratingMin') {
apiKey = 'rating_min';
} else if (key === 'weightMin') {
apiKey = 'weight_min';
} else if (key === 'weightMax') {
apiKey = 'weight_max';
} else if (key === 'stockStatus') {
apiKey = 'stock_status';
}
url.searchParams.set(apiKey, currentFilters[key]);
}
});
// Afficher le loader
document.getElementById('productsContainer').innerHTML = '<div class=\"col-12 text-center\"><i class=\"fa fa-spinner fa-spin\"></i> Chargement...</div>';
// Faire la requête AJAX
fetch(url).then(response => response.json()).then(data => {
if (data.success) { // Mettre à jour les produits
document.getElementById('productsContainer').innerHTML = data.products;
// Mettre à jour la pagination
currentPage = data.pagination.currentPage;
totalPages = data.pagination.totalPages;
hasMoreProducts = currentPage < totalPages;
// Préserver l'état des filtres statiques avant la mise à jour
const preservedFilters = {
featured: currentFilters.featured,
digital: currentFilters.digital,
availability: currentFilters.availability,
rating: currentFilters.rating || currentFilters.ratingMin
};
// Mettre à jour les marques disponibles (toujours afficher toutes)
updateAvailableBrands(data.availableBrands || []);
// Mettre à jour les conditions disponibles (toujours afficher toutes)
updateAvailableConditions(data.availableConditions || []);
// Mettre à jour les boutiques disponibles (toujours afficher toutes)
updateAvailableShops(data.availableShops || []);
// Mettre à jour les attributs disponibles (toujours afficher tous)
updateAvailableAttributes(data.availableAttributes || {});
// Restaurer l'état des filtres statiques après la mise à jour
restoreStaticFiltersState(preservedFilters);
// Réinitialiser les filtres depuis currentFilters pour s'assurer qu'ils sont tous cochés
if (typeof initializeFiltersFromURL === 'function') {
initializeFiltersFromURL();
}
// Mettre à jour l'URL
updateURL();
// Mettre à jour l'affichage du bouton
updateLoadMoreButton();
// Réinitialiser les event listeners pour les nouveaux produits
const tempDiv = document.createElement('div');
tempDiv.innerHTML = data.products;
initializeProductEventListeners(tempDiv);
initializeProductImages(tempDiv);
// Mettre à jour les filtres actifs
if (typeof updateActiveFilters === 'function') {
updateActiveFilters();
}
}
}).catch(error => {
console.error('Erreur lors du filtrage:', error);
document.getElementById('productsContainer').innerHTML = '<div class=\"col-12 text-center text-danger\">Erreur lors du chargement des produits</div>';
});
}
// Exposer la fonction globalement
window.applyFilters = applyFilters;
// Fonction pour appliquer le tri
function applySorting() {
currentFilters.sort = document.getElementById('sortSelect').value;
currentFilters.page = 1;
applyFilters();
}
// Fonction pour appliquer le filtre de prix
function applyPriceFilter() {
currentFilters.priceMin = document.getElementById('priceMin').value;
currentFilters.priceMax = document.getElementById('priceMax').value;
currentFilters.page = 1;
applyFilters();
}
// Fonction pour appliquer le filtre de poids
function applyWeightFilter() {
currentFilters.weightMin = document.getElementById('weightMin').value;
currentFilters.weightMax = document.getElementById('weightMax').value;
currentFilters.page = 1;
applyFilters();
}
// Fonction pour changer de page
function changePage(page) {
currentFilters.page = page;
applyFilters();
}
// Fonction pour mettre à jour les marques disponibles
function updateAvailableBrands(brands) {
const brandsFilter = document.getElementById('brandsFilter');
const brandList = document.getElementById('brandList');
const currentBrandValue = currentFilters.brand || '';
// Toujours afficher le filtre des marques
brandsFilter.style.display = 'block';
// Si pas de marques disponibles, garder les marques existantes ou afficher un message
if (brands.length === 0) { // Ne pas réinitialiser si la liste existe déjà et a du contenu
if (brandList && brandList.children.length > 0) { // Juste mettre à jour les états cochés
const existingRadios = brandList.querySelectorAll('input[name=\"brand\"]');
existingRadios.forEach(radio => {
if (currentBrandValue && radio.value === currentBrandValue) {
radio.checked = true;
} else if (! currentBrandValue && radio.id === 'all-brands') {
radio.checked = true;
} else {
radio.checked = false;
}
});
return; // Garder les marques existantes
}
// Sinon, afficher un message
brandList.innerHTML = '<li class=\"filter-list\"><span class=\"text-muted\">Aucune marque disponible</span></li>';
return;
}
let html = '';
const isAllSelected = ! currentBrandValue || currentBrandValue === '';
html += `<li class=\"filter-list\"><input class=\"pixel-radio\" type=\"radio\" id=\"all-brands\" name=\"brand\" \${
isAllSelected ? 'checked' : ''
}><label for=\"all-brands\">Toutes les marques</label></li>`;
brands.forEach(brand => {
const isSelected = currentBrandValue === brand.slug;
html += `<li class=\"filter-list\">
<input class=\"pixel-radio\" type=\"radio\" id=\"brand-\${
brand.id
}\" name=\"brand\" value=\"\${
brand.slug
}\" \${
isSelected ? 'checked' : ''
}>
<label for=\"brand-\${
brand.id
}\">\${
brand.name
}<span>(\${
brand.productCount
})</span></label>
</li>`;
});
brandList.innerHTML = html;
// Ajouter les event listeners
brandList.querySelectorAll('input[name=\"brand\"]').forEach(radio => {
radio.addEventListener('change', function () {
if (this.id === 'all-brands') {
currentFilters.brand = '';
} else {
currentFilters.brand = this.value;
} currentFilters.page = 1;
applyFilters();
});
});
}
// Fonction pour mettre à jour les conditions disponibles
function updateAvailableConditions(conditions) {
const conditionList = document.getElementById('conditionList');
const currentConditionValue = currentFilters.condition || '';
// Toujours garder le contenu statique et juste mettre à jour les états cochés
if (conditionList && conditionList.children.length > 0) {
const existingRadios = conditionList.querySelectorAll('input[name=\"condition\"]');
existingRadios.forEach(radio => {
if (currentConditionValue && radio.value === currentConditionValue) {
radio.checked = true;
} else if (! currentConditionValue && radio.id === 'all-conditions') {
radio.checked = true;
} else {
radio.checked = false;
}
});
return; // Garder les conditions existantes
}
// Si pas de contenu statique, générer dynamiquement
if (conditions.length === 0) {
conditionList.innerHTML = '<li class=\"filter-list\"><span class=\"text-muted\">Aucune condition disponible</span></li>';
return;
}
let html = '';
const isAllSelected = ! currentConditionValue || currentConditionValue === '';
html += `<li class=\"filter-list\"><input class=\"pixel-radio\" type=\"radio\" id=\"all-conditions\" name=\"condition\" \${
isAllSelected ? 'checked' : ''
}><label for=\"all-conditions\">Toutes les conditions</label></li>`;
conditions.forEach(condition => {
const isSelected = currentConditionValue === condition.slug;
html += `<li class=\"filter-list\">
<input class=\"pixel-radio\" type=\"radio\" id=\"condition-\${
condition.id
}\" name=\"condition\" value=\"\${
condition.slug
}\" \${
isSelected ? 'checked' : ''
}>
<label for=\"condition-\${
condition.id
}\">\${
condition.name
}<span>(\${
condition.productCount
})</span></label>
</li>`;
});
conditionList.innerHTML = html;
// Ajouter les event listeners
conditionList.querySelectorAll('input[name=\"condition\"]').forEach(radio => {
radio.addEventListener('change', function () {
if (this.id === 'all-conditions') {
currentFilters.condition = '';
} else {
currentFilters.condition = this.value;
} currentFilters.page = 1;
applyFilters();
});
});
}
// Fonction pour mettre à jour les boutiques disponibles
function updateAvailableShops(shops) {
const shopsFilter = document.getElementById('shopsFilter');
const shopList = document.getElementById('shopList');
const currentShopValue = currentFilters.shop || '';
// Toujours afficher le filtre des boutiques
shopsFilter.style.display = 'block';
// Si pas de boutiques disponibles, afficher un message ou garder les boutiques existantes
if (shops.length === 0) { // Ne pas réinitialiser si la liste existe déjà et a du contenu
if (shopList && shopList.children.length > 0) {
return; // Garder les boutiques existantes
}
// Sinon, afficher un message
shopList.innerHTML = '<li class=\"filter-list\"><span class=\"text-muted\">Aucune boutique disponible</span></li>';
return;
}
let html = '';
const isAllSelected = ! currentShopValue || currentShopValue === '';
html += `<li class=\"filter-list\"><input class=\"pixel-radio\" type=\"radio\" id=\"all-shops\" name=\"shop\" \${
isAllSelected ? 'checked' : ''
}><label for=\"all-shops\">Toutes les boutiques</label></li>`;
shops.forEach(shop => {
const isSelected = currentShopValue === shop.slug;
html += `<li class=\"filter-list\">
<input class=\"pixel-radio\" type=\"radio\" id=\"shop-\${
shop.id
}\" name=\"shop\" value=\"\${
shop.slug
}\" \${
isSelected ? 'checked' : ''
}>
<label for=\"shop-\${
shop.id
}\">\${
shop.name
}<span>(\${
shop.productCount
})</span></label>
</li>`;
});
shopList.innerHTML = html;
// Mettre à jour aussi le modal
const modalShopList = document.getElementById('modalShopList');
if (modalShopList) {
modalShopList.innerHTML = html.replace(/id=\"all-shops\"/g, 'id=\"modal-all-shops\"').replace(/id=\"shop-/g, 'id=\"modal-shop-').replace(/name=\"shop\"/g, 'name=\"modal-shop\"').replace(/for=\"all-shops\"/g, 'for=\"modal-all-shops\"').replace(/for=\"shop-/g, 'for=\"modal-shop-');
}
// Ajouter les event listeners (seulement pour la sidebar, le modal gère ses propres listeners)
shopList.querySelectorAll('input[name=\"shop\"]').forEach(radio => {
radio.addEventListener('change', function () {
if (this.id === 'all-shops') {
currentFilters.shop = '';
} else {
currentFilters.shop = this.value;
} currentFilters.page = 1;
applyFilters();
});
});
}
// Fonction pour mettre à jour les attributs disponibles
function updateAvailableAttributes(attributes) {
// Toujours afficher tous les filtres d'attributs, même s'ils ne sont pas pertinents
// Couleurs
updateAttributeFilter('colors', attributes.colors, 'colorList', 'colorsFilter');
// Tailles
updateAttributeFilter('sizes', attributes.sizes, 'sizeList', 'sizesFilter');
// Matériaux
updateAttributeFilter('materials', attributes.materials, 'materialList', 'materialsFilter');
// Conditions
updateAttributeFilter('conditions', attributes.conditions, 'conditionList', 'conditionsFilter');
}
// Fonction générique pour mettre à jour les filtres d'attributs
function updateAttributeFilter(attributeType, attributes, listId, filterId) {
const filter = document.getElementById(filterId);
const list = document.getElementById(listId);
const currentValue = currentFilters[attributeType] || '';
// Toujours afficher les filtres d'attributs
filter.style.display = 'block';
// Si pas d'attributs disponibles, afficher un message ou garder les attributs existants
if (! attributes || attributes.length === 0) { // Ne pas réinitialiser si la liste existe déjà et a du contenu
if (list && list.children.length > 0) {
return; // Garder les attributs existants
}
// Sinon, afficher un message
list.innerHTML = '<li class=\"filter-list\"><span class=\"text-muted\">Aucun attribut disponible</span></li>';
return;
}
let html = '';
const isAllSelected = ! currentValue || currentValue === '';
html += `<li class=\"filter-list\"><input class=\"pixel-radio\" type=\"radio\" id=\"all-\${attributeType}\" name=\"\${attributeType}\" \${
isAllSelected ? 'checked' : ''
}><label for=\"all-\${attributeType}\">Tous</label></li>`;
attributes.forEach(attr => {
const isSelected = currentValue === attr.value;
html += `<li class=\"filter-list\">
<input class=\"pixel-radio\" type=\"radio\" id=\"\${attributeType}-\${
attr.value
}\" name=\"\${attributeType}\" value=\"\${
attr.value
}\" \${
isSelected ? 'checked' : ''
}>
<label for=\"\${attributeType}-\${
attr.value
}\">\${
attr.value
}<span>(\${
attr.count
})</span></label>
</li>`;
});
list.innerHTML = html;
// Mettre à jour aussi le modal (si l'élément existe)
const modalListId = 'modal' + listId.charAt(0).toUpperCase() + listId.slice(1); // modalColorList, modalSizeList, etc.
const modalList = document.getElementById(modalListId);
if (modalList) { // Adapter le HTML pour le modal (changer les IDs et names)
let modalHtml = html.replace(new RegExp (`id=\"all-\${attributeType}\"`, 'g'), `id=\"modal-all-\${attributeType}\"`).replace(new RegExp (`id=\"\${attributeType}-`, 'g'), `id=\"modal-\${attributeType}-`).replace(new RegExp (`name=\"\${attributeType}\"`, 'g'), `name=\"modal-\${attributeType}\"`).replace(new RegExp (`for=\"all-\${attributeType}\"`, 'g'), `for=\"modal-all-\${attributeType}\"`).replace(new RegExp (`for=\"\${attributeType}-`, 'g'), `for=\"modal-\${attributeType}-`);
modalList.innerHTML = modalHtml;
}
// Ajouter les event listeners (seulement pour la sidebar, le modal gère ses propres listeners)
list.querySelectorAll (`input[name=\"\${attributeType}\"]`).forEach(radio => {
radio.addEventListener('change', function () {
if (this.id === `all-\${attributeType}`) {
currentFilters[attributeType] = '';
} else {
currentFilters[attributeType] = this.value;
} currentFilters.page = 1;
applyFilters();
});
});
} else {
filter.style.display = 'none';
}
}
// Fonction pour mettre à jour l'URL
function updateURL () {
const url = new URL(window.location);
// Supprimer les anciens paramètres
const paramsToRemove = [
'category',
'brand',
'sort',
'price_min',
'price_max',
'page',
'shop',
'featured',
'digital',
'stock_status',
'rating_min',
'weight_min',
'weight_max',
'color',
'size',
'material',
'condition',
'availability'
];
paramsToRemove.forEach(param => url.searchParams.delete(param));
// Ajouter les nouveaux paramètres
Object.keys(currentFilters).forEach(key => {
if (currentFilters[key]) {
url.searchParams.set(key, currentFilters[key]);
}
});
// Mettre à jour l'URL sans recharger la page
window.history.pushState({}, '', url);
}
// Fonction pour restaurer l'état des filtres statiques
function restoreStaticFiltersState (preservedFilters) { // Restaurer featured
if (preservedFilters.featured) {
const featuredInput = document.querySelector (`input[name=\"featured\"][value=\"\${
preservedFilters.featured
}\"]`);
if (featuredInput) {
featuredInput.checked = true;
} else {
const featuredAll = document.getElementById('featured-all');
if (featuredAll)
featuredAll.checked = true;
}
} else {
const featuredAll = document.getElementById('featured-all');
if (featuredAll)
featuredAll.checked = true;
}
// Restaurer digital
if (preservedFilters.digital) {
const digitalInput = document.querySelector (`input[name=\"digital\"][value=\"\${
preservedFilters.digital
}\"]`);
if (digitalInput) {
digitalInput.checked = true;
} else {
const digitalAll = document.getElementById('digital-all');
if (digitalAll)
digitalAll.checked = true;
}
} else {
const digitalAll = document.getElementById('digital-all');
if (digitalAll)
digitalAll.checked = true;
}
// Restaurer availability
if (preservedFilters.availability) {
const availabilityInput = document.querySelector (`input[name=\"availability\"][value=\"\${
preservedFilters.availability
}\"]`);
if (availabilityInput) {
availabilityInput.checked = true;
} else {
const availabilityAll = document.getElementById('availability-all');
if (availabilityAll)
availabilityAll.checked = true;
}
} else {
const availabilityAll = document.getElementById('availability-all');
if (availabilityAll)
availabilityAll.checked = true;
}
// Restaurer rating (mapping vers ratingMin)
if (preservedFilters.rating) {
const ratingInput = document.querySelector (`input[name=\"rating\"][value=\"\${
preservedFilters.rating
}\"]`);
if (ratingInput) {
ratingInput.checked = true;
} else {
const ratingAll = document.getElementById('rating-all');
if (ratingAll)
ratingAll.checked = true;
}
} else {
const ratingAll = document.getElementById('rating-all');
if (ratingAll)
ratingAll.checked = true;
}
}
// Fonction pour initialiser tous les filtres avec les valeurs de l'URL
function initializeFiltersFromURL () { // Initialiser les filtres statiques
const staticFilters = {
featured: currentFilters.featured || '',
digital: currentFilters.digital || '',
availability: currentFilters.availability || '',
rating: currentFilters.rating || currentFilters.ratingMin || ''
};
// Cocher les filtres statiques
Object.keys(staticFilters).forEach(filterName => {
const value = staticFilters[filterName];
if (value) {
const input = document.querySelector(`input[name=\"\${filterName}\"][value=\"\${value}\"]`);
if (input) {
input.checked = true;
} else { // Cocher \"all\" si la valeur n'existe pas
const allInput = document.getElementById (`\${filterName}-all`);
if (allInput)
allInput.checked = true;
}
} else {
const allInput = document.getElementById (`\${filterName}-all`);
if (allInput)
allInput.checked = true;
}
});
// Initialiser les filtres de poids
if (currentFilters.weightMin) {
const weightMinInput = document.getElementById('weightMin');
if (weightMinInput)
weightMinInput.value = currentFilters.weightMin;
}
if (currentFilters.weightMax) {
const weightMaxInput = document.getElementById('weightMax');
if (weightMaxInput)
weightMaxInput.value = currentFilters.weightMax;
}
// Initialiser les filtres de marque (si déjà chargés)
if (currentFilters.brand) {
const brandInput = document.querySelector (`input[name=\"brand\"][value=\"\${
currentFilters.brand
}\"]`);
if (brandInput) {
brandInput.checked = true;
} else {
const allBrands = document.getElementById('all-brands');
if (allBrands)
allBrands.checked = true;
}
}
// Initialiser les filtres de boutique (si déjà chargés)
if (currentFilters.shop) {
const shopInput = document.querySelector (`input[name=\"shop\"][value=\"\${
currentFilters.shop
}\"]`);
if (shopInput) {
shopInput.checked = true;
} else {
const allShops = document.getElementById('all-shops');
if (allShops)
allShops.checked = true;
}
}
// Initialiser les filtres d'attributs (si déjà chargés)
['color', 'size', 'material', 'condition'].forEach(attrType => {
if (currentFilters[attrType]) {
const attrInput = document.querySelector(`input[name=\"\${attrType}\"][value=\"\${
currentFilters[attrType]
}\"]`);
if (attrInput) {
attrInput.checked = true;
} else {
const allAttr = document.getElementById (`all-\${attrType}`);
if (allAttr)
allAttr.checked = true;
}
}
});
}
// Initialiser les filtres
document.addEventListener('DOMContentLoaded', function () { // Initialiser les filtres depuis l'URL
initializeFiltersFromURL();
// Event listeners pour les filtres statiques
const staticFilters = ['featured', 'digital', 'availability'];
staticFilters.forEach(filterName => {
const inputs = document.querySelectorAll (`input[name=\"\${filterName}\"]`);
inputs.forEach(input => {
input.addEventListener('change', function () {
if (this.id.includes('-all')) {
currentFilters[filterName] = '';
} else {
currentFilters[filterName] = this.value;
}
currentFilters.page = 1;
applyFilters();
});
});
});
// Event listener spécial pour rating (mapping vers ratingMin)
const ratingInputs = document.querySelectorAll('input[name=\"rating\"]');
ratingInputs.forEach(input => {
input.addEventListener('change', function () {
if (this.id === 'rating-all') {
currentFilters.ratingMin = '';
currentFilters.rating = '';
} else {
currentFilters.ratingMin = this.value;
currentFilters.rating = this.value;
}
currentFilters.page = 1;
applyFilters();
});
});
// Event listeners pour les filtres de poids
const weightInputs = ['weightMin', 'weightMax'];
weightInputs.forEach(inputId => {
const input = document.getElementById(inputId);
if (input) {
input.addEventListener('change', applyWeightFilter);
input.addEventListener('input', debounce(applyWeightFilter, 500));
}
});
// Event listeners pour les filtres de prix
const priceInputs = ['priceMin', 'priceMax'];
priceInputs.forEach(inputId => {
const input = document.getElementById(inputId);
if (input) {
input.addEventListener('change', applyPriceFilter);
input.addEventListener('input', debounce(applyPriceFilter, 500));
}
});
// Ajouter les event listeners pour les marques existantes
const brandList = document.getElementById('brandList');
if (brandList) {
brandList.querySelectorAll('input[name=\"brand\"]').forEach(radio => {
radio.addEventListener('change', function () {
if (this.id === 'all-brands') {
currentFilters.brand = '';
} else {
currentFilters.brand = this.value;
}
currentFilters.page = 1;
applyFilters();
});
});
}
// Appliquer les filtres initiaux si une catégorie est sélectionnée
if (currentFilters.category) {
applyFilters();
} else { // Initialiser l'affichage du bouton au chargement de la page
updateLoadMoreButton();
}
});
// Fonction de debounce pour éviter trop de requêtes
function debounce (func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// Les fonctions toggleComparison, toggleWishlist, et showNotification sont définies globalement dans base_home.html.twig
// Pas besoin de les redéfinir ici
// Fonctions pour le dropshipping
function generateDropshipLink (productId) {
showEbayPromptModal('URL originale (optionnel):', '').then(originalUrl => {
if (originalUrl === null)
return;
// Utilisateur a annulé
const formData = new FormData();
formData.append('originalUrl', originalUrl || '');
fetch (`/api/dropship/generate/\${productId}`, {
method: 'POST',
body: formData
}).then(response => response.json()).then(data => {
if (data.success) { // Afficher le lien généré dans une modal
showDropshipLinkModal(data.data);
} else {
showNotification(data.message || 'Erreur lors de la génération du lien', 'error');
}
}).catch(error => {
console.error('Erreur:', error);
showNotification('Erreur lors de la génération du lien', 'error');
});
});
}
function showDropshipLinkModal (linkData) {
const modal = document.createElement('div');
modal.className = 'modal fade show';
modal.style.display = 'block';
modal.innerHTML = `
<div class=\"modal-dialog\">
<div class=\"modal-content\">
<div class=\"modal-header\">
<h5 class=\"modal-title\">
<i class=\"fa fa-share-alt\"></i> Lien de dropshipping généré
</h5>
<button type=\"button\" class=\"btn-close\" onclick=\"closeModal(this)\"></button>
</div>
<div class=\"modal-body\">
<div class=\"mb-3\">
<label class=\"form-label\">Lien de dropshipping :</label>
<div class=\"input-group\">
<input type=\"text\" class=\"form-control\" value=\"\${
linkData.dropshipUrl
}\" readonly id=\"dropshipUrl\">
<button class=\"btn btn-outline-secondary\" onclick=\"copyToClipboard('\${
linkData.dropshipUrl
}')\">
<i class=\"fa fa-copy\"></i>
</button>
</div>
</div>
<div class=\"row\">
<div class=\"col-md-6\">
<div class=\"card\">
<div class=\"card-body text-center\">
<h6 class=\"card-title\">Taux de commission</h6>
<h4 class=\"text-primary\">\${
linkData.commissionRate
}%</h4>
</div>
</div>
</div>
<div class=\"col-md-6\">
<div class=\"card\">
<div class=\"card-body text-center\">
<h6 class=\"card-title\">Commission par vente</h6>
<h4 class=\"text-success\">\${
linkData.commissionAmount
} HTG</h4>
</div>
</div>
</div>
</div>
<div class=\"alert alert-info\">
<i class=\"fa fa-info-circle\"></i>
<strong>Note :</strong> Ce lien expire le \${
new Date(linkData.expiresAt).toLocaleDateString('fr-FR')
}.
</div>
</div>
<div class=\"modal-footer\">
<button type=\"button\" class=\"btn btn-secondary\" onclick=\"closeModal(this)\">Fermer</button>
<a href=\"/dropship/dashboard\" class=\"btn btn-primary\">
<i class=\"fa fa-tachometer\"></i> Voir le dashboard
</a>
</div>
</div>
</div>
`;
document.body.appendChild(modal);
// Ajouter le backdrop
const backdrop = document.createElement('div');
backdrop.className = 'modal-backdrop fade show';
document.body.appendChild(backdrop);
}
function closeModal (button) {
const modal = button.closest('.modal');
const backdrop = document.querySelector('.modal-backdrop');
if (modal) {
modal.remove();
}
if (backdrop) {
backdrop.remove();
}
}
function copyToClipboard (text) {
navigator.clipboard.writeText(text).then(function () {
showNotification('Lien copié dans le presse-papiers !', 'success');
}, function (err) {
console.error('Erreur lors de la copie:', err);
showNotification('Erreur lors de la copie du lien', 'error');
});
}
// Fonction pour initialiser le chargement infini
function initInfiniteScroll () {
const loader = document.getElementById('infiniteScrollLoader');
const noMoreProducts = document.getElementById('noMoreProducts');
// Afficher le loader si il y a plus de produits
if (hasMoreProducts && loader) {
loader.style.display = 'block';
} else if (!hasMoreProducts && noMoreProducts) {
noMoreProducts.style.display = 'block';
}
// Observer pour détecter quand l'utilisateur arrive en bas
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting && !isLoading && hasMoreProducts) {
loadMoreProducts();
}
});
}, {
root: null,
rootMargin: '200px', // Démarrer le chargement 200px avant d'arriver en bas
threshold: 0.1
});
// Observer le loader
if (loader) {
observer.observe(loader);
}
}
// Fonction pour mettre à jour l'affichage du bouton
function updateLoadMoreButton () {
const loadMoreContainer = document.getElementById('loadMoreContainer');
const noMoreProducts = document.getElementById('noMoreProducts');
if (hasMoreProducts) {
if (loadMoreContainer) {
loadMoreContainer.style.display = 'block';
}
if (noMoreProducts) {
noMoreProducts.style.display = 'none';
}
} else {
if (loadMoreContainer) {
loadMoreContainer.style.display = 'none';
}
if (noMoreProducts) {
noMoreProducts.style.display = 'block';
}
}
}
// Fonction pour initialiser les images des nouveaux produits
function initializeProductImages (container) {
const productCards = container.querySelectorAll('.single-product');
productCards.forEach(card => {
const productId = card.querySelector('.add-to-cart') ?. getAttribute('data-product-id');
if (productId) { // Récupérer les images depuis les attributs data ou depuis le DOM
const imgElement = card.querySelector('.main-product-img');
if (imgElement && imgElement.dataset.images) {
const images = JSON.parse(imgElement.dataset.images);
productImages[productId] = images;
currentImageIndex[productId] = 0;
}
}
});
}
// Fonction pour initialiser les event listeners des nouveaux produits
function initializeProductEventListeners (container) { // Boutons d'ajout au panier
const cartButtons = container.querySelectorAll('.add-to-cart');
cartButtons.forEach(button => {
button.addEventListener('click', function () {
const productId = this.getAttribute('data-product-id');
const qty = this.getAttribute('data-qty');
fetch('";
// line 2206
yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("ui_cart_add");
yield "', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: 'productId=' + productId + '&qty=' + qty
}).then(response => response.json()).then(data => {
if (data.ok) {
showEbayModal('Produit ajouté au panier !', 'success');
const cartBadge = document.querySelector('.cart-badge');
if (cartBadge) {
cartBadge.textContent = data.totalQty;
}
} else {
showEbayModal(data.message || 'Erreur lors de l\\'ajout au panier', 'error');
}
}).catch(error => {
console.error('Erreur:', error);
showEbayModal('Erreur lors de l\\'ajout au panier', 'error');
});
});
});
}
// La fonction showEbayModal est déjà définie plus haut
// Modal style eBay pour remplacer prompt()
function showEbayPromptModal (message, defaultValue = '') {
return new Promise((resolve) => {
const modalId = 'ebayPromptModal';
let existingModal = document.getElementById(modalId);
if (existingModal) {
existingModal.remove();
}
const modal = document.createElement('div');
modal.id = modalId;
modal.className = 'modal fade';
modal.setAttribute('tabindex', '-1');
modal.setAttribute('aria-labelledby', 'ebayPromptModalLabel');
modal.setAttribute('aria-hidden', 'true');
modal.innerHTML = `
<div class=\"modal-dialog modal-dialog-centered\">
<div class=\"modal-content\" style=\"border-radius: 8px; border: none; box-shadow: 0 4px 20px rgba(0,0,0,0.15);\">
<div class=\"modal-header\" style=\"border-bottom: 1px solid #e0e0e0; padding: 20px 24px;\">
<h5 class=\"modal-title\" id=\"ebayPromptModalLabel\" style=\"font-weight: 600; font-size: 18px; color: #333;\">
<i class=\"ti-pencil-alt\" style=\"color: #0064D2; margin-right: 8px;\"></i>Saisie
</h5>
<button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\" aria-label=\"Close\" style=\"margin: 0;\"></button>
</div>
<div class=\"modal-body\" style=\"padding: 24px;\">
<p style=\"margin-bottom: 16px; font-size: 16px; color: #333;\">\${message}</p>
<input type=\"text\" class=\"form-control\" id=\"ebayPromptInput\" value=\"\${defaultValue}\" style=\"border-radius: 4px; border: 1px solid #ccc; padding: 10px; font-size: 14px;\" autofocus>
</div>
<div class=\"modal-footer\" style=\"border-top: 1px solid #e0e0e0; padding: 16px 24px; justify-content: flex-end;\">
<button type=\"button\" class=\"btn btn-secondary\" data-bs-dismiss=\"modal\" style=\"min-width: 80px; border-radius: 4px; font-weight: 500; margin-right: 8px;\">
Annuler
</button>
<button type=\"button\" class=\"btn btn-primary\" id=\"ebayPromptConfirm\" style=\"min-width: 80px; background-color: #0064D2; border-color: #0064D2; border-radius: 4px; font-weight: 500;\">
OK
</button>
</div>
</div>
</div>
`;
document.body.appendChild(modal);
const bsModal = new bootstrap.Modal(modal);
const input = modal.querySelector('#ebayPromptInput');
const confirmBtn = modal.querySelector('#ebayPromptConfirm');
// Gérer la confirmation
confirmBtn.addEventListener('click', function () {
const value = input.value;
bsModal.hide();
resolve(value);
});
// Gérer l'annulation
modal.addEventListener('hidden.bs.modal', function () {
if (input.value === undefined || input.value === '') {
resolve(null);
}
modal.remove();
});
// Gérer la touche Entrée
input.addEventListener('keypress', function (e) {
if (e.key === 'Enter') {
confirmBtn.click();
}
});
bsModal.show();
input.focus();
input.select();
});
}
// Remplacer window.alert et window.prompt
window.alert = showEbayModal;
window.prompt = showEbayPromptModal;
</script>
<script>
\t// Gestion du toggle de la sidebar sur mobile
document.addEventListener('DOMContentLoaded', function () {
const sidebarToggle = document.querySelector('.listing-sidebar-toggle');
const sidebarCollapse = document.getElementById('listingSidebarCollapse');
if (sidebarToggle && sidebarCollapse) { // Bootstrap 5 utilise des événements natifs
sidebarCollapse.addEventListener('show.bs.collapse', function () {
sidebarToggle.classList.remove('collapsed');
sidebarToggle.setAttribute('aria-expanded', 'true');
});
sidebarCollapse.addEventListener('hide.bs.collapse', function () {
sidebarToggle.classList.add('collapsed');
sidebarToggle.setAttribute('aria-expanded', 'false');
});
sidebarCollapse.addEventListener('shown.bs.collapse', function () {
sidebarToggle.classList.remove('collapsed');
});
sidebarCollapse.addEventListener('hidden.bs.collapse', function () {
sidebarToggle.classList.add('collapsed');
});
// Vérifier l'état initial
if (sidebarCollapse.classList.contains('show')) {
sidebarToggle.classList.remove('collapsed');
sidebarToggle.setAttribute('aria-expanded', 'true');
} else {
sidebarToggle.classList.add('collapsed');
sidebarToggle.setAttribute('aria-expanded', 'false');
}
}
});
// Synchroniser la recherche avec la barre de recherche du header
const headerSearchInput = document.getElementById('search_input');
if (headerSearchInput && typeof currentFilters !== 'undefined') { // Mettre à jour la valeur de la barre de recherche du header
headerSearchInput.value = currentFilters.q || '';
// Afficher le bouton clear si nécessaire
const clearSearchBtn = document.getElementById('clear_search_btn');
if (clearSearchBtn) {
clearSearchBtn.style.display = currentFilters.q ? 'block' : 'none';
}
}
// Réinitialiser tous les filtres
const resetFiltersBtn = document.getElementById('resetFiltersBtn');
if (resetFiltersBtn) {
resetFiltersBtn.addEventListener('click', function () {
resetAllFilters();
});
}
// Fonction pour réinitialiser tous les filtres
function resetAllFilters () {
currentFilters = {
category: '',
brand: '',
sort: 'newest',
priceMin: '',
priceMax: '',
page: 1,
q: '',
shop: '',
featured: '',
digital: '',
stockStatus: '',
ratingMin: '',
rating: '',
weightMin: '',
weightMax: '',
color: '',
size: '',
material: '',
condition: '',
availability: ''
};
// Réinitialiser la barre de recherche du header
const headerSearchInput = document.getElementById('search_input');
if (headerSearchInput) {
headerSearchInput.value = '';
}
const clearSearchBtn = document.getElementById('clear_search_btn');
if (clearSearchBtn) {
clearSearchBtn.style.display = 'none';
}
// Réinitialiser les inputs
document.getElementById('sortSelect').value = 'newest';
// Réinitialiser les radios
document.querySelectorAll('input[type=\"radio\"]').forEach(radio => {
if (radio.id.includes('all-') || radio.id.includes('featured-all') || radio.id.includes('digital-all') || radio.id.includes('availability-all') || radio.id.includes('rating-all')) {
radio.checked = true;
} else {
radio.checked = false;
}
});
// Réinitialiser les inputs de prix et poids
const weightMinInput = document.getElementById('weightMin');
const weightMaxInput = document.getElementById('weightMax');
if (weightMinInput)
weightMinInput.value = '';
if (weightMaxInput)
weightMaxInput.value = '';
applyFilters();
updateActiveFilters();
}
// Fonction pour mettre à jour l'affichage des filtres actifs
function updateActiveFilters () {
const activeFiltersDiv = document.getElementById('activeFilters');
const activeFiltersList = document.getElementById('activeFiltersList');
const filters = [];
if (currentFilters.q) {
filters.push (`<span class=\"badge bg-primary\">Recherche: \"\${
currentFilters.q
}\"</span>`);
}
if (currentFilters.category) {
filters.push(`<span class=\"badge bg-secondary\">Catégorie</span>`);
}
if (currentFilters.brand) {
filters.push(`<span class=\"badge bg-secondary\">Marque</span>`);
}
if (currentFilters.priceMin || currentFilters.priceMax) {
filters.push(`<span class=\"badge bg-info\">Prix</span>`);
}
if (currentFilters.featured === 'true') {
filters.push(`<span class=\"badge bg-warning\">Produits vedettes</span>`);
}
if (currentFilters.digital === 'true') {
filters.push(`<span class=\"badge bg-success\">Numériques</span>`);
}
if (currentFilters.digital === 'false') {
filters.push(`<span class=\"badge bg-success\">Physiques</span>`);
}
if (currentFilters.availability) {
filters.push(`<span class=\"badge bg-info\">Disponibilité</span>`);
}
if (currentFilters.ratingMin || currentFilters.rating) {
const ratingValue = currentFilters.ratingMin || currentFilters.rating;
filters.push (`<span class=\"badge bg-warning\">Note ≥ \${ratingValue}</span>`);
}
if (currentFilters.weightMin || currentFilters.weightMax) {
filters.push(`<span class=\"badge bg-secondary\">Poids</span>`);
}
if (filters.length > 0) {
activeFiltersList.innerHTML = filters.join(' ');
activeFiltersDiv.style.display = 'block';
} else {
activeFiltersDiv.style.display = 'none';
}
}
// Mettre à jour les filtres actifs au chargement et après chaque filtrage
document.addEventListener('DOMContentLoaded', function () {
updateActiveFilters();
});
// Mettre à jour les filtres actifs après chaque application de filtres
const originalApplyFilters = applyFilters;
applyFilters = function () {
originalApplyFilters();
setTimeout(updateActiveFilters, 100);
// Mettre à jour le compteur de filtres actifs
updateActiveFiltersCount();
};
// S'assurer que applyFilters est accessible globalement
window.applyFilters = applyFilters;
// Fonction pour mettre à jour le compteur de filtres actifs
function updateActiveFiltersCount () {
const count = Object.keys(currentFilters).filter(key => {
const value = currentFilters[key];
return value && value !== '' && key !== 'page' && key !== 'sort';
}).length;
const badge = document.getElementById('activeFiltersCount');
if (badge) {
if (count > 0) {
badge.textContent = count;
badge.style.display = 'inline-block';
} else {
badge.style.display = 'none';
}
}
}
// Initialiser le compteur au chargement
document.addEventListener('DOMContentLoaded', function () {
updateActiveFiltersCount();
});
</script>
<!-- Modal de filtres -->
<div class=\"modal fade\" id=\"filtersModal\" tabindex=\"-1\" aria-labelledby=\"filtersModalLabel\" aria-hidden=\"true\">
\t<div class=\"modal-dialog modal-lg\">
\t\t<div class=\"modal-content\" style=\"display: flex; flex-direction: column; max-height: 90vh;\">
\t\t\t<div class=\"modal-header\" style=\"flex-shrink: 0;\">
\t\t\t\t<h5 class=\"modal-title\" id=\"filtersModalLabel\">
\t\t\t\t\t<i class=\"lnr lnr-filter me-2\"></i>Filtres de recherche
\t\t\t\t</h5>
\t\t\t\t<button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\" aria-label=\"Close\"></button>
\t\t\t</div>
\t\t\t<div class=\"modal-body\" style=\"overflow-y: auto; flex: 1; min-height: 0;\">
\t\t\t\t<div
\t\t\t\t\tclass=\"row\">
\t\t\t\t\t<!-- Colonne gauche -->
\t\t\t\t\t<div
\t\t\t\t\t\tclass=\"col-md-6\">
\t\t\t\t\t\t<!-- Marques -->
\t\t\t\t\t\t<div class=\"common-filter mb-4\">
\t\t\t\t\t\t\t<div class=\"head\">Marques</div>
\t\t\t\t\t\t\t<ul class=\"brand-list\" id=\"modalBrandList\">
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-all-brands\" name=\"modal-brand\" checked>
\t\t\t\t\t\t\t\t\t<label for=\"modal-all-brands\">Toutes les marques</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t";
// line 2543
$context['_parent'] = $context;
$context['_seq'] = CoreExtension::ensureTraversable(($context["brands"] ?? null));
foreach ($context['_seq'] as $context["_key"] => $context["brand"]) {
// line 2544
yield "\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-brand-";
// line 2545
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["brand"], "id", [], "any", false, false, false, 2545), "html", null, true);
yield "\" name=\"modal-brand\" value=\"";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["brand"], "slug", [], "any", false, false, false, 2545), "html", null, true);
yield "\">
\t\t\t\t\t\t\t\t\t\t<label for=\"modal-brand-";
// line 2546
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["brand"], "id", [], "any", false, false, false, 2546), "html", null, true);
yield "\">";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["brand"], "name", [], "any", false, false, false, 2546), "html", null, true);
yield "<span>(";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["brand"], "getActiveProductsCount", [], "method", false, false, false, 2546), "html", null, true);
yield ")</span>
\t\t\t\t\t\t\t\t\t\t</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t";
}
$_parent = $context['_parent'];
unset($context['_seq'], $context['_key'], $context['brand'], $context['_parent']);
$context = array_intersect_key($context, $_parent) + $_parent;
// line 2550
yield "\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<!-- Conditions -->
\t\t\t\t\t\t<div class=\"common-filter mb-4\">
\t\t\t\t\t\t\t<div class=\"head\">Condition</div>
\t\t\t\t\t\t\t<ul class=\"condition-list\" id=\"modalConditionList\">
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-all-conditions\" name=\"modal-condition\" checked>
\t\t\t\t\t\t\t\t\t<label for=\"modal-all-conditions\">Toutes les conditions</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t";
// line 2561
$context['_parent'] = $context;
$context['_seq'] = CoreExtension::ensureTraversable(($context["conditions"] ?? null));
foreach ($context['_seq'] as $context["_key"] => $context["condition"]) {
// line 2562
yield "\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-condition-";
// line 2563
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["condition"], "id", [], "any", false, false, false, 2563), "html", null, true);
yield "\" name=\"modal-condition\" value=\"";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["condition"], "slug", [], "any", false, false, false, 2563), "html", null, true);
yield "\">
\t\t\t\t\t\t\t\t\t\t<label for=\"modal-condition-";
// line 2564
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["condition"], "id", [], "any", false, false, false, 2564), "html", null, true);
yield "\">";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["condition"], "name", [], "any", false, false, false, 2564), "html", null, true);
yield "<span>(";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["condition"], "getActiveProductsCount", [], "method", false, false, false, 2564), "html", null, true);
yield ")</span>
\t\t\t\t\t\t\t\t\t\t</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t";
}
$_parent = $context['_parent'];
unset($context['_seq'], $context['_key'], $context['condition'], $context['_parent']);
$context = array_intersect_key($context, $_parent) + $_parent;
// line 2568
yield "\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<!-- Boutiques -->
\t\t\t\t\t\t<div class=\"common-filter mb-4\">
\t\t\t\t\t\t\t<div class=\"head\">Boutiques</div>
\t\t\t\t\t\t\t<div id=\"modalShopsFilter\">
\t\t\t\t\t\t\t\t<ul
\t\t\t\t\t\t\t\t\tclass=\"shop-list\" id=\"modalShopList\"><!-- Les boutiques seront chargées dynamiquement -->
\t\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<!-- Produits vedettes -->
\t\t\t\t\t\t<div class=\"common-filter mb-4\">
\t\t\t\t\t\t\t<div class=\"head\">Produits vedettes</div>
\t\t\t\t\t\t\t<ul>
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-featured-all\" name=\"modal-featured\" checked>
\t\t\t\t\t\t\t\t\t<label for=\"modal-featured-all\">Tous les produits</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-featured-only\" name=\"modal-featured\" value=\"true\">
\t\t\t\t\t\t\t\t\t<label for=\"modal-featured-only\">Produits vedettes uniquement</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<!-- Type de produit -->
\t\t\t\t\t\t<div class=\"common-filter mb-4\">
\t\t\t\t\t\t\t<div class=\"head\">Type de produit</div>
\t\t\t\t\t\t\t<ul>
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-digital-all\" name=\"modal-digital\" checked>
\t\t\t\t\t\t\t\t\t<label for=\"modal-digital-all\">Tous les types</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-digital-physical\" name=\"modal-digital\" value=\"false\">
\t\t\t\t\t\t\t\t\t<label for=\"modal-digital-physical\">Produits physiques</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-digital-digital\" name=\"modal-digital\" value=\"true\">
\t\t\t\t\t\t\t\t\t<label for=\"modal-digital-digital\">Produits numériques</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t</div>
\t\t\t\t\t</div>
\t\t\t\t\t<!-- Colonne droite -->
\t\t\t\t\t<div
\t\t\t\t\t\tclass=\"col-md-6\">
\t\t\t\t\t\t<!-- Disponibilité -->
\t\t\t\t\t\t<div class=\"common-filter mb-4\">
\t\t\t\t\t\t\t<div class=\"head\">Disponibilité</div>
\t\t\t\t\t\t\t<ul>
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-availability-all\" name=\"modal-availability\" checked>
\t\t\t\t\t\t\t\t\t<label for=\"modal-availability-all\">Tous</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-availability-in-stock\" name=\"modal-availability\" value=\"in_stock\">
\t\t\t\t\t\t\t\t\t<label for=\"modal-availability-in-stock\">En stock</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-availability-low-stock\" name=\"modal-availability\" value=\"low_stock\">
\t\t\t\t\t\t\t\t\t<label for=\"modal-availability-low-stock\">Stock faible</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-availability-out-of-stock\" name=\"modal-availability\" value=\"out_of_stock\">
\t\t\t\t\t\t\t\t\t<label for=\"modal-availability-out-of-stock\">Rupture de stock</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<!-- Note minimale -->
\t\t\t\t\t\t<div class=\"common-filter mb-4\">
\t\t\t\t\t\t\t<div class=\"head\">Note minimale</div>
\t\t\t\t\t\t\t<ul>
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-rating-all\" name=\"modal-rating\" checked>
\t\t\t\t\t\t\t\t\t<label for=\"modal-rating-all\">Toutes les notes</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-rating-4\" name=\"modal-rating\" value=\"4\">
\t\t\t\t\t\t\t\t\t<label for=\"modal-rating-4\">4 étoiles et plus</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-rating-3\" name=\"modal-rating\" value=\"3\">
\t\t\t\t\t\t\t\t\t<label for=\"modal-rating-3\">3 étoiles et plus</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-rating-2\" name=\"modal-rating\" value=\"2\">
\t\t\t\t\t\t\t\t\t<label for=\"modal-rating-2\">2 étoiles et plus</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<!-- Prix -->
\t\t\t\t\t\t<div class=\"common-filter mb-4\">
\t\t\t\t\t\t\t<div class=\"head\">Prix (HTG)</div>
\t\t\t\t\t\t\t<div class=\"price-range-area\">
\t\t\t\t\t\t\t\t<div class=\"d-flex gap-3\">
\t\t\t\t\t\t\t\t\t<div class=\"flex-grow-1\">
\t\t\t\t\t\t\t\t\t\t<label class=\"form-label\">Min</label>
\t\t\t\t\t\t\t\t\t\t<input type=\"number\" class=\"form-control\" id=\"modal-priceMin\" placeholder=\"0\" min=\"0\" step=\"0.01\">
\t\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t\t\t<div class=\"flex-grow-1\">
\t\t\t\t\t\t\t\t\t\t<label class=\"form-label\">Max</label>
\t\t\t\t\t\t\t\t\t\t<input type=\"number\" class=\"form-control\" id=\"modal-priceMax\" placeholder=\"999999\" min=\"0\" step=\"0.01\">
\t\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<!-- Poids -->
\t\t\t\t\t\t<div class=\"common-filter mb-4\">
\t\t\t\t\t\t\t<div class=\"head\">Poids (kg)</div>
\t\t\t\t\t\t\t<div class=\"weight-range-area\">
\t\t\t\t\t\t\t\t<div class=\"d-flex gap-3\">
\t\t\t\t\t\t\t\t\t<div class=\"flex-grow-1\">
\t\t\t\t\t\t\t\t\t\t<label class=\"form-label\">Min</label>
\t\t\t\t\t\t\t\t\t\t<input type=\"number\" class=\"form-control\" id=\"modal-weightMin\" placeholder=\"0\" step=\"0.1\" min=\"0\">
\t\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t\t\t<div class=\"flex-grow-1\">
\t\t\t\t\t\t\t\t\t\t<label class=\"form-label\">Max</label>
\t\t\t\t\t\t\t\t\t\t<input type=\"number\" class=\"form-control\" id=\"modal-weightMax\" placeholder=\"100\" step=\"0.1\" min=\"0\">
\t\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<!-- Couleur -->
\t\t\t\t\t\t<div class=\"common-filter mb-4\">
\t\t\t\t\t\t\t<div class=\"head\">Couleur</div>
\t\t\t\t\t\t\t<div id=\"modalColorsFilter\">
\t\t\t\t\t\t\t\t<ul
\t\t\t\t\t\t\t\t\tclass=\"color-list\" id=\"modalColorList\"><!-- Les couleurs seront chargées dynamiquement -->
\t\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<!-- Taille -->
\t\t\t\t\t\t<div class=\"common-filter mb-4\">
\t\t\t\t\t\t\t<div class=\"head\">Taille</div>
\t\t\t\t\t\t\t<div id=\"modalSizesFilter\">
\t\t\t\t\t\t\t\t<ul
\t\t\t\t\t\t\t\t\tclass=\"size-list\" id=\"modalSizeList\"><!-- Les tailles seront chargées dynamiquement -->
\t\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<!-- Matériau -->
\t\t\t\t\t\t<div class=\"common-filter mb-4\">
\t\t\t\t\t\t\t<div class=\"head\">Matériau</div>
\t\t\t\t\t\t\t<div id=\"modalMaterialsFilter\">
\t\t\t\t\t\t\t\t<ul
\t\t\t\t\t\t\t\t\tclass=\"material-list\" id=\"modalMaterialList\"><!-- Les matériaux seront chargés dynamiquement -->
\t\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t</div>
\t\t\t\t\t</div>
\t\t\t\t</div>
\t\t\t</div>
\t\t\t<div class=\"modal-footer\" style=\"flex-shrink: 0; border-top: 1px solid #dee2e6; padding: 1rem 1.5rem; background: #f8f9fa;\">
\t\t\t\t<button type=\"button\" class=\"btn btn-secondary\" data-bs-dismiss=\"modal\">
\t\t\t\t\t<i class=\"lnr lnr-cross-circle me-1\"></i>Annuler
\t\t\t\t</button>
\t\t\t\t<button type=\"button\" class=\"btn btn-outline-danger\" id=\"modalResetFiltersBtn\">
\t\t\t\t\t<i class=\"lnr lnr-refresh me-1\"></i>Réinitialiser
\t\t\t\t</button>
\t\t\t\t<button type=\"button\" class=\"btn btn-primary\" id=\"modalApplyFiltersBtn\">
\t\t\t\t\t<i class=\"lnr lnr-checkmark-circle me-1\"></i>Appliquer les filtres
\t\t\t\t</button>
\t\t\t</div>
\t\t</div>
\t</div>
</div>
<script>
\t// Synchroniser les filtres du modal avec currentFilters au chargement
document.addEventListener('DOMContentLoaded', function () {
console.log('[Modal] Initializing filter modal...');
// Fonction pour synchroniser les valeurs du modal avec currentFilters
function syncModalFilters() {
console.log('[Modal] Syncing filters with currentFilters:', currentFilters);
// Réinitialiser tous les radios \"Tous\" d'abord
document.querySelectorAll('#filtersModal input[type=\"radio\"][id*=\"-all\"]').forEach(radio => {
radio.checked = true;
});
// Marques
if (currentFilters.brand) {
const brandRadio = document.querySelector (`#modalBrandList input[value=\"\${
currentFilters.brand
}\"]`);
if (brandRadio) {
brandRadio.checked = true;
console.log('[Modal] Brand synced:', currentFilters.brand);
}
} else {
const allBrands = document.getElementById('modal-all-brands');
if (allBrands)
allBrands.checked = true;
}
// Conditions
if (currentFilters.condition) {
const conditionRadio = document.querySelector (`#modalConditionList input[value=\"\${
currentFilters.condition
}\"]`);
if (conditionRadio) {
conditionRadio.checked = true;
console.log('[Modal] Condition synced:', currentFilters.condition);
}
} else {
const allConditions = document.getElementById('modal-all-conditions');
if (allConditions)
allConditions.checked = true;
}
// Featured
if (currentFilters.featured === 'true') {
const featuredRadio = document.getElementById('modal-featured-only');
if (featuredRadio) {
featuredRadio.checked = true;
console.log('[Modal] Featured synced');
}
} else {
const allFeatured = document.getElementById('modal-featured-all');
if (allFeatured)
allFeatured.checked = true;
}
// Digital
if (currentFilters.digital === 'true') {
const digitalRadio = document.getElementById('modal-digital-digital');
if (digitalRadio)
digitalRadio.checked = true;
} else if (currentFilters.digital === 'false') {
const physicalRadio = document.getElementById('modal-digital-physical');
if (physicalRadio)
physicalRadio.checked = true;
} else {
const allDigital = document.getElementById('modal-digital-all');
if (allDigital)
allDigital.checked = true;
}
// Availability
if (currentFilters.availability) {
const availabilityId = `modal-availability-\${
currentFilters.availability.replace('_', '-')
}`;
const availabilityRadio = document.getElementById(availabilityId);
if (availabilityRadio) {
availabilityRadio.checked = true;
console.log('[Modal] Availability synced:', currentFilters.availability);
}
} else {
const allAvailability = document.getElementById('modal-availability-all');
if (allAvailability)
allAvailability.checked = true;
}
// Rating
if (currentFilters.ratingMin || currentFilters.rating) {
const ratingValue = currentFilters.ratingMin || currentFilters.rating;
const ratingRadio = document.getElementById (`modal-rating-\${ratingValue}`);
if (ratingRadio) {
ratingRadio.checked = true;
console.log('[Modal] Rating synced:', ratingValue);
}
} else {
const allRating = document.getElementById('modal-rating-all');
if (allRating)
allRating.checked = true;
}
// Prix
const priceMinInput = document.getElementById('modal-priceMin');
const priceMaxInput = document.getElementById('modal-priceMax');
if (priceMinInput)
priceMinInput.value = currentFilters.priceMin || '';
if (priceMaxInput)
priceMaxInput.value = currentFilters.priceMax || '';
// Poids
const weightMinInput = document.getElementById('modal-weightMin');
const weightMaxInput = document.getElementById('modal-weightMax');
if (weightMinInput)
weightMinInput.value = currentFilters.weightMin || '';
if (weightMaxInput)
weightMaxInput.value = currentFilters.weightMax || '';
console.log('[Modal] Filters synced successfully');
}
// Fonction pour charger les filtres dynamiques dans le modal
function loadDynamicFiltersToModal() {
console.log('[Modal] Loading dynamic filters...');
// Boutiques
const sidebarShopList = document.getElementById('shopList');
const modalShopList = document.getElementById('modalShopList');
if (modalShopList) { // Si la sidebar a déjà les boutiques, les copier
if (sidebarShopList && sidebarShopList.innerHTML.trim() && ! sidebarShopList.innerHTML.includes('Aucune boutique') && ! sidebarShopList.innerHTML.includes('seront chargées')) {
let shopHtml = sidebarShopList.innerHTML.replace(/id=\"all-shops\"/g, 'id=\"modal-all-shops\"').replace(/id=\"shop-/g, 'id=\"modal-shop-').replace(/name=\"shop\"/g, 'name=\"modal-shop\"').replace(/for=\"all-shops\"/g, 'for=\"modal-all-shops\"').replace(/for=\"shop-/g, 'for=\"modal-shop-');
modalShopList.innerHTML = shopHtml;
// Synchroniser la sélection
if (currentFilters.shop) {
const shopRadio = document.querySelector (`#modalShopList input[value=\"\${
currentFilters.shop
}\"]`);
if (shopRadio)
shopRadio.checked = true;
} else {
const allShops = document.getElementById('modal-all-shops');
if (allShops)
allShops.checked = true;
}
console.log('[Modal] Shops loaded from sidebar');
} else { // Si pas encore chargés, afficher un message ou laisser vide
if (! modalShopList.innerHTML.trim() || modalShopList.innerHTML.includes('seront chargées')) {
modalShopList.innerHTML = '<li class=\"filter-list\"><span class=\"text-muted\">Les boutiques seront chargées lors de l\\'application des filtres</span></li>';
}
}
}
// Couleurs
const sidebarColorList = document.getElementById('colorList');
const modalColorList = document.getElementById('modalColorList');
if (sidebarColorList && modalColorList) {
if (sidebarColorList.innerHTML.trim() && ! sidebarColorList.innerHTML.includes('Aucun')) {
let colorHtml = sidebarColorList.innerHTML.replace(/id=\"all-color\"/g, 'id=\"modal-all-color\"').replace(/id=\"color-/g, 'id=\"modal-color-').replace(/name=\"color\"/g, 'name=\"modal-color\"').replace(/for=\"all-color\"/g, 'for=\"modal-all-color\"').replace(/for=\"color-/g, 'for=\"modal-color-');
modalColorList.innerHTML = colorHtml;
// Synchroniser la sélection
if (currentFilters.color) {
const colorRadio = document.querySelector (`#modalColorList input[value=\"\${
currentFilters.color
}\"]`);
if (colorRadio)
colorRadio.checked = true;
} else {
const allColor = document.getElementById('modal-all-color');
if (allColor)
allColor.checked = true;
}
console.log('[Modal] Colors loaded');
}
}
// Tailles
const sidebarSizeList = document.getElementById('sizeList');
const modalSizeList = document.getElementById('modalSizeList');
if (sidebarSizeList && modalSizeList) {
if (sidebarSizeList.innerHTML.trim() && ! sidebarSizeList.innerHTML.includes('Aucun')) {
let sizeHtml = sidebarSizeList.innerHTML.replace(/id=\"all-size\"/g, 'id=\"modal-all-size\"').replace(/id=\"size-/g, 'id=\"modal-size-').replace(/name=\"size\"/g, 'name=\"modal-size\"').replace(/for=\"all-size\"/g, 'for=\"modal-all-size\"').replace(/for=\"size-/g, 'for=\"modal-size-');
modalSizeList.innerHTML = sizeHtml;
// Synchroniser la sélection
if (currentFilters.size) {
const sizeRadio = document.querySelector (`#modalSizeList input[value=\"\${
currentFilters.size
}\"]`);
if (sizeRadio)
sizeRadio.checked = true;
} else {
const allSize = document.getElementById('modal-all-size');
if (allSize)
allSize.checked = true;
}
console.log('[Modal] Sizes loaded');
}
}
// Matériaux
const sidebarMaterialList = document.getElementById('materialList');
const modalMaterialList = document.getElementById('modalMaterialList');
if (sidebarMaterialList && modalMaterialList) {
if (sidebarMaterialList.innerHTML.trim() && ! sidebarMaterialList.innerHTML.includes('Aucun')) {
let materialHtml = sidebarMaterialList.innerHTML.replace(/id=\"all-material\"/g, 'id=\"modal-all-material\"').replace(/id=\"material-/g, 'id=\"modal-material-').replace(/name=\"material\"/g, 'name=\"modal-material\"').replace(/for=\"all-material\"/g, 'for=\"modal-all-material\"').replace(/for=\"material-/g, 'for=\"modal-material-');
modalMaterialList.innerHTML = materialHtml;
// Synchroniser la sélection
if (currentFilters.material) {
const materialRadio = document.querySelector (`#modalMaterialList input[value=\"\${
currentFilters.material
}\"]`);
if (materialRadio)
materialRadio.checked = true;
} else {
const allMaterial = document.getElementById('modal-all-material');
if (allMaterial)
allMaterial.checked = true;
}
console.log('[Modal] Materials loaded');
}
}
}
// Synchroniser à l'ouverture du modal
const filtersModal = document.getElementById('filtersModal');
if (filtersModal) {
filtersModal.addEventListener('show.bs.modal', function () {
console.log('[Modal] Modal opening, syncing filters...');
// Charger les filtres dynamiques d'abord si pas encore chargés
loadDynamicFiltersToModal();
// Puis synchroniser les valeurs
setTimeout(() => {
syncModalFilters();
}, 100);
});
}
// Charger les filtres dynamiques au chargement initial si la sidebar les a déjà
loadDynamicFiltersToModal();
// Bouton Appliquer les filtres
const applyBtn = document.getElementById('modalApplyFiltersBtn');
if (applyBtn) {
applyBtn.addEventListener('click', function (e) {
e.preventDefault();
console.log('[Modal] Apply button clicked, collecting filter values...');
// Collecter les valeurs du modal
const brandRadio = document.querySelector('#modalBrandList input[name=\"modal-brand\"]:checked');
if (brandRadio) {
currentFilters.brand = brandRadio.id !== 'modal-all-brands' ? brandRadio.value : '';
console.log('[Modal] Brand:', currentFilters.brand);
} else {
currentFilters.brand = '';
console.log('[Modal] Brand: No selection found');
}
// Conditions
const conditionRadio = document.querySelector('#modalConditionList input[name=\"modal-condition\"]:checked');
if (conditionRadio) {
currentFilters.condition = conditionRadio.id !== 'modal-all-conditions' ? conditionRadio.value : '';
console.log('[Modal] Condition:', currentFilters.condition);
} else {
currentFilters.condition = '';
}
// Featured
const featuredRadio = document.querySelector('#filtersModal input[name=\"modal-featured\"]:checked');
if (featuredRadio) {
currentFilters.featured = featuredRadio.id !== 'modal-featured-all' ? featuredRadio.value : '';
console.log('[Modal] Featured:', currentFilters.featured);
} else {
currentFilters.featured = '';
}
// Digital
const digitalRadio = document.querySelector('#filtersModal input[name=\"modal-digital\"]:checked');
if (digitalRadio) {
currentFilters.digital = digitalRadio.id !== 'modal-digital-all' ? digitalRadio.value : '';
console.log('[Modal] Digital:', currentFilters.digital);
} else {
currentFilters.digital = '';
}
// Availability
const availabilityRadio = document.querySelector('#filtersModal input[name=\"modal-availability\"]:checked');
if (availabilityRadio) {
currentFilters.availability = availabilityRadio.id !== 'modal-availability-all' ? availabilityRadio.value : '';
console.log('[Modal] Availability:', currentFilters.availability);
} else {
currentFilters.availability = '';
}
// Rating
const ratingRadio = document.querySelector('#filtersModal input[name=\"modal-rating\"]:checked');
if (ratingRadio && ratingRadio.id !== 'modal-rating-all') {
currentFilters.ratingMin = ratingRadio.value;
currentFilters.rating = ratingRadio.value;
console.log('[Modal] Rating:', currentFilters.ratingMin);
} else {
currentFilters.ratingMin = '';
currentFilters.rating = '';
}
// Prix
const priceMinInput = document.getElementById('modal-priceMin');
const priceMaxInput = document.getElementById('modal-priceMax');
currentFilters.priceMin = priceMinInput ? priceMinInput.value.trim() : '';
currentFilters.priceMax = priceMaxInput ? priceMaxInput.value.trim() : '';
console.log('[Modal] Price:', currentFilters.priceMin, '-', currentFilters.priceMax);
// Poids
const weightMinInput = document.getElementById('modal-weightMin');
const weightMaxInput = document.getElementById('modal-weightMax');
currentFilters.weightMin = weightMinInput ? weightMinInput.value.trim() : '';
currentFilters.weightMax = weightMaxInput ? weightMaxInput.value.trim() : '';
console.log('[Modal] Weight:', currentFilters.weightMin, '-', currentFilters.weightMax);
// Couleur
const colorRadio = document.querySelector('#modalColorList input[name=\"modal-color\"]:checked');
if (colorRadio) {
currentFilters.color = colorRadio.id !== 'modal-all-color' ? colorRadio.value : '';
console.log('[Modal] Color:', currentFilters.color);
} else {
currentFilters.color = '';
}
// Taille
const sizeRadio = document.querySelector('#modalSizeList input[name=\"modal-size\"]:checked');
if (sizeRadio) {
currentFilters.size = sizeRadio.id !== 'modal-all-size' ? sizeRadio.value : '';
console.log('[Modal] Size:', currentFilters.size);
} else {
currentFilters.size = '';
}
// Matériau
const materialRadio = document.querySelector('#modalMaterialList input[name=\"modal-material\"]:checked');
if (materialRadio) {
currentFilters.material = materialRadio.id !== 'modal-all-material' ? materialRadio.value : '';
console.log('[Modal] Material:', currentFilters.material);
} else {
currentFilters.material = '';
}
// Boutiques
const shopRadio = document.querySelector('#modalShopList input[name=\"modal-shop\"]:checked');
if (shopRadio) {
currentFilters.shop = shopRadio.id !== 'modal-all-shops' ? shopRadio.value : '';
console.log('[Modal] Shop:', currentFilters.shop);
} else {
currentFilters.shop = '';
}
currentFilters.page = 1;
console.log('[Modal] All filters collected:', currentFilters);
// Fermer le modal d'abord
const modalElement = document.getElementById('filtersModal');
const modal = bootstrap.Modal.getInstance(modalElement);
if (modal) {
modal.hide();
console.log('[Modal] Modal closed');
}
// Appliquer les filtres après un court délai pour laisser le modal se fermer
setTimeout(() => { // Vérifier que applyFilters existe
if (typeof window.applyFilters === 'function') {
console.log('[Modal] Calling applyFilters()...');
window.applyFilters();
// Mettre à jour le compteur de filtres actifs
setTimeout(() => {
if (typeof updateActiveFiltersCount === 'function') {
updateActiveFiltersCount();
}
}, 100);
} else {
console.error('[Modal] applyFilters is not available!', typeof window.applyFilters);
// Essayer de recharger la page avec les nouveaux paramètres
const url = new URL(window.location.href);
Object.keys(currentFilters).forEach(key => {
if (currentFilters[key] && currentFilters[key] !== '') {
let apiKey = key;
if (key === 'priceMin') {
apiKey = 'price_min';
} else if (key === 'priceMax') {
apiKey = 'price_max';
} else if (key === 'ratingMin') {
apiKey = 'rating_min';
} else if (key === 'weightMin') {
apiKey = 'weight_min';
} else if (key === 'weightMax') {
apiKey = 'weight_max';
} else if (key === 'stockStatus') {
apiKey = 'stock_status';
}
url.searchParams.set(apiKey, currentFilters[key]);
} else {
let apiKey = key;
if (key === 'priceMin') {
apiKey = 'price_min';
} else if (key === 'priceMax') {
apiKey = 'price_max';
} else if (key === 'ratingMin') {
apiKey = 'rating_min';
} else if (key === 'weightMin') {
apiKey = 'weight_min';
} else if (key === 'weightMax') {
apiKey = 'weight_max';
} else if (key === 'stockStatus') {
apiKey = 'stock_status';
}
url.searchParams.delete(apiKey);
}
});
window.location.href = url.toString();
}
}, 300);
});
} else {
console.error('[Modal] Apply button not found!');
}
// Bouton Réinitialiser
const resetBtn = document.getElementById('modalResetFiltersBtn');
if (resetBtn) {
resetBtn.addEventListener('click', function () {
console.log('[Modal] Reset button clicked');
// Réinitialiser tous les filtres du modal
document.querySelectorAll('#filtersModal input[type=\"radio\"]').forEach(radio => {
if (radio.id && radio.id.includes('-all')) {
radio.checked = true;
} else {
radio.checked = false;
}
});
const priceMinInput = document.getElementById('modal-priceMin');
const priceMaxInput = document.getElementById('modal-priceMax');
const weightMinInput = document.getElementById('modal-weightMin');
const weightMaxInput = document.getElementById('modal-weightMax');
if (priceMinInput)
priceMinInput.value = '';
if (priceMaxInput)
priceMaxInput.value = '';
if (weightMinInput)
weightMinInput.value = '';
if (weightMaxInput)
weightMaxInput.value = '';
// Réinitialiser currentFilters (garder category et sort)
const category = currentFilters.category || '';
const sort = currentFilters.sort || 'newest';
currentFilters = {
category: category,
sort: sort,
page: 1,
brand: '',
condition: '',
featured: '',
digital: '',
availability: '',
ratingMin: '',
rating: '',
priceMin: '',
priceMax: '',
weightMin: '',
weightMax: '',
color: '',
size: '',
material: '',
shop: ''
};
console.log('[Modal] Filters reset, currentFilters:', currentFilters);
// Fermer le modal d'abord
const modalElement = document.getElementById('filtersModal');
const modal = bootstrap.Modal.getInstance(modalElement);
if (modal) {
modal.hide();
console.log('[Modal] Modal closed after reset');
}
// Appliquer les filtres après un court délai
setTimeout(() => {
if (typeof window.applyFilters === 'function') {
window.applyFilters();
} else {
console.error('[Modal] applyFilters not available, reloading page...');
// Recharger la page avec les filtres réinitialisés
const url = new URL(window.location.href);
url.searchParams.delete('price_min');
url.searchParams.delete('price_max');
url.searchParams.delete('rating_min');
url.searchParams.delete('weight_min');
url.searchParams.delete('weight_max');
url.searchParams.delete('brand');
url.searchParams.delete('condition');
url.searchParams.delete('featured');
url.searchParams.delete('digital');
url.searchParams.delete('availability');
url.searchParams.delete('color');
url.searchParams.delete('size');
url.searchParams.delete('material');
url.searchParams.delete('shop');
window.location.href = url.toString();
}
}, 300);
});
} else {
console.error('[Modal] Reset button not found!');
}
// S'assurer que les filtres dynamiques sont chargés au premier chargement si disponibles
setTimeout(() => {
loadDynamicFiltersToModal();
}, 500);
});
</script>";
$__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
$__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
yield from [];
}
/**
* @codeCoverageIgnore
*/
public function getTemplateName(): string
{
return "home/listing.html.twig";
}
/**
* @codeCoverageIgnore
*/
public function isTraitable(): bool
{
return false;
}
/**
* @codeCoverageIgnore
*/
public function getDebugInfo(): array
{
return array ( 3341 => 2568, 3327 => 2564, 3321 => 2563, 3318 => 2562, 3314 => 2561, 3301 => 2550, 3287 => 2546, 3281 => 2545, 3278 => 2544, 3274 => 2543, 2934 => 2206, 2013 => 1288, 2004 => 1282, 2000 => 1281, 1996 => 1280, 1992 => 1279, 1988 => 1278, 1984 => 1277, 1980 => 1276, 1976 => 1275, 1972 => 1274, 1968 => 1273, 1964 => 1272, 1960 => 1271, 1956 => 1270, 1951 => 1268, 1947 => 1267, 1943 => 1266, 1939 => 1265, 1935 => 1264, 1931 => 1263, 1927 => 1262, 1923 => 1261, 1916 => 1257, 1910 => 1254, 1904 => 1251, 1898 => 1248, 1892 => 1245, 1886 => 1242, 1880 => 1239, 1874 => 1236, 1868 => 1233, 1862 => 1230, 1856 => 1227, 1850 => 1224, 1844 => 1221, 1838 => 1218, 1834 => 1217, 1830 => 1216, 1826 => 1215, 1822 => 1214, 1818 => 1213, 1814 => 1212, 1810 => 1211, 1614 => 1018, 1604 => 1010, 1594 => 1009, 1590 => 1008, 1549 => 1007, 1542 => 1005, 1539 => 1004, 1533 => 1003, 1530 => 1002, 1525 => 1001, 1522 => 1000, 1517 => 999, 1515 => 998, 1513 => 997, 1509 => 996, 1429 => 919, 1425 => 918, 1421 => 917, 1417 => 916, 1413 => 915, 1338 => 843, 1334 => 842, 1330 => 840, 1317 => 839, 882 => 415, 847 => 414, 825 => 403, 817 => 397, 815 => 396, 810 => 393, 801 => 389, 799 => 388, 786 => 380, 771 => 376, 756 => 372, 749 => 368, 745 => 366, 738 => 363, 736 => 362, 731 => 360, 725 => 356, 721 => 354, 715 => 351, 710 => 350, 708 => 349, 697 => 341, 693 => 340, 688 => 337, 684 => 335, 661 => 333, 644 => 332, 640 => 331, 630 => 326, 621 => 323, 618 => 322, 615 => 321, 609 => 320, 606 => 319, 600 => 318, 597 => 317, 592 => 316, 589 => 315, 584 => 314, 581 => 313, 579 => 312, 574 => 309, 564 => 307, 554 => 305, 551 => 304, 548 => 303, 542 => 302, 539 => 301, 533 => 300, 530 => 299, 525 => 298, 522 => 297, 517 => 296, 514 => 295, 512 => 294, 508 => 293, 502 => 292, 498 => 290, 493 => 289, 480 => 281, 474 => 280, 468 => 279, 462 => 278, 456 => 277, 450 => 276, 277 => 105, 268 => 101, 266 => 100, 254 => 97, 248 => 96, 245 => 95, 240 => 94, 231 => 88, 214 => 73, 200 => 69, 194 => 68, 191 => 67, 187 => 66, 174 => 55, 165 => 51, 163 => 50, 155 => 47, 151 => 46, 140 => 44, 137 => 43, 132 => 42, 126 => 39, 117 => 37, 89 => 12, 79 => 4, 66 => 3, 43 => 1,);
}
public function getSourceContext(): Source
{
return new Source("{% extends 'base_home.html.twig' %}
{% block body %}
\t<!-- Start Banner Area -->
\t<section class=\"banner-area organic-breadcrumb\">
\t\t<div class=\"container\">
\t\t\t<div class=\"breadcrumb-banner d-flex flex-wrap align-items-center justify-content-end\">
\t\t\t\t<div class=\"col-first\">
\t\t\t\t\t<h1>Page de listage de produit</h1>
\t\t\t\t\t<nav class=\"d-flex align-items-center\">
\t\t\t\t\t\t<a href=\"{{ path('ui_home') }}\">Accueil<span class=\"lnr lnr-arrow-right\"></span>
\t\t\t\t\t\t</a>
\t\t\t\t\t\t<a href=\"javascript:void(0);\">Liste des produits</a>
\t\t\t\t\t</nav>
\t\t\t\t</div>
\t\t\t</div>
\t\t</div>
\t</section>
\t<!-- End Banner Area -->
\t<div class=\"container\">
\t\t<div class=\"row\">
\t\t\t<div class=\"col-xl-3 col-lg-4 col-md-5\">
\t\t\t\t<!-- Bouton toggle sidebar mobile -->
\t\t\t\t<button class=\"btn btn-outline-primary w-100 d-md-none mb-3 listing-sidebar-toggle\" type=\"button\" data-bs-toggle=\"collapse\" data-bs-target=\"#listingSidebarCollapse\" aria-expanded=\"false\" aria-controls=\"listingSidebarCollapse\">
\t\t\t\t\t<i class=\"lnr lnr-menu me-2\"></i>Filtres et catégories
\t\t\t\t\t<i class=\"lnr lnr-chevron-down ms-2 toggle-icon\"></i>
\t\t\t\t</button>
\t\t\t\t<!-- Sidebar avec collapse -->
\t\t\t\t<div class=\"collapse d-md-block\" id=\"listingSidebarCollapse\">
\t\t\t\t\t<div class=\"sidebar-categories\">
\t\t\t\t\t\t<div class=\"head\">Catégories</div>
\t\t\t\t\t\t<ul class=\"main-categories\">
\t\t\t\t\t\t\t<li class=\"main-nav-list\">
\t\t\t\t\t\t\t\t<a href=\"{{ path('ui_listing') }}\" class=\"category-link {% if not currentCategory %}active{% endif %}\">
\t\t\t\t\t\t\t\t\t<span class=\"lnr lnr-tag\"></span>Toutes les catégories
\t\t\t\t\t\t\t\t\t<span class=\"number\">({{ totalProducts }})</span>
\t\t\t\t\t\t\t\t</a>
\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t{% for category in categories %}
\t\t\t\t\t\t\t\t<li class=\"main-nav-list\">
\t\t\t\t\t\t\t\t\t<a href=\"{{ path('ui_listing', {'category': category.slug}) }}\" class=\"category-link {% if currentCategory == category.slug %}active{% endif %}\" data-category=\"{{ category.slug }}\">
\t\t\t\t\t\t\t\t\t\t<span class=\"lnr lnr-tag\"></span>
\t\t\t\t\t\t\t\t\t\t{{ category.name }}
\t\t\t\t\t\t\t\t\t\t<span class=\"number\">({{ category.products|length }})</span>
\t\t\t\t\t\t\t\t\t</a>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t{% else %}
\t\t\t\t\t\t\t\t<li class=\"main-nav-list\">
\t\t\t\t\t\t\t\t\t<span>Aucune catégorie</span>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t{% endfor %}
\t\t\t\t\t\t</ul>
\t\t\t\t\t</div>
\t\t\t\t\t<div class=\"sidebar-filter mt-50\" id=\"brandsFilter\">
\t\t\t\t\t\t<div class=\"top-filter-head\">Filtres</div>
\t\t\t\t\t\t<div class=\"common-filter\">
\t\t\t\t\t\t\t<div class=\"head\">Marques</div>
\t\t\t\t\t\t\t<ul class=\"brand-list\" id=\"brandList\">
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"all-brands\" name=\"brand\" checked>
\t\t\t\t\t\t\t\t\t<label for=\"all-brands\">Toutes les marques</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t{% for brand in brands %}
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"brand-{{ brand.id }}\" name=\"brand\" value=\"{{ brand.slug }}\">
\t\t\t\t\t\t\t\t\t\t<label for=\"brand-{{ brand.id }}\">{{ brand.name }}<span>({{ brand.getActiveProductsCount() }})</span>
\t\t\t\t\t\t\t\t\t\t</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t{% endfor %}
\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<!-- Filtres avancés -->
\t\t\t\t\t\t<div class=\"common-filter\">
\t\t\t\t\t\t\t<div class=\"head\">Boutiques</div>
\t\t\t\t\t\t\t<div id=\"shopsFilter\">
\t\t\t\t\t\t\t\t<form action=\"#\">
\t\t\t\t\t\t\t\t\t<ul
\t\t\t\t\t\t\t\t\t\tclass=\"shop-list\" id=\"shopList\"><!-- Les boutiques seront chargées dynamiquement -->
\t\t\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t\t\t</form>
\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<div class=\"common-filter\">
\t\t\t\t\t\t\t<div class=\"head\">Condition ({{ conditions|length }})</div>
\t\t\t\t\t\t\t<ul class=\"condition-list\" id=\"conditionList\">
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"all-conditions\" name=\"condition\" checked>
\t\t\t\t\t\t\t\t\t<label for=\"all-conditions\">Toutes les conditions</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t{% for condition in conditions %}
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"condition-{{ condition.id }}\" name=\"condition\" value=\"{{ condition.slug }}\">
\t\t\t\t\t\t\t\t\t\t<label for=\"condition-{{ condition.id }}\">{{ condition.name }}<span>({{ condition.getActiveProductsCount() }})</span>
\t\t\t\t\t\t\t\t\t\t</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t{% else %}
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<span class=\"text-muted\">Aucune condition disponible</span>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t{% endfor %}
\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<div class=\"common-filter\">
\t\t\t\t\t\t\t<div class=\"head\">Produits vedettes</div>
\t\t\t\t\t\t\t<form action=\"#\">
\t\t\t\t\t\t\t\t<ul>
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"featured-all\" name=\"featured\" checked>
\t\t\t\t\t\t\t\t\t\t<label for=\"featured-all\">Tous les produits</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"featured-only\" name=\"featured\" value=\"true\">
\t\t\t\t\t\t\t\t\t\t<label for=\"featured-only\">Produits vedettes uniquement</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t\t</form>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<div class=\"common-filter\">
\t\t\t\t\t\t\t<div class=\"head\">Type de produit</div>
\t\t\t\t\t\t\t<form action=\"#\">
\t\t\t\t\t\t\t\t<ul>
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"digital-all\" name=\"digital\" checked>
\t\t\t\t\t\t\t\t\t\t<label for=\"digital-all\">Tous les types</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"digital-physical\" name=\"digital\" value=\"false\">
\t\t\t\t\t\t\t\t\t\t<label for=\"digital-physical\">Produits physiques</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"digital-digital\" name=\"digital\" value=\"true\">
\t\t\t\t\t\t\t\t\t\t<label for=\"digital-digital\">Produits numériques</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t\t</form>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<div class=\"common-filter\">
\t\t\t\t\t\t\t<div class=\"head\">Disponibilité</div>
\t\t\t\t\t\t\t<form action=\"#\">
\t\t\t\t\t\t\t\t<ul>
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"availability-all\" name=\"availability\" checked>
\t\t\t\t\t\t\t\t\t\t<label for=\"availability-all\">Tous</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"availability-in-stock\" name=\"availability\" value=\"in_stock\">
\t\t\t\t\t\t\t\t\t\t<label for=\"availability-in-stock\">En stock</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"availability-low-stock\" name=\"availability\" value=\"low_stock\">
\t\t\t\t\t\t\t\t\t\t<label for=\"availability-low-stock\">Stock faible</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"availability-out-of-stock\" name=\"availability\" value=\"out_of_stock\">
\t\t\t\t\t\t\t\t\t\t<label for=\"availability-out-of-stock\">Rupture de stock</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t\t</form>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<div class=\"common-filter\">
\t\t\t\t\t\t\t<div class=\"head\">Note minimale</div>
\t\t\t\t\t\t\t<form action=\"#\">
\t\t\t\t\t\t\t\t<ul>
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"rating-all\" name=\"rating\" checked>
\t\t\t\t\t\t\t\t\t\t<label for=\"rating-all\">Toutes les notes</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"rating-4\" name=\"rating\" value=\"4\">
\t\t\t\t\t\t\t\t\t\t<label for=\"rating-4\">4 étoiles et plus</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"rating-3\" name=\"rating\" value=\"3\">
\t\t\t\t\t\t\t\t\t\t<label for=\"rating-3\">3 étoiles et plus</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"rating-2\" name=\"rating\" value=\"2\">
\t\t\t\t\t\t\t\t\t\t<label for=\"rating-2\">2 étoiles et plus</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t\t</form>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<div class=\"common-filter\">
\t\t\t\t\t\t\t<div class=\"head\">Poids</div>
\t\t\t\t\t\t\t<div class=\"weight-range-area\">
\t\t\t\t\t\t\t\t<div class=\"weight-inputs d-flex\">
\t\t\t\t\t\t\t\t\t<div class=\"weight-input\">
\t\t\t\t\t\t\t\t\t\t<label>Min (kg):</label>
\t\t\t\t\t\t\t\t\t\t<input type=\"number\" id=\"weightMin\" placeholder=\"0\" step=\"0.1\" min=\"0\">
\t\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t\t\t<div class=\"weight-input\">
\t\t\t\t\t\t\t\t\t\t<label>Max (kg):</label>
\t\t\t\t\t\t\t\t\t\t<input type=\"number\" id=\"weightMax\" placeholder=\"100\" step=\"0.1\" min=\"0\">
\t\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<div class=\"common-filter\">
\t\t\t\t\t\t\t<div class=\"head\">Couleur</div>
\t\t\t\t\t\t\t<div id=\"colorsFilter\">
\t\t\t\t\t\t\t\t<form action=\"#\">
\t\t\t\t\t\t\t\t\t<ul
\t\t\t\t\t\t\t\t\t\tclass=\"color-list\" id=\"colorList\"><!-- Les couleurs seront chargées dynamiquement -->
\t\t\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t\t\t</form>
\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<div class=\"common-filter\">
\t\t\t\t\t\t\t<div class=\"head\">Taille</div>
\t\t\t\t\t\t\t<div id=\"sizesFilter\">
\t\t\t\t\t\t\t\t<form action=\"#\">
\t\t\t\t\t\t\t\t\t<ul
\t\t\t\t\t\t\t\t\t\tclass=\"size-list\" id=\"sizeList\"><!-- Les tailles seront chargées dynamiquement -->
\t\t\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t\t\t</form>
\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<div class=\"common-filter\">
\t\t\t\t\t\t\t<div class=\"head\">Matériau</div>
\t\t\t\t\t\t\t<div id=\"materialsFilter\">
\t\t\t\t\t\t\t\t<form action=\"#\">
\t\t\t\t\t\t\t\t\t<ul
\t\t\t\t\t\t\t\t\t\tclass=\"material-list\" id=\"materialList\"><!-- Les matériaux seront chargés dynamiquement -->
\t\t\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t\t\t</form>
\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<div class=\"common-filter\">
\t\t\t\t\t\t\t<div class=\"head\">Prix</div>
\t\t\t\t\t\t\t<div class=\"price-range-area\">
\t\t\t\t\t\t\t\t<div id=\"price-range\"></div>
\t\t\t\t\t\t\t\t<div class=\"value-wrapper d-flex\">
\t\t\t\t\t\t\t\t\t<div class=\"price\">Prix:</div>
\t\t\t\t\t\t\t\t\t<span>\$</span>
\t\t\t\t\t\t\t\t\t<div id=\"lower-value\"></div>
\t\t\t\t\t\t\t\t\t<div class=\"to\">to</div>
\t\t\t\t\t\t\t\t\t<span>\$</span>
\t\t\t\t\t\t\t\t\t<div id=\"upper-value\"></div>
\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t</div>
\t\t\t\t\t</div>
\t\t\t\t</div>
\t\t\t\t<!-- Fin du collapse sidebar -->
\t\t\t</div>
\t\t\t<div class=\"col-xl-9 col-lg-8 col-md-7\">
\t\t\t<!-- Barre de tri et bouton de filtres -->
\t\t\t<div class=\"row mb-4\">
\t\t\t\t<div
\t\t\t\t\tclass=\"col-md-6 mb-3 mb-md-0\">
\t\t\t\t\t<!-- Bouton pour ouvrir le modal de filtres -->
\t\t\t\t\t<button type=\"button\" class=\"btn btn-lg d-flex align-items-center\" data-bs-toggle=\"modal\" data-bs-target=\"#filtersModal\" style=\"background: transparent; border: none; padding: 10px 16px; font-weight: 600; transition: all 0.3s ease;\">
\t\t\t\t\t\t<div class=\"filter-icon-circle d-flex align-items-center justify-content-center\" style=\"width: 42px; height: 42px; background: linear-gradient(135deg, #ffa200 0%, #ff8c00 100%); border-radius: 50%; border: 2px solid #ffa200; flex-shrink: 0; margin-right: 10px; box-shadow: 0 2px 8px rgba(255, 162, 0, 0.3);\">
\t\t\t\t\t\t\t<i class=\"lnr lnr-filter\" style=\"font-size: 1.3rem; color: white; font-weight: bold;\"></i>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<span style=\"font-size: 1.1rem; font-weight: 600; color: #333;\">Filtres</span>
\t\t\t\t\t\t<span class=\"badge bg-warning text-dark ms-2\" id=\"activeFiltersCount\" style=\"display: none; font-size: 0.85rem; padding: 4px 10px; border-radius: 12px; font-weight: 600;\">0</span>
\t\t\t\t\t</button>
\t\t\t\t</div>
\t\t\t\t<div class=\"col-md-6\">
\t\t\t\t\t<select class=\"form-select\" id=\"sortSelect\" onchange=\"applySorting()\">
\t\t\t\t\t\t<option value=\"newest\" {% if currentSort == 'newest' %} selected {% endif %}>Plus récents</option>
\t\t\t\t\t\t<option value=\"price_asc\" {% if currentSort == 'price_asc' %} selected {% endif %}>Prix croissant</option>
\t\t\t\t\t\t<option value=\"price_desc\" {% if currentSort == 'price_desc' %} selected {% endif %}>Prix décroissant</option>
\t\t\t\t\t\t<option value=\"name_asc\" {% if currentSort == 'name_asc' %} selected {% endif %}>Nom A-Z</option>
\t\t\t\t\t\t<option value=\"name_desc\" {% if currentSort == 'name_desc' %} selected {% endif %}>Nom Z-A</option>
\t\t\t\t\t\t<option value=\"popular\" {% if currentSort == 'popular' %} selected {% endif %}>Plus populaires</option>
\t\t\t\t\t</select>
\t\t\t\t</div>
\t\t\t</div>
\t\t\t<!-- Start Best Seller -->
\t\t\t<section class=\"lattest-product-area pb-40 category-list\">
\t\t\t\t<div class=\"row\" id=\"productsContainer\">
\t\t\t\t\t{% for product in products %}
\t\t\t\t\t\t<div class=\"col-lg-4 col-md-6\">
\t\t\t\t\t\t\t<div class=\"single-product\">
\t\t\t\t\t\t\t\t<div class=\"product-image-container mb-2\" onmouseenter=\"showImageNav({{ product.id }})\" onmouseleave=\"hideImageNav({{ product.id }})\">
\t\t\t\t\t\t\t\t\t<a href=\"{{ path('ui_product_show', { slug: product.slug }) }}\">
\t\t\t\t\t\t\t\t\t\t{% set allImages = product.images|default([]) %}
\t\t\t\t\t\t\t\t\t\t{% if product.variants is defined %}
\t\t\t\t\t\t\t\t\t\t\t{% for variant in product.variants %}
\t\t\t\t\t\t\t\t\t\t\t\t{% if variant.isActive and variant.images is defined %}
\t\t\t\t\t\t\t\t\t\t\t\t\t{% for variantImg in variant.images %}
\t\t\t\t\t\t\t\t\t\t\t\t\t\t{% set allImages = allImages|merge([variantImg]) %}
\t\t\t\t\t\t\t\t\t\t\t\t\t{% endfor %}
\t\t\t\t\t\t\t\t\t\t\t\t{% endif %}
\t\t\t\t\t\t\t\t\t\t\t{% endfor %}
\t\t\t\t\t\t\t\t\t\t{% endif %}
\t\t\t\t\t\t\t\t\t\t{% if allImages|length > 0 %}
\t\t\t\t\t\t\t\t\t\t\t<img class=\"img-fluid main-product-img\" id=\"main-img-{{ product.id }}\" src=\"{{ asset(allImages[0]) }}\" alt=\"{{ product.name }}\">
\t\t\t\t\t\t\t\t\t\t{% else %}
\t\t\t\t\t\t\t\t\t\t\t<img class=\"img-fluid main-product-img\" id=\"main-img-{{ product.id }}\" src=\"{{ asset('ui/img/product/p1.jpg') }}\" alt=\"{{ product.name }}\">
\t\t\t\t\t\t\t\t\t\t{% endif %}
\t\t\t\t\t\t\t\t\t</a>
\t\t\t\t\t\t\t\t\t<!-- Boutons de navigation (visibles au survol) -->
\t\t\t\t\t\t\t\t\t{% set allImages = product.images|default([]) %}
\t\t\t\t\t\t\t\t\t{% if product.variants is defined %}
\t\t\t\t\t\t\t\t\t\t{% for variant in product.variants %}
\t\t\t\t\t\t\t\t\t\t\t{% if variant.isActive and variant.images is defined %}
\t\t\t\t\t\t\t\t\t\t\t\t{% for variantImg in variant.images %}
\t\t\t\t\t\t\t\t\t\t\t\t\t{% set allImages = allImages|merge([variantImg]) %}
\t\t\t\t\t\t\t\t\t\t\t\t{% endfor %}
\t\t\t\t\t\t\t\t\t\t\t{% endif %}
\t\t\t\t\t\t\t\t\t\t{% endfor %}
\t\t\t\t\t\t\t\t\t{% endif %}
\t\t\t\t\t\t\t\t\t{% if allImages|length > 1 %}
\t\t\t\t\t\t\t\t\t\t<button class=\"img-nav-btn img-nav-left\" id=\"img-left-{{ product.id }}\" onclick=\"prevImage({{ product.id }})\" style=\"display: none;\">
\t\t\t\t\t\t\t\t\t\t\t<span class=\"lnr lnr-chevron-left\"></span>
\t\t\t\t\t\t\t\t\t\t</button>
\t\t\t\t\t\t\t\t\t\t<button class=\"img-nav-btn img-nav-right\" id=\"img-right-{{ product.id }}\" onclick=\"nextImage({{ product.id }})\" style=\"display: none;\">
\t\t\t\t\t\t\t\t\t\t\t<span class=\"lnr lnr-chevron-right\"></span>
\t\t\t\t\t\t\t\t\t\t</button>
\t\t\t\t\t\t\t\t\t\t<!-- Indicateurs de position -->
\t\t\t\t\t\t\t\t\t\t<div class=\"img-indicators\" id=\"img-indicators-{{ product.id }}\" style=\"display: none;\">
\t\t\t\t\t\t\t\t\t\t\t{% for img in allImages %}
\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"indicator\" id=\"indicator-{{ product.id }}-{{ loop.index0 }}\" onclick=\"showImage({{ product.id }}, {{ loop.index0 }})\"></span>
\t\t\t\t\t\t\t\t\t\t\t{% endfor %}
\t\t\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t\t\t{% endif %}
\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t\t<div class=\"product-details\">
\t\t\t\t\t\t\t\t\t<a href=\"{{ path('ui_product_show', { slug: product.slug }) }}\">
\t\t\t\t\t\t\t\t\t\t<h6>{{ product.name }}</h6>
\t\t\t\t\t\t\t\t\t</a>
\t\t\t\t\t\t\t\t\t<!-- Affichage de la boutique -->
\t\t\t\t\t\t\t\t\t<div class=\"shop-info\">
\t\t\t\t\t\t\t\t\t\t<small class=\"text-muted\">
\t\t\t\t\t\t\t\t\t\t\t<i class=\"lnr lnr-store\"></i>
\t\t\t\t\t\t\t\t\t\t\tVendu par :
\t\t\t\t\t\t\t\t\t\t\t{% if product.shop is defined and product.shop %}
\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"{{ path('ui_shop_show', {'slug': product.shop.slug}) }}\" class=\"shop-link\">
\t\t\t\t\t\t\t\t\t\t\t\t\t{{ product.shop.name }}
\t\t\t\t\t\t\t\t\t\t\t\t</a>
\t\t\t\t\t\t\t\t\t\t\t{% else %}
\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"text-muted\">Boutique inconnue</span>
\t\t\t\t\t\t\t\t\t\t\t{% endif %}
\t\t\t\t\t\t\t\t\t\t</small>
\t\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t\t\t<div class=\"price\">
\t\t\t\t\t\t\t\t\t\t<h6>{{ product.price|number_format(2, '.', ' ') }}
\t\t\t\t\t\t\t\t\t\t\tHTG</h6>
\t\t\t\t\t\t\t\t\t\t{% if product.compareAtPrice %}
\t\t\t\t\t\t\t\t\t\t\t<h6 class=\"l-through\">{{ product.compareAtPrice|number_format(2, '.', ' ') }}
\t\t\t\t\t\t\t\t\t\t\t\tHTG</h6>
\t\t\t\t\t\t\t\t\t\t{% endif %}
\t\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t\t\t<div class=\"prd-bottom\">
\t\t\t\t\t\t\t\t\t\t<a href=\"javascript:void(0)\" class=\"social-info add-to-cart\" data-product-id=\"{{ product.id }}\" data-qty=\"1\">
\t\t\t\t\t\t\t\t\t\t\t<span class=\"ti-bag\"></span>
\t\t\t\t\t\t\t\t\t\t\t<p class=\"hover-text\">+ panier</p>
\t\t\t\t\t\t\t\t\t\t</a>
\t\t\t\t\t\t\t\t\t\t<a href=\"#\" class=\"social-info wishlist-btn\" data-product-id=\"{{ product.id }}\" {% if app.user %} onclick=\"toggleWishlist({{ product.id }}, this); return false;\" {% else %} onclick=\"alert('Vous devez être connecté pour ajouter aux favoris'); return false;\" {% endif %}>
\t\t\t\t\t\t\t\t\t\t\t<span class=\"lnr lnr-heart\"></span>
\t\t\t\t\t\t\t\t\t\t\t<p class=\"hover-text\">Favoris</p>
\t\t\t\t\t\t\t\t\t\t</a>
\t\t\t\t\t\t\t\t\t\t<a href=\"#\" class=\"social-info comparison-btn\" data-product-id=\"{{ product.id }}\" {% if app.user %} onclick=\"toggleComparison({{ product.id }}, this); return false;\" {% else %} onclick=\"alert('Vous devez être connecté pour comparer des produits'); return false;\" {% endif %}>
\t\t\t\t\t\t\t\t\t\t\t<span class=\"lnr lnr-sync\"></span>
\t\t\t\t\t\t\t\t\t\t\t<p class=\"hover-text\">Comparer</p>
\t\t\t\t\t\t\t\t\t\t</a>
\t\t\t\t\t\t\t\t\t\t<a href=\"{{ path('ui_product_show', { slug: product.slug }) }}\" class=\"social-info\">
\t\t\t\t\t\t\t\t\t\t\t<span class=\"lnr lnr-move\"></span>
\t\t\t\t\t\t\t\t\t\t\t<p class=\"hover-text\">Voir plus</p>
\t\t\t\t\t\t\t\t\t\t</a>
\t\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t</div>
\t\t\t\t\t{% else %}
\t\t\t\t\t\t<div class=\"col-12\">
\t\t\t\t\t\t\t<p>Aucun produit disponible.</p>
\t\t\t\t\t\t</div>
\t\t\t\t\t{% endfor %}
\t\t\t\t</div>
\t\t\t\t<!-- Bouton Charger plus de produits -->
\t\t\t\t{% if totalPages > currentPage %}
\t\t\t\t\t<div class=\"text-center mt-4 mb-4\" id=\"loadMoreContainer\">
\t\t\t\t\t\t<button type=\"button\" class=\"btn btn-primary btn-lg\" id=\"loadMoreBtn\" onclick=\"loadMoreProducts()\">
\t\t\t\t\t\t\t<i class=\"lnr lnr-plus-circle me-2\"></i>Charger plus de produits
\t\t\t\t\t\t</button>
\t\t\t\t\t</div>
\t\t\t\t{% endif %}
\t\t\t\t<!-- Message de fin -->
\t\t\t\t<div id=\"noMoreProducts\" class=\"text-center py-4\" style=\"display: none;\">
\t\t\t\t\t<p class=\"text-muted\">
\t\t\t\t\t\t<i class=\"lnr lnr-checkmark-circle\"></i>
\t\t\t\t\t\tTous les produits ont été chargés</p>
\t\t\t\t</div>
\t\t\t</section>
\t\t\t<!-- End Best Seller -->
\t\t</div>
\t</div>
</div>{% endblock %}{% block title %}Liste des produits | MaketOu{% endblock %}{% block stylesheets %}
<style>
\t/* Styles pour la navigation des images */
\t.product-image-container {
\t\tposition: relative;
\t\toverflow: hidden;
\t\tborder-radius: 8px;
\t}
\t.img-nav-btn {
\t\tposition: absolute;
\t\ttop: 50%;
\t\ttransform: translateY(-50%);
\t\tbackground: rgba(0, 0, 0, 0.6);
\t\tcolor: white;
\t\tborder: none;
\t\twidth: 35px;
\t\theight: 35px;
\t\tborder-radius: 50%;
\t\tdisplay: flex;
\t\talign-items: center;
\t\tjustify-content: center;
\t\tcursor: pointer;
\t\ttransition: all 0.3s ease;
\t\tz-index: 10;
\t}
\t.img-nav-btn:hover {
\t\tbackground: #095ad3;
\t\ttransform: translateY(-50%) scale(1.1);
\t}
\t.img-nav-left {
\t\tleft: 10px;
\t}
\t.img-nav-right {
\t\tright: 10px;
\t}
\t.img-indicators {
\t\tposition: absolute;
\t\tbottom: 10px;
\t\tleft: 50%;
\t\ttransform: translateX(-50%);
\t\tdisplay: flex;
\t\tgap: 5px;
\t\tz-index: 10;
\t}
\t.indicator {
\t\twidth: 8px;
\t\theight: 8px;
\t\tborder-radius: 50%;
\t\tbackground: rgba(255, 255, 255, 0.5);
\t\tcursor: pointer;
\t\tmargin-bottom: 10px;
\t\ttransition: all 0.3s ease;
\t\tborder: 1px solid rgba(255, 255, 255, 0.3);
\t}
\t.indicator.active {
\t\tbackground: #ffa200;
\t\tborder-color: #ffa200;
\t\ttransform: scale(1.2);
\t}
\t.indicator:hover {
\t\tbackground: rgba(255, 255, 255, 0.8);
\t}
\t/* Styles pour l'affichage de la boutique */
\t.shop-info {
\t\tmargin: 8px 0;
\t\tpadding: 5px 0;
\t\tborder-bottom: 1px solid #f0f0f0;
\t}
\t.shop-link {
\t\tcolor: #007bff;
\t\ttext-decoration: none;
\t\tfont-weight: 500;
\t}
\t.shop-link:hover {
\t\tcolor: #ffa200;
\t\ttext-decoration: underline;
\t}
\t/* Animation pour le survol */
\t.product-image-container:hover .main-product-img {
\t\ttransform: scale(1.05);
\t\ttransition: transform 0.3s ease;
\t}
\t.main-product-img {
\t\ttransition: transform 0.3s ease;
\t\twidth: 100%;
\t\theight: 100%;
\t\tobject-fit: cover; /* Recadre l'image pour remplir le conteneur */
\t\tobject-position: center; /* Centre l'image */
\t\tdisplay: block;
\t}
\t/* Styles pour les images des produits associés (Deals de la semaine) */
\t.related-product-img-container {
\t\tposition: relative;
\t\toverflow: hidden;
\t\tborder-radius: 8px;
\t\twidth: 100%;
\t\theight: 200px; /* Hauteur fixe pour les produits associés */
\t\tbackground: #f8f9fa; /* Fond au cas où l'image ne charge pas */
\t}
\t.related-product-img {
\t\twidth: 100%;
\t\theight: 100%;
\t\tobject-fit: cover; /* Recadre l'image pour remplir le conteneur */
\t\tobject-position: center; /* Centre l'image */
\t\tdisplay: block;
\t\ttransition: transform 0.3s ease;
\t}
\t.related-product-img-container:hover .related-product-img {
\t\ttransform: scale(1.05);
\t}
\t/* Styles pour l'image de catégorie dans les deals */
\t.category-banner-container {
\t\tdisplay: block;
\t\tposition: relative;
\t\toverflow: hidden;
\t\tborder-radius: 8px;
\t\twidth: 100%;
\t\theight: 400px; /* Hauteur fixe pour la bannière de catégorie */
\t\tbackground: #f8f9fa; /* Fond au cas où l'image ne charge pas */
\t}
\t.category-banner-img {
\t\twidth: 100%;
\t\theight: 100%;
\t\tobject-fit: cover; /* Recadre l'image pour remplir le conteneur */
\t\tobject-position: center; /* Centre l'image */
\t\tdisplay: block;
\t\ttransition: transform 0.3s ease;
\t}
\t.category-banner-container:hover .category-banner-img {
\t\ttransform: scale(1.05);
\t}
\t/* Styles pour les images de la modal Quick Product View */
\t.quick-view-carousel .item {
\t\twidth: 100%;
\t\theight: 400px; /* Hauteur fixe pour les images du carousel */
\t\tbackground-size: cover;
\t\tbackground-position: center;
\t\tbackground-repeat: no-repeat;
\t\tborder-radius: 8px;
\t}
\t/* Contraindre le conteneur d'image pour maintenir les proportions */
\t.product-image-container {
\t\tposition: relative;
\t\toverflow: hidden;
\t\tborder-radius: 8px;
\t\twidth: 200px;
\t\taspect-ratio: 1 / 1; /* Conteneur carré */
\t\tbackground: #f8f9fa; /* Fond au cas où l'image ne charge pas */
\t}
\t/* Styles pour le bouton de filtre amélioré */
\t.filter-icon-circle {
\t\ttransition: all 0.3s ease;
\t}
\tbutton[data-bs-target=\"#filtersModal\"]:hover .filter-icon-circle {
\t\tbackground: linear-gradient(135deg, #ff8c00 0%, #ff7700 100%) !important;
\t\ttransform: rotate(15deg) scale(1.1);
\t\tbox-shadow: 0 4px 15px rgba(255, 162, 0, 0.5);
\t}
\tbutton[data-bs-target=\"#filtersModal\"]:hover {
\t\ttransform: translateY(-2px);
\t}
\tbutton[data-bs-target=\"#filtersModal\"]:active {
\t\ttransform: translateY(0);
\t}
\tbutton[data-bs-target=\"#filtersModal\"]:hover span {
\t\tcolor: #ffa200 !important;
\t}
\t/* Styles pour le modal de filtres */
\t#filtersModal .modal-body {
\t\tpadding: 1.5rem;
\t}
\t#filtersModal .modal-body::-webkit-scrollbar {
\t\twidth: 8px;
\t}
\t#filtersModal .modal-body::-webkit-scrollbar-track {
\t\tbackground: #f1f1f1;
\t\tborder-radius: 4px;
\t}
\t#filtersModal .modal-body::-webkit-scrollbar-thumb {
\t\tbackground: #ffa200;
\t\tborder-radius: 4px;
\t}
\t#filtersModal .modal-body::-webkit-scrollbar-thumb:hover {
\t\tbackground: #e69100;
\t}
\t#filtersModal .modal-footer {
\t\tbox-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
\t}
\t/* Styles pour les filtres avancés */
\t.weight-range-area {
\t\tpadding: 15px 0;
\t}
\t.weight-inputs {
\t\tgap: 15px;
\t\talign-items: center;
\t}
\t.weight-input {
\t\tflex: 1;
\t}
\t.weight-input label {
\t\tdisplay: block;
\t\tmargin-bottom: 5px;
\t\tfont-weight: 500;
\t\tcolor: #333;
\t}
\t.weight-input input {
\t\twidth: 100%;
\t\tpadding: 8px 12px;
\t\tborder: 1px solid #ddd;
\t\tborder-radius: 4px;
\t\tfont-size: 14px;
\t}
\t.weight-input input:focus {
\t\toutline: none;
\t\tborder-color: #ffa200;
\t\tbox-shadow: 0 0 0 2px rgba(255, 162, 0, 0.2);
\t}
\t/* Styles pour les filtres dynamiques */
\t.shop-list,
\t.color-list,
\t.size-list,
\t.material-list,
\t.condition-list {
\t\tmax-height: 200px;
\t\toverflow-y: auto;
\t\tpadding-right: 5px;
\t}
\t.shop-list::-webkit-scrollbar,
\t.color-list::-webkit-scrollbar,
\t.size-list::-webkit-scrollbar,
\t.material-list::-webkit-scrollbar,
\t.condition-list::-webkit-scrollbar {
\t\twidth: 6px;
\t}
\t.shop-list::-webkit-scrollbar-track,
\t.color-list::-webkit-scrollbar-track,
\t.size-list::-webkit-scrollbar-track,
\t.material-list::-webkit-scrollbar-track,
\t.condition-list::-webkit-scrollbar-track {
\t\tbackground: #f1f1f1;
\t\tborder-radius: 3px;
\t}
\t.shop-list::-webkit-scrollbar-thumb,
\t.color-list::-webkit-scrollbar-thumb,
\t.size-list::-webkit-scrollbar-thumb,
\t.material-list::-webkit-scrollbar-thumb,
\t.condition-list::-webkit-scrollbar-thumb {
\t\tbackground: #ffa200;
\t\tborder-radius: 3px;
\t}
\t.shop-list::-webkit-scrollbar-thumb:hover,
\t.color-list::-webkit-scrollbar-thumb:hover,
\t.size-list::-webkit-scrollbar-thumb:hover,
\t.material-list::-webkit-scrollbar-thumb:hover,
\t.condition-list::-webkit-scrollbar-thumb:hover {
\t\tbackground: #e69100;
\t}
\t/* Animation pour les filtres qui apparaissent */
\t.common-filter {
\t\ttransition: all 0.3s ease;
\t}
\t.common-filter[style*=\"display: none\"] {
\t\topacity: 0;
\t\ttransform: translateY(-10px);
\t}
\t.common-filter[style*=\"display: block\"] {
\t\topacity: 1;
\t\ttransform: translateY(0);
\t}
\t/* Styles pour les indicateurs de chargement */
\t.loading-indicator {
\t\tdisplay: inline-block;
\t\twidth: 20px;
\t\theight: 20px;
\t\tborder: 3px solid #f3f3f3;
\t\tborder-top: 3px solid #ffa200;
\t\tborder-radius: 50%;
\t\tanimation: spin 1s linear infinite;
\t}
\t@keyframes spin {
\t\t0% {
\t\t\ttransform: rotate(0deg);
\t\t}
\t\t100% {
\t\t\ttransform: rotate(360deg);
\t\t}
\t}
\t/* Styles pour le loader de chargement infini */
\t.infinite-loader {
\t\tdisplay: flex;
\t\tflex-direction: column;
\t\talign-items: center;
\t\tjustify-content: center;
\t\tpadding: 20px;
\t}
\t.loader-spinner {
\t\twidth: 50px;
\t\theight: 50px;
\t\tborder: 4px solid #f3f3f3;
\t\tborder-top: 4px solid #ffa200;
\t\tborder-radius: 50%;
\t\tanimation: spin 1s linear infinite;
\t}
\t#infiniteScrollLoader {
\t\tmin-height: 100px;
\t}
\t#noMoreProducts {
\t\tmin-height: 60px;
\t\tcolor: #6c757d;
\t}
\t#noMoreProducts i {
\t\tfont-size: 24px;
\t\tcolor: #28a745;
\t\tmargin-right: 8px;
\t}
\t/* Responsive pour les filtres */
\t@media(max-width: 768px) {
\t\t.weight-inputs {
\t\t\tflex-direction: column;
\t\t\tgap: 10px;
\t\t}
\t\t.weight-input {
\t\t\twidth: 100%;
\t\t}
\t\t.common-filter {
\t\t\tmargin-bottom: 20px;
\t\t}
\t\t.shop-list,
\t\t.color-list,
\t\t.size-list,
\t\t.material-list,
\t\t.condition-list {
\t\t\tmax-height: 150px;
\t\t}
\t}
\t/* Bouton toggle sidebar mobile */
\t.listing-sidebar-toggle {
\t\tborder-radius: 0.5rem;
\t\tpadding: 0.75rem;
\t\tfont-weight: 500;
\t\tdisplay: flex;
\t\talign-items: center;
\t\tjustify-content: center;
\t}
\t.listing-sidebar-toggle .toggle-icon {
\t\ttransition: transform 0.3s ease;
\t\tdisplay: inline-block;
\t}
\t/* État fermé (par défaut) */
\t.listing-sidebar-toggle[aria-expanded=\"false\"] .toggle-icon,
\t.listing-sidebar-toggle.collapsed .toggle-icon {
\t\ttransform: rotate(0deg);
\t}
\t/* État ouvert */
\t.listing-sidebar-toggle[aria-expanded=\"true\"] .toggle-icon,
\t.listing-sidebar-toggle:not(.collapsed) .toggle-icon {
\t\ttransform: rotate(180deg);
\t}
\t/* Sidebar mobile */
\t@media(max-width: 767.98px) {
\t\t#listingSidebarCollapse {
\t\t\tmargin-bottom: 1rem;
\t\t}
\t}
</style>{% endblock %}{% block javascripts %}
<script>
// === Script isolé : chargement de plus de produits (comme les boutiques) ===
var currentPage = {{ currentPage }};
var totalPages = {{ totalPages }};
var isLoading = false;
function loadMoreProducts() {
if (isLoading || currentPage >= totalPages) return;
isLoading = true;
var btn = document.getElementById('loadMoreBtn');
var productsContainer = document.getElementById('productsContainer');
if (!btn || !productsContainer) {
isLoading = false;
return;
}
var originalText = btn.innerHTML;
btn.disabled = true;
btn.innerHTML = '<span class=\"spinner-border spinner-border-sm me-2\"></span>Chargement...';
currentPage++;
var url = new URL(window.location.href);
url.searchParams.set('page', currentPage);
fetch(url.toString(), {
headers: { 'X-Requested-With': 'XMLHttpRequest' }
})
.then(function(response) { return response.json(); })
.then(function(data) {
if (data.success && data.products) {
var tempDiv = document.createElement('div');
tempDiv.innerHTML = data.products;
var newProducts = tempDiv.querySelectorAll('.col-lg-4, .col-lg-3, [class*=\"col-lg\"]');
newProducts.forEach(function(product) {
productsContainer.appendChild(product);
});
currentPage = data.pagination.currentPage;
totalPages = data.pagination.totalPages;
// Initialiser les images et events pour les nouveaux produits
if (typeof initializeProductImages === 'function') initializeProductImages(tempDiv);
if (typeof initializeProductEventListeners === 'function') initializeProductEventListeners(tempDiv);
if (currentPage >= totalPages) {
document.getElementById('loadMoreContainer').style.display = 'none';
} else {
btn.disabled = false;
btn.innerHTML = originalText;
}
} else {
document.getElementById('loadMoreContainer').style.display = 'none';
}
isLoading = false;
})
.catch(function(error) {
btn.disabled = false;
btn.innerHTML = originalText;
isLoading = false;
});
}
</script>
<script>
\t// Variables globales pour la navigation des images
const productImages = {};
const currentImageIndex = {};
// Variables pour le chargement infini (utilise les var globales définies au-dessus)
let hasMoreProducts = totalPages > currentPage;
let currentFilters = {
category: '{{ currentCategory ?? '' }}',
brand: '{{ currentBrand ?? '' }}',
sort: '{{ currentSort ?? 'newest' }}',
priceMin: '{{ priceMin ?? '' }}',
priceMax: '{{ priceMax ?? '' }}'
};
// Modal style eBay pour remplacer les alertes - Définir AVANT son utilisation
function showEbayModal(message, type = 'info') {
const modalId = 'ebayAlertModal';
let existingModal = document.getElementById(modalId);
if (existingModal) {
existingModal.remove();
}
const modal = document.createElement('div');
modal.id = modalId;
modal.className = 'modal fade';
modal.setAttribute('tabindex', '-1');
modal.setAttribute('aria-labelledby', 'ebayAlertModalLabel');
modal.setAttribute('aria-hidden', 'true');
// Définir les couleurs et icônes selon le type
let iconClass = 'ti-info-alt';
let iconColor = '#0064D2';
let title = 'Information';
switch (type) {
case 'success': iconClass = 'ti-check-box';
iconColor = '#0A7C42';
title = 'Succès';
break;
case 'error':
case 'danger': iconClass = 'ti-alert';
iconColor = '#D32F2F';
title = 'Erreur';
break;
case 'warning': iconClass = 'ti-alert-triangle';
iconColor = '#F57C00';
title = 'Attention';
break;
default: iconClass = 'ti-info-alt';
iconColor = '#0064D2';
title = 'Information';
}
modal.innerHTML = `
<div class=\"modal-dialog modal-dialog-centered\">
<div class=\"modal-content\" style=\"border-radius: 8px; border: none; box-shadow: 0 4px 20px rgba(0,0,0,0.15);\">
<div class=\"modal-header\" style=\"border-bottom: 1px solid #e0e0e0; padding: 20px 24px;\">
<h5 class=\"modal-title\" id=\"ebayAlertModalLabel\" style=\"font-weight: 600; font-size: 18px; color: #333;\">
<i class=\"\${iconClass}\" style=\"color: \${iconColor}; margin-right: 8px;\"></i>\${title}
</h5>
<button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\" aria-label=\"Close\" style=\"margin: 0;\"></button>
</div>
<div class=\"modal-body\" style=\"padding: 24px; text-align: center;\">
<p style=\"margin: 0; font-size: 16px; color: #333; line-height: 1.5;\">\${message}</p>
</div>
<div class=\"modal-footer\" style=\"border-top: 1px solid #e0e0e0; padding: 16px 24px; justify-content: center;\">
<button type=\"button\" class=\"btn btn-primary\" data-bs-dismiss=\"modal\" style=\"min-width: 100px; background-color: \${iconColor}; border-color: \${iconColor}; border-radius: 4px; font-weight: 500;\">
OK
</button>
</div>
</div>
</div>
`;
document.body.appendChild(modal);
const bsModal = new bootstrap.Modal(modal);
bsModal.show();
// Supprimer le modal du DOM après fermeture
modal.addEventListener('hidden.bs.modal', function () {
modal.remove();
});
}
// Rendre la fonction globale
window.showEbayModal = showEbayModal;
document.addEventListener('DOMContentLoaded', function () { // Initialisation des données d'images pour chaque produit
{% for product in products %}
{% set allImages = product.images|default([]) %}
{% if product.variants is defined %}
\t{% for variant in product.variants %}
\t\t{% if variant.isActive and variant.images is defined %}
\t\t\t{% for variantImg in variant.images %}
\t\t\t\t{% set allImages = allImages|merge([variantImg]) %}
\t\t\t{% endfor %}
\t\t{% endif %}
\t{% endfor %}
{% endif %}
{% if allImages|length > 0 %}productImages[{{ product.id }}] = [{% for img in allImages %}'{{ asset(img) }}'{% if not loop.last %},{% endif %}{% endfor %}];
currentImageIndex[{{ product.id }}] = 0;
console.log('Initialized product {{ product.id }} with images:', productImages[{{ product.id }}]);{% endif %}{% endfor %}
// Gestion du panier
const cartButtons = document.querySelectorAll('.add-to-cart');
cartButtons.forEach(button => {
button.addEventListener('click', function () {
const productId = this.getAttribute('data-product-id');
const qty = this.getAttribute('data-qty');
fetch('{{ path(\"ui_cart_add\") }}', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: 'productId=' + productId + '&qty=' + qty
}).then(response => response.json()).then(data => {
if (data.ok) {
showEbayModal('Produit ajouté au panier !', 'success');
// Mettre à jour le compteur du panier si présent
const cartBadge = document.querySelector('.cart-badge');
if (cartBadge) {
cartBadge.textContent = data.totalQty;
}
} else {
showEbayModal(data.message || 'Erreur lors de l\\'ajout au panier', 'error');
}
}).catch(error => {
console.error('Erreur:', error);
showEbayModal('Erreur lors de l\\'ajout au panier', 'error');
});
});
});
});
// Fonctions pour la navigation des images
window.showImageNav = function(productId) {
const leftBtn = document.getElementById('img-left-' + productId);
const rightBtn = document.getElementById('img-right-' + productId);
const indicators = document.getElementById('img-indicators-' + productId);
if (leftBtn) {
leftBtn.style.display = 'flex';
}
if (rightBtn) {
rightBtn.style.display = 'flex';
}
if (indicators) {
indicators.style.display = 'flex';
}
};
window.hideImageNav = function(productId) {
const leftBtn = document.getElementById('img-left-' + productId);
const rightBtn = document.getElementById('img-right-' + productId);
const indicators = document.getElementById('img-indicators-' + productId);
if (leftBtn) {
leftBtn.style.display = 'none';
}
if (rightBtn) {
rightBtn.style.display = 'none';
}
if (indicators) {
indicators.style.display = 'none';
}
};
window.showImage = function(productId, imageIndex) {
if (! productImages[productId] || ! productImages[productId][imageIndex]) {
console.log('Image not found for product', productId, 'index', imageIndex);
return;
}
const img = document.getElementById('main-img-' + productId);
if (img) {
console.log('Changing image to:', productImages[productId][imageIndex]);
// Force le rechargement de l'image
img.style.opacity = '0.5';
setTimeout(() => {
img.src = productImages[productId][imageIndex];
img.style.opacity = '1';
currentImageIndex[productId] = imageIndex;
updateIndicators(productId);
}, 100);
} else {
console.log('Image element not found:', 'main-img-' + productId);
}
};
window.nextImage = function(productId) {
if (! productImages[productId]) {
console.log('No images for product', productId);
return;
}
const nextIndex = (currentImageIndex[productId] + 1) % productImages[productId].length;
showImage(productId, nextIndex);
};
window.prevImage = function(productId) {
if (! productImages[productId]) {
console.log('No images for product', productId);
return;
}
const prevIndex = currentImageIndex[productId] === 0 ? productImages[productId].length - 1 : currentImageIndex[productId] - 1;
showImage(productId, prevIndex);
};
function updateIndicators(productId) {
const indicators = document.querySelectorAll('#img-indicators-' + productId + ' .indicator');
indicators.forEach((indicator, index) => {
indicator.classList.toggle('active', index === currentImageIndex[productId]);
});
}
// Fonction pour tracker la vue d'un produit
function trackProductView(productId) {
fetch (`/api/track-product-view/\${productId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
}
}).then(response => response.json()).then(data => {
if (data.success) {
console.log (`Vue enregistrée pour le produit \${productId}:`, data.viewCount);
}
}).catch(error => {
console.error('Erreur lors du tracking:', error);
});
}
// Fonction pour tracker la vue d'une boutique
function trackShopView(shopId) {
fetch (`/api/track-shop-view/\${shopId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
}
}).then(response => response.json()).then(data => {
if (data.success) {
console.log (`Vue enregistrée pour la boutique \${shopId}:`, data.viewCount);
}
}).catch(error => {
console.error('Erreur lors du tracking:', error);
});
}
// Ajouter le tracking aux événements existants
document.addEventListener('DOMContentLoaded', function () { // Tracking au survol des produits (avec délai)
const productCards = document.querySelectorAll('.single_product_item');
productCards.forEach(card => {
const productId = card.dataset.productId;
const shopId = card.dataset.shopId;
if (productId) {
let hoverTimeout;
card.addEventListener('mouseenter', () => { // Tracker la vue du produit après 2 secondes de survol
hoverTimeout = setTimeout(() => {
trackProductView(productId);
}, 2000);
});
card.addEventListener('mouseleave', () => {
clearTimeout(hoverTimeout);
});
// Tracking au clic sur le lien du produit
const productLink = card.querySelector('.product_img a');
if (productLink) {
productLink.addEventListener('click', () => {
trackProductView(productId);
});
}
}
// Tracking au clic sur le lien de la boutique
if (shopId) {
const shopLink = card.querySelector('.shop-link');
if (shopLink) {
shopLink.addEventListener('click', () => {
trackShopView(shopId);
});
}
}
});
});
</script>
<script>
\t// Système de filtrage AJAX avancé
// currentFilters est déjà déclaré plus haut, on met juste à jour les valeurs
if (typeof currentFilters !== 'undefined') { // Mettre à jour les valeurs existantes
currentFilters.category = '{{ currentCategory }}';
currentFilters.brand = '{{ currentBrand }}';
currentFilters.condition = '{{ currentCondition }}';
currentFilters.sort = '{{ currentSort }}';
currentFilters.priceMin = '{{ priceMin }}';
currentFilters.priceMax = '{{ priceMax }}';
currentFilters.page = {{ currentPage }};
currentFilters.q = currentFilters.q || '{{ app.request.query.get('q', '') }}';
// Ajouter les nouveaux filtres depuis l'URL s'ils n'existent pas
if (! currentFilters.shop)
currentFilters.shop = '{{ app.request.query.get('shop', '') }}';
if (! currentFilters.featured)
currentFilters.featured = '{{ app.request.query.get('featured', '') }}';
if (! currentFilters.digital)
currentFilters.digital = '{{ app.request.query.get('digital', '') }}';
if (! currentFilters.stockStatus)
currentFilters.stockStatus = '{{ app.request.query.get('stock_status', '') }}';
if (! currentFilters.ratingMin)
currentFilters.ratingMin = '{{ app.request.query.get('rating_min', '') }}';
if (! currentFilters.rating)
currentFilters.rating = '{{ app.request.query.get('rating_min', '') }}';
if (! currentFilters.weightMin)
currentFilters.weightMin = '{{ app.request.query.get('weight_min', '') }}';
if (! currentFilters.weightMax)
currentFilters.weightMax = '{{ app.request.query.get('weight_max', '') }}';
if (! currentFilters.color)
currentFilters.color = '{{ app.request.query.get('color', '') }}';
if (! currentFilters.size)
currentFilters.size = '{{ app.request.query.get('size', '') }}';
if (! currentFilters.material)
currentFilters.material = '{{ app.request.query.get('material', '') }}';
if (! currentFilters.condition)
currentFilters.condition = '{{ app.request.query.get('condition', '') }}';
if (! currentFilters.availability)
currentFilters.availability = '{{ app.request.query.get('availability', '') }}';
} else { // Si currentFilters n'existe pas, le créer avec les valeurs de l'URL
let currentFilters = {
category: '{{ currentCategory ?? '' }}',
brand: '{{ currentBrand ?? '' }}',
condition: '{{ currentCondition ?? '' }}',
sort: '{{ currentSort ?? 'newest' }}',
priceMin: '{{ app.request.query.get('price_min', '') }}',
priceMax: '{{ app.request.query.get('price_max', '') }}',
page: {{ currentPage }},
q: '{{ app.request.query.get('q', '') }}',
// Nouveaux filtres depuis l'URL
shop: '{{ app.request.query.get('shop', '') }}',
featured: '{{ app.request.query.get('featured', '') }}',
digital: '{{ app.request.query.get('digital', '') }}',
stockStatus: '{{ app.request.query.get('stock_status', '') }}',
ratingMin: '{{ app.request.query.get('rating_min', '') }}',
rating: '{{ app.request.query.get('rating_min', '') }}',
weightMin: '{{ app.request.query.get('weight_min', '') }}',
weightMax: '{{ app.request.query.get('weight_max', '') }}',
color: '{{ app.request.query.get('color', '') }}',
size: '{{ app.request.query.get('size', '') }}',
material: '{{ app.request.query.get('material', '') }}',
condition: '{{ app.request.query.get('condition', '') }}',
availability: '{{ app.request.query.get('availability', '') }}'
};
}
// Fonction pour appliquer les filtres
function applyFilters() {
const url = new URL('{{ path('ui_api_products_filter') }}', window.location.origin);
// Ajouter les paramètres
Object.keys(currentFilters).forEach(key => {
if (currentFilters[key] && currentFilters[key] !== '') { // Mapper les clés pour l'API
let apiKey = key;
if (key === 'priceMin') {
apiKey = 'price_min';
} else if (key === 'priceMax') {
apiKey = 'price_max';
} else if (key === 'ratingMin') {
apiKey = 'rating_min';
} else if (key === 'weightMin') {
apiKey = 'weight_min';
} else if (key === 'weightMax') {
apiKey = 'weight_max';
} else if (key === 'stockStatus') {
apiKey = 'stock_status';
}
url.searchParams.set(apiKey, currentFilters[key]);
}
});
// Afficher le loader
document.getElementById('productsContainer').innerHTML = '<div class=\"col-12 text-center\"><i class=\"fa fa-spinner fa-spin\"></i> Chargement...</div>';
// Faire la requête AJAX
fetch(url).then(response => response.json()).then(data => {
if (data.success) { // Mettre à jour les produits
document.getElementById('productsContainer').innerHTML = data.products;
// Mettre à jour la pagination
currentPage = data.pagination.currentPage;
totalPages = data.pagination.totalPages;
hasMoreProducts = currentPage < totalPages;
// Préserver l'état des filtres statiques avant la mise à jour
const preservedFilters = {
featured: currentFilters.featured,
digital: currentFilters.digital,
availability: currentFilters.availability,
rating: currentFilters.rating || currentFilters.ratingMin
};
// Mettre à jour les marques disponibles (toujours afficher toutes)
updateAvailableBrands(data.availableBrands || []);
// Mettre à jour les conditions disponibles (toujours afficher toutes)
updateAvailableConditions(data.availableConditions || []);
// Mettre à jour les boutiques disponibles (toujours afficher toutes)
updateAvailableShops(data.availableShops || []);
// Mettre à jour les attributs disponibles (toujours afficher tous)
updateAvailableAttributes(data.availableAttributes || {});
// Restaurer l'état des filtres statiques après la mise à jour
restoreStaticFiltersState(preservedFilters);
// Réinitialiser les filtres depuis currentFilters pour s'assurer qu'ils sont tous cochés
if (typeof initializeFiltersFromURL === 'function') {
initializeFiltersFromURL();
}
// Mettre à jour l'URL
updateURL();
// Mettre à jour l'affichage du bouton
updateLoadMoreButton();
// Réinitialiser les event listeners pour les nouveaux produits
const tempDiv = document.createElement('div');
tempDiv.innerHTML = data.products;
initializeProductEventListeners(tempDiv);
initializeProductImages(tempDiv);
// Mettre à jour les filtres actifs
if (typeof updateActiveFilters === 'function') {
updateActiveFilters();
}
}
}).catch(error => {
console.error('Erreur lors du filtrage:', error);
document.getElementById('productsContainer').innerHTML = '<div class=\"col-12 text-center text-danger\">Erreur lors du chargement des produits</div>';
});
}
// Exposer la fonction globalement
window.applyFilters = applyFilters;
// Fonction pour appliquer le tri
function applySorting() {
currentFilters.sort = document.getElementById('sortSelect').value;
currentFilters.page = 1;
applyFilters();
}
// Fonction pour appliquer le filtre de prix
function applyPriceFilter() {
currentFilters.priceMin = document.getElementById('priceMin').value;
currentFilters.priceMax = document.getElementById('priceMax').value;
currentFilters.page = 1;
applyFilters();
}
// Fonction pour appliquer le filtre de poids
function applyWeightFilter() {
currentFilters.weightMin = document.getElementById('weightMin').value;
currentFilters.weightMax = document.getElementById('weightMax').value;
currentFilters.page = 1;
applyFilters();
}
// Fonction pour changer de page
function changePage(page) {
currentFilters.page = page;
applyFilters();
}
// Fonction pour mettre à jour les marques disponibles
function updateAvailableBrands(brands) {
const brandsFilter = document.getElementById('brandsFilter');
const brandList = document.getElementById('brandList');
const currentBrandValue = currentFilters.brand || '';
// Toujours afficher le filtre des marques
brandsFilter.style.display = 'block';
// Si pas de marques disponibles, garder les marques existantes ou afficher un message
if (brands.length === 0) { // Ne pas réinitialiser si la liste existe déjà et a du contenu
if (brandList && brandList.children.length > 0) { // Juste mettre à jour les états cochés
const existingRadios = brandList.querySelectorAll('input[name=\"brand\"]');
existingRadios.forEach(radio => {
if (currentBrandValue && radio.value === currentBrandValue) {
radio.checked = true;
} else if (! currentBrandValue && radio.id === 'all-brands') {
radio.checked = true;
} else {
radio.checked = false;
}
});
return; // Garder les marques existantes
}
// Sinon, afficher un message
brandList.innerHTML = '<li class=\"filter-list\"><span class=\"text-muted\">Aucune marque disponible</span></li>';
return;
}
let html = '';
const isAllSelected = ! currentBrandValue || currentBrandValue === '';
html += `<li class=\"filter-list\"><input class=\"pixel-radio\" type=\"radio\" id=\"all-brands\" name=\"brand\" \${
isAllSelected ? 'checked' : ''
}><label for=\"all-brands\">Toutes les marques</label></li>`;
brands.forEach(brand => {
const isSelected = currentBrandValue === brand.slug;
html += `<li class=\"filter-list\">
<input class=\"pixel-radio\" type=\"radio\" id=\"brand-\${
brand.id
}\" name=\"brand\" value=\"\${
brand.slug
}\" \${
isSelected ? 'checked' : ''
}>
<label for=\"brand-\${
brand.id
}\">\${
brand.name
}<span>(\${
brand.productCount
})</span></label>
</li>`;
});
brandList.innerHTML = html;
// Ajouter les event listeners
brandList.querySelectorAll('input[name=\"brand\"]').forEach(radio => {
radio.addEventListener('change', function () {
if (this.id === 'all-brands') {
currentFilters.brand = '';
} else {
currentFilters.brand = this.value;
} currentFilters.page = 1;
applyFilters();
});
});
}
// Fonction pour mettre à jour les conditions disponibles
function updateAvailableConditions(conditions) {
const conditionList = document.getElementById('conditionList');
const currentConditionValue = currentFilters.condition || '';
// Toujours garder le contenu statique et juste mettre à jour les états cochés
if (conditionList && conditionList.children.length > 0) {
const existingRadios = conditionList.querySelectorAll('input[name=\"condition\"]');
existingRadios.forEach(radio => {
if (currentConditionValue && radio.value === currentConditionValue) {
radio.checked = true;
} else if (! currentConditionValue && radio.id === 'all-conditions') {
radio.checked = true;
} else {
radio.checked = false;
}
});
return; // Garder les conditions existantes
}
// Si pas de contenu statique, générer dynamiquement
if (conditions.length === 0) {
conditionList.innerHTML = '<li class=\"filter-list\"><span class=\"text-muted\">Aucune condition disponible</span></li>';
return;
}
let html = '';
const isAllSelected = ! currentConditionValue || currentConditionValue === '';
html += `<li class=\"filter-list\"><input class=\"pixel-radio\" type=\"radio\" id=\"all-conditions\" name=\"condition\" \${
isAllSelected ? 'checked' : ''
}><label for=\"all-conditions\">Toutes les conditions</label></li>`;
conditions.forEach(condition => {
const isSelected = currentConditionValue === condition.slug;
html += `<li class=\"filter-list\">
<input class=\"pixel-radio\" type=\"radio\" id=\"condition-\${
condition.id
}\" name=\"condition\" value=\"\${
condition.slug
}\" \${
isSelected ? 'checked' : ''
}>
<label for=\"condition-\${
condition.id
}\">\${
condition.name
}<span>(\${
condition.productCount
})</span></label>
</li>`;
});
conditionList.innerHTML = html;
// Ajouter les event listeners
conditionList.querySelectorAll('input[name=\"condition\"]').forEach(radio => {
radio.addEventListener('change', function () {
if (this.id === 'all-conditions') {
currentFilters.condition = '';
} else {
currentFilters.condition = this.value;
} currentFilters.page = 1;
applyFilters();
});
});
}
// Fonction pour mettre à jour les boutiques disponibles
function updateAvailableShops(shops) {
const shopsFilter = document.getElementById('shopsFilter');
const shopList = document.getElementById('shopList');
const currentShopValue = currentFilters.shop || '';
// Toujours afficher le filtre des boutiques
shopsFilter.style.display = 'block';
// Si pas de boutiques disponibles, afficher un message ou garder les boutiques existantes
if (shops.length === 0) { // Ne pas réinitialiser si la liste existe déjà et a du contenu
if (shopList && shopList.children.length > 0) {
return; // Garder les boutiques existantes
}
// Sinon, afficher un message
shopList.innerHTML = '<li class=\"filter-list\"><span class=\"text-muted\">Aucune boutique disponible</span></li>';
return;
}
let html = '';
const isAllSelected = ! currentShopValue || currentShopValue === '';
html += `<li class=\"filter-list\"><input class=\"pixel-radio\" type=\"radio\" id=\"all-shops\" name=\"shop\" \${
isAllSelected ? 'checked' : ''
}><label for=\"all-shops\">Toutes les boutiques</label></li>`;
shops.forEach(shop => {
const isSelected = currentShopValue === shop.slug;
html += `<li class=\"filter-list\">
<input class=\"pixel-radio\" type=\"radio\" id=\"shop-\${
shop.id
}\" name=\"shop\" value=\"\${
shop.slug
}\" \${
isSelected ? 'checked' : ''
}>
<label for=\"shop-\${
shop.id
}\">\${
shop.name
}<span>(\${
shop.productCount
})</span></label>
</li>`;
});
shopList.innerHTML = html;
// Mettre à jour aussi le modal
const modalShopList = document.getElementById('modalShopList');
if (modalShopList) {
modalShopList.innerHTML = html.replace(/id=\"all-shops\"/g, 'id=\"modal-all-shops\"').replace(/id=\"shop-/g, 'id=\"modal-shop-').replace(/name=\"shop\"/g, 'name=\"modal-shop\"').replace(/for=\"all-shops\"/g, 'for=\"modal-all-shops\"').replace(/for=\"shop-/g, 'for=\"modal-shop-');
}
// Ajouter les event listeners (seulement pour la sidebar, le modal gère ses propres listeners)
shopList.querySelectorAll('input[name=\"shop\"]').forEach(radio => {
radio.addEventListener('change', function () {
if (this.id === 'all-shops') {
currentFilters.shop = '';
} else {
currentFilters.shop = this.value;
} currentFilters.page = 1;
applyFilters();
});
});
}
// Fonction pour mettre à jour les attributs disponibles
function updateAvailableAttributes(attributes) {
// Toujours afficher tous les filtres d'attributs, même s'ils ne sont pas pertinents
// Couleurs
updateAttributeFilter('colors', attributes.colors, 'colorList', 'colorsFilter');
// Tailles
updateAttributeFilter('sizes', attributes.sizes, 'sizeList', 'sizesFilter');
// Matériaux
updateAttributeFilter('materials', attributes.materials, 'materialList', 'materialsFilter');
// Conditions
updateAttributeFilter('conditions', attributes.conditions, 'conditionList', 'conditionsFilter');
}
// Fonction générique pour mettre à jour les filtres d'attributs
function updateAttributeFilter(attributeType, attributes, listId, filterId) {
const filter = document.getElementById(filterId);
const list = document.getElementById(listId);
const currentValue = currentFilters[attributeType] || '';
// Toujours afficher les filtres d'attributs
filter.style.display = 'block';
// Si pas d'attributs disponibles, afficher un message ou garder les attributs existants
if (! attributes || attributes.length === 0) { // Ne pas réinitialiser si la liste existe déjà et a du contenu
if (list && list.children.length > 0) {
return; // Garder les attributs existants
}
// Sinon, afficher un message
list.innerHTML = '<li class=\"filter-list\"><span class=\"text-muted\">Aucun attribut disponible</span></li>';
return;
}
let html = '';
const isAllSelected = ! currentValue || currentValue === '';
html += `<li class=\"filter-list\"><input class=\"pixel-radio\" type=\"radio\" id=\"all-\${attributeType}\" name=\"\${attributeType}\" \${
isAllSelected ? 'checked' : ''
}><label for=\"all-\${attributeType}\">Tous</label></li>`;
attributes.forEach(attr => {
const isSelected = currentValue === attr.value;
html += `<li class=\"filter-list\">
<input class=\"pixel-radio\" type=\"radio\" id=\"\${attributeType}-\${
attr.value
}\" name=\"\${attributeType}\" value=\"\${
attr.value
}\" \${
isSelected ? 'checked' : ''
}>
<label for=\"\${attributeType}-\${
attr.value
}\">\${
attr.value
}<span>(\${
attr.count
})</span></label>
</li>`;
});
list.innerHTML = html;
// Mettre à jour aussi le modal (si l'élément existe)
const modalListId = 'modal' + listId.charAt(0).toUpperCase() + listId.slice(1); // modalColorList, modalSizeList, etc.
const modalList = document.getElementById(modalListId);
if (modalList) { // Adapter le HTML pour le modal (changer les IDs et names)
let modalHtml = html.replace(new RegExp (`id=\"all-\${attributeType}\"`, 'g'), `id=\"modal-all-\${attributeType}\"`).replace(new RegExp (`id=\"\${attributeType}-`, 'g'), `id=\"modal-\${attributeType}-`).replace(new RegExp (`name=\"\${attributeType}\"`, 'g'), `name=\"modal-\${attributeType}\"`).replace(new RegExp (`for=\"all-\${attributeType}\"`, 'g'), `for=\"modal-all-\${attributeType}\"`).replace(new RegExp (`for=\"\${attributeType}-`, 'g'), `for=\"modal-\${attributeType}-`);
modalList.innerHTML = modalHtml;
}
// Ajouter les event listeners (seulement pour la sidebar, le modal gère ses propres listeners)
list.querySelectorAll (`input[name=\"\${attributeType}\"]`).forEach(radio => {
radio.addEventListener('change', function () {
if (this.id === `all-\${attributeType}`) {
currentFilters[attributeType] = '';
} else {
currentFilters[attributeType] = this.value;
} currentFilters.page = 1;
applyFilters();
});
});
} else {
filter.style.display = 'none';
}
}
// Fonction pour mettre à jour l'URL
function updateURL () {
const url = new URL(window.location);
// Supprimer les anciens paramètres
const paramsToRemove = [
'category',
'brand',
'sort',
'price_min',
'price_max',
'page',
'shop',
'featured',
'digital',
'stock_status',
'rating_min',
'weight_min',
'weight_max',
'color',
'size',
'material',
'condition',
'availability'
];
paramsToRemove.forEach(param => url.searchParams.delete(param));
// Ajouter les nouveaux paramètres
Object.keys(currentFilters).forEach(key => {
if (currentFilters[key]) {
url.searchParams.set(key, currentFilters[key]);
}
});
// Mettre à jour l'URL sans recharger la page
window.history.pushState({}, '', url);
}
// Fonction pour restaurer l'état des filtres statiques
function restoreStaticFiltersState (preservedFilters) { // Restaurer featured
if (preservedFilters.featured) {
const featuredInput = document.querySelector (`input[name=\"featured\"][value=\"\${
preservedFilters.featured
}\"]`);
if (featuredInput) {
featuredInput.checked = true;
} else {
const featuredAll = document.getElementById('featured-all');
if (featuredAll)
featuredAll.checked = true;
}
} else {
const featuredAll = document.getElementById('featured-all');
if (featuredAll)
featuredAll.checked = true;
}
// Restaurer digital
if (preservedFilters.digital) {
const digitalInput = document.querySelector (`input[name=\"digital\"][value=\"\${
preservedFilters.digital
}\"]`);
if (digitalInput) {
digitalInput.checked = true;
} else {
const digitalAll = document.getElementById('digital-all');
if (digitalAll)
digitalAll.checked = true;
}
} else {
const digitalAll = document.getElementById('digital-all');
if (digitalAll)
digitalAll.checked = true;
}
// Restaurer availability
if (preservedFilters.availability) {
const availabilityInput = document.querySelector (`input[name=\"availability\"][value=\"\${
preservedFilters.availability
}\"]`);
if (availabilityInput) {
availabilityInput.checked = true;
} else {
const availabilityAll = document.getElementById('availability-all');
if (availabilityAll)
availabilityAll.checked = true;
}
} else {
const availabilityAll = document.getElementById('availability-all');
if (availabilityAll)
availabilityAll.checked = true;
}
// Restaurer rating (mapping vers ratingMin)
if (preservedFilters.rating) {
const ratingInput = document.querySelector (`input[name=\"rating\"][value=\"\${
preservedFilters.rating
}\"]`);
if (ratingInput) {
ratingInput.checked = true;
} else {
const ratingAll = document.getElementById('rating-all');
if (ratingAll)
ratingAll.checked = true;
}
} else {
const ratingAll = document.getElementById('rating-all');
if (ratingAll)
ratingAll.checked = true;
}
}
// Fonction pour initialiser tous les filtres avec les valeurs de l'URL
function initializeFiltersFromURL () { // Initialiser les filtres statiques
const staticFilters = {
featured: currentFilters.featured || '',
digital: currentFilters.digital || '',
availability: currentFilters.availability || '',
rating: currentFilters.rating || currentFilters.ratingMin || ''
};
// Cocher les filtres statiques
Object.keys(staticFilters).forEach(filterName => {
const value = staticFilters[filterName];
if (value) {
const input = document.querySelector(`input[name=\"\${filterName}\"][value=\"\${value}\"]`);
if (input) {
input.checked = true;
} else { // Cocher \"all\" si la valeur n'existe pas
const allInput = document.getElementById (`\${filterName}-all`);
if (allInput)
allInput.checked = true;
}
} else {
const allInput = document.getElementById (`\${filterName}-all`);
if (allInput)
allInput.checked = true;
}
});
// Initialiser les filtres de poids
if (currentFilters.weightMin) {
const weightMinInput = document.getElementById('weightMin');
if (weightMinInput)
weightMinInput.value = currentFilters.weightMin;
}
if (currentFilters.weightMax) {
const weightMaxInput = document.getElementById('weightMax');
if (weightMaxInput)
weightMaxInput.value = currentFilters.weightMax;
}
// Initialiser les filtres de marque (si déjà chargés)
if (currentFilters.brand) {
const brandInput = document.querySelector (`input[name=\"brand\"][value=\"\${
currentFilters.brand
}\"]`);
if (brandInput) {
brandInput.checked = true;
} else {
const allBrands = document.getElementById('all-brands');
if (allBrands)
allBrands.checked = true;
}
}
// Initialiser les filtres de boutique (si déjà chargés)
if (currentFilters.shop) {
const shopInput = document.querySelector (`input[name=\"shop\"][value=\"\${
currentFilters.shop
}\"]`);
if (shopInput) {
shopInput.checked = true;
} else {
const allShops = document.getElementById('all-shops');
if (allShops)
allShops.checked = true;
}
}
// Initialiser les filtres d'attributs (si déjà chargés)
['color', 'size', 'material', 'condition'].forEach(attrType => {
if (currentFilters[attrType]) {
const attrInput = document.querySelector(`input[name=\"\${attrType}\"][value=\"\${
currentFilters[attrType]
}\"]`);
if (attrInput) {
attrInput.checked = true;
} else {
const allAttr = document.getElementById (`all-\${attrType}`);
if (allAttr)
allAttr.checked = true;
}
}
});
}
// Initialiser les filtres
document.addEventListener('DOMContentLoaded', function () { // Initialiser les filtres depuis l'URL
initializeFiltersFromURL();
// Event listeners pour les filtres statiques
const staticFilters = ['featured', 'digital', 'availability'];
staticFilters.forEach(filterName => {
const inputs = document.querySelectorAll (`input[name=\"\${filterName}\"]`);
inputs.forEach(input => {
input.addEventListener('change', function () {
if (this.id.includes('-all')) {
currentFilters[filterName] = '';
} else {
currentFilters[filterName] = this.value;
}
currentFilters.page = 1;
applyFilters();
});
});
});
// Event listener spécial pour rating (mapping vers ratingMin)
const ratingInputs = document.querySelectorAll('input[name=\"rating\"]');
ratingInputs.forEach(input => {
input.addEventListener('change', function () {
if (this.id === 'rating-all') {
currentFilters.ratingMin = '';
currentFilters.rating = '';
} else {
currentFilters.ratingMin = this.value;
currentFilters.rating = this.value;
}
currentFilters.page = 1;
applyFilters();
});
});
// Event listeners pour les filtres de poids
const weightInputs = ['weightMin', 'weightMax'];
weightInputs.forEach(inputId => {
const input = document.getElementById(inputId);
if (input) {
input.addEventListener('change', applyWeightFilter);
input.addEventListener('input', debounce(applyWeightFilter, 500));
}
});
// Event listeners pour les filtres de prix
const priceInputs = ['priceMin', 'priceMax'];
priceInputs.forEach(inputId => {
const input = document.getElementById(inputId);
if (input) {
input.addEventListener('change', applyPriceFilter);
input.addEventListener('input', debounce(applyPriceFilter, 500));
}
});
// Ajouter les event listeners pour les marques existantes
const brandList = document.getElementById('brandList');
if (brandList) {
brandList.querySelectorAll('input[name=\"brand\"]').forEach(radio => {
radio.addEventListener('change', function () {
if (this.id === 'all-brands') {
currentFilters.brand = '';
} else {
currentFilters.brand = this.value;
}
currentFilters.page = 1;
applyFilters();
});
});
}
// Appliquer les filtres initiaux si une catégorie est sélectionnée
if (currentFilters.category) {
applyFilters();
} else { // Initialiser l'affichage du bouton au chargement de la page
updateLoadMoreButton();
}
});
// Fonction de debounce pour éviter trop de requêtes
function debounce (func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// Les fonctions toggleComparison, toggleWishlist, et showNotification sont définies globalement dans base_home.html.twig
// Pas besoin de les redéfinir ici
// Fonctions pour le dropshipping
function generateDropshipLink (productId) {
showEbayPromptModal('URL originale (optionnel):', '').then(originalUrl => {
if (originalUrl === null)
return;
// Utilisateur a annulé
const formData = new FormData();
formData.append('originalUrl', originalUrl || '');
fetch (`/api/dropship/generate/\${productId}`, {
method: 'POST',
body: formData
}).then(response => response.json()).then(data => {
if (data.success) { // Afficher le lien généré dans une modal
showDropshipLinkModal(data.data);
} else {
showNotification(data.message || 'Erreur lors de la génération du lien', 'error');
}
}).catch(error => {
console.error('Erreur:', error);
showNotification('Erreur lors de la génération du lien', 'error');
});
});
}
function showDropshipLinkModal (linkData) {
const modal = document.createElement('div');
modal.className = 'modal fade show';
modal.style.display = 'block';
modal.innerHTML = `
<div class=\"modal-dialog\">
<div class=\"modal-content\">
<div class=\"modal-header\">
<h5 class=\"modal-title\">
<i class=\"fa fa-share-alt\"></i> Lien de dropshipping généré
</h5>
<button type=\"button\" class=\"btn-close\" onclick=\"closeModal(this)\"></button>
</div>
<div class=\"modal-body\">
<div class=\"mb-3\">
<label class=\"form-label\">Lien de dropshipping :</label>
<div class=\"input-group\">
<input type=\"text\" class=\"form-control\" value=\"\${
linkData.dropshipUrl
}\" readonly id=\"dropshipUrl\">
<button class=\"btn btn-outline-secondary\" onclick=\"copyToClipboard('\${
linkData.dropshipUrl
}')\">
<i class=\"fa fa-copy\"></i>
</button>
</div>
</div>
<div class=\"row\">
<div class=\"col-md-6\">
<div class=\"card\">
<div class=\"card-body text-center\">
<h6 class=\"card-title\">Taux de commission</h6>
<h4 class=\"text-primary\">\${
linkData.commissionRate
}%</h4>
</div>
</div>
</div>
<div class=\"col-md-6\">
<div class=\"card\">
<div class=\"card-body text-center\">
<h6 class=\"card-title\">Commission par vente</h6>
<h4 class=\"text-success\">\${
linkData.commissionAmount
} HTG</h4>
</div>
</div>
</div>
</div>
<div class=\"alert alert-info\">
<i class=\"fa fa-info-circle\"></i>
<strong>Note :</strong> Ce lien expire le \${
new Date(linkData.expiresAt).toLocaleDateString('fr-FR')
}.
</div>
</div>
<div class=\"modal-footer\">
<button type=\"button\" class=\"btn btn-secondary\" onclick=\"closeModal(this)\">Fermer</button>
<a href=\"/dropship/dashboard\" class=\"btn btn-primary\">
<i class=\"fa fa-tachometer\"></i> Voir le dashboard
</a>
</div>
</div>
</div>
`;
document.body.appendChild(modal);
// Ajouter le backdrop
const backdrop = document.createElement('div');
backdrop.className = 'modal-backdrop fade show';
document.body.appendChild(backdrop);
}
function closeModal (button) {
const modal = button.closest('.modal');
const backdrop = document.querySelector('.modal-backdrop');
if (modal) {
modal.remove();
}
if (backdrop) {
backdrop.remove();
}
}
function copyToClipboard (text) {
navigator.clipboard.writeText(text).then(function () {
showNotification('Lien copié dans le presse-papiers !', 'success');
}, function (err) {
console.error('Erreur lors de la copie:', err);
showNotification('Erreur lors de la copie du lien', 'error');
});
}
// Fonction pour initialiser le chargement infini
function initInfiniteScroll () {
const loader = document.getElementById('infiniteScrollLoader');
const noMoreProducts = document.getElementById('noMoreProducts');
// Afficher le loader si il y a plus de produits
if (hasMoreProducts && loader) {
loader.style.display = 'block';
} else if (!hasMoreProducts && noMoreProducts) {
noMoreProducts.style.display = 'block';
}
// Observer pour détecter quand l'utilisateur arrive en bas
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting && !isLoading && hasMoreProducts) {
loadMoreProducts();
}
});
}, {
root: null,
rootMargin: '200px', // Démarrer le chargement 200px avant d'arriver en bas
threshold: 0.1
});
// Observer le loader
if (loader) {
observer.observe(loader);
}
}
// Fonction pour mettre à jour l'affichage du bouton
function updateLoadMoreButton () {
const loadMoreContainer = document.getElementById('loadMoreContainer');
const noMoreProducts = document.getElementById('noMoreProducts');
if (hasMoreProducts) {
if (loadMoreContainer) {
loadMoreContainer.style.display = 'block';
}
if (noMoreProducts) {
noMoreProducts.style.display = 'none';
}
} else {
if (loadMoreContainer) {
loadMoreContainer.style.display = 'none';
}
if (noMoreProducts) {
noMoreProducts.style.display = 'block';
}
}
}
// Fonction pour initialiser les images des nouveaux produits
function initializeProductImages (container) {
const productCards = container.querySelectorAll('.single-product');
productCards.forEach(card => {
const productId = card.querySelector('.add-to-cart') ?. getAttribute('data-product-id');
if (productId) { // Récupérer les images depuis les attributs data ou depuis le DOM
const imgElement = card.querySelector('.main-product-img');
if (imgElement && imgElement.dataset.images) {
const images = JSON.parse(imgElement.dataset.images);
productImages[productId] = images;
currentImageIndex[productId] = 0;
}
}
});
}
// Fonction pour initialiser les event listeners des nouveaux produits
function initializeProductEventListeners (container) { // Boutons d'ajout au panier
const cartButtons = container.querySelectorAll('.add-to-cart');
cartButtons.forEach(button => {
button.addEventListener('click', function () {
const productId = this.getAttribute('data-product-id');
const qty = this.getAttribute('data-qty');
fetch('{{ path(\"ui_cart_add\") }}', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: 'productId=' + productId + '&qty=' + qty
}).then(response => response.json()).then(data => {
if (data.ok) {
showEbayModal('Produit ajouté au panier !', 'success');
const cartBadge = document.querySelector('.cart-badge');
if (cartBadge) {
cartBadge.textContent = data.totalQty;
}
} else {
showEbayModal(data.message || 'Erreur lors de l\\'ajout au panier', 'error');
}
}).catch(error => {
console.error('Erreur:', error);
showEbayModal('Erreur lors de l\\'ajout au panier', 'error');
});
});
});
}
// La fonction showEbayModal est déjà définie plus haut
// Modal style eBay pour remplacer prompt()
function showEbayPromptModal (message, defaultValue = '') {
return new Promise((resolve) => {
const modalId = 'ebayPromptModal';
let existingModal = document.getElementById(modalId);
if (existingModal) {
existingModal.remove();
}
const modal = document.createElement('div');
modal.id = modalId;
modal.className = 'modal fade';
modal.setAttribute('tabindex', '-1');
modal.setAttribute('aria-labelledby', 'ebayPromptModalLabel');
modal.setAttribute('aria-hidden', 'true');
modal.innerHTML = `
<div class=\"modal-dialog modal-dialog-centered\">
<div class=\"modal-content\" style=\"border-radius: 8px; border: none; box-shadow: 0 4px 20px rgba(0,0,0,0.15);\">
<div class=\"modal-header\" style=\"border-bottom: 1px solid #e0e0e0; padding: 20px 24px;\">
<h5 class=\"modal-title\" id=\"ebayPromptModalLabel\" style=\"font-weight: 600; font-size: 18px; color: #333;\">
<i class=\"ti-pencil-alt\" style=\"color: #0064D2; margin-right: 8px;\"></i>Saisie
</h5>
<button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\" aria-label=\"Close\" style=\"margin: 0;\"></button>
</div>
<div class=\"modal-body\" style=\"padding: 24px;\">
<p style=\"margin-bottom: 16px; font-size: 16px; color: #333;\">\${message}</p>
<input type=\"text\" class=\"form-control\" id=\"ebayPromptInput\" value=\"\${defaultValue}\" style=\"border-radius: 4px; border: 1px solid #ccc; padding: 10px; font-size: 14px;\" autofocus>
</div>
<div class=\"modal-footer\" style=\"border-top: 1px solid #e0e0e0; padding: 16px 24px; justify-content: flex-end;\">
<button type=\"button\" class=\"btn btn-secondary\" data-bs-dismiss=\"modal\" style=\"min-width: 80px; border-radius: 4px; font-weight: 500; margin-right: 8px;\">
Annuler
</button>
<button type=\"button\" class=\"btn btn-primary\" id=\"ebayPromptConfirm\" style=\"min-width: 80px; background-color: #0064D2; border-color: #0064D2; border-radius: 4px; font-weight: 500;\">
OK
</button>
</div>
</div>
</div>
`;
document.body.appendChild(modal);
const bsModal = new bootstrap.Modal(modal);
const input = modal.querySelector('#ebayPromptInput');
const confirmBtn = modal.querySelector('#ebayPromptConfirm');
// Gérer la confirmation
confirmBtn.addEventListener('click', function () {
const value = input.value;
bsModal.hide();
resolve(value);
});
// Gérer l'annulation
modal.addEventListener('hidden.bs.modal', function () {
if (input.value === undefined || input.value === '') {
resolve(null);
}
modal.remove();
});
// Gérer la touche Entrée
input.addEventListener('keypress', function (e) {
if (e.key === 'Enter') {
confirmBtn.click();
}
});
bsModal.show();
input.focus();
input.select();
});
}
// Remplacer window.alert et window.prompt
window.alert = showEbayModal;
window.prompt = showEbayPromptModal;
</script>
<script>
\t// Gestion du toggle de la sidebar sur mobile
document.addEventListener('DOMContentLoaded', function () {
const sidebarToggle = document.querySelector('.listing-sidebar-toggle');
const sidebarCollapse = document.getElementById('listingSidebarCollapse');
if (sidebarToggle && sidebarCollapse) { // Bootstrap 5 utilise des événements natifs
sidebarCollapse.addEventListener('show.bs.collapse', function () {
sidebarToggle.classList.remove('collapsed');
sidebarToggle.setAttribute('aria-expanded', 'true');
});
sidebarCollapse.addEventListener('hide.bs.collapse', function () {
sidebarToggle.classList.add('collapsed');
sidebarToggle.setAttribute('aria-expanded', 'false');
});
sidebarCollapse.addEventListener('shown.bs.collapse', function () {
sidebarToggle.classList.remove('collapsed');
});
sidebarCollapse.addEventListener('hidden.bs.collapse', function () {
sidebarToggle.classList.add('collapsed');
});
// Vérifier l'état initial
if (sidebarCollapse.classList.contains('show')) {
sidebarToggle.classList.remove('collapsed');
sidebarToggle.setAttribute('aria-expanded', 'true');
} else {
sidebarToggle.classList.add('collapsed');
sidebarToggle.setAttribute('aria-expanded', 'false');
}
}
});
// Synchroniser la recherche avec la barre de recherche du header
const headerSearchInput = document.getElementById('search_input');
if (headerSearchInput && typeof currentFilters !== 'undefined') { // Mettre à jour la valeur de la barre de recherche du header
headerSearchInput.value = currentFilters.q || '';
// Afficher le bouton clear si nécessaire
const clearSearchBtn = document.getElementById('clear_search_btn');
if (clearSearchBtn) {
clearSearchBtn.style.display = currentFilters.q ? 'block' : 'none';
}
}
// Réinitialiser tous les filtres
const resetFiltersBtn = document.getElementById('resetFiltersBtn');
if (resetFiltersBtn) {
resetFiltersBtn.addEventListener('click', function () {
resetAllFilters();
});
}
// Fonction pour réinitialiser tous les filtres
function resetAllFilters () {
currentFilters = {
category: '',
brand: '',
sort: 'newest',
priceMin: '',
priceMax: '',
page: 1,
q: '',
shop: '',
featured: '',
digital: '',
stockStatus: '',
ratingMin: '',
rating: '',
weightMin: '',
weightMax: '',
color: '',
size: '',
material: '',
condition: '',
availability: ''
};
// Réinitialiser la barre de recherche du header
const headerSearchInput = document.getElementById('search_input');
if (headerSearchInput) {
headerSearchInput.value = '';
}
const clearSearchBtn = document.getElementById('clear_search_btn');
if (clearSearchBtn) {
clearSearchBtn.style.display = 'none';
}
// Réinitialiser les inputs
document.getElementById('sortSelect').value = 'newest';
// Réinitialiser les radios
document.querySelectorAll('input[type=\"radio\"]').forEach(radio => {
if (radio.id.includes('all-') || radio.id.includes('featured-all') || radio.id.includes('digital-all') || radio.id.includes('availability-all') || radio.id.includes('rating-all')) {
radio.checked = true;
} else {
radio.checked = false;
}
});
// Réinitialiser les inputs de prix et poids
const weightMinInput = document.getElementById('weightMin');
const weightMaxInput = document.getElementById('weightMax');
if (weightMinInput)
weightMinInput.value = '';
if (weightMaxInput)
weightMaxInput.value = '';
applyFilters();
updateActiveFilters();
}
// Fonction pour mettre à jour l'affichage des filtres actifs
function updateActiveFilters () {
const activeFiltersDiv = document.getElementById('activeFilters');
const activeFiltersList = document.getElementById('activeFiltersList');
const filters = [];
if (currentFilters.q) {
filters.push (`<span class=\"badge bg-primary\">Recherche: \"\${
currentFilters.q
}\"</span>`);
}
if (currentFilters.category) {
filters.push(`<span class=\"badge bg-secondary\">Catégorie</span>`);
}
if (currentFilters.brand) {
filters.push(`<span class=\"badge bg-secondary\">Marque</span>`);
}
if (currentFilters.priceMin || currentFilters.priceMax) {
filters.push(`<span class=\"badge bg-info\">Prix</span>`);
}
if (currentFilters.featured === 'true') {
filters.push(`<span class=\"badge bg-warning\">Produits vedettes</span>`);
}
if (currentFilters.digital === 'true') {
filters.push(`<span class=\"badge bg-success\">Numériques</span>`);
}
if (currentFilters.digital === 'false') {
filters.push(`<span class=\"badge bg-success\">Physiques</span>`);
}
if (currentFilters.availability) {
filters.push(`<span class=\"badge bg-info\">Disponibilité</span>`);
}
if (currentFilters.ratingMin || currentFilters.rating) {
const ratingValue = currentFilters.ratingMin || currentFilters.rating;
filters.push (`<span class=\"badge bg-warning\">Note ≥ \${ratingValue}</span>`);
}
if (currentFilters.weightMin || currentFilters.weightMax) {
filters.push(`<span class=\"badge bg-secondary\">Poids</span>`);
}
if (filters.length > 0) {
activeFiltersList.innerHTML = filters.join(' ');
activeFiltersDiv.style.display = 'block';
} else {
activeFiltersDiv.style.display = 'none';
}
}
// Mettre à jour les filtres actifs au chargement et après chaque filtrage
document.addEventListener('DOMContentLoaded', function () {
updateActiveFilters();
});
// Mettre à jour les filtres actifs après chaque application de filtres
const originalApplyFilters = applyFilters;
applyFilters = function () {
originalApplyFilters();
setTimeout(updateActiveFilters, 100);
// Mettre à jour le compteur de filtres actifs
updateActiveFiltersCount();
};
// S'assurer que applyFilters est accessible globalement
window.applyFilters = applyFilters;
// Fonction pour mettre à jour le compteur de filtres actifs
function updateActiveFiltersCount () {
const count = Object.keys(currentFilters).filter(key => {
const value = currentFilters[key];
return value && value !== '' && key !== 'page' && key !== 'sort';
}).length;
const badge = document.getElementById('activeFiltersCount');
if (badge) {
if (count > 0) {
badge.textContent = count;
badge.style.display = 'inline-block';
} else {
badge.style.display = 'none';
}
}
}
// Initialiser le compteur au chargement
document.addEventListener('DOMContentLoaded', function () {
updateActiveFiltersCount();
});
</script>
<!-- Modal de filtres -->
<div class=\"modal fade\" id=\"filtersModal\" tabindex=\"-1\" aria-labelledby=\"filtersModalLabel\" aria-hidden=\"true\">
\t<div class=\"modal-dialog modal-lg\">
\t\t<div class=\"modal-content\" style=\"display: flex; flex-direction: column; max-height: 90vh;\">
\t\t\t<div class=\"modal-header\" style=\"flex-shrink: 0;\">
\t\t\t\t<h5 class=\"modal-title\" id=\"filtersModalLabel\">
\t\t\t\t\t<i class=\"lnr lnr-filter me-2\"></i>Filtres de recherche
\t\t\t\t</h5>
\t\t\t\t<button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\" aria-label=\"Close\"></button>
\t\t\t</div>
\t\t\t<div class=\"modal-body\" style=\"overflow-y: auto; flex: 1; min-height: 0;\">
\t\t\t\t<div
\t\t\t\t\tclass=\"row\">
\t\t\t\t\t<!-- Colonne gauche -->
\t\t\t\t\t<div
\t\t\t\t\t\tclass=\"col-md-6\">
\t\t\t\t\t\t<!-- Marques -->
\t\t\t\t\t\t<div class=\"common-filter mb-4\">
\t\t\t\t\t\t\t<div class=\"head\">Marques</div>
\t\t\t\t\t\t\t<ul class=\"brand-list\" id=\"modalBrandList\">
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-all-brands\" name=\"modal-brand\" checked>
\t\t\t\t\t\t\t\t\t<label for=\"modal-all-brands\">Toutes les marques</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t{% for brand in brands %}
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-brand-{{ brand.id }}\" name=\"modal-brand\" value=\"{{ brand.slug }}\">
\t\t\t\t\t\t\t\t\t\t<label for=\"modal-brand-{{ brand.id }}\">{{ brand.name }}<span>({{ brand.getActiveProductsCount() }})</span>
\t\t\t\t\t\t\t\t\t\t</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t{% endfor %}
\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<!-- Conditions -->
\t\t\t\t\t\t<div class=\"common-filter mb-4\">
\t\t\t\t\t\t\t<div class=\"head\">Condition</div>
\t\t\t\t\t\t\t<ul class=\"condition-list\" id=\"modalConditionList\">
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-all-conditions\" name=\"modal-condition\" checked>
\t\t\t\t\t\t\t\t\t<label for=\"modal-all-conditions\">Toutes les conditions</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t{% for condition in conditions %}
\t\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-condition-{{ condition.id }}\" name=\"modal-condition\" value=\"{{ condition.slug }}\">
\t\t\t\t\t\t\t\t\t\t<label for=\"modal-condition-{{ condition.id }}\">{{ condition.name }}<span>({{ condition.getActiveProductsCount() }})</span>
\t\t\t\t\t\t\t\t\t\t</label>
\t\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t{% endfor %}
\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<!-- Boutiques -->
\t\t\t\t\t\t<div class=\"common-filter mb-4\">
\t\t\t\t\t\t\t<div class=\"head\">Boutiques</div>
\t\t\t\t\t\t\t<div id=\"modalShopsFilter\">
\t\t\t\t\t\t\t\t<ul
\t\t\t\t\t\t\t\t\tclass=\"shop-list\" id=\"modalShopList\"><!-- Les boutiques seront chargées dynamiquement -->
\t\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<!-- Produits vedettes -->
\t\t\t\t\t\t<div class=\"common-filter mb-4\">
\t\t\t\t\t\t\t<div class=\"head\">Produits vedettes</div>
\t\t\t\t\t\t\t<ul>
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-featured-all\" name=\"modal-featured\" checked>
\t\t\t\t\t\t\t\t\t<label for=\"modal-featured-all\">Tous les produits</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-featured-only\" name=\"modal-featured\" value=\"true\">
\t\t\t\t\t\t\t\t\t<label for=\"modal-featured-only\">Produits vedettes uniquement</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<!-- Type de produit -->
\t\t\t\t\t\t<div class=\"common-filter mb-4\">
\t\t\t\t\t\t\t<div class=\"head\">Type de produit</div>
\t\t\t\t\t\t\t<ul>
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-digital-all\" name=\"modal-digital\" checked>
\t\t\t\t\t\t\t\t\t<label for=\"modal-digital-all\">Tous les types</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-digital-physical\" name=\"modal-digital\" value=\"false\">
\t\t\t\t\t\t\t\t\t<label for=\"modal-digital-physical\">Produits physiques</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-digital-digital\" name=\"modal-digital\" value=\"true\">
\t\t\t\t\t\t\t\t\t<label for=\"modal-digital-digital\">Produits numériques</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t</div>
\t\t\t\t\t</div>
\t\t\t\t\t<!-- Colonne droite -->
\t\t\t\t\t<div
\t\t\t\t\t\tclass=\"col-md-6\">
\t\t\t\t\t\t<!-- Disponibilité -->
\t\t\t\t\t\t<div class=\"common-filter mb-4\">
\t\t\t\t\t\t\t<div class=\"head\">Disponibilité</div>
\t\t\t\t\t\t\t<ul>
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-availability-all\" name=\"modal-availability\" checked>
\t\t\t\t\t\t\t\t\t<label for=\"modal-availability-all\">Tous</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-availability-in-stock\" name=\"modal-availability\" value=\"in_stock\">
\t\t\t\t\t\t\t\t\t<label for=\"modal-availability-in-stock\">En stock</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-availability-low-stock\" name=\"modal-availability\" value=\"low_stock\">
\t\t\t\t\t\t\t\t\t<label for=\"modal-availability-low-stock\">Stock faible</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-availability-out-of-stock\" name=\"modal-availability\" value=\"out_of_stock\">
\t\t\t\t\t\t\t\t\t<label for=\"modal-availability-out-of-stock\">Rupture de stock</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<!-- Note minimale -->
\t\t\t\t\t\t<div class=\"common-filter mb-4\">
\t\t\t\t\t\t\t<div class=\"head\">Note minimale</div>
\t\t\t\t\t\t\t<ul>
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-rating-all\" name=\"modal-rating\" checked>
\t\t\t\t\t\t\t\t\t<label for=\"modal-rating-all\">Toutes les notes</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-rating-4\" name=\"modal-rating\" value=\"4\">
\t\t\t\t\t\t\t\t\t<label for=\"modal-rating-4\">4 étoiles et plus</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-rating-3\" name=\"modal-rating\" value=\"3\">
\t\t\t\t\t\t\t\t\t<label for=\"modal-rating-3\">3 étoiles et plus</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t\t<li class=\"filter-list\">
\t\t\t\t\t\t\t\t\t<input class=\"pixel-radio\" type=\"radio\" id=\"modal-rating-2\" name=\"modal-rating\" value=\"2\">
\t\t\t\t\t\t\t\t\t<label for=\"modal-rating-2\">2 étoiles et plus</label>
\t\t\t\t\t\t\t\t</li>
\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<!-- Prix -->
\t\t\t\t\t\t<div class=\"common-filter mb-4\">
\t\t\t\t\t\t\t<div class=\"head\">Prix (HTG)</div>
\t\t\t\t\t\t\t<div class=\"price-range-area\">
\t\t\t\t\t\t\t\t<div class=\"d-flex gap-3\">
\t\t\t\t\t\t\t\t\t<div class=\"flex-grow-1\">
\t\t\t\t\t\t\t\t\t\t<label class=\"form-label\">Min</label>
\t\t\t\t\t\t\t\t\t\t<input type=\"number\" class=\"form-control\" id=\"modal-priceMin\" placeholder=\"0\" min=\"0\" step=\"0.01\">
\t\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t\t\t<div class=\"flex-grow-1\">
\t\t\t\t\t\t\t\t\t\t<label class=\"form-label\">Max</label>
\t\t\t\t\t\t\t\t\t\t<input type=\"number\" class=\"form-control\" id=\"modal-priceMax\" placeholder=\"999999\" min=\"0\" step=\"0.01\">
\t\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<!-- Poids -->
\t\t\t\t\t\t<div class=\"common-filter mb-4\">
\t\t\t\t\t\t\t<div class=\"head\">Poids (kg)</div>
\t\t\t\t\t\t\t<div class=\"weight-range-area\">
\t\t\t\t\t\t\t\t<div class=\"d-flex gap-3\">
\t\t\t\t\t\t\t\t\t<div class=\"flex-grow-1\">
\t\t\t\t\t\t\t\t\t\t<label class=\"form-label\">Min</label>
\t\t\t\t\t\t\t\t\t\t<input type=\"number\" class=\"form-control\" id=\"modal-weightMin\" placeholder=\"0\" step=\"0.1\" min=\"0\">
\t\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t\t\t<div class=\"flex-grow-1\">
\t\t\t\t\t\t\t\t\t\t<label class=\"form-label\">Max</label>
\t\t\t\t\t\t\t\t\t\t<input type=\"number\" class=\"form-control\" id=\"modal-weightMax\" placeholder=\"100\" step=\"0.1\" min=\"0\">
\t\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<!-- Couleur -->
\t\t\t\t\t\t<div class=\"common-filter mb-4\">
\t\t\t\t\t\t\t<div class=\"head\">Couleur</div>
\t\t\t\t\t\t\t<div id=\"modalColorsFilter\">
\t\t\t\t\t\t\t\t<ul
\t\t\t\t\t\t\t\t\tclass=\"color-list\" id=\"modalColorList\"><!-- Les couleurs seront chargées dynamiquement -->
\t\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<!-- Taille -->
\t\t\t\t\t\t<div class=\"common-filter mb-4\">
\t\t\t\t\t\t\t<div class=\"head\">Taille</div>
\t\t\t\t\t\t\t<div id=\"modalSizesFilter\">
\t\t\t\t\t\t\t\t<ul
\t\t\t\t\t\t\t\t\tclass=\"size-list\" id=\"modalSizeList\"><!-- Les tailles seront chargées dynamiquement -->
\t\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t</div>
\t\t\t\t\t\t<!-- Matériau -->
\t\t\t\t\t\t<div class=\"common-filter mb-4\">
\t\t\t\t\t\t\t<div class=\"head\">Matériau</div>
\t\t\t\t\t\t\t<div id=\"modalMaterialsFilter\">
\t\t\t\t\t\t\t\t<ul
\t\t\t\t\t\t\t\t\tclass=\"material-list\" id=\"modalMaterialList\"><!-- Les matériaux seront chargés dynamiquement -->
\t\t\t\t\t\t\t\t</ul>
\t\t\t\t\t\t\t</div>
\t\t\t\t\t\t</div>
\t\t\t\t\t</div>
\t\t\t\t</div>
\t\t\t</div>
\t\t\t<div class=\"modal-footer\" style=\"flex-shrink: 0; border-top: 1px solid #dee2e6; padding: 1rem 1.5rem; background: #f8f9fa;\">
\t\t\t\t<button type=\"button\" class=\"btn btn-secondary\" data-bs-dismiss=\"modal\">
\t\t\t\t\t<i class=\"lnr lnr-cross-circle me-1\"></i>Annuler
\t\t\t\t</button>
\t\t\t\t<button type=\"button\" class=\"btn btn-outline-danger\" id=\"modalResetFiltersBtn\">
\t\t\t\t\t<i class=\"lnr lnr-refresh me-1\"></i>Réinitialiser
\t\t\t\t</button>
\t\t\t\t<button type=\"button\" class=\"btn btn-primary\" id=\"modalApplyFiltersBtn\">
\t\t\t\t\t<i class=\"lnr lnr-checkmark-circle me-1\"></i>Appliquer les filtres
\t\t\t\t</button>
\t\t\t</div>
\t\t</div>
\t</div>
</div>
<script>
\t// Synchroniser les filtres du modal avec currentFilters au chargement
document.addEventListener('DOMContentLoaded', function () {
console.log('[Modal] Initializing filter modal...');
// Fonction pour synchroniser les valeurs du modal avec currentFilters
function syncModalFilters() {
console.log('[Modal] Syncing filters with currentFilters:', currentFilters);
// Réinitialiser tous les radios \"Tous\" d'abord
document.querySelectorAll('#filtersModal input[type=\"radio\"][id*=\"-all\"]').forEach(radio => {
radio.checked = true;
});
// Marques
if (currentFilters.brand) {
const brandRadio = document.querySelector (`#modalBrandList input[value=\"\${
currentFilters.brand
}\"]`);
if (brandRadio) {
brandRadio.checked = true;
console.log('[Modal] Brand synced:', currentFilters.brand);
}
} else {
const allBrands = document.getElementById('modal-all-brands');
if (allBrands)
allBrands.checked = true;
}
// Conditions
if (currentFilters.condition) {
const conditionRadio = document.querySelector (`#modalConditionList input[value=\"\${
currentFilters.condition
}\"]`);
if (conditionRadio) {
conditionRadio.checked = true;
console.log('[Modal] Condition synced:', currentFilters.condition);
}
} else {
const allConditions = document.getElementById('modal-all-conditions');
if (allConditions)
allConditions.checked = true;
}
// Featured
if (currentFilters.featured === 'true') {
const featuredRadio = document.getElementById('modal-featured-only');
if (featuredRadio) {
featuredRadio.checked = true;
console.log('[Modal] Featured synced');
}
} else {
const allFeatured = document.getElementById('modal-featured-all');
if (allFeatured)
allFeatured.checked = true;
}
// Digital
if (currentFilters.digital === 'true') {
const digitalRadio = document.getElementById('modal-digital-digital');
if (digitalRadio)
digitalRadio.checked = true;
} else if (currentFilters.digital === 'false') {
const physicalRadio = document.getElementById('modal-digital-physical');
if (physicalRadio)
physicalRadio.checked = true;
} else {
const allDigital = document.getElementById('modal-digital-all');
if (allDigital)
allDigital.checked = true;
}
// Availability
if (currentFilters.availability) {
const availabilityId = `modal-availability-\${
currentFilters.availability.replace('_', '-')
}`;
const availabilityRadio = document.getElementById(availabilityId);
if (availabilityRadio) {
availabilityRadio.checked = true;
console.log('[Modal] Availability synced:', currentFilters.availability);
}
} else {
const allAvailability = document.getElementById('modal-availability-all');
if (allAvailability)
allAvailability.checked = true;
}
// Rating
if (currentFilters.ratingMin || currentFilters.rating) {
const ratingValue = currentFilters.ratingMin || currentFilters.rating;
const ratingRadio = document.getElementById (`modal-rating-\${ratingValue}`);
if (ratingRadio) {
ratingRadio.checked = true;
console.log('[Modal] Rating synced:', ratingValue);
}
} else {
const allRating = document.getElementById('modal-rating-all');
if (allRating)
allRating.checked = true;
}
// Prix
const priceMinInput = document.getElementById('modal-priceMin');
const priceMaxInput = document.getElementById('modal-priceMax');
if (priceMinInput)
priceMinInput.value = currentFilters.priceMin || '';
if (priceMaxInput)
priceMaxInput.value = currentFilters.priceMax || '';
// Poids
const weightMinInput = document.getElementById('modal-weightMin');
const weightMaxInput = document.getElementById('modal-weightMax');
if (weightMinInput)
weightMinInput.value = currentFilters.weightMin || '';
if (weightMaxInput)
weightMaxInput.value = currentFilters.weightMax || '';
console.log('[Modal] Filters synced successfully');
}
// Fonction pour charger les filtres dynamiques dans le modal
function loadDynamicFiltersToModal() {
console.log('[Modal] Loading dynamic filters...');
// Boutiques
const sidebarShopList = document.getElementById('shopList');
const modalShopList = document.getElementById('modalShopList');
if (modalShopList) { // Si la sidebar a déjà les boutiques, les copier
if (sidebarShopList && sidebarShopList.innerHTML.trim() && ! sidebarShopList.innerHTML.includes('Aucune boutique') && ! sidebarShopList.innerHTML.includes('seront chargées')) {
let shopHtml = sidebarShopList.innerHTML.replace(/id=\"all-shops\"/g, 'id=\"modal-all-shops\"').replace(/id=\"shop-/g, 'id=\"modal-shop-').replace(/name=\"shop\"/g, 'name=\"modal-shop\"').replace(/for=\"all-shops\"/g, 'for=\"modal-all-shops\"').replace(/for=\"shop-/g, 'for=\"modal-shop-');
modalShopList.innerHTML = shopHtml;
// Synchroniser la sélection
if (currentFilters.shop) {
const shopRadio = document.querySelector (`#modalShopList input[value=\"\${
currentFilters.shop
}\"]`);
if (shopRadio)
shopRadio.checked = true;
} else {
const allShops = document.getElementById('modal-all-shops');
if (allShops)
allShops.checked = true;
}
console.log('[Modal] Shops loaded from sidebar');
} else { // Si pas encore chargés, afficher un message ou laisser vide
if (! modalShopList.innerHTML.trim() || modalShopList.innerHTML.includes('seront chargées')) {
modalShopList.innerHTML = '<li class=\"filter-list\"><span class=\"text-muted\">Les boutiques seront chargées lors de l\\'application des filtres</span></li>';
}
}
}
// Couleurs
const sidebarColorList = document.getElementById('colorList');
const modalColorList = document.getElementById('modalColorList');
if (sidebarColorList && modalColorList) {
if (sidebarColorList.innerHTML.trim() && ! sidebarColorList.innerHTML.includes('Aucun')) {
let colorHtml = sidebarColorList.innerHTML.replace(/id=\"all-color\"/g, 'id=\"modal-all-color\"').replace(/id=\"color-/g, 'id=\"modal-color-').replace(/name=\"color\"/g, 'name=\"modal-color\"').replace(/for=\"all-color\"/g, 'for=\"modal-all-color\"').replace(/for=\"color-/g, 'for=\"modal-color-');
modalColorList.innerHTML = colorHtml;
// Synchroniser la sélection
if (currentFilters.color) {
const colorRadio = document.querySelector (`#modalColorList input[value=\"\${
currentFilters.color
}\"]`);
if (colorRadio)
colorRadio.checked = true;
} else {
const allColor = document.getElementById('modal-all-color');
if (allColor)
allColor.checked = true;
}
console.log('[Modal] Colors loaded');
}
}
// Tailles
const sidebarSizeList = document.getElementById('sizeList');
const modalSizeList = document.getElementById('modalSizeList');
if (sidebarSizeList && modalSizeList) {
if (sidebarSizeList.innerHTML.trim() && ! sidebarSizeList.innerHTML.includes('Aucun')) {
let sizeHtml = sidebarSizeList.innerHTML.replace(/id=\"all-size\"/g, 'id=\"modal-all-size\"').replace(/id=\"size-/g, 'id=\"modal-size-').replace(/name=\"size\"/g, 'name=\"modal-size\"').replace(/for=\"all-size\"/g, 'for=\"modal-all-size\"').replace(/for=\"size-/g, 'for=\"modal-size-');
modalSizeList.innerHTML = sizeHtml;
// Synchroniser la sélection
if (currentFilters.size) {
const sizeRadio = document.querySelector (`#modalSizeList input[value=\"\${
currentFilters.size
}\"]`);
if (sizeRadio)
sizeRadio.checked = true;
} else {
const allSize = document.getElementById('modal-all-size');
if (allSize)
allSize.checked = true;
}
console.log('[Modal] Sizes loaded');
}
}
// Matériaux
const sidebarMaterialList = document.getElementById('materialList');
const modalMaterialList = document.getElementById('modalMaterialList');
if (sidebarMaterialList && modalMaterialList) {
if (sidebarMaterialList.innerHTML.trim() && ! sidebarMaterialList.innerHTML.includes('Aucun')) {
let materialHtml = sidebarMaterialList.innerHTML.replace(/id=\"all-material\"/g, 'id=\"modal-all-material\"').replace(/id=\"material-/g, 'id=\"modal-material-').replace(/name=\"material\"/g, 'name=\"modal-material\"').replace(/for=\"all-material\"/g, 'for=\"modal-all-material\"').replace(/for=\"material-/g, 'for=\"modal-material-');
modalMaterialList.innerHTML = materialHtml;
// Synchroniser la sélection
if (currentFilters.material) {
const materialRadio = document.querySelector (`#modalMaterialList input[value=\"\${
currentFilters.material
}\"]`);
if (materialRadio)
materialRadio.checked = true;
} else {
const allMaterial = document.getElementById('modal-all-material');
if (allMaterial)
allMaterial.checked = true;
}
console.log('[Modal] Materials loaded');
}
}
}
// Synchroniser à l'ouverture du modal
const filtersModal = document.getElementById('filtersModal');
if (filtersModal) {
filtersModal.addEventListener('show.bs.modal', function () {
console.log('[Modal] Modal opening, syncing filters...');
// Charger les filtres dynamiques d'abord si pas encore chargés
loadDynamicFiltersToModal();
// Puis synchroniser les valeurs
setTimeout(() => {
syncModalFilters();
}, 100);
});
}
// Charger les filtres dynamiques au chargement initial si la sidebar les a déjà
loadDynamicFiltersToModal();
// Bouton Appliquer les filtres
const applyBtn = document.getElementById('modalApplyFiltersBtn');
if (applyBtn) {
applyBtn.addEventListener('click', function (e) {
e.preventDefault();
console.log('[Modal] Apply button clicked, collecting filter values...');
// Collecter les valeurs du modal
const brandRadio = document.querySelector('#modalBrandList input[name=\"modal-brand\"]:checked');
if (brandRadio) {
currentFilters.brand = brandRadio.id !== 'modal-all-brands' ? brandRadio.value : '';
console.log('[Modal] Brand:', currentFilters.brand);
} else {
currentFilters.brand = '';
console.log('[Modal] Brand: No selection found');
}
// Conditions
const conditionRadio = document.querySelector('#modalConditionList input[name=\"modal-condition\"]:checked');
if (conditionRadio) {
currentFilters.condition = conditionRadio.id !== 'modal-all-conditions' ? conditionRadio.value : '';
console.log('[Modal] Condition:', currentFilters.condition);
} else {
currentFilters.condition = '';
}
// Featured
const featuredRadio = document.querySelector('#filtersModal input[name=\"modal-featured\"]:checked');
if (featuredRadio) {
currentFilters.featured = featuredRadio.id !== 'modal-featured-all' ? featuredRadio.value : '';
console.log('[Modal] Featured:', currentFilters.featured);
} else {
currentFilters.featured = '';
}
// Digital
const digitalRadio = document.querySelector('#filtersModal input[name=\"modal-digital\"]:checked');
if (digitalRadio) {
currentFilters.digital = digitalRadio.id !== 'modal-digital-all' ? digitalRadio.value : '';
console.log('[Modal] Digital:', currentFilters.digital);
} else {
currentFilters.digital = '';
}
// Availability
const availabilityRadio = document.querySelector('#filtersModal input[name=\"modal-availability\"]:checked');
if (availabilityRadio) {
currentFilters.availability = availabilityRadio.id !== 'modal-availability-all' ? availabilityRadio.value : '';
console.log('[Modal] Availability:', currentFilters.availability);
} else {
currentFilters.availability = '';
}
// Rating
const ratingRadio = document.querySelector('#filtersModal input[name=\"modal-rating\"]:checked');
if (ratingRadio && ratingRadio.id !== 'modal-rating-all') {
currentFilters.ratingMin = ratingRadio.value;
currentFilters.rating = ratingRadio.value;
console.log('[Modal] Rating:', currentFilters.ratingMin);
} else {
currentFilters.ratingMin = '';
currentFilters.rating = '';
}
// Prix
const priceMinInput = document.getElementById('modal-priceMin');
const priceMaxInput = document.getElementById('modal-priceMax');
currentFilters.priceMin = priceMinInput ? priceMinInput.value.trim() : '';
currentFilters.priceMax = priceMaxInput ? priceMaxInput.value.trim() : '';
console.log('[Modal] Price:', currentFilters.priceMin, '-', currentFilters.priceMax);
// Poids
const weightMinInput = document.getElementById('modal-weightMin');
const weightMaxInput = document.getElementById('modal-weightMax');
currentFilters.weightMin = weightMinInput ? weightMinInput.value.trim() : '';
currentFilters.weightMax = weightMaxInput ? weightMaxInput.value.trim() : '';
console.log('[Modal] Weight:', currentFilters.weightMin, '-', currentFilters.weightMax);
// Couleur
const colorRadio = document.querySelector('#modalColorList input[name=\"modal-color\"]:checked');
if (colorRadio) {
currentFilters.color = colorRadio.id !== 'modal-all-color' ? colorRadio.value : '';
console.log('[Modal] Color:', currentFilters.color);
} else {
currentFilters.color = '';
}
// Taille
const sizeRadio = document.querySelector('#modalSizeList input[name=\"modal-size\"]:checked');
if (sizeRadio) {
currentFilters.size = sizeRadio.id !== 'modal-all-size' ? sizeRadio.value : '';
console.log('[Modal] Size:', currentFilters.size);
} else {
currentFilters.size = '';
}
// Matériau
const materialRadio = document.querySelector('#modalMaterialList input[name=\"modal-material\"]:checked');
if (materialRadio) {
currentFilters.material = materialRadio.id !== 'modal-all-material' ? materialRadio.value : '';
console.log('[Modal] Material:', currentFilters.material);
} else {
currentFilters.material = '';
}
// Boutiques
const shopRadio = document.querySelector('#modalShopList input[name=\"modal-shop\"]:checked');
if (shopRadio) {
currentFilters.shop = shopRadio.id !== 'modal-all-shops' ? shopRadio.value : '';
console.log('[Modal] Shop:', currentFilters.shop);
} else {
currentFilters.shop = '';
}
currentFilters.page = 1;
console.log('[Modal] All filters collected:', currentFilters);
// Fermer le modal d'abord
const modalElement = document.getElementById('filtersModal');
const modal = bootstrap.Modal.getInstance(modalElement);
if (modal) {
modal.hide();
console.log('[Modal] Modal closed');
}
// Appliquer les filtres après un court délai pour laisser le modal se fermer
setTimeout(() => { // Vérifier que applyFilters existe
if (typeof window.applyFilters === 'function') {
console.log('[Modal] Calling applyFilters()...');
window.applyFilters();
// Mettre à jour le compteur de filtres actifs
setTimeout(() => {
if (typeof updateActiveFiltersCount === 'function') {
updateActiveFiltersCount();
}
}, 100);
} else {
console.error('[Modal] applyFilters is not available!', typeof window.applyFilters);
// Essayer de recharger la page avec les nouveaux paramètres
const url = new URL(window.location.href);
Object.keys(currentFilters).forEach(key => {
if (currentFilters[key] && currentFilters[key] !== '') {
let apiKey = key;
if (key === 'priceMin') {
apiKey = 'price_min';
} else if (key === 'priceMax') {
apiKey = 'price_max';
} else if (key === 'ratingMin') {
apiKey = 'rating_min';
} else if (key === 'weightMin') {
apiKey = 'weight_min';
} else if (key === 'weightMax') {
apiKey = 'weight_max';
} else if (key === 'stockStatus') {
apiKey = 'stock_status';
}
url.searchParams.set(apiKey, currentFilters[key]);
} else {
let apiKey = key;
if (key === 'priceMin') {
apiKey = 'price_min';
} else if (key === 'priceMax') {
apiKey = 'price_max';
} else if (key === 'ratingMin') {
apiKey = 'rating_min';
} else if (key === 'weightMin') {
apiKey = 'weight_min';
} else if (key === 'weightMax') {
apiKey = 'weight_max';
} else if (key === 'stockStatus') {
apiKey = 'stock_status';
}
url.searchParams.delete(apiKey);
}
});
window.location.href = url.toString();
}
}, 300);
});
} else {
console.error('[Modal] Apply button not found!');
}
// Bouton Réinitialiser
const resetBtn = document.getElementById('modalResetFiltersBtn');
if (resetBtn) {
resetBtn.addEventListener('click', function () {
console.log('[Modal] Reset button clicked');
// Réinitialiser tous les filtres du modal
document.querySelectorAll('#filtersModal input[type=\"radio\"]').forEach(radio => {
if (radio.id && radio.id.includes('-all')) {
radio.checked = true;
} else {
radio.checked = false;
}
});
const priceMinInput = document.getElementById('modal-priceMin');
const priceMaxInput = document.getElementById('modal-priceMax');
const weightMinInput = document.getElementById('modal-weightMin');
const weightMaxInput = document.getElementById('modal-weightMax');
if (priceMinInput)
priceMinInput.value = '';
if (priceMaxInput)
priceMaxInput.value = '';
if (weightMinInput)
weightMinInput.value = '';
if (weightMaxInput)
weightMaxInput.value = '';
// Réinitialiser currentFilters (garder category et sort)
const category = currentFilters.category || '';
const sort = currentFilters.sort || 'newest';
currentFilters = {
category: category,
sort: sort,
page: 1,
brand: '',
condition: '',
featured: '',
digital: '',
availability: '',
ratingMin: '',
rating: '',
priceMin: '',
priceMax: '',
weightMin: '',
weightMax: '',
color: '',
size: '',
material: '',
shop: ''
};
console.log('[Modal] Filters reset, currentFilters:', currentFilters);
// Fermer le modal d'abord
const modalElement = document.getElementById('filtersModal');
const modal = bootstrap.Modal.getInstance(modalElement);
if (modal) {
modal.hide();
console.log('[Modal] Modal closed after reset');
}
// Appliquer les filtres après un court délai
setTimeout(() => {
if (typeof window.applyFilters === 'function') {
window.applyFilters();
} else {
console.error('[Modal] applyFilters not available, reloading page...');
// Recharger la page avec les filtres réinitialisés
const url = new URL(window.location.href);
url.searchParams.delete('price_min');
url.searchParams.delete('price_max');
url.searchParams.delete('rating_min');
url.searchParams.delete('weight_min');
url.searchParams.delete('weight_max');
url.searchParams.delete('brand');
url.searchParams.delete('condition');
url.searchParams.delete('featured');
url.searchParams.delete('digital');
url.searchParams.delete('availability');
url.searchParams.delete('color');
url.searchParams.delete('size');
url.searchParams.delete('material');
url.searchParams.delete('shop');
window.location.href = url.toString();
}
}, 300);
});
} else {
console.error('[Modal] Reset button not found!');
}
// S'assurer que les filtres dynamiques sont chargés au premier chargement si disponibles
setTimeout(() => {
loadDynamicFiltersToModal();
}, 500);
});
</script>{% endblock %}
", "home/listing.html.twig", "/home/u540977899/domains/maketou-ht.com/public_html/templates/home/listing.html.twig");
}
}