var/cache/dev/twig/8c/8cf2610927a83a8b2df7360bd78bd0a1.php line 45

Open in your IDE?
  1. <?php
  2. use Twig\Environment;
  3. use Twig\Error\LoaderError;
  4. use Twig\Error\RuntimeError;
  5. use Twig\Extension\CoreExtension;
  6. use Twig\Extension\SandboxExtension;
  7. use Twig\Markup;
  8. use Twig\Sandbox\SecurityError;
  9. use Twig\Sandbox\SecurityNotAllowedTagError;
  10. use Twig\Sandbox\SecurityNotAllowedFilterError;
  11. use Twig\Sandbox\SecurityNotAllowedFunctionError;
  12. use Twig\Source;
  13. use Twig\Template;
  14. use Twig\TemplateWrapper;
  15. /* home/single-product.html.twig */
  16. class __TwigTemplate_de682e8426eeeb206a96a6b28fceddbb extends Template
  17. {
  18.     private Source $source;
  19.     /**
  20.      * @var array<string, Template>
  21.      */
  22.     private array $macros = [];
  23.     public function __construct(Environment $env)
  24.     {
  25.         parent::__construct($env);
  26.         $this->source $this->getSourceContext();
  27.         $this->blocks = [
  28.             'title' => [$this'block_title'],
  29.             'stylesheets' => [$this'block_stylesheets'],
  30.             'body' => [$this'block_body'],
  31.         ];
  32.     }
  33.     protected function doGetParent(array $context): bool|string|Template|TemplateWrapper
  34.     {
  35.         // line 1
  36.         return "base_home.html.twig";
  37.     }
  38.     protected function doDisplay(array $context, array $blocks = []): iterable
  39.     {
  40.         $macros $this->macros;
  41.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  42.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "template""home/single-product.html.twig"));
  43.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  44.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "template""home/single-product.html.twig"));
  45.         $this->parent $this->load("base_home.html.twig"1);
  46.         yield from $this->parent->unwrap()->yield($contextarray_merge($this->blocks$blocks));
  47.         
  48.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  49.         
  50.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  51.     }
  52.     // line 3
  53.     /**
  54.      * @return iterable<null|scalar|\Stringable>
  55.      */
  56.     public function block_title(array $context, array $blocks = []): iterable
  57.     {
  58.         $macros $this->macros;
  59.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  60.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""title"));
  61.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  62.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""title"));
  63.         // line 4
  64.         yield "\t";
  65.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "name", [], "any"falsefalsefalse4), "html"nulltrue);
  66.         yield "
  67. \t| MaketOu
  68. ";
  69.         
  70.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  71.         
  72.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  73.         yield from [];
  74.     }
  75.     // line 8
  76.     /**
  77.      * @return iterable<null|scalar|\Stringable>
  78.      */
  79.     public function block_stylesheets(array $context, array $blocks = []): iterable
  80.     {
  81.         $macros $this->macros;
  82.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  83.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""stylesheets"));
  84.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  85.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""stylesheets"));
  86.         // line 9
  87.         yield "\t<style>
  88. \t\t/* Styles pour l'affichage de la boutique */
  89. \t\t.shop-info {
  90. \t\t\tpadding: 10px 0;
  91. \t\t\tborder-bottom: 1px solid #f0f0f0;
  92. \t\t\tmargin-bottom: 15px;
  93. \t\t}
  94. \t\t.shop-link {
  95. \t\t\tcolor: #ffa200;
  96. \t\t\ttext-decoration: none;
  97. \t\t\tfont-weight: 500;
  98. \t\t}
  99. \t\t.shop-link:hover {
  100. \t\t\tcolor: #e8910a;
  101. \t\t\ttext-decoration: underline;
  102. \t\t}
  103. \t\t/* Styles pour les statistiques du produit */
  104. \t\t.product-stats {
  105. \t\t\tbackground: #f8f9fa;
  106. \t\t\tpadding: 15px;
  107. \t\t\tborder-radius: 8px;
  108. \t\t\tborder: 1px solid #e9ecef;
  109. \t\t}
  110. \t\t.product-stats .stat-item {
  111. \t\t\ttext-align: center;
  112. \t\t}
  113. \t\t.product-stats .stat-number {
  114. \t\t\tdisplay: block;
  115. \t\t\tfont-size: 1.2rem;
  116. \t\t\tfont-weight: bold;
  117. \t\t\tcolor: #ffa200;
  118. \t\t}
  119. \t\t.product-stats .stat-label {
  120. \t\t\tcolor: #666;
  121. \t\t\tfont-size: 0.8rem;
  122. \t\t\ttext-transform: uppercase;
  123. \t\t\tletter-spacing: 0.5px;
  124. \t\t}
  125. \t\t/* Message de confirmation */
  126. \t\t#cart-message {
  127. \t\t\tborder: none;
  128. \t\t\tbackground: #d4edda;
  129. \t\t\tcolor: #155724;
  130. \t\t\tborder-radius: 6px;
  131. \t\t\tpadding: 12px 16px;
  132. \t\t\tmargin-top: 15px;
  133. \t\t}
  134. \t\t/* Amélioration des boutons */
  135. \t\t.card_area .primary-btn {
  136. \t\t\tbackground: #ffa200;
  137. \t\t\tborder: none;
  138. \t\t\tpadding: 12px 24px;
  139. \t\t\tborder-radius: 6px;
  140. \t\t\tcolor: white;
  141. \t\t\tfont-weight: 500;
  142. \t\t\ttransition: all 0.3s ease;
  143. \t\t}
  144. \t\t.card_area .primary-btn:hover {
  145. \t\t\tbackground: #e8910a;
  146. \t\t\ttransform: translateY(-2px);
  147. \t\t\tbox-shadow: 0 4px 12px rgba(255, 162, 0, 0.3);
  148. \t\t}
  149. \t\t.icon_btn:hover {
  150. \t\t\tbackground: #ffa200;
  151. \t\t\tcolor: white;
  152. \t\t\tborder-color: #ffa200;
  153. \t\t}
  154. \t\t/* Styles pour la galerie moderne de produits */
  155. \t\t.product-gallery-modern {
  156. \t\t\tdisplay: flex;
  157. \t\t\tgap: 15px;
  158. \t\t\tposition: relative;
  159. \t\t}
  160. \t\t.thumbnails-container {
  161. \t\t\tposition: relative;
  162. \t\t\tdisplay: flex;
  163. \t\t\tflex-direction: column;
  164. \t\t\talign-items: center;
  165. \t\t\twidth: 80px;
  166. \t\t\tflex-shrink: 0;
  167. \t\t}
  168. \t\t/* Cacher les boutons jusqu'au survol */
  169. \t\t.thumbnails-container .thumbnail-nav-btn {
  170. \t\t\topacity: 0;
  171. \t\t\tvisibility: hidden;
  172. \t\t\ttransition: opacity 0.2s ease, visibility 0.2s ease;
  173. \t\t}
  174. \t\t.thumbnails-container:hover .thumbnail-nav-btn {
  175. \t\t\topacity: 1;
  176. \t\t\tvisibility: visible;
  177. \t\t}
  178. \t\t.product-thumbnails {
  179. \t\t\tdisplay: flex;
  180. \t\t\tflex-direction: column;
  181. \t\t\tgap: 10px;
  182. \t\t\twidth: 100%;
  183. \t\t\theight: 400px;
  184. \t\t\toverflow: hidden;
  185. \t\t\tposition: relative;
  186. \t\t}
  187. \t\t.thumbnails-wrapper {
  188. \t\t\tdisplay: flex;
  189. \t\t\tflex-direction: column;
  190. \t\t\tgap: 10px;
  191. \t\t\ttransition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
  192. \t\t\twill-change: transform;
  193. \t\t}
  194. \t\t.thumbnail-nav-btn {
  195. \t\t\twidth: 30px;
  196. \t\t\theight: 30px;
  197. \t\t\tborder-radius: 50%;
  198. \t\t\tbackground: white;
  199. \t\t\tborder: 2px solid #e0e0e0;
  200. \t\t\tdisplay: flex !important;
  201. \t\t\talign-items: center;
  202. \t\t\tjustify-content: center;
  203. \t\t\tcursor: pointer;
  204. \t\t\ttransition: all 0.3s ease;
  205. \t\t\tmargin: 0;
  206. \t\t\tcolor: #666;
  207. \t\t\tz-index: 10;
  208. \t\t\tbox-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  209. \t\t\tposition: relative;
  210. \t\t\tflex-shrink: 0;
  211. \t\t}
  212. \t\t.thumbnail-nav-btn:hover {
  213. \t\t\tbackground: #ffa200;
  214. \t\t\tborder-color: #ffa200;
  215. \t\t\tcolor: white;
  216. \t\t\ttransform: scale(1.1);
  217. \t\t\tbox-shadow: 0 4px 12px rgba(255, 162, 0, 0.3);
  218. \t\t}
  219. \t\t.thumbnail-nav-btn:active {
  220. \t\t\ttransform: scale(0.95);
  221. \t\t}
  222. \t\t.thumbnail-nav-btn.disabled {
  223. \t\t\topacity: 0.3;
  224. \t\t\tcursor: not-allowed;
  225. \t\t\tpointer-events: none;
  226. \t\t\tfilter: grayscale(1);
  227. \t\t}
  228. \t\t.thumbnail-nav-btn i {
  229. \t\t\tfont-size: 20px;
  230. \t\t\tfont-weight: bold;
  231. \t\t}
  232. \t\t.thumbnail-item {
  233. \t\t\twidth: 80px;
  234. \t\t\theight: 80px;
  235. \t\t\tmin-width: 80px;
  236. \t\t\tmin-height: 80px;
  237. \t\t\tmax-width: 80px;
  238. \t\t\tmax-height: 80px;
  239. \t\t\tborder: 2px solid #e0e0e0;
  240. \t\t\tborder-radius: 8px;
  241. \t\t\toverflow: hidden;
  242. \t\t\tcursor: pointer;
  243. \t\t\ttransition: border-color 0.3s ease, border-width 0.3s ease, box-shadow 0.3s ease;
  244. \t\t\tposition: relative;
  245. \t\t\tbackground: #f8f9fa;
  246. \t\t\tborder-bottom: 2px solid #e0e0e0;
  247. \t\t\tflex-shrink: 0;
  248. \t\t\tdisplay: flex;
  249. \t\t\talign-items: center;
  250. \t\t\tjustify-content: center;
  251. \t\t}
  252. \t\t.thumbnail-item:hover {
  253. \t\t\tborder-color: #ffa200;
  254. \t\t\tborder-bottom-color: #ffa200;
  255. \t\t\tborder-width: 3px;
  256. \t\t\tbox-shadow: 0 0 0 2px rgba(255, 162, 0, 0.2);
  257. \t\t}
  258. \t\t.thumbnail-item.active {
  259. \t\t\tborder-color: #ffa200 !important;
  260. \t\t\tborder-bottom-color: #ffa200 !important;
  261. \t\t\tborder-width: 3px !important;
  262. \t\t\tbox-shadow: 0 0 0 2px rgba(255, 162, 0, 0.2) !important;
  263. \t\t}
  264. \t\t.thumbnail-item::after,
  265. \t\t.thumbnail-item::before {
  266. \t\t\tdisplay: none !important;
  267. \t\t\tcontent: none !important;
  268. \t\t}
  269. \t\t.thumbnail-item img {
  270. \t\t\twidth: 100%;
  271. \t\t\theight: 100%;
  272. \t\t\tobject-fit: cover !important;
  273. \t\t\tobject-position: center !important;
  274. \t\t\ttransition: transform 0.3s ease;
  275. \t\t}
  276. \t\t.thumbnail-item:hover img {
  277. \t\t\ttransform: scale(1.05);
  278. \t\t}
  279. \t\t.thumbnail-item.active img {
  280. \t\t\ttransform: scale(1.05);
  281. \t\t}
  282. \t\t.product-main-image-wrapper {
  283. \t\t\tflex: 1;
  284. \t\t\tposition: relative;
  285. \t\t\tbackground: #fff;
  286. \t\t\theight: 400px;
  287. \t\t\tborder-radius: 12px;
  288. \t\t\toverflow: visible;
  289. \t\t\tborder: 1px solid #e0e0e0;
  290. \t\t\tz-index: 1;
  291. \t\t}
  292. \t\t.product-main-image {
  293. \t\t\tposition: relative;
  294. \t\t\twidth: 100%;
  295. \t\t\tpadding-top: 100%;
  296. \t\t\toverflow: visible;
  297. \t\t\tbackground: #f8f9fa;
  298. \t\t\tdisplay: flex;
  299. \t\t\talign-items: center;
  300. \t\t\tjustify-content: center;
  301. \t\t\tz-index: 1;
  302. \t\t}
  303. \t\t.product-main-image img {
  304. \t\t\tposition: absolute;
  305. \t\t\ttop: 0;
  306. \t\t\tleft: 0;
  307. \t\t\twidth: 100%;
  308. \t\t\theight: 100%;
  309. \t\t\tobject-fit: contain !important;
  310. \t\t\tobject-position: center !important;
  311. \t\t\ttransition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease;
  312. \t\t\topacity: 1;
  313. \t\t}
  314. \t\t.product-main-image img.loading {
  315. \t\t\topacity: 0.5;
  316. \t\t}
  317. \t\t.product-main-image:hover img {
  318. \t\t\ttransform: scale(1.08);
  319. \t\t}
  320. \t\t.product-main-image img.fade-in {
  321. \t\t\tanimation: fadeInImage 0.4s ease;
  322. \t\t}
  323. \t\t@keyframes fadeInImage {
  324. \t\t\tfrom {
  325. \t\t\t\topacity: 0;
  326. \t\t\t\ttransform: scale(0.95);
  327. \t\t\t}
  328. \t\t\tto {
  329. \t\t\t\topacity: 1;
  330. \t\t\t\ttransform: scale(1);
  331. \t\t\t}
  332. \t\t}
  333. \t\t.image-overlay-icons {
  334. \t\t\tposition: absolute !important;
  335. \t\t\ttop: 20px !important;
  336. \t\t\tright: 20px !important;
  337. \t\t\tdisplay: flex !important;
  338. \t\t\tflex-direction: column !important;
  339. \t\t\tgap: 12px !important;
  340. \t\t\tz-index: 10 !important;
  341. \t\t\topacity: 0 !important;
  342. \t\t\ttransition: opacity 0.3s ease, transform 0.3s ease !important;
  343. \t\t\ttransform: translateX(10px) !important;
  344. \t\t}
  345. \t\t.product-main-image-wrapper:hover .image-overlay-icons {
  346. \t\t\topacity: 1 !important;
  347. \t\t\ttransform: translateX(0) !important;
  348. \t\t}
  349. \t\t.product-main-image-wrapper .icon-btn,
  350. \t\t.image-overlay-icons .icon-btn {
  351. \t\t\twidth: 48px !important;
  352. \t\t\theight: 48px !important;
  353. \t\t\tmin-width: 48px !important;
  354. \t\t\tmin-height: 48px !important;
  355. \t\t\tmax-width: 48px !important;
  356. \t\t\tmax-height: 48px !important;
  357. \t\t\tborder-radius: 50% !important;
  358. \t\t\tbackground: rgba(255, 255, 255, 0.95) !important;
  359. \t\t\tbackdrop-filter: blur(10px) !important;
  360. \t\t\tborder: 2px solid rgba(255, 255, 255, 0.8) !important;
  361. \t\t\tdisplay: flex !important;
  362. \t\t\talign-items: center !important;
  363. \t\t\tjustify-content: center !important;
  364. \t\t\tcursor: pointer !important;
  365. \t\t\ttransition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
  366. \t\t\tbox-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important;
  367. \t\t\tcolor: #333 !important;
  368. \t\t\tposition: relative !important;
  369. \t\t\toverflow: hidden !important;
  370. \t\t\tpadding: 0 !important;
  371. \t\t\tmargin: 0 !important;
  372. \t\t\tfont-size: inherit !important;
  373. \t\t\tfont-weight: normal !important;
  374. \t\t\tline-height: 1 !important;
  375. \t\t\ttext-align: center !important;
  376. \t\t\ttext-decoration: none !important;
  377. \t\t\twhite-space: nowrap !important;
  378. \t\t\tvertical-align: middle !important;
  379. \t\t\tfont-family: inherit !important;
  380. \t\t\ttext-transform: none !important;
  381. \t\t\tletter-spacing: normal !important;
  382. \t\t}
  383. \t\t.product-main-image-wrapper .icon-btn::before,
  384. \t\t.image-overlay-icons .icon-btn::before {
  385. \t\t\tcontent: '' !important;
  386. \t\t\tposition: absolute !important;
  387. \t\t\ttop: 50% !important;
  388. \t\t\tleft: 50% !important;
  389. \t\t\twidth: 0 !important;
  390. \t\t\theight: 0 !important;
  391. \t\t\tborder-radius: 50% !important;
  392. \t\t\tbackground: rgba(255, 162, 0, 0.2) !important;
  393. \t\t\ttransform: translate(-50%, -50%) !important;
  394. \t\t\ttransition: width 0.4s ease, height 0.4s ease !important;
  395. \t\t}
  396. \t\t.product-main-image-wrapper .icon-btn:hover::before,
  397. \t\t.image-overlay-icons .icon-btn:hover::before {
  398. \t\t\twidth: 100% !important;
  399. \t\t\theight: 100% !important;
  400. \t\t}
  401. \t\t.product-main-image-wrapper .icon-btn:hover,
  402. \t\t.image-overlay-icons .icon-btn:hover {
  403. \t\t\tbackground: #ffa200 !important;
  404. \t\t\tborder-color: #ffa200 !important;
  405. \t\t\tcolor: white !important;
  406. \t\t\ttransform: scale(1.15) rotate(5deg) !important;
  407. \t\t\tbox-shadow: 0 6px 20px rgba(255, 162, 0, 0.5) !important;
  408. \t\t}
  409. \t\t.product-main-image-wrapper .icon-btn:active,
  410. \t\t.image-overlay-icons .icon-btn:active {
  411. \t\t\ttransform: scale(1.05) rotate(0deg) !important;
  412. \t\t}
  413. \t\t.product-main-image-wrapper .icon-btn i,
  414. \t\t.image-overlay-icons .icon-btn i {
  415. \t\t\tfont-size: 20px !important;
  416. \t\t\tposition: relative !important;
  417. \t\t\tz-index: 1 !important;
  418. \t\t\ttransition: transform 0.3s ease !important;
  419. \t\t\tmargin: 0 !important;
  420. \t\t\tdisplay: block !important;
  421. \t\t}
  422. \t\t.product-main-image-wrapper .icon-btn:hover i,
  423. \t\t.image-overlay-icons .icon-btn:hover i {
  424. \t\t\ttransform: scale(1.1) !important;
  425. \t\t}
  426. \t\t.product-main-image-wrapper .favorite-btn.active,
  427. \t\t.image-overlay-icons .favorite-btn.active {
  428. \t\t\tbackground: linear-gradient(135deg, #ff6b6b 0%, #ee5a6f 100%) !important;
  429. \t\t\tborder-color: #ff6b6b !important;
  430. \t\t\tcolor: white !important;
  431. \t\t\tbox-shadow: 0 4px 15px rgba(255, 107, 107, 0.4) !important;
  432. \t\t}
  433. \t\t.product-main-image-wrapper .favorite-btn.active:hover,
  434. \t\t.image-overlay-icons .favorite-btn.active:hover {
  435. \t\t\tbackground: linear-gradient(135deg, #ee5a6f 0%, #dd4a5f 100%) !important;
  436. \t\t\ttransform: scale(1.15) rotate(-5deg) !important;
  437. \t\t}
  438. \t\t.product-main-image-wrapper .image-counter,
  439. \t\t.image-counter {
  440. \t\t\tposition: absolute !important;
  441. \t\t\tbottom: 20px !important;
  442. \t\t\tright: 20px !important;
  443. \t\t\tbackground: rgba(0, 0, 0, 0.75) !important;
  444. \t\t\tbackdrop-filter: blur(8px) !important;
  445. \t\t\tcolor: white !important;
  446. \t\t\tpadding: 8px 16px !important;
  447. \t\t\tborder-radius: 25px !important;
  448. \t\t\tfont-size: 14px !important;
  449. \t\t\tfont-weight: 600 !important;
  450. \t\t\tbox-shadow: 0 2px 10px rgba(0, 0, 0, 0.3) !important;
  451. \t\t\tz-index: 5 !important;
  452. \t\t\tdisplay: flex !important;
  453. \t\t\talign-items: center !important;
  454. \t\t\tgap: 6px !important;
  455. \t\t}
  456. \t\t.product-main-image-wrapper .image-counter span,
  457. \t\t.image-counter span {
  458. \t\t\tfont-weight: 700 !important;
  459. \t\t\tcolor: #ffa200 !important;
  460. \t\t}
  461. \t\t.product-main-image-wrapper .image-indicators,
  462. \t\t#image-indicators {
  463. \t\t\tposition: absolute !important;
  464. \t\t\tbottom: 20px !important;
  465. \t\t\tleft: 50% !important;
  466. \t\t\ttransform: translateX(-50%) !important;
  467. \t\t\tdisplay: flex !important;
  468. \t\t\talign-items: center !important;
  469. \t\t\tjustify-content: center !important;
  470. \t\t\tgap: 10px !important;
  471. \t\t\tbackground: rgba(0, 0, 0, 0.4) !important;
  472. \t\t\tbackdrop-filter: blur(8px) !important;
  473. \t\t\tpadding: 8px 16px !important;
  474. \t\t\tborder-radius: 25px !important;
  475. \t\t\tz-index: 5 !important;
  476. \t\t}
  477. \t\t.product-main-image-wrapper .indicator,
  478. \t\t#image-indicators .indicator,
  479. \t\t.image-indicators .indicator {
  480. \t\t\twidth: 12px !important;
  481. \t\t\theight: 12px !important;
  482. \t\t\tmin-width: 12px !important;
  483. \t\t\tmin-height: 12px !important;
  484. \t\t\tmax-width: 12px !important;
  485. \t\t\tmax-height: 12px !important;
  486. \t\t\tborder-radius: 50% !important;
  487. \t\t\tborder: 2px solid rgba(255, 255, 255, 0.6) !important;
  488. \t\t\tbackground: rgba(255, 255, 255, 0.3) !important;
  489. \t\t\tcursor: pointer !important;
  490. \t\t\ttransition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
  491. \t\t\tpadding: 0 !important;
  492. \t\t\tmargin: 0 !important;
  493. \t\t\tposition: relative !important;
  494. \t\t\tdisplay: block !important;
  495. \t\t\ttext-align: center !important;
  496. \t\t\ttext-decoration: none !important;
  497. \t\t\twhite-space: nowrap !important;
  498. \t\t\tvertical-align: middle !important;
  499. \t\t\tfont-size: 0 !important;
  500. \t\t\tline-height: 0 !important;
  501. \t\t\tbox-sizing: border-box !important;
  502. \t\t}
  503. \t\t.product-main-image-wrapper .indicator::before,
  504. \t\t#image-indicators .indicator::before,
  505. \t\t.image-indicators .indicator::before {
  506. \t\t\tcontent: '' !important;
  507. \t\t\tposition: absolute !important;
  508. \t\t\ttop: 50% !important;
  509. \t\t\tleft: 50% !important;
  510. \t\t\ttransform: translate(-50%, -50%) scale(0) !important;
  511. \t\t\twidth: 20px !important;
  512. \t\t\theight: 20px !important;
  513. \t\t\tborder-radius: 50% !important;
  514. \t\t\tbackground: rgba(255, 162, 0, 0.3) !important;
  515. \t\t\ttransition: transform 0.3s ease !important;
  516. \t\t}
  517. \t\t.product-main-image-wrapper .indicator:hover,
  518. \t\t#image-indicators .indicator:hover,
  519. \t\t.image-indicators .indicator:hover {
  520. \t\t\tborder-color: #ffa200 !important;
  521. \t\t\tbackground: rgba(255, 162, 0, 0.6) !important;
  522. \t\t\ttransform: scale(1.2) !important;
  523. \t\t}
  524. \t\t.product-main-image-wrapper .indicator:hover::before,
  525. \t\t#image-indicators .indicator:hover::before,
  526. \t\t.image-indicators .indicator:hover::before {
  527. \t\t\ttransform: translate(-50%, -50%) scale(1) !important;
  528. \t\t}
  529. \t\t.product-main-image-wrapper .indicator.active,
  530. \t\t#image-indicators .indicator.active,
  531. \t\t.image-indicators .indicator.active {
  532. \t\t\tborder-color: #ffa200 !important;
  533. \t\t\tbackground: #ffa200 !important;
  534. \t\t\tbox-shadow: 0 0 0 3px rgba(255, 162, 0, 0.3), 0 2px 8px rgba(255, 162, 0, 0.5) !important;
  535. \t\t\ttransform: scale(1.3) !important;
  536. \t\t}
  537. \t\t.product-main-image-wrapper .indicator.active::before,
  538. \t\t#image-indicators .indicator.active::before,
  539. \t\t.image-indicators .indicator.active::before {
  540. \t\t\ttransform: translate(-50%, -50%) scale(1) !important;
  541. \t\t\tbackground: rgba(255, 162, 0, 0.4) !important;
  542. \t\t}
  543. \t\t/* Modal de zoom d'image avec transitions modernes */
  544. \t\t.image-zoom-modal {
  545. \t\t\tdisplay: none;
  546. \t\t\tposition: fixed;
  547. \t\t\tz-index: 9999;
  548. \t\t\tleft: 0;
  549. \t\t\ttop: 0;
  550. \t\t\twidth: 100%;
  551. \t\t\theight: 100%;
  552. \t\t\tbackground: rgba(0, 0, 0, 0);
  553. \t\t\toverflow: auto;
  554. \t\t\topacity: 0;
  555. \t\t\ttransition: opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1), background 0.3s ease;
  556. \t\t\tbackdrop-filter: blur(0px);
  557. \t\t}
  558. \t\t.image-zoom-modal.active {
  559. \t\t\tdisplay: flex;
  560. \t\t\talign-items: center;
  561. \t\t\tjustify-content: center;
  562. \t\t\topacity: 1;
  563. \t\t\tbackground: rgba(0, 0, 0, 0.95);
  564. \t\t\tbackdrop-filter: blur(10px);
  565. \t\t}
  566. \t\t.zoom-modal-content {
  567. \t\t\tposition: relative;
  568. \t\t\tmax-width: 90%;
  569. \t\t\tmax-height: 90%;
  570. \t\t\tmargin: auto;
  571. \t\t\topacity: 0;
  572. \t\t\ttransform: scale(0.8);
  573. \t\t\ttransition: opacity 0.4s cubic-bezier(0.4, 0, 0.2, 1), transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
  574. \t\t}
  575. \t\t.image-zoom-modal.active .zoom-modal-content {
  576. \t\t\topacity: 1;
  577. \t\t\ttransform: scale(1);
  578. \t\t}
  579. \t\t.zoom-modal-content img {
  580. \t\t\twidth: 100%;
  581. \t\t\theight: auto;
  582. \t\t\tmax-height: 90vh;
  583. \t\t\tobject-fit: contain !important;
  584. \t\t\tobject-position: center !important;
  585. \t\t\tborder-radius: 8px;
  586. \t\t\tbox-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
  587. \t\t\topacity: 0;
  588. \t\t\ttransition: opacity 0.3s ease;
  589. \t\t}
  590. \t\t.zoom-modal-content img.loaded {
  591. \t\t\topacity: 1;
  592. \t\t}
  593. \t\t/* Loader moderne */
  594. \t\t.zoom-loader {
  595. \t\t\tposition: absolute;
  596. \t\t\ttop: 50%;
  597. \t\t\tleft: 50%;
  598. \t\t\ttransform: translate(-50%, -50%);
  599. \t\t\tz-index: 1;
  600. \t\t\tdisplay: flex;
  601. \t\t\tflex-direction: column;
  602. \t\t\talign-items: center;
  603. \t\t\tjustify-content: center;
  604. \t\t}
  605. \t\t.zoom-loader-spinner {
  606. \t\t\twidth: 60px;
  607. \t\t\theight: 60px;
  608. \t\t\tborder: 4px solid rgba(255, 255, 255, 0.1);
  609. \t\t\tborder-top-color: #ffa200;
  610. \t\t\tborder-radius: 50%;
  611. \t\t\tanimation: spin 1s linear infinite;
  612. \t\t}
  613. \t\t@keyframes spin {
  614. \t\t\tto {
  615. \t\t\t\ttransform: rotate(360deg);
  616. \t\t\t}
  617. \t\t}
  618. \t\t.zoom-loader-text {
  619. \t\t\tcolor: white;
  620. \t\t\tmargin-top: 15px;
  621. \t\t\ttext-align: center;
  622. \t\t\tfont-size: 14px;
  623. \t\t\tfont-weight: 500;
  624. \t\t}
  625. \t\t.close-zoom {
  626. \t\t\tposition: absolute;
  627. \t\t\ttop: 30px;
  628. \t\t\tright: 30px;
  629. \t\t\tcolor: white;
  630. \t\t\tfont-size: 32px;
  631. \t\t\tfont-weight: 300;
  632. \t\t\tcursor: pointer;
  633. \t\t\tz-index: 10000;
  634. \t\t\twidth: 50px;
  635. \t\t\theight: 50px;
  636. \t\t\tdisplay: flex;
  637. \t\t\talign-items: center;
  638. \t\t\tjustify-content: center;
  639. \t\t\tbackground: rgba(255, 255, 255, 0.1);
  640. \t\t\tborder: 2px solid rgba(255, 255, 255, 0.2);
  641. \t\t\tborder-radius: 50%;
  642. \t\t\ttransition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  643. \t\t\topacity: 0;
  644. \t\t\ttransform: scale(0.8);
  645. \t\t}
  646. \t\t.image-zoom-modal.active .close-zoom {
  647. \t\t\topacity: 1;
  648. \t\t\ttransform: scale(1);
  649. \t\t\ttransition-delay: 0.2s;
  650. \t\t}
  651. \t\t.close-zoom:hover {
  652. \t\t\tbackground: rgba(255, 162, 0, 0.9);
  653. \t\t\tborder-color: #ffa200;
  654. \t\t\ttransform: scale(1.1) rotate(90deg);
  655. \t\t\tbox-shadow: 0 4px 20px rgba(255, 162, 0, 0.4);
  656. \t\t}
  657. \t\t
  658. \t\t/* Styles pour le contrôle de quantité amélioré */
  659. \t\t.product_count {
  660. \t\t\tdisplay: flex !important;
  661. \t\t\talign-items: center !important;
  662. \t\t\tgap: 15px !important;
  663. \t\t\tmargin-bottom: 24px !important;
  664. \t\t\tposition: relative !important;
  665. \t\t}
  666. \t\t
  667. \t\t.product_count label {
  668. \t\t\tfont-size: 14px !important;
  669. \t\t\tcolor: #777777 !important;
  670. \t\t\tfont-family: \"Roboto\", sans-serif !important;
  671. \t\t\tfont-weight: normal !important;
  672. \t\t\tmargin-bottom: 0 !important;
  673. \t\t\twhite-space: nowrap !important;
  674. \t\t\tpadding-right: 10px !important;
  675. \t\t}
  676. \t\t
  677. \t\t.quantity-controls-wrapper {
  678. \t\t\tdisplay: flex !important;
  679. \t\t\talign-items: center !important;
  680. \t\t\tborder: 1px solid #eeeeee !important;
  681. \t\t\tborder-radius: 4px !important;
  682. \t\t\toverflow: hidden !important;
  683. \t\t\tbackground: #fff !important;
  684. \t\t\tposition: relative !important;
  685. \t\t}
  686. \t\t
  687. \t\t.quantity-btn {
  688. \t\t\tdisplay: flex !important;
  689. \t\t\talign-items: center !important;
  690. \t\t\tjustify-content: center !important;
  691. \t\t\twidth: 40px !important;
  692. \t\t\theight: 40px !important;
  693. \t\t\tborder: none !important;
  694. \t\t\tbackground: #f8f9fa !important;
  695. \t\t\tcolor: #666 !important;
  696. \t\t\tcursor: pointer !important;
  697. \t\t\ttransition: all 0.3s ease !important;
  698. \t\t\tfont-size: 16px !important;
  699. \t\t\tpadding: 0 !important;
  700. \t\t\tmargin: 0 !important;
  701. \t\t\tposition: relative !important;
  702. \t\t\ttop: auto !important;
  703. \t\t\tbottom: auto !important;
  704. \t\t\tright: auto !important;
  705. \t\t\tleft: auto !important;
  706. \t\t}
  707. \t\t
  708. \t\t.quantity-btn:hover {
  709. \t\t\tbackground: #e9ecef !important;
  710. \t\t\tcolor: #ffa200 !important;
  711. \t\t}
  712. \t\t
  713. \t\t.quantity-btn:active {
  714. \t\t\tbackground: #dee2e6 !important;
  715. \t\t\ttransform: scale(0.95) !important;
  716. \t\t}
  717. \t\t
  718. \t\t.quantity-btn i {
  719. \t\t\tfont-size: 14px !important;
  720. \t\t}
  721. \t\t
  722. \t\t.quantity-input {
  723. \t\t\twidth: 60px !important;
  724. \t\t\theight: 40px !important;
  725. \t\t\tborder: none !important;
  726. \t\t\tborder-left: 1px solid #eeeeee !important;
  727. \t\t\tborder-right: 1px solid #eeeeee !important;
  728. \t\t\ttext-align: center !important;
  729. \t\t\tfont-size: 14px !important;
  730. \t\t\tfont-weight: 500 !important;
  731. \t\t\tpadding: 0 !important;
  732. \t\t\tmargin: 0 !important;
  733. \t\t\toutline: none !important;
  734. \t\t\tbackground: #fff !important;
  735. \t\t\tposition: relative !important;
  736. \t\t}
  737. \t\t
  738. \t\t.quantity-input:focus {
  739. \t\t\tborder-left-color: #ffa200 !important;
  740. \t\t\tborder-right-color: #ffa200 !important;
  741. \t\t}
  742. \t\t
  743. \t\t/* Surcharger les styles existants pour les boutons */
  744. \t\t.product_count .quantity-btn {
  745. \t\t\tposition: relative !important;
  746. \t\t\tdisplay: flex !important;
  747. \t\t\talign-items: center !important;
  748. \t\t\tjustify-content: center !important;
  749. \t\t\twidth: 40px !important;
  750. \t\t\theight: 40px !important;
  751. \t\t\tborder: none !important;
  752. \t\t\tbackground: #f8f9fa !important;
  753. \t\t\tcolor: #666 !important;
  754. \t\t\tcursor: pointer !important;
  755. \t\t\ttransition: all 0.3s ease !important;
  756. \t\t\tfont-size: 16px !important;
  757. \t\t\tpadding: 0 !important;
  758. \t\t\tmargin: 0 !important;
  759. \t\t\ttop: auto !important;
  760. \t\t\tbottom: auto !important;
  761. \t\t\tright: auto !important;
  762. \t\t\tleft: auto !important;
  763. \t\t}
  764. \t\t
  765. \t\t.product_count .quantity-btn:hover {
  766. \t\t\tbackground: #e9ecef !important;
  767. \t\t\tcolor: #ffa200 !important;
  768. \t\t}
  769. \t\t
  770. \t\t.product_count .quantity-btn:active {
  771. \t\t\tbackground: #dee2e6 !important;
  772. \t\t\ttransform: scale(0.95) !important;
  773. \t\t}
  774. \t\t
  775. \t\t.product_count .quantity-btn i,
  776. \t\t.product_count .quantity-btn .quantity-icon {
  777. \t\t\tfont-size: 20px !important;
  778. \t\t\tfont-weight: 300 !important;
  779. \t\t\tline-height: 1 !important;
  780. \t\t\tdisplay: inline-block !important;
  781. \t\t}
  782. \t\t
  783. \t\t.product_count .quantity-btn .quantity-icon {
  784. \t\t\tfont-size: 24px !important;
  785. \t\t\tfont-weight: 300 !important;
  786. \t\t\tline-height: 1 !important;
  787. \t\t}
  788. \t\t
  789. \t\t/* Désactiver les boutons si nécessaire */
  790. \t\t.quantity-btn:disabled {
  791. \t\t\topacity: 0.5 !important;
  792. \t\t\tcursor: not-allowed !important;
  793. \t\t}
  794. \t\t
  795. \t\t.quantity-btn:disabled:hover {
  796. \t\t\tbackground: #f8f9fa !important;
  797. \t\t\tcolor: #666 !important;
  798. \t\t}
  799. \t\t
  800. \t\t/* Surcharger les styles pour le wrapper */
  801. \t\t.product_count .quantity-controls-wrapper {
  802. \t\t\tdisplay: flex !important;
  803. \t\t\talign-items: center !important;
  804. \t\t\tborder: 1px solid #eeeeee !important;
  805. \t\t\tborder-radius: 4px !important;
  806. \t\t\toverflow: hidden !important;
  807. \t\t\tbackground: #fff !important;
  808. \t\t\tposition: relative !important;
  809. \t\t}
  810. \t\t
  811. \t\t/* Surcharger tous les styles de main.css pour les boutons dans product_count */
  812. \t\t.product_count button.quantity-btn,
  813. \t\t.product_count .quantity-btn {
  814. \t\t\tdisplay: flex !important;
  815. \t\t\tposition: relative !important;
  816. \t\t\ttop: auto !important;
  817. \t\t\tbottom: auto !important;
  818. \t\t\tright: auto !important;
  819. \t\t\tleft: auto !important;
  820. \t\t\twidth: 40px !important;
  821. \t\t\theight: 40px !important;
  822. \t\t\tbackground: #f8f9fa !important;
  823. \t\t\tcolor: #666 !important;
  824. \t\t\tborder: none !important;
  825. \t\t\tbox-shadow: none !important;
  826. \t\t}
  827. \t\t
  828. \t\t.product_count button.quantity-btn:hover,
  829. \t\t.product_count .quantity-btn:hover {
  830. \t\t\tbackground: #e9ecef !important;
  831. \t\t\tcolor: #ffa200 !important;
  832. \t\t}
  833. \t\t
  834. \t\t/* Surcharger les styles pour l'input */
  835. \t\t.product_count .quantity-input,
  836. \t\t.product_count input.quantity-input {
  837. \t\t\twidth: 60px !important;
  838. \t\t\theight: 40px !important;
  839. \t\t\tborder: none !important;
  840. \t\t\tborder-left: 1px solid #eeeeee !important;
  841. \t\t\tborder-right: 1px solid #eeeeee !important;
  842. \t\t\ttext-align: center !important;
  843. \t\t\tpadding: 0 !important;
  844. \t\t\tpadding-left: 0 !important;
  845. \t\t\tposition: relative !important;
  846. \t\t}
  847. \t\t/* Boutons de navigation sur l'image principale */
  848. \t\t.main-image-nav {
  849. \t\t\tposition: absolute;
  850. \t\t\ttop: 50%;
  851. \t\t\tleft: 0;
  852. \t\t\tright: 0;
  853. \t\t\ttransform: translateY(-50%);
  854. \t\t\tdisplay: flex;
  855. \t\t\tjustify-content: space-between;
  856. \t\t\tpadding: 0 12px;
  857. \t\t\tpointer-events: none !important;
  858. \t\t\tz-index: 10 !important;
  859. \t\t}
  860. \t\t.main-image-nav .main-image-nav-btn,
  861. \t\t.main-image-nav-btn {
  862. \t\t\tpointer-events: all !important;
  863. \t\t\tz-index: 1000 !important;
  864. \t\t\tposition: relative !important;
  865. \t\t\tcursor: pointer !important;
  866. \t\t\t-webkit-user-select: none !important;
  867. \t\t\t-moz-user-select: none !important;
  868. \t\t\t-ms-user-select: none !important;
  869. \t\t\tuser-select: none !important;
  870. \t\t\tuser-select: none !important;
  871. \t\t\t-webkit-user-select: none !important;
  872. \t\t\t-moz-user-select: none !important;
  873. \t\t\t-ms-user-select: none !important;
  874. \t\t\twidth: 48px !important;
  875. \t\t\theight: 48px !important;
  876. \t\t\tmin-width: 48px !important;
  877. \t\t\tmin-height: 48px !important;
  878. \t\t\tmax-width: 48px !important;
  879. \t\t\tmax-height: 48px !important;
  880. \t\t\tborder-radius: 50% !important;
  881. \t\t\tbackground: rgba(255, 255, 255, 0.95) !important;
  882. \t\t\tbackdrop-filter: blur(10px) !important;
  883. \t\t\tborder: 2px solid rgba(255, 255, 255, 0.8) !important;
  884. \t\t\tdisplay: flex !important;
  885. \t\t\talign-items: center !important;
  886. \t\t\tjustify-content: center !important;
  887. \t\t\tbox-shadow: 0 4px 15px rgba(0, 0, 0, 0.2) !important;
  888. \t\t\tcolor: #333 !important;
  889. \t\t\ttransition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
  890. \t\t\tcursor: pointer !important;
  891. \t\t\toverflow: hidden !important;
  892. \t\t\tpadding: 0 !important;
  893. \t\t\tmargin: 0 !important;
  894. \t\t\tfont-size: inherit !important;
  895. \t\t\tfont-weight: normal !important;
  896. \t\t\tline-height: 1 !important;
  897. \t\t\ttext-align: center !important;
  898. \t\t\ttext-decoration: none !important;
  899. \t\t\twhite-space: nowrap !important;
  900. \t\t\tvertical-align: middle !important;
  901. \t\t\tfont-family: inherit !important;
  902. \t\t\ttext-transform: none !important;
  903. \t\t\tletter-spacing: normal !important;
  904. \t\t\t-webkit-tap-highlight-color: transparent !important;
  905. \t\t\ttouch-action: manipulation !important;
  906. \t\t}
  907. \t\t.main-image-nav .main-image-nav-btn::before,
  908. \t\t.main-image-nav-btn::before {
  909. \t\t\tcontent: '' !important;
  910. \t\t\tposition: absolute !important;
  911. \t\t\ttop: 50% !important;
  912. \t\t\tleft: 50% !important;
  913. \t\t\twidth: 0 !important;
  914. \t\t\theight: 0 !important;
  915. \t\t\tborder-radius: 50% !important;
  916. \t\t\tbackground: rgba(255, 162, 0, 0.2) !important;
  917. \t\t\ttransform: translate(-50%, -50%) !important;
  918. \t\t\ttransition: width 0.4s ease, height 0.4s ease !important;
  919. \t\t}
  920. \t\t.main-image-nav .main-image-nav-btn:hover::before,
  921. \t\t.main-image-nav-btn:hover::before {
  922. \t\t\twidth: 100% !important;
  923. \t\t\theight: 100% !important;
  924. \t\t}
  925. \t\t.main-image-nav .main-image-nav-btn:hover,
  926. \t\t.main-image-nav-btn:hover {
  927. \t\t\tbackground: #ffa200 !important;
  928. \t\t\tborder-color: #ffa200 !important;
  929. \t\t\tcolor: #fff !important;
  930. \t\t\ttransform: scale(1.15) !important;
  931. \t\t\tbox-shadow: 0 6px 20px rgba(255, 162, 0, 0.5) !important;
  932. \t\t}
  933. \t\t.main-image-nav .main-image-nav-btn:active,
  934. \t\t.main-image-nav-btn:active {
  935. \t\t\ttransform: scale(1.05) !important;
  936. \t\t}
  937. \t\t.main-image-nav .main-image-nav-btn i,
  938. \t\t.main-image-nav-btn i {
  939. \t\t\tposition: relative !important;
  940. \t\t\tz-index: 1 !important;
  941. \t\t\tfont-size: 20px !important;
  942. \t\t\ttransition: transform 0.3s ease !important;
  943. \t\t\tmargin: 0 !important;
  944. \t\t\tdisplay: block !important;
  945. \t\t}
  946. \t\t.main-image-nav .main-image-nav-btn:hover i,
  947. \t\t.main-image-nav-btn:hover i {
  948. \t\t\ttransform: scale(1.2) !important;
  949. \t\t}
  950. \t\t.main-image-nav .main-image-nav-btn.disabled,
  951. \t\t.main-image-nav-btn.disabled {
  952. \t\t\topacity: 0.4 !important;
  953. \t\t\tcursor: not-allowed !important;
  954. \t\t\tpointer-events: none !important;
  955. \t\t}
  956. \t\t/* Modal personnalisé pour remplacer les alert */
  957. \t\t.custom-alert-modal .modal-content {
  958. \t\t\tborder-radius: 12px;
  959. \t\t\tborder: none;
  960. \t\t\tbox-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
  961. \t\t}
  962. \t\t.custom-alert-modal .modal-header {
  963. \t\t\tborder-bottom: none;
  964. \t\t\tpadding: 1.5rem 1.5rem 0.5rem;
  965. \t\t\tbackground: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  966. \t\t\tcolor: white;
  967. \t\t\tborder-radius: 12px 12px 0 0;
  968. \t\t}
  969. \t\t.custom-alert-modal .modal-header .btn-close {
  970. \t\t\tfilter: brightness(0) invert(1);
  971. \t\t\topacity: 0.8;
  972. \t\t}
  973. \t\t.custom-alert-modal .modal-header .btn-close:hover {
  974. \t\t\topacity: 1;
  975. \t\t}
  976. \t\t.custom-alert-modal .modal-body {
  977. \t\t\tpadding: 1.5rem;
  978. \t\t\ttext-align: center;
  979. \t\t}
  980. \t\t.custom-alert-modal .modal-body .alert-icon {
  981. \t\t\tfont-size: 3rem;
  982. \t\t\tmargin-bottom: 1rem;
  983. \t\t}
  984. \t\t.custom-alert-modal .modal-body .alert-icon.success {
  985. \t\t\tcolor: #28a745;
  986. \t\t}
  987. \t\t.custom-alert-modal .modal-body .alert-icon.error {
  988. \t\t\tcolor: #dc3545;
  989. \t\t}
  990. \t\t.custom-alert-modal .modal-body .alert-icon.warning {
  991. \t\t\tcolor: #ffc107;
  992. \t\t}
  993. \t\t.custom-alert-modal .modal-body .alert-icon.info {
  994. \t\t\tcolor: #17a2b8;
  995. \t\t}
  996. \t\t.custom-alert-modal .modal-body .alert-message {
  997. \t\t\tfont-size: 1.1rem;
  998. \t\t\tcolor: #333;
  999. \t\t\tmargin-bottom: 1rem;
  1000. \t\t\tline-height: 1.6;
  1001. \t\t}
  1002. \t\t.custom-alert-modal .modal-footer {
  1003. \t\t\tborder-top: none;
  1004. \t\t\tpadding: 0.5rem 1.5rem 1.5rem;
  1005. \t\t\tjustify-content: center;
  1006. \t\t}
  1007. \t\t.custom-alert-modal .modal-footer .btn {
  1008. \t\t\tmin-width: 120px;
  1009. \t\t\tpadding: 0.6rem 1.5rem;
  1010. \t\t\tborder-radius: 8px;
  1011. \t\t\tfont-weight: 500;
  1012. \t\t}
  1013. \t\t/* Responsive pour single-product */
  1014. \t\t@media(max-width: 991.98px) {
  1015. \t\t\t.product-gallery-modern {
  1016. \t\t\t\tflex-direction: column;
  1017. \t\t\t}
  1018. \t\t\t.thumbnails-container {
  1019. \t\t\t\tflex-direction: row;
  1020. \t\t\t\twidth: 100%;
  1021. \t\t\t\toverflow-x: auto;
  1022. \t\t\t\tpadding: 10px 0;
  1023. \t\t\t}
  1024. \t\t\t.thumbnail-item {
  1025. \t\t\t\tflex-shrink: 0;
  1026. \t\t\t}
  1027. \t\t\t.main-image-container {
  1028. \t\t\t\twidth: 100%;
  1029. \t\t\t}
  1030. \t\t}
  1031. \t\t@media(max-width: 768px) {
  1032. \t\t\t.product-gallery-modern {
  1033. \t\t\t\tflex-direction: column;
  1034. \t\t\t}
  1035. \t\t\t.thumbnails-container {
  1036. \t\t\t\twidth: 100%;
  1037. \t\t\t\tflex-direction: row;
  1038. \t\t\t\talign-items: center;
  1039. \t\t\t}
  1040. \t\t\t.product-thumbnails {
  1041. \t\t\t\tflex-direction: row;
  1042. \t\t\t\twidth: 100%;
  1043. \t\t\t\tmax-height: 100px;
  1044. \t\t\t\toverflow-x: auto;
  1045. \t\t\t\toverflow-y: hidden;
  1046. \t\t\t}
  1047. \t\t\t.thumbnail-item {
  1048. \t\t\t\tflex-shrink: 0;
  1049. \t\t\t}
  1050. \t\t\t.thumbnail-nav-btn {
  1051. \t\t\t\tmargin: 0 5px;
  1052. \t\t\t}
  1053. \t\t\t.thumbnail-nav-up {
  1054. \t\t\t\torder: 1;
  1055. \t\t\t}
  1056. \t\t\t.product-thumbnails {
  1057. \t\t\t\torder: 2;
  1058. \t\t\t}
  1059. \t\t\t.thumbnail-nav-down {
  1060. \t\t\t\torder: 3;
  1061. \t\t\t}
  1062. \t\t\t.product-main-image-wrapper .image-overlay-icons,
  1063. \t\t\t.image-overlay-icons {
  1064. \t\t\t\topacity: 1 !important;
  1065. \t\t\t\ttop: 10px !important;
  1066. \t\t\t\tright: 10px !important;
  1067. \t\t\t}
  1068. \t\t\t.product-main-image-wrapper .icon-btn,
  1069. \t\t\t.image-overlay-icons .icon-btn {
  1070. \t\t\t\twidth: 40px !important;
  1071. \t\t\t\theight: 40px !important;
  1072. \t\t\t\tmin-width: 40px !important;
  1073. \t\t\t\tmin-height: 40px !important;
  1074. \t\t\t\tmax-width: 40px !important;
  1075. \t\t\t\tmax-height: 40px !important;
  1076. \t\t\t}
  1077. \t\t\t.product-main-image-wrapper .icon-btn i,
  1078. \t\t\t.image-overlay-icons .icon-btn i {
  1079. \t\t\t\tfont-size: 18px !important;
  1080. \t\t\t}
  1081. \t\t\t.product-main-image-wrapper .image-indicators,
  1082. \t\t\t#image-indicators {
  1083. \t\t\t\tbottom: 15px !important;
  1084. \t\t\t\tpadding: 6px 12px !important;
  1085. \t\t\t\tgap: 8px !important;
  1086. \t\t\t}
  1087. \t\t\t.product-main-image-wrapper .indicator,
  1088. \t\t\t#image-indicators .indicator {
  1089. \t\t\t\twidth: 10px !important;
  1090. \t\t\t\theight: 10px !important;
  1091. \t\t\t\tmin-width: 10px !important;
  1092. \t\t\t\tmin-height: 10px !important;
  1093. \t\t\t\tmax-width: 10px !important;
  1094. \t\t\t\tmax-height: 10px !important;
  1095. \t\t\t}
  1096. \t\t\t.product-main-image-wrapper .image-counter,
  1097. \t\t\t.image-counter {
  1098. \t\t\t\tbottom: 15px !important;
  1099. \t\t\t\tright: 15px !important;
  1100. \t\t\t\tpadding: 6px 12px !important;
  1101. \t\t\t\tfont-size: 12px !important;
  1102. \t\t\t}
  1103. \t\t\t.main-image-nav .main-image-nav-btn,
  1104. \t\t\t.main-image-nav-btn {
  1105. \t\t\t\twidth: 40px !important;
  1106. \t\t\t\theight: 40px !important;
  1107. \t\t\t\tmin-width: 40px !important;
  1108. \t\t\t\tmin-height: 40px !important;
  1109. \t\t\t\tmax-width: 40px !important;
  1110. \t\t\t\tmax-height: 40px !important;
  1111. \t\t\t}
  1112. \t\t\t.main-image-nav .main-image-nav-btn i,
  1113. \t\t\t.main-image-nav-btn i {
  1114. \t\t\t\tfont-size: 18px !important;
  1115. \t\t\t}
  1116. \t\t}
  1117. \t\t@media(max-width: 576px) {
  1118. \t\t\t.product-main-image-wrapper .image-indicators,
  1119. \t\t\t#image-indicators {
  1120. \t\t\t\tbottom: 10px !important;
  1121. \t\t\t\tpadding: 5px 10px !important;
  1122. \t\t\t\tgap: 6px !important;
  1123. \t\t\t}
  1124. \t\t\t.product-main-image-wrapper .indicator,
  1125. \t\t\t#image-indicators .indicator {
  1126. \t\t\t\twidth: 8px !important;
  1127. \t\t\t\theight: 8px !important;
  1128. \t\t\t\tmin-width: 8px !important;
  1129. \t\t\t\tmin-height: 8px !important;
  1130. \t\t\t\tmax-width: 8px !important;
  1131. \t\t\t\tmax-height: 8px !important;
  1132. \t\t\t}
  1133. \t\t\t.product-main-image-wrapper .image-counter,
  1134. \t\t\t.image-counter {
  1135. \t\t\t\tbottom: 10px !important;
  1136. \t\t\t\tright: 10px !important;
  1137. \t\t\t\tpadding: 5px 10px !important;
  1138. \t\t\t\tfont-size: 11px !important;
  1139. \t\t\t}
  1140. \t\t\t.product-main-image-wrapper .icon-btn,
  1141. \t\t\t.image-overlay-icons .icon-btn {
  1142. \t\t\t\twidth: 36px !important;
  1143. \t\t\t\theight: 36px !important;
  1144. \t\t\t\tmin-width: 36px !important;
  1145. \t\t\t\tmin-height: 36px !important;
  1146. \t\t\t\tmax-width: 36px !important;
  1147. \t\t\t\tmax-height: 36px !important;
  1148. \t\t\t}
  1149. \t\t\t.product-main-image-wrapper .icon-btn i,
  1150. \t\t\t.image-overlay-icons .icon-btn i {
  1151. \t\t\t\tfont-size: 16px !important;
  1152. \t\t\t}
  1153. \t\t\t.main-image-nav .main-image-nav-btn,
  1154. \t\t\t.main-image-nav-btn {
  1155. \t\t\t\twidth: 36px !important;
  1156. \t\t\t\theight: 36px !important;
  1157. \t\t\t\tmin-width: 36px !important;
  1158. \t\t\t\tmin-height: 36px !important;
  1159. \t\t\t\tmax-width: 36px !important;
  1160. \t\t\t\tmax-height: 36px !important;
  1161. \t\t\t}
  1162. \t\t\t.main-image-nav .main-image-nav-btn i,
  1163. \t\t\t.main-image-nav-btn i {
  1164. \t\t\t\tfont-size: 16px !important;
  1165. \t\t\t}
  1166. \t\t}
  1167. \t\t
  1168. \t\t/* Styles finaux pour forcer l'affichage des boutons de quantité */
  1169. \t\t.product_count .quantity-controls-wrapper button.quantity-btn,
  1170. \t\t.product_count button.quantity-btn-decrease,
  1171. \t\t.product_count button.quantity-btn-increase {
  1172. \t\t\tdisplay: flex !important;
  1173. \t\t\tvisibility: visible !important;
  1174. \t\t\topacity: 1 !important;
  1175. \t\t\tposition: relative !important;
  1176. \t\t\ttop: auto !important;
  1177. \t\t\tbottom: auto !important;
  1178. \t\t\tright: auto !important;
  1179. \t\t\tleft: auto !important;
  1180. \t\t\twidth: 40px !important;
  1181. \t\t\theight: 40px !important;
  1182. \t\t\tbackground: #f8f9fa !important;
  1183. \t\t\tcolor: #666 !important;
  1184. \t\t\tborder: none !important;
  1185. \t\t\tbox-shadow: none !important;
  1186. \t\t\tmargin: 0 !important;
  1187. \t\t\tpadding: 0 !important;
  1188. \t\t}
  1189. \t\t
  1190. \t\t.product_count .quantity-controls-wrapper {
  1191. \t\t\tdisplay: flex !important;
  1192. \t\t\tvisibility: visible !important;
  1193. \t\t\topacity: 1 !important;
  1194. \t\t}
  1195. \t</style>
  1196. ";
  1197.         
  1198.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  1199.         
  1200.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  1201.         yield from [];
  1202.     }
  1203.     // line 1236
  1204.     /**
  1205.      * @return iterable<null|scalar|\Stringable>
  1206.      */
  1207.     public function block_body(array $context, array $blocks = []): iterable
  1208.     {
  1209.         $macros $this->macros;
  1210.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  1211.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""body"));
  1212.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  1213.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""body"));
  1214.         // line 1237
  1215.         yield "\t<!-- Start Banner Area -->
  1216. \t<section class=\"banner-area organic-breadcrumb\">
  1217. \t\t<div class=\"container\">
  1218. \t\t\t<div class=\"breadcrumb-banner d-flex flex-wrap align-items-center justify-content-end\">
  1219. \t\t\t\t<div class=\"col-first\">
  1220. \t\t\t\t\t<h1>Product Details Page</h1>
  1221. \t\t\t\t\t<nav class=\"d-flex align-items-center\">
  1222. \t\t\t\t\t\t<a href=\"index.html\">Home<span class=\"lnr lnr-arrow-right\"></span>
  1223. \t\t\t\t\t\t</a>
  1224. \t\t\t\t\t\t<a href=\"#\">Shop<span class=\"lnr lnr-arrow-right\"></span>
  1225. \t\t\t\t\t\t</a>
  1226. \t\t\t\t\t\t<a href=\"single-product.html\">product-details</a>
  1227. \t\t\t\t\t</nav>
  1228. \t\t\t\t</div>
  1229. \t\t\t</div>
  1230. \t\t</div>
  1231. \t</section>
  1232. \t<!-- End Banner Area -->
  1233. \t<!--================Single Product Area =================-->
  1234. \t<div class=\"product_image_area\">
  1235. \t\t<div class=\"container\">
  1236. \t\t\t<div class=\"row s_product_inner\">
  1237. \t\t\t\t<div class=\"col-lg-6\">
  1238. \t\t\t\t\t<div
  1239. \t\t\t\t\t\tclass=\"product-gallery-modern\">
  1240. \t\t\t\t\t\t<!-- Colonne de miniatures à gauche avec navigation -->
  1241. \t\t\t\t\t\t<div class=\"thumbnails-container\">
  1242. \t\t\t\t\t\t\t<button class=\"thumbnail-nav-btn thumbnail-nav-up\" id=\"thumbnail-nav-up\" title=\"Image précédente\">
  1243. \t\t\t\t\t\t\t\t<i class=\"lnr lnr-chevron-up\"></i>
  1244. \t\t\t\t\t\t\t</button>
  1245. \t\t\t\t\t\t\t<div class=\"product-thumbnails\" id=\"product-thumbnails\">
  1246. \t\t\t\t\t\t\t\t<div class=\"thumbnails-wrapper\" id=\"thumbnails-wrapper\">
  1247. \t\t\t\t\t\t\t\t\t";
  1248.         // line 1270
  1249.         $context["allProductImages"] = ((CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "images", [], "any"truetruefalse1270)) ? (Twig\Extension\CoreExtension::default(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "images", [], "any"falsefalsefalse1270), [])) : ([]));
  1250.         // line 1271
  1251.         yield "\t\t\t\t\t\t\t\t\t";
  1252.         if (CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "variants", [], "any"truetruefalse1271)) {
  1253.             // line 1272
  1254.             yield "\t\t\t\t\t\t\t\t\t\t";
  1255.             $context['_parent'] = $context;
  1256.             $context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "variants", [], "any"falsefalsefalse1272));
  1257.             foreach ($context['_seq'] as $context["_key"] => $context["variant"]) {
  1258.                 // line 1273
  1259.                 yield "\t\t\t\t\t\t\t\t\t\t\t";
  1260.                 if ((CoreExtension::getAttribute($this->env$this->source$context["variant"], "isActive", [], "any"falsefalsefalse1273) && CoreExtension::getAttribute($this->env$this->source$context["variant"], "images", [], "any"truetruefalse1273))) {
  1261.                     // line 1274
  1262.                     yield "\t\t\t\t\t\t\t\t\t\t\t\t";
  1263.                     $context['_parent'] = $context;
  1264.                     $context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env$this->source$context["variant"], "images", [], "any"falsefalsefalse1274));
  1265.                     foreach ($context['_seq'] as $context["_key"] => $context["variantImg"]) {
  1266.                         // line 1275
  1267.                         yield "\t\t\t\t\t\t\t\t\t\t\t\t\t";
  1268.                         $context["allProductImages"] = Twig\Extension\CoreExtension::merge(($context["allProductImages"] ?? null), [$context["variantImg"]]);
  1269.                         // line 1276
  1270.                         yield "\t\t\t\t\t\t\t\t\t\t\t\t";
  1271.                     }
  1272.                     $_parent $context['_parent'];
  1273.                     unset($context['_seq'], $context['_key'], $context['variantImg'], $context['_parent']);
  1274.                     $context array_intersect_key($context$_parent) + $_parent;
  1275.                     // line 1277
  1276.                     yield "\t\t\t\t\t\t\t\t\t\t\t";
  1277.                 }
  1278.                 // line 1278
  1279.                 yield "\t\t\t\t\t\t\t\t\t\t";
  1280.             }
  1281.             $_parent $context['_parent'];
  1282.             unset($context['_seq'], $context['_key'], $context['variant'], $context['_parent']);
  1283.             $context array_intersect_key($context$_parent) + $_parent;
  1284.             // line 1279
  1285.             yield "\t\t\t\t\t\t\t\t\t";
  1286.         }
  1287.         // line 1280
  1288.         yield "\t\t\t\t\t\t\t\t\t";
  1289.         if ((Twig\Extension\CoreExtension::length($this->env->getCharset(), ($context["allProductImages"] ?? null)) > 0)) {
  1290.             // line 1281
  1291.             yield "\t\t\t\t\t\t\t\t\t\t";
  1292.             $context['_parent'] = $context;
  1293.             $context['_seq'] = CoreExtension::ensureTraversable(($context["allProductImages"] ?? null));
  1294.             $context['loop'] = [
  1295.               'parent' => $context['_parent'],
  1296.               'index0' => 0,
  1297.               'index'  => 1,
  1298.               'first'  => true,
  1299.             ];
  1300.             if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof \Countable)) {
  1301.                 $length count($context['_seq']);
  1302.                 $context['loop']['revindex0'] = $length 1;
  1303.                 $context['loop']['revindex'] = $length;
  1304.                 $context['loop']['length'] = $length;
  1305.                 $context['loop']['last'] = === $length;
  1306.             }
  1307.             foreach ($context['_seq'] as $context["_key"] => $context["img"]) {
  1308.                 // line 1282
  1309.                 yield "\t\t\t\t\t\t\t\t\t\t\t<div class=\"thumbnail-item ";
  1310.                 if ((($tmp CoreExtension::getAttribute($this->env$this->source$context["loop"], "first", [], "any"falsefalsefalse1282)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  1311.                     yield "active permanently-active";
  1312.                 }
  1313.                 yield "\" data-image=\"";
  1314.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl($context["img"]), "html"nulltrue);
  1315.                 yield "\" data-index=\"";
  1316.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["loop"], "index0", [], "any"falsefalsefalse1282), "html"nulltrue);
  1317.                 yield "\">
  1318. \t\t\t\t\t\t\t\t\t\t\t\t<img src=\"";
  1319.                 // line 1283
  1320.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl($context["img"]), "html"nulltrue);
  1321.                 yield "\" alt=\"";
  1322.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "name", [], "any"falsefalsefalse1283), "html"nulltrue);
  1323.                 yield " - Image ";
  1324.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["loop"], "index", [], "any"falsefalsefalse1283), "html"nulltrue);
  1325.                 yield "\">
  1326. \t\t\t\t\t\t\t\t\t\t\t</div>
  1327. \t\t\t\t\t\t\t\t\t\t";
  1328.                 ++$context['loop']['index0'];
  1329.                 ++$context['loop']['index'];
  1330.                 $context['loop']['first'] = false;
  1331.                 if (isset($context['loop']['revindex0'], $context['loop']['revindex'])) {
  1332.                     --$context['loop']['revindex0'];
  1333.                     --$context['loop']['revindex'];
  1334.                     $context['loop']['last'] = === $context['loop']['revindex0'];
  1335.                 }
  1336.             }
  1337.             $_parent $context['_parent'];
  1338.             unset($context['_seq'], $context['_key'], $context['img'], $context['_parent'], $context['loop']);
  1339.             $context array_intersect_key($context$_parent) + $_parent;
  1340.             // line 1286
  1341.             yield "\t\t\t\t\t\t\t\t\t";
  1342.         } else {
  1343.             // line 1287
  1344.             yield "\t\t\t\t\t\t\t\t\t\t<div class=\"thumbnail-item active permanently-active\" data-image=\"";
  1345.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl("ui/img/category/s-p1.jpg"), "html"nulltrue);
  1346.             yield "\" data-index=\"0\">
  1347. \t\t\t\t\t\t\t\t\t\t\t<img src=\"";
  1348.             // line 1288
  1349.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl("ui/img/category/s-p1.jpg"), "html"nulltrue);
  1350.             yield "\" alt=\"";
  1351.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "name", [], "any"falsefalsefalse1288), "html"nulltrue);
  1352.             yield "\">
  1353. \t\t\t\t\t\t\t\t\t\t</div>
  1354. \t\t\t\t\t\t\t\t\t";
  1355.         }
  1356.         // line 1291
  1357.         yield "\t\t\t\t\t\t\t\t</div>
  1358. \t\t\t\t\t\t\t</div>
  1359. \t\t\t\t\t\t\t<button class=\"thumbnail-nav-btn thumbnail-nav-down\" id=\"thumbnail-nav-down\" title=\"Image suivante\">
  1360. \t\t\t\t\t\t\t\t<i class=\"lnr lnr-chevron-down\"></i>
  1361. \t\t\t\t\t\t\t</button>
  1362. \t\t\t\t\t\t</div>
  1363. \t\t\t\t\t\t<!-- Grande image principale -->
  1364. \t\t\t\t\t\t<div class=\"product-main-image-wrapper\">
  1365. \t\t\t\t\t\t\t<div class=\"product-main-image\">
  1366. \t\t\t\t\t\t\t\t";
  1367.         // line 1301
  1368.         $context["allProductImages"] = ((CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "images", [], "any"truetruefalse1301)) ? (Twig\Extension\CoreExtension::default(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "images", [], "any"falsefalsefalse1301), [])) : ([]));
  1369.         // line 1302
  1370.         yield "\t\t\t\t\t\t\t\t";
  1371.         if (CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "variants", [], "any"truetruefalse1302)) {
  1372.             // line 1303
  1373.             yield "\t\t\t\t\t\t\t\t\t";
  1374.             $context['_parent'] = $context;
  1375.             $context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "variants", [], "any"falsefalsefalse1303));
  1376.             foreach ($context['_seq'] as $context["_key"] => $context["variant"]) {
  1377.                 // line 1304
  1378.                 yield "\t\t\t\t\t\t\t\t\t\t";
  1379.                 if ((CoreExtension::getAttribute($this->env$this->source$context["variant"], "isActive", [], "any"falsefalsefalse1304) && CoreExtension::getAttribute($this->env$this->source$context["variant"], "images", [], "any"truetruefalse1304))) {
  1380.                     // line 1305
  1381.                     yield "\t\t\t\t\t\t\t\t\t\t\t";
  1382.                     $context['_parent'] = $context;
  1383.                     $context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env$this->source$context["variant"], "images", [], "any"falsefalsefalse1305));
  1384.                     foreach ($context['_seq'] as $context["_key"] => $context["variantImg"]) {
  1385.                         // line 1306
  1386.                         yield "\t\t\t\t\t\t\t\t\t\t\t\t";
  1387.                         $context["allProductImages"] = Twig\Extension\CoreExtension::merge(($context["allProductImages"] ?? null), [$context["variantImg"]]);
  1388.                         // line 1307
  1389.                         yield "\t\t\t\t\t\t\t\t\t\t\t";
  1390.                     }
  1391.                     $_parent $context['_parent'];
  1392.                     unset($context['_seq'], $context['_key'], $context['variantImg'], $context['_parent']);
  1393.                     $context array_intersect_key($context$_parent) + $_parent;
  1394.                     // line 1308
  1395.                     yield "\t\t\t\t\t\t\t\t\t\t";
  1396.                 }
  1397.                 // line 1309
  1398.                 yield "\t\t\t\t\t\t\t\t\t";
  1399.             }
  1400.             $_parent $context['_parent'];
  1401.             unset($context['_seq'], $context['_key'], $context['variant'], $context['_parent']);
  1402.             $context array_intersect_key($context$_parent) + $_parent;
  1403.             // line 1310
  1404.             yield "\t\t\t\t\t\t\t\t";
  1405.         }
  1406.         // line 1311
  1407.         yield "\t\t\t\t\t\t\t\t";
  1408.         if ((Twig\Extension\CoreExtension::length($this->env->getCharset(), ($context["allProductImages"] ?? null)) > 0)) {
  1409.             // line 1312
  1410.             yield "\t\t\t\t\t\t\t\t\t<img id=\"main-product-image\" src=\"";
  1411.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl((($_v0 = ($context["allProductImages"] ?? null)) && is_array($_v0) || $_v0 instanceof ArrayAccess ? ($_v0[0] ?? null) : null)), "html"nulltrue);
  1412.             yield "\" alt=\"";
  1413.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "name", [], "any"falsefalsefalse1312), "html"nulltrue);
  1414.             yield "\">
  1415. \t\t\t\t\t\t\t\t";
  1416.         } else {
  1417.             // line 1314
  1418.             yield "\t\t\t\t\t\t\t\t\t<img id=\"main-product-image\" src=\"";
  1419.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl("ui/img/category/s-p1.jpg"), "html"nulltrue);
  1420.             yield "\" alt=\"";
  1421.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "name", [], "any"falsefalsefalse1314), "html"nulltrue);
  1422.             yield "\">
  1423. \t\t\t\t\t\t\t\t";
  1424.         }
  1425.         // line 1316
  1426.         yield "
  1427. \t\t\t\t\t\t\t\t<!-- Overlay avec icônes -->
  1428. \t\t\t\t\t\t\t\t<div class=\"image-overlay-icons\">
  1429. \t\t\t\t\t\t\t\t\t<button class=\"icon-btn zoom-btn\" onclick=\"openImageZoom()\" title=\"Agrandir l'image\">
  1430. \t\t\t\t\t\t\t\t\t\t<i class=\"lnr lnr-magnifier\"></i>
  1431. \t\t\t\t\t\t\t\t\t</button>
  1432. \t\t\t\t\t\t\t\t\t<button class=\"icon-btn favorite-btn\" ";
  1433.         // line 1322
  1434.         if ((($tmp CoreExtension::getAttribute($this->env$this->source, ($context["app"] ?? null), "user", [], "any"falsefalsefalse1322)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  1435.             yield " onclick=\"toggleWishlist(";
  1436.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "id", [], "any"falsefalsefalse1322), "html"nulltrue);
  1437.             yield ", this); return false;\" ";
  1438.         } else {
  1439.             yield " onclick=\"showCustomAlert('Vous devez être connecté pour ajouter aux favoris', 'warning'); return false;\" ";
  1440.         }
  1441.         yield " title=\"Ajouter aux favoris\" data-product-id=\"";
  1442.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "id", [], "any"falsefalsefalse1322), "html"nulltrue);
  1443.         yield "\">
  1444. \t\t\t\t\t\t\t\t\t\t<i class=\"lnr lnr-heart\"></i>
  1445. \t\t\t\t\t\t\t\t\t</button>
  1446. \t\t\t\t\t\t\t\t</div>
  1447. \t\t\t\t\t\t\t\t<!-- Navigation sur l'image principale -->
  1448. \t\t\t\t\t\t\t\t<div class=\"main-image-nav\">
  1449. \t\t\t\t\t\t\t\t\t<button type=\"button\" class=\"main-image-nav-btn\" id=\"main-image-prev\" title=\"Image précédente\">
  1450. \t\t\t\t\t\t\t\t\t\t<i class=\"lnr lnr-chevron-left\"></i>
  1451. \t\t\t\t\t\t\t\t\t</button>
  1452. \t\t\t\t\t\t\t\t\t<button type=\"button\" class=\"main-image-nav-btn\" id=\"main-image-next\" title=\"Image suivante\">
  1453. \t\t\t\t\t\t\t\t\t\t<i class=\"lnr lnr-chevron-right\"></i>
  1454. \t\t\t\t\t\t\t\t\t</button>
  1455. \t\t\t\t\t\t\t\t</div>
  1456. \t\t\t\t\t\t\t</div>
  1457. \t\t\t\t\t\t\t<!-- Indicateur d'image active -->
  1458. \t\t\t\t\t\t\t<div class=\"image-counter\">
  1459. \t\t\t\t\t\t\t\t<span id=\"current-image-index\">1</span>
  1460. \t\t\t\t\t\t\t\t/
  1461. \t\t\t\t\t\t\t\t";
  1462.         // line 1342
  1463.         $context["allProductImages"] = ((CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "images", [], "any"truetruefalse1342)) ? (Twig\Extension\CoreExtension::default(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "images", [], "any"falsefalsefalse1342), [])) : ([]));
  1464.         // line 1343
  1465.         yield "\t\t\t\t\t\t\t\t";
  1466.         if (CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "variants", [], "any"truetruefalse1343)) {
  1467.             // line 1344
  1468.             yield "\t\t\t\t\t\t\t\t\t";
  1469.             $context['_parent'] = $context;
  1470.             $context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "variants", [], "any"falsefalsefalse1344));
  1471.             foreach ($context['_seq'] as $context["_key"] => $context["variant"]) {
  1472.                 // line 1345
  1473.                 yield "\t\t\t\t\t\t\t\t\t\t";
  1474.                 if ((CoreExtension::getAttribute($this->env$this->source$context["variant"], "isActive", [], "any"falsefalsefalse1345) && CoreExtension::getAttribute($this->env$this->source$context["variant"], "images", [], "any"truetruefalse1345))) {
  1475.                     // line 1346
  1476.                     yield "\t\t\t\t\t\t\t\t\t\t\t";
  1477.                     $context['_parent'] = $context;
  1478.                     $context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env$this->source$context["variant"], "images", [], "any"falsefalsefalse1346));
  1479.                     foreach ($context['_seq'] as $context["_key"] => $context["variantImg"]) {
  1480.                         // line 1347
  1481.                         yield "\t\t\t\t\t\t\t\t\t\t\t\t";
  1482.                         $context["allProductImages"] = Twig\Extension\CoreExtension::merge(($context["allProductImages"] ?? null), [$context["variantImg"]]);
  1483.                         // line 1348
  1484.                         yield "\t\t\t\t\t\t\t\t\t\t\t";
  1485.                     }
  1486.                     $_parent $context['_parent'];
  1487.                     unset($context['_seq'], $context['_key'], $context['variantImg'], $context['_parent']);
  1488.                     $context array_intersect_key($context$_parent) + $_parent;
  1489.                     // line 1349
  1490.                     yield "\t\t\t\t\t\t\t\t\t\t";
  1491.                 }
  1492.                 // line 1350
  1493.                 yield "\t\t\t\t\t\t\t\t\t";
  1494.             }
  1495.             $_parent $context['_parent'];
  1496.             unset($context['_seq'], $context['_key'], $context['variant'], $context['_parent']);
  1497.             $context array_intersect_key($context$_parent) + $_parent;
  1498.             // line 1351
  1499.             yield "\t\t\t\t\t\t\t\t";
  1500.         }
  1501.         // line 1352
  1502.         yield "\t\t\t\t\t\t\t\t<span id=\"total-images\">";
  1503.         yield ((Twig\Extension\CoreExtension::length($this->env->getCharset(), ($context["allProductImages"] ?? null))) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::length($this->env->getCharset(), ($context["allProductImages"] ?? null)), "html"nulltrue)) : (1));
  1504.         yield "</span>
  1505. \t\t\t\t\t\t\t</div>
  1506. \t\t\t\t\t\t\t<!-- Indicateurs d'images (points) -->
  1507. \t\t\t\t\t\t\t<div class=\"image-indicators\" id=\"image-indicators\">
  1508. \t\t\t\t\t\t\t\t";
  1509.         // line 1357
  1510.         $context["allProductImages"] = ((CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "images", [], "any"truetruefalse1357)) ? (Twig\Extension\CoreExtension::default(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "images", [], "any"falsefalsefalse1357), [])) : ([]));
  1511.         // line 1358
  1512.         yield "\t\t\t\t\t\t\t\t";
  1513.         if (CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "variants", [], "any"truetruefalse1358)) {
  1514.             // line 1359
  1515.             yield "\t\t\t\t\t\t\t\t\t";
  1516.             $context['_parent'] = $context;
  1517.             $context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "variants", [], "any"falsefalsefalse1359));
  1518.             foreach ($context['_seq'] as $context["_key"] => $context["variant"]) {
  1519.                 // line 1360
  1520.                 yield "\t\t\t\t\t\t\t\t\t\t";
  1521.                 if ((CoreExtension::getAttribute($this->env$this->source$context["variant"], "isActive", [], "any"falsefalsefalse1360) && CoreExtension::getAttribute($this->env$this->source$context["variant"], "images", [], "any"truetruefalse1360))) {
  1522.                     // line 1361
  1523.                     yield "\t\t\t\t\t\t\t\t\t\t\t";
  1524.                     $context['_parent'] = $context;
  1525.                     $context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env$this->source$context["variant"], "images", [], "any"falsefalsefalse1361));
  1526.                     foreach ($context['_seq'] as $context["_key"] => $context["variantImg"]) {
  1527.                         // line 1362
  1528.                         yield "\t\t\t\t\t\t\t\t\t\t\t\t";
  1529.                         $context["allProductImages"] = Twig\Extension\CoreExtension::merge(($context["allProductImages"] ?? null), [$context["variantImg"]]);
  1530.                         // line 1363
  1531.                         yield "\t\t\t\t\t\t\t\t\t\t\t";
  1532.                     }
  1533.                     $_parent $context['_parent'];
  1534.                     unset($context['_seq'], $context['_key'], $context['variantImg'], $context['_parent']);
  1535.                     $context array_intersect_key($context$_parent) + $_parent;
  1536.                     // line 1364
  1537.                     yield "\t\t\t\t\t\t\t\t\t\t";
  1538.                 }
  1539.                 // line 1365
  1540.                 yield "\t\t\t\t\t\t\t\t\t";
  1541.             }
  1542.             $_parent $context['_parent'];
  1543.             unset($context['_seq'], $context['_key'], $context['variant'], $context['_parent']);
  1544.             $context array_intersect_key($context$_parent) + $_parent;
  1545.             // line 1366
  1546.             yield "\t\t\t\t\t\t\t\t";
  1547.         }
  1548.         // line 1367
  1549.         yield "\t\t\t\t\t\t\t\t";
  1550.         $context['_parent'] = $context;
  1551.         $context['_seq'] = CoreExtension::ensureTraversable(range(0, (((Twig\Extension\CoreExtension::length($this->env->getCharset(), ($context["allProductImages"] ?? null))) ? (Twig\Extension\CoreExtension::length($this->env->getCharset(), ($context["allProductImages"] ?? null))) : (1)) - 1)));
  1552.         foreach ($context['_seq'] as $context["_key"] => $context["i"]) {
  1553.             // line 1368
  1554.             yield "\t\t\t\t\t\t\t\t<button class=\"indicator ";
  1555.             yield ((($context["i"] == 0)) ? ("active") : (""));
  1556.             yield "\" data-index=\"";
  1557.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($context["i"], "html"nulltrue);
  1558.             yield "\" title=\"Image ";
  1559.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(($context["i"] + 1), "html"nulltrue);
  1560.             yield "\"></button>
  1561. \t\t\t\t\t\t\t\t";
  1562.         }
  1563.         $_parent $context['_parent'];
  1564.         unset($context['_seq'], $context['_key'], $context['i'], $context['_parent']);
  1565.         $context array_intersect_key($context$_parent) + $_parent;
  1566.         // line 1370
  1567.         yield "\t\t\t\t\t\t\t</div>
  1568. \t\t\t\t\t\t</div>
  1569. \t\t\t\t\t</div>
  1570. \t\t\t\t</div>
  1571. \t\t\t\t<div class=\"col-lg-5 offset-lg-1\">
  1572. \t\t\t\t\t<div class=\"s_product_text\">
  1573. \t\t\t\t\t\t<h3>";
  1574.         // line 1376
  1575.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "name", [], "any"falsefalsefalse1376), "html"nulltrue);
  1576.         yield "</h3>
  1577. \t\t\t\t\t\t<h2>
  1578. \t\t\t\t\t\t\t<span id=\"main-unit-price\">";
  1579.         // line 1378
  1580.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "price", [], "any"falsefalsefalse1378), 2"."" "), "html"nulltrue);
  1581.         yield "</span>
  1582. \t\t\t\t\t\t\tHTG
  1583. \t\t\t\t\t\t</h2>
  1584. \t\t\t\t\t\t<ul class=\"list\">
  1585. \t\t\t\t\t\t\t<li>
  1586. \t\t\t\t\t\t\t\t<a class=\"active\" href=\"#\">
  1587. \t\t\t\t\t\t\t\t\t<span>Category</span>
  1588. \t\t\t\t\t\t\t\t\t:
  1589. \t\t\t\t\t\t\t\t\t";
  1590.         // line 1386
  1591.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "category", [], "any"falsefalsefalse1386), "name", [], "any"falsefalsefalse1386), "html"nulltrue);
  1592.         yield "</a>
  1593. \t\t\t\t\t\t\t</li>
  1594. \t\t\t\t\t\t\t<li>
  1595. \t\t\t\t\t\t\t\t<a href=\"#\">
  1596. \t\t\t\t\t\t\t\t\t<span>Disponibilité</span>
  1597. \t\t\t\t\t\t\t\t\t:
  1598. \t\t\t\t\t\t\t\t\t";
  1599.         // line 1392
  1600.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "stockStatus", [], "any"falsefalsefalse1392), "html"nulltrue);
  1601.         yield "</a>
  1602. \t\t\t\t\t\t\t</li>
  1603. \t\t\t\t\t\t</ul>
  1604. \t\t\t\t\t\t<div class=\"product-description-preview\">";
  1605.         // line 1395
  1606.         yield (((Twig\Extension\CoreExtension::length($this->env->getCharset(), Twig\Extension\CoreExtension::striptags(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "description", [], "any"falsefalsefalse1395))) > 150)) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((Twig\Extension\CoreExtension::slice($this->env->getCharset(), Twig\Extension\CoreExtension::striptags(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "description", [], "any"falsefalsefalse1395)), 0150) . "..."), "html"nulltrue)) : ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::striptags(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "description", [], "any"falsefalsefalse1395)), "html"nulltrue)));
  1607.         yield "</div>
  1608. \t\t\t\t\t\t<!-- Sélection de variantes (Couleurs, Tailles, etc.) -->
  1609. \t\t\t\t\t\t";
  1610.         // line 1398
  1611.         if ((CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "variants", [], "any"truetruefalse1398) && (Twig\Extension\CoreExtension::length($this->env->getCharset(), CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "variants", [], "any"falsefalsefalse1398)) > 0))) {
  1612.             // line 1399
  1613.             yield "\t\t\t\t\t\t\t<div class=\"product-variants mb-4\" id=\"product-variants\" data-product-id=\"";
  1614.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "id", [], "any"falsefalsefalse1399), "html"nulltrue);
  1615.             yield "\">
  1616. \t\t\t\t\t\t\t\t";
  1617.             // line 1400
  1618.             $context["variantAttributes"] = [];
  1619.             // line 1401
  1620.             yield "\t\t\t\t\t\t\t\t";
  1621.             $context['_parent'] = $context;
  1622.             $context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "variants", [], "any"falsefalsefalse1401));
  1623.             foreach ($context['_seq'] as $context["_key"] => $context["variant"]) {
  1624.                 // line 1402
  1625.                 yield "\t\t\t\t\t\t\t\t\t";
  1626.                 if ((($tmp CoreExtension::getAttribute($this->env$this->source$context["variant"], "isActive", [], "any"falsefalsefalse1402)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  1627.                     // line 1403
  1628.                     yield "\t\t\t\t\t\t\t\t\t\t";
  1629.                     $context['_parent'] = $context;
  1630.                     $context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env$this->source$context["variant"], "attributeValues", [], "any"falsefalsefalse1403));
  1631.                     foreach ($context['_seq'] as $context["_key"] => $context["attrValue"]) {
  1632.                         // line 1404
  1633.                         yield "\t\t\t\t\t\t\t\t\t\t\t";
  1634.                         $context["attrName"] = Twig\Extension\CoreExtension::lower($this->env->getCharset(), CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source$context["attrValue"], "attribute", [], "any"falsefalsefalse1404), "name", [], "any"falsefalsefalse1404));
  1635.                         // line 1405
  1636.                         yield "\t\t\t\t\t\t\t\t\t\t\t";
  1637.                         if ((($tmp =  !CoreExtension::getAttribute($this->env$this->source, ($context["variantAttributes"] ?? null), ($context["attrName"] ?? null), [], "array"truetruefalse1405)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  1638.                             // line 1406
  1639.                             yield "\t\t\t\t\t\t\t\t\t\t\t\t";
  1640.                             $context["variantAttributes"] = Twig\Extension\CoreExtension::merge(($context["variantAttributes"] ?? null), [ (string)($context["attrName"] ?? null) => ["attribute" => CoreExtension::getAttribute($this->env$this->source$context["attrValue"], "attribute", [], "any"falsefalsefalse1406), "values" => []]]);
  1641.                             // line 1407
  1642.                             yield "\t\t\t\t\t\t\t\t\t\t\t";
  1643.                         }
  1644.                         // line 1408
  1645.                         yield "\t\t\t\t\t\t\t\t\t\t\t";
  1646.                         if (!CoreExtension::inFilter($context["attrValue"], CoreExtension::getAttribute($this->env$this->source, (($_v1 = ($context["variantAttributes"] ?? null)) && is_array($_v1) || $_v1 instanceof ArrayAccess ? ($_v1[($context["attrName"] ?? null)] ?? null) : null), "values", [], "any"falsefalsefalse1408))) {
  1647.                             // line 1409
  1648.                             yield "\t\t\t\t\t\t\t\t\t\t\t\t";
  1649.                             $context["variantAttributes"] = Twig\Extension\CoreExtension::merge(($context["variantAttributes"] ?? null), [ (string)($context["attrName"] ?? null) => Twig\Extension\CoreExtension::merge((($_v2 = ($context["variantAttributes"] ?? null)) && is_array($_v2) || $_v2 instanceof ArrayAccess ? ($_v2[($context["attrName"] ?? null)] ?? null) : null), ["values" => Twig\Extension\CoreExtension::merge(CoreExtension::getAttribute($this->env$this->source, (($_v3 = ($context["variantAttributes"] ?? null)) && is_array($_v3) || $_v3 instanceof ArrayAccess ? ($_v3[($context["attrName"] ?? null)] ?? null) : null), "values", [], "any"falsefalsefalse1409), [$context["attrValue"]])])]);
  1650.                             // line 1410
  1651.                             yield "\t\t\t\t\t\t\t\t\t\t\t";
  1652.                         }
  1653.                         // line 1411
  1654.                         yield "\t\t\t\t\t\t\t\t\t\t";
  1655.                     }
  1656.                     $_parent $context['_parent'];
  1657.                     unset($context['_seq'], $context['_key'], $context['attrValue'], $context['_parent']);
  1658.                     $context array_intersect_key($context$_parent) + $_parent;
  1659.                     // line 1412
  1660.                     yield "\t\t\t\t\t\t\t\t\t";
  1661.                 }
  1662.                 // line 1413
  1663.                 yield "\t\t\t\t\t\t\t\t";
  1664.             }
  1665.             $_parent $context['_parent'];
  1666.             unset($context['_seq'], $context['_key'], $context['variant'], $context['_parent']);
  1667.             $context array_intersect_key($context$_parent) + $_parent;
  1668.             // line 1414
  1669.             yield "
  1670. \t\t\t\t\t\t\t\t";
  1671.             // line 1415
  1672.             $context['_parent'] = $context;
  1673.             $context['_seq'] = CoreExtension::ensureTraversable(($context["variantAttributes"] ?? null));
  1674.             foreach ($context['_seq'] as $context["attrName"] => $context["attrData"]) {
  1675.                 // line 1416
  1676.                 yield "\t\t\t\t\t\t\t\t\t<div class=\"variant-selector mb-3\" data-attribute=\"";
  1677.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source$context["attrData"], "attribute", [], "any"falsefalsefalse1416), "slug", [], "any"falsefalsefalse1416), "html"nulltrue);
  1678.                 yield "\">
  1679. \t\t\t\t\t\t\t\t\t\t<label class=\"variant-label mb-2\">
  1680. \t\t\t\t\t\t\t\t\t\t\t<strong>";
  1681.                 // line 1418
  1682.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source$context["attrData"], "attribute", [], "any"falsefalsefalse1418), "name", [], "any"falsefalsefalse1418), "html"nulltrue);
  1683.                 yield ":</strong>
  1684. \t\t\t\t\t\t\t\t\t\t\t<span class=\"selected-variant-value\" id=\"selected-";
  1685.                 // line 1419
  1686.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source$context["attrData"], "attribute", [], "any"falsefalsefalse1419), "slug", [], "any"falsefalsefalse1419), "html"nulltrue);
  1687.                 yield "\"></span>
  1688. \t\t\t\t\t\t\t\t\t\t</label>
  1689. \t\t\t\t\t\t\t\t\t\t<div class=\"variant-options d-flex flex-wrap gap-2\">
  1690. \t\t\t\t\t\t\t\t\t\t\t";
  1691.                 // line 1422
  1692.                 $context['_parent'] = $context;
  1693.                 $context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env$this->source$context["attrData"], "values", [], "any"falsefalsefalse1422));
  1694.                 $context['loop'] = [
  1695.                   'parent' => $context['_parent'],
  1696.                   'index0' => 0,
  1697.                   'index'  => 1,
  1698.                   'first'  => true,
  1699.                 ];
  1700.                 if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof \Countable)) {
  1701.                     $length count($context['_seq']);
  1702.                     $context['loop']['revindex0'] = $length 1;
  1703.                     $context['loop']['revindex'] = $length;
  1704.                     $context['loop']['length'] = $length;
  1705.                     $context['loop']['last'] = === $length;
  1706.                 }
  1707.                 foreach ($context['_seq'] as $context["_key"] => $context["attrValue"]) {
  1708.                     // line 1423
  1709.                     yield "\t\t\t\t\t\t\t\t\t\t\t\t";
  1710.                     if ((($tmp CoreExtension::getAttribute($this->env$this->source$context["attrValue"], "isActive", [], "any"falsefalsefalse1423)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  1711.                         // line 1424
  1712.                         yield "\t\t\t\t\t\t\t\t\t\t\t\t\t";
  1713.                         if ((CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source$context["attrData"], "attribute", [], "any"falsefalsefalse1424), "type", [], "any"falsefalsefalse1424) == "color")) {
  1714.                             // line 1425
  1715.                             yield "\t\t\t\t\t\t\t\t\t\t\t\t\t\t<button type=\"button\" 
  1716. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclass=\"variant-option variant-color-option ";
  1717.                             // line 1426
  1718.                             if ((($tmp CoreExtension::getAttribute($this->env$this->source$context["loop"], "first", [], "any"falsefalsefalse1426)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  1719.                                 yield "selected";
  1720.                             }
  1721.                             yield "\" 
  1722. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata-value-id=\"";
  1723.                             // line 1427
  1724.                             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attrValue"], "id", [], "any"falsefalsefalse1427), "html"nulltrue);
  1725.                             yield "\"
  1726. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata-value=\"";
  1727.                             // line 1428
  1728.                             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attrValue"], "value", [], "any"falsefalsefalse1428), "html"nulltrue);
  1729.                             yield "\"
  1730. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata-attribute=\"";
  1731.                             // line 1429
  1732.                             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source$context["attrData"], "attribute", [], "any"falsefalsefalse1429), "slug", [], "any"falsefalsefalse1429), "html"nulltrue);
  1733.                             yield "\"
  1734. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle=\"";
  1735.                             // line 1430
  1736.                             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attrValue"], "value", [], "any"falsefalsefalse1430), "html"nulltrue);
  1737.                             yield "\"
  1738. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"";
  1739.                             // line 1431
  1740.                             if ((($tmp CoreExtension::getAttribute($this->env$this->source$context["attrValue"], "colorCode", [], "any"falsefalsefalse1431)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  1741.                                 yield "background-color: ";
  1742.                                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attrValue"], "colorCode", [], "any"falsefalsefalse1431), "html"nulltrue);
  1743.                                 yield ";";
  1744.                             }
  1745.                             yield " width: 40px; height: 40px; border-radius: 50%; border: 2px solid ";
  1746.                             if ((($tmp CoreExtension::getAttribute($this->env$this->source$context["loop"], "first", [], "any"falsefalsefalse1431)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  1747.                                 yield "#007bff";
  1748.                             } else {
  1749.                                 yield "#ddd";
  1750.                             }
  1751.                             yield "; cursor: pointer; position: relative;\">
  1752. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  1753.                             // line 1432
  1754.                             if ((($tmp CoreExtension::getAttribute($this->env$this->source$context["loop"], "first", [], "any"falsefalsefalse1432)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  1755.                                 // line 1433
  1756.                                 yield "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"check-icon\" style=\"position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: ";
  1757.                                 if ((CoreExtension::getAttribute($this->env$this->source$context["attrValue"], "colorCode", [], "any"falsefalsefalse1433) && $this->extensions['App\Twig\ColorExtension']->isDarkColor(CoreExtension::getAttribute($this->env$this->source$context["attrValue"], "colorCode", [], "any"falsefalsefalse1433)))) {
  1758.                                     yield "white";
  1759.                                 } else {
  1760.                                     yield "black";
  1761.                                 }
  1762.                                 yield "; font-size: 18px;\">✓</span>
  1763. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  1764.                             }
  1765.                             // line 1435
  1766.                             yield "\t\t\t\t\t\t\t\t\t\t\t\t\t\t</button>
  1767. \t\t\t\t\t\t\t\t\t\t\t\t\t";
  1768.                         } else {
  1769.                             // line 1437
  1770.                             yield "\t\t\t\t\t\t\t\t\t\t\t\t\t\t<button type=\"button\" 
  1771. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclass=\"variant-option variant-text-option btn btn-outline-secondary ";
  1772.                             // line 1438
  1773.                             if ((($tmp CoreExtension::getAttribute($this->env$this->source$context["loop"], "first", [], "any"falsefalsefalse1438)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  1774.                                 yield "active";
  1775.                             }
  1776.                             yield "\" 
  1777. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata-value-id=\"";
  1778.                             // line 1439
  1779.                             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attrValue"], "id", [], "any"falsefalsefalse1439), "html"nulltrue);
  1780.                             yield "\"
  1781. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata-value=\"";
  1782.                             // line 1440
  1783.                             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attrValue"], "value", [], "any"falsefalsefalse1440), "html"nulltrue);
  1784.                             yield "\"
  1785. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata-attribute=\"";
  1786.                             // line 1441
  1787.                             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source$context["attrData"], "attribute", [], "any"falsefalsefalse1441), "slug", [], "any"falsefalsefalse1441), "html"nulltrue);
  1788.                             yield "\">
  1789. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  1790.                             // line 1442
  1791.                             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attrValue"], "value", [], "any"falsefalsefalse1442), "html"nulltrue);
  1792.                             yield "
  1793. \t\t\t\t\t\t\t\t\t\t\t\t\t\t</button>
  1794. \t\t\t\t\t\t\t\t\t\t\t\t\t";
  1795.                         }
  1796.                         // line 1445
  1797.                         yield "\t\t\t\t\t\t\t\t\t\t\t\t";
  1798.                     }
  1799.                     // line 1446
  1800.                     yield "\t\t\t\t\t\t\t\t\t\t\t";
  1801.                     ++$context['loop']['index0'];
  1802.                     ++$context['loop']['index'];
  1803.                     $context['loop']['first'] = false;
  1804.                     if (isset($context['loop']['revindex0'], $context['loop']['revindex'])) {
  1805.                         --$context['loop']['revindex0'];
  1806.                         --$context['loop']['revindex'];
  1807.                         $context['loop']['last'] = === $context['loop']['revindex0'];
  1808.                     }
  1809.                 }
  1810.                 $_parent $context['_parent'];
  1811.                 unset($context['_seq'], $context['_key'], $context['attrValue'], $context['_parent'], $context['loop']);
  1812.                 $context array_intersect_key($context$_parent) + $_parent;
  1813.                 // line 1447
  1814.                 yield "\t\t\t\t\t\t\t\t\t\t</div>
  1815. \t\t\t\t\t\t\t\t\t</div>
  1816. \t\t\t\t\t\t\t\t";
  1817.             }
  1818.             $_parent $context['_parent'];
  1819.             unset($context['_seq'], $context['attrName'], $context['attrData'], $context['_parent']);
  1820.             $context array_intersect_key($context$_parent) + $_parent;
  1821.             // line 1450
  1822.             yield "
  1823. \t\t\t\t\t\t\t\t<!-- Affichage du stock et du prix de la variante sélectionnée -->
  1824. \t\t\t\t\t\t\t\t<div class=\"variant-info mt-3 p-3 bg-light rounded\" id=\"variant-info\" style=\"display: none;\">
  1825. \t\t\t\t\t\t\t\t\t<div class=\"d-flex justify-content-between align-items-center mb-2\">
  1826. \t\t\t\t\t\t\t\t\t\t<span><strong>Prix:</strong></span>
  1827. \t\t\t\t\t\t\t\t\t\t<span class=\"variant-price text-primary fw-bold\" id=\"variant-price\"></span>
  1828. \t\t\t\t\t\t\t\t\t</div>
  1829. \t\t\t\t\t\t\t\t\t<div class=\"d-flex justify-content-between align-items-center\">
  1830. \t\t\t\t\t\t\t\t\t\t<span><strong>Stock:</strong></span>
  1831. \t\t\t\t\t\t\t\t\t\t<span class=\"variant-stock\" id=\"variant-stock\"></span>
  1832. \t\t\t\t\t\t\t\t\t</div>
  1833. \t\t\t\t\t\t\t\t\t<input type=\"hidden\" id=\"selected-variant-id\" value=\"\">
  1834. \t\t\t\t\t\t\t\t\t<input type=\"hidden\" id=\"selected-variant-sku\" value=\"\">
  1835. \t\t\t\t\t\t\t\t</div>
  1836. \t\t\t\t\t\t\t</div>
  1837. \t\t\t\t\t\t";
  1838.         }
  1839.         // line 1466
  1840.         yield "
  1841. \t\t\t\t\t\t<!-- Informations sur la boutique -->
  1842. \t\t\t\t\t\t<div class=\"shop-info mb-3\">
  1843. \t\t\t\t\t\t\t<small class=\"text-muted\">
  1844. \t\t\t\t\t\t\t\t<i class=\"lnr lnr-store\"></i>
  1845. \t\t\t\t\t\t\t\tVendu par :
  1846. \t\t\t\t\t\t\t\t";
  1847.         // line 1472
  1848.         if ((CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "shop", [], "any"truetruefalse1472) && CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "shop", [], "any"falsefalsefalse1472))) {
  1849.             // line 1473
  1850.             yield "\t\t\t\t\t\t\t\t\t<a href=\"";
  1851.             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->sourceCoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "shop", [], "any"falsefalsefalse1473), "slug", [], "any"falsefalsefalse1473)]), "html"nulltrue);
  1852.             yield "\" class=\"shop-link\">
  1853. \t\t\t\t\t\t\t\t\t\t";
  1854.             // line 1474
  1855.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "shop", [], "any"falsefalsefalse1474), "name", [], "any"falsefalsefalse1474), "html"nulltrue);
  1856.             yield "
  1857. \t\t\t\t\t\t\t\t\t</a>
  1858. \t\t\t\t\t\t\t\t";
  1859.         } else {
  1860.             // line 1477
  1861.             yield "\t\t\t\t\t\t\t\t\t<span class=\"text-muted\">Boutique inconnue</span>
  1862. \t\t\t\t\t\t\t\t";
  1863.         }
  1864.         // line 1479
  1865.         yield "\t\t\t\t\t\t\t</small>
  1866. \t\t\t\t\t\t</div>
  1867. \t\t\t\t\t\t<div class=\"product_count\">
  1868. \t\t\t\t\t\t\t<label for=\"qty\">Quantité :</label>
  1869. \t\t\t\t\t\t\t<div class=\"quantity-controls-wrapper\">
  1870. \t\t\t\t\t\t\t\t<button onclick=\"var result = document.getElementById('sst'); var sst = result.value; if( !isNaN( sst ) && sst > 1 ) result.value--;return false;\" class=\"quantity-btn quantity-btn-decrease\" type=\"button\" title=\"Diminuer\">
  1871. \t\t\t\t\t\t\t\t\t<span class=\"quantity-icon\">−</span>
  1872. \t\t\t\t\t\t\t\t</button>
  1873. \t\t\t\t\t\t\t\t<input type=\"text\" name=\"qty\" id=\"sst\" maxlength=\"12\" value=\"1\" title=\"Quantité:\" class=\"input-text qty quantity-input\" max=\"";
  1874.         // line 1488
  1875.         yield (((CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "stock", [], "any"truetruefalse1488) &&  !(null === CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "stock", [], "any"falsefalsefalse1488)))) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "stock", [], "any"falsefalsefalse1488), "html"nulltrue)) : (99));
  1876.         yield "\">
  1877. \t\t\t\t\t\t\t\t<button onclick=\"var result = document.getElementById('sst'); var sst = result.value; if( !isNaN( sst ) && sst < ";
  1878.         // line 1489
  1879.         yield (((CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "stock", [], "any"truetruefalse1489) &&  !(null === CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "stock", [], "any"falsefalsefalse1489)))) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "stock", [], "any"falsefalsefalse1489), "html"nulltrue)) : (99));
  1880.         yield ") result.value++;return false;\" class=\"quantity-btn quantity-btn-increase\" type=\"button\" title=\"Augmenter\">
  1881. \t\t\t\t\t\t\t\t\t<span class=\"quantity-icon\">+</span>
  1882. \t\t\t\t\t\t\t\t</button>
  1883. \t\t\t\t\t\t\t</div>
  1884. \t\t\t\t\t\t</div>
  1885. \t\t\t\t\t\t<input
  1886. \t\t\t\t\t\ttype=\"hidden\" id=\"unit-price-input\" value=\"";
  1887.         // line 1496
  1888.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "price", [], "any"falsefalsefalse1496), 2"."""), "html"nulltrue);
  1889.         yield "\"/>
  1890. \t\t\t\t\t\t";
  1891.         // line 1499
  1892.         yield "\t\t\t\t\t\t";
  1893.         if (((CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "hasTierPricing", [], "any"falsefalsefalse1499) && CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "tierPrices", [], "any"truetruefalse1499)) && (Twig\Extension\CoreExtension::length($this->env->getCharset(), CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "tierPrices", [], "any"falsefalsefalse1499)) > 0))) {
  1894.             // line 1500
  1895.             yield "\t\t\t\t\t\t";
  1896.             $context["tierPrices"] = [];
  1897.             // line 1501
  1898.             yield "\t\t\t\t\t\t\t";
  1899.             $context['_parent'] = $context;
  1900.             $context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "tierPrices", [], "any"falsefalsefalse1501));
  1901.             foreach ($context['_seq'] as $context["_key"] => $context["tier"]) {
  1902.                 // line 1502
  1903.                 yield "\t\t\t\t\t\t\t\t";
  1904.                 $context["tierPrices"] = Twig\Extension\CoreExtension::merge(($context["tierPrices"] ?? null), [["min" => CoreExtension::getAttribute($this->env$this->source$context["tier"], "min", [], "any"falsefalsefalse1502), "price" => CoreExtension::getAttribute($this->env$this->source$context["tier"], "price", [], "any"falsefalsefalse1502)]]);
  1905.                 // line 1503
  1906.                 yield "\t\t\t\t\t\t\t";
  1907.             }
  1908.             $_parent $context['_parent'];
  1909.             unset($context['_seq'], $context['_key'], $context['tier'], $context['_parent']);
  1910.             $context array_intersect_key($context$_parent) + $_parent;
  1911.             // line 1504
  1912.             yield "
  1913. \t\t\t\t\t\t\t<div id=\"bulk-pricing\" class=\"mt-4 p-3 bg-light rounded\" data-tiers='";
  1914.             // line 1505
  1915.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(json_encode(($context["tierPrices"] ?? null)), "html_attr");
  1916.             yield "'>
  1917. \t\t\t\t\t\t\t\t<div class=\"d-flex align-items-center mb-3\">
  1918. \t\t\t\t\t\t\t\t\t<i class=\"lnr lnr-tag text-primary me-2\" style=\"font-size: 1.2rem;\"></i>
  1919. \t\t\t\t\t\t\t\t\t<strong class=\"me-2\">Prix de gros disponible</strong>
  1920. \t\t\t\t\t\t\t\t\t<span id=\"unit-price-value\" class=\"badge bg-primary ms-2 text-white p-2\">";
  1921.             // line 1509
  1922.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "price", [], "any"falsefalsefalse1509), 2"."" "), "html"nulltrue);
  1923.             yield " HTG</span>
  1924. \t\t\t\t\t\t\t</div>
  1925. \t\t\t\t\t\t\t<div class=\"table-responsive\">
  1926. \t\t\t\t\t\t\t\t\t<table class=\"table table-sm mb-3\" style=\"border:1px solid #dee2e6; background: white;\">
  1927. \t\t\t\t\t\t\t\t\t\t<thead class=\"table-primary\">
  1928. \t\t\t\t\t\t\t\t\t\t<tr>
  1929. \t\t\t\t\t\t\t\t\t\t\t\t<th style=\"font-weight: 600;\">Quantité minimale</th>
  1930. \t\t\t\t\t\t\t\t\t\t\t\t<th style=\"font-weight: 600;\">Prix unitaire (HTG)</th>
  1931. \t\t\t\t\t\t\t\t\t\t\t\t<th style=\"font-weight: 600;\">Économie</th>
  1932. \t\t\t\t\t\t\t\t\t\t</tr>
  1933. \t\t\t\t\t\t\t\t\t</thead>
  1934. \t\t\t\t\t\t\t\t\t<tbody id=\"bulk-tier-rows\">
  1935. \t\t\t\t\t\t\t\t\t\t";
  1936.             // line 1521
  1937.             $context['_parent'] = $context;
  1938.             $context['_seq'] = CoreExtension::ensureTraversable(Twig\Extension\CoreExtension::sort($this->env, ($context["tierPrices"] ?? null), function ($__a__$__b__) use ($context$macros) { $context["a"] = $__a__$context["b"] = $__b__; return (CoreExtension::getAttribute($this->env$this->source, ($context["a"] ?? null), "min", [], "any"falsefalsefalse1521) <=> CoreExtension::getAttribute($this->env$this->source, ($context["b"] ?? null), "min", [], "any"falsefalsefalse1521)); }));
  1939.             $context['loop'] = [
  1940.               'parent' => $context['_parent'],
  1941.               'index0' => 0,
  1942.               'index'  => 1,
  1943.               'first'  => true,
  1944.             ];
  1945.             if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof \Countable)) {
  1946.                 $length count($context['_seq']);
  1947.                 $context['loop']['revindex0'] = $length 1;
  1948.                 $context['loop']['revindex'] = $length;
  1949.                 $context['loop']['length'] = $length;
  1950.                 $context['loop']['last'] = === $length;
  1951.             }
  1952.             foreach ($context['_seq'] as $context["_key"] => $context["tier"]) {
  1953.                 // line 1522
  1954.                 yield "\t\t\t\t\t\t\t\t\t\t\t\t";
  1955.                 $context["savings"] = Twig\Extension\CoreExtension::round((((CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "price", [], "any"falsefalsefalse1522) - CoreExtension::getAttribute($this->env$this->source$context["tier"], "price", [], "any"falsefalsefalse1522)) / CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "price", [], "any"falsefalsefalse1522)) * 100), 1);
  1956.                 // line 1523
  1957.                 yield "\t\t\t\t\t\t\t\t\t\t\t\t<tr data-min=\"";
  1958.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["tier"], "min", [], "any"falsefalsefalse1523), "html"nulltrue);
  1959.                 yield "\" class=\"";
  1960.                 if ((($tmp CoreExtension::getAttribute($this->env$this->source$context["loop"], "first", [], "any"falsefalsefalse1523)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  1961.                     yield "table-active";
  1962.                 }
  1963.                 yield "\">
  1964. \t\t\t\t\t\t\t\t\t\t\t\t\t<td><strong>≥ ";
  1965.                 // line 1524
  1966.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["tier"], "min", [], "any"falsefalsefalse1524), "html"nulltrue);
  1967.                 yield "</strong></td>
  1968. \t\t\t\t\t\t\t\t\t\t\t\t\t<td><strong class=\"text-primary\">";
  1969.                 // line 1525
  1970.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(CoreExtension::getAttribute($this->env$this->source$context["tier"], "price", [], "any"falsefalsefalse1525), 2"."" "), "html"nulltrue);
  1971.                 yield "</strong></td>
  1972. \t\t\t\t\t\t\t\t\t\t\t\t\t<td>
  1973. \t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  1974.                 // line 1527
  1975.                 if ((($context["savings"] ?? null) > 0)) {
  1976.                     // line 1528
  1977.                     yield "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"badge bg-success text-white p-2\">-";
  1978.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(($context["savings"] ?? null), "html"nulltrue);
  1979.                     yield "%</span>
  1980. \t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  1981.                 } else {
  1982.                     // line 1530
  1983.                     yield "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"text-muted\">-</span>
  1984. \t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  1985.                 }
  1986.                 // line 1532
  1987.                 yield "\t\t\t\t\t\t\t\t\t\t\t\t\t</td>
  1988. \t\t\t\t\t\t\t\t\t\t\t</tr>
  1989. \t\t\t\t\t\t\t\t\t\t";
  1990.                 ++$context['loop']['index0'];
  1991.                 ++$context['loop']['index'];
  1992.                 $context['loop']['first'] = false;
  1993.                 if (isset($context['loop']['revindex0'], $context['loop']['revindex'])) {
  1994.                     --$context['loop']['revindex0'];
  1995.                     --$context['loop']['revindex'];
  1996.                     $context['loop']['last'] = === $context['loop']['revindex0'];
  1997.                 }
  1998.             }
  1999.             $_parent $context['_parent'];
  2000.             unset($context['_seq'], $context['_key'], $context['tier'], $context['_parent'], $context['loop']);
  2001.             $context array_intersect_key($context$_parent) + $_parent;
  2002.             // line 1535
  2003.             yield "\t\t\t\t\t\t\t\t\t</tbody>
  2004. \t\t\t\t\t\t\t\t</table>
  2005. \t\t\t\t\t\t\t</div>
  2006. \t\t\t\t\t\t\t\t<div class=\"d-flex flex-wrap gap-3 align-items-baseline mb-2 p-2 bg-white rounded\">
  2007. \t\t\t\t\t\t\t\t<div>
  2008. \t\t\t\t\t\t\t\t\t<strong>Total:</strong>
  2009. \t\t\t\t\t\t\t\t\t\t<span id=\"total-price-value\" class=\"text-primary fs-5\">";
  2010.             // line 1541
  2011.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "price", [], "any"falsefalsefalse1541), 2"."" "), "html"nulltrue);
  2012.             yield "</span>
  2013. \t\t\t\t\t\t\t\t\tHTG
  2014. \t\t\t\t\t\t\t\t</div>
  2015. \t\t\t\t\t\t\t\t<div class=\"text-success\">
  2016. \t\t\t\t\t\t\t\t\t<strong>Économies:</strong>
  2017. \t\t\t\t\t\t\t\t\t<span id=\"savings-amount\">0.00</span>
  2018. \t\t\t\t\t\t\t\t\tHTG
  2019. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(<span id=\"savings-percent\">0</span>%)
  2020. \t\t\t\t\t\t\t\t</div>
  2021. \t\t\t\t\t\t\t</div>
  2022. \t\t\t\t\t\t\t\t<small class=\"text-muted d-block mt-2\">
  2023. \t\t\t\t\t\t\t\t\t<i class=\"lnr lnr-info-circle me-1\"></i>
  2024. \t\t\t\t\t\t\t\t\tLe prix et le total s'adaptent automatiquement selon la quantité sélectionnée.
  2025. \t\t\t\t\t\t\t\t</small>
  2026. \t\t\t\t\t\t</div>
  2027. \t\t\t\t\t\t";
  2028.         }
  2029.         // line 1557
  2030.         yield "
  2031. \t\t\t\t\t\t<!-- Stock disponible -->
  2032. \t\t\t\t\t\t";
  2033.         // line 1559
  2034.         if (CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "stock", [], "any"truetruefalse1559)) {
  2035.             // line 1560
  2036.             yield "\t\t\t\t\t\t\t<small class=\"text-muted\">Stock disponible :
  2037. \t\t\t\t\t\t\t\t";
  2038.             // line 1561
  2039.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "stock", [], "any"falsefalsefalse1561), "html"nulltrue);
  2040.             yield "
  2041. \t\t\t\t\t\t\t\tunités</small>
  2042. \t\t\t\t\t\t";
  2043.         }
  2044.         // line 1564
  2045.         yield "
  2046. \t\t\t\t\t\t<!-- Statistiques du produit -->
  2047. \t\t\t\t\t\t";
  2048.         // line 1566
  2049.         if (array_key_exists("productStats"$context)) {
  2050.             // line 1567
  2051.             yield "\t\t\t\t\t\t\t<div class=\"product-stats mt-3\">
  2052. \t\t\t\t\t\t\t\t<div class=\"row text-center\">
  2053. \t\t\t\t\t\t\t\t\t<div class=\"col-4\">
  2054. \t\t\t\t\t\t\t\t\t\t<div class=\"stat-item\">
  2055. \t\t\t\t\t\t\t\t\t\t\t<span class=\"stat-number\">";
  2056.             // line 1571
  2057.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["productStats"] ?? null), "totalViews", [], "any"falsefalsefalse1571), "html"nulltrue);
  2058.             yield "</span>
  2059. \t\t\t\t\t\t\t\t\t\t\t<small class=\"stat-label\">Vues</small>
  2060. \t\t\t\t\t\t\t\t\t\t</div>
  2061. \t\t\t\t\t\t\t\t\t</div>
  2062. \t\t\t\t\t\t\t\t\t<div class=\"col-4\">
  2063. \t\t\t\t\t\t\t\t\t\t<div class=\"stat-item\">
  2064. \t\t\t\t\t\t\t\t\t\t\t<span class=\"stat-number\">";
  2065.             // line 1577
  2066.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["productStats"] ?? null), "salesCount", [], "any"falsefalsefalse1577), "html"nulltrue);
  2067.             yield "</span>
  2068. \t\t\t\t\t\t\t\t\t\t\t<small class=\"stat-label\">Ventes</small>
  2069. \t\t\t\t\t\t\t\t\t\t</div>
  2070. \t\t\t\t\t\t\t\t\t</div>
  2071. \t\t\t\t\t\t\t\t\t<div class=\"col-4\">
  2072. \t\t\t\t\t\t\t\t\t\t<div class=\"stat-item\">
  2073. \t\t\t\t\t\t\t\t\t\t\t<span class=\"stat-number\">";
  2074.             // line 1583
  2075.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["productStats"] ?? null), "conversionRate", [], "any"falsefalsefalse1583), "html"nulltrue);
  2076.             yield "%</span>
  2077. \t\t\t\t\t\t\t\t\t\t\t<small class=\"stat-label\">Conversion</small>
  2078. \t\t\t\t\t\t\t\t\t\t</div>
  2079. \t\t\t\t\t\t\t\t\t</div>
  2080. \t\t\t\t\t\t\t\t</div>
  2081. \t\t\t\t\t\t\t</div>
  2082. \t\t\t\t\t\t";
  2083.         }
  2084.         // line 1590
  2085.         yield "
  2086. \t\t\t\t\t\t<div class=\"card_area d-flex align-items-center\">
  2087. \t\t\t\t\t\t\t<a class=\"primary-btn btn-add-to-cart\" href=\"javascript:void(0);\" id=\"add-to-cart-btn\" data-product-id=\"";
  2088.         // line 1592
  2089.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "id", [], "any"falsefalsefalse1592), "html"nulltrue);
  2090.         yield "\" data-qty=\"1\">
  2091. \t\t\t\t\t\t\t\t<i class=\"lnr lnr-cart\"></i>
  2092. \t\t\t\t\t\t\t\tAjouter au panier
  2093. \t\t\t\t\t\t\t</a>
  2094. \t\t\t\t\t\t\t<a class=\"icon_btn wishlist-btn\" href=\"#\" title=\"Ajouter aux favoris\" data-product-id=\"";
  2095.         // line 1596
  2096.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "id", [], "any"falsefalsefalse1596), "html"nulltrue);
  2097.         yield "\" ";
  2098.         if ((($tmp CoreExtension::getAttribute($this->env$this->source, ($context["app"] ?? null), "user", [], "any"falsefalsefalse1596)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  2099.             yield " onclick=\"toggleWishlist(";
  2100.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "id", [], "any"falsefalsefalse1596), "html"nulltrue);
  2101.             yield ", this); return false;\" ";
  2102.         } else {
  2103.             yield " onclick=\"showCustomAlert('Vous devez être connecté pour ajouter aux favoris', 'warning'); return false;\" ";
  2104.         }
  2105.         yield ">
  2106. \t\t\t\t\t\t\t\t<i class=\"lnr lnr-heart\"></i>
  2107. \t\t\t\t\t\t\t</a>
  2108. \t\t\t\t\t\t\t<a class=\"icon_btn comparison-btn\" href=\"#\" title=\"Comparer\" data-product-id=\"";
  2109.         // line 1599
  2110.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "id", [], "any"falsefalsefalse1599), "html"nulltrue);
  2111.         yield "\" ";
  2112.         if ((($tmp CoreExtension::getAttribute($this->env$this->source, ($context["app"] ?? null), "user", [], "any"falsefalsefalse1599)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  2113.             yield " onclick=\"toggleComparison(";
  2114.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "id", [], "any"falsefalsefalse1599), "html"nulltrue);
  2115.             yield ", this); return false;\" ";
  2116.         } else {
  2117.             yield " onclick=\"showCustomAlert('Vous devez être connecté pour comparer des produits', 'warning'); return false;\" ";
  2118.         }
  2119.         yield ">
  2120. \t\t\t\t\t\t\t\t<i class=\"lnr lnr-sync\"></i>
  2121. \t\t\t\t\t\t\t</a>
  2122. \t\t\t\t\t\t</div>
  2123. \t\t\t\t\t\t<!-- Message de confirmation -->
  2124. \t\t\t\t\t\t<div id=\"cart-message\" class=\"alert alert-success mt-3\" style=\"display: none;\">
  2125. \t\t\t\t\t\t\t<i class=\"lnr lnr-checkmark-circle\"></i>
  2126. \t\t\t\t\t\t\tProduit ajouté au panier avec succès !
  2127. \t\t\t\t\t\t</div>
  2128. \t\t\t\t\t\t<!-- ... existing code ... -->
  2129. \t\t\t\t\t</div>
  2130. \t\t\t\t</div>
  2131. \t\t\t</div>
  2132. \t\t</div>
  2133. \t</div>
  2134. \t<!--================End Single Product Area =================-->
  2135. \t<!--================Product Description Area =================-->
  2136. \t<section class=\"product_description_area\">
  2137. \t\t<div class=\"container\">
  2138. \t\t\t<ul class=\"nav nav-tabs\" id=\"myTab\" role=\"tablist\">
  2139. \t\t\t\t<li class=\"nav-item\">
  2140. \t\t\t\t\t<a class=\"nav-link active\" id=\"home-tab\" data-bs-toggle=\"tab\" href=\"#home\" role=\"tab\" aria-controls=\"home\" aria-selected=\"true\">Description</a>
  2141. \t\t\t\t</li>
  2142. \t\t\t\t<li class=\"nav-item\">
  2143. \t\t\t\t\t<a class=\"nav-link\" id=\"profile-tab\" data-bs-toggle=\"tab\" href=\"#profile\" role=\"tab\" aria-controls=\"profile\" aria-selected=\"false\">Spécifications</a>
  2144. \t\t\t\t</li>
  2145. \t\t\t\t<li class=\"nav-item\">
  2146. \t\t\t\t\t<a class=\"nav-link\" id=\"contact-tab\" data-bs-toggle=\"tab\" href=\"#contact\" role=\"tab\" aria-controls=\"contact\" aria-selected=\"false\">Commentaires</a>
  2147. \t\t\t\t</li>
  2148. \t\t\t\t<li class=\"nav-item\">
  2149. \t\t\t\t\t<a class=\"nav-link\" id=\"review-tab\" data-bs-toggle=\"tab\" href=\"#review\" role=\"tab\" aria-controls=\"review\" aria-selected=\"false\">Avis (";
  2150.         // line 1631
  2151.         yield (((CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "reviewCount", [], "any"truetruefalse1631) &&  !(null === CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "reviewCount", [], "any"falsefalsefalse1631)))) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "reviewCount", [], "any"falsefalsefalse1631), "html"nulltrue)) : (0));
  2152.         yield ")</a>
  2153. \t\t\t\t</li>
  2154. \t\t\t</ul>
  2155. \t\t\t<div class=\"tab-content\" id=\"myTabContent\">
  2156. \t\t\t\t<div class=\"tab-pane fade show active\" id=\"home\" role=\"tabpanel\" aria-labelledby=\"home-tab\">
  2157. \t\t\t\t\t<div class=\"description\">
  2158. \t\t\t\t\t\t";
  2159.         // line 1637
  2160.         if ((($tmp CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "description", [], "any"falsefalsefalse1637)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  2161.             // line 1638
  2162.             yield "\t\t\t\t\t\t\t<div class=\"product-description-content\">
  2163. \t\t\t\t\t\t\t\t";
  2164.             // line 1639
  2165.             yield CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "description", [], "any"falsefalsefalse1639);
  2166.             yield "
  2167. \t\t\t\t\t\t\t</div>
  2168. \t\t\t\t\t\t";
  2169.         } else {
  2170.             // line 1642
  2171.             yield "\t\t\t\t\t\t\t<p class=\"text-muted\">Aucune description disponible pour ce produit.</p>
  2172. \t\t\t\t\t\t";
  2173.         }
  2174.         // line 1644
  2175.         yield "\t\t\t\t\t</div>
  2176. \t\t\t\t</div>
  2177. \t\t\t\t<div class=\"tab-pane fade\" id=\"profile\" role=\"tabpanel\" aria-labelledby=\"profile-tab\">
  2178. \t\t\t\t\t<div class=\"specification-table\">
  2179. \t\t\t\t\t\t";
  2180.         // line 1648
  2181.         if (((((CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "weight", [], "any"falsefalsefalse1648) || CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "length", [], "any"falsefalsefalse1648)) || CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "width", [], "any"falsefalsefalse1648)) || CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "height", [], "any"falsefalsefalse1648)) || CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "attributes", [], "any"falsefalsefalse1648))) {
  2182.             // line 1649
  2183.             yield "\t\t\t\t\t\t\t<div class=\"table-responsive\">
  2184. \t\t\t\t\t\t\t\t<table class=\"table\">
  2185. \t\t\t\t\t\t\t\t\t<tbody>
  2186. \t\t\t\t\t\t\t\t\t\t";
  2187.             // line 1652
  2188.             if ((($tmp CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "sku", [], "any"falsefalsefalse1652)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  2189.                 // line 1653
  2190.                 yield "\t\t\t\t\t\t\t\t\t\t\t<tr>
  2191. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  2192. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>Référence (SKU)</h5>
  2193. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  2194. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  2195. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>";
  2196.                 // line 1658
  2197.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "sku", [], "any"falsefalsefalse1658), "html"nulltrue);
  2198.                 yield "</h5>
  2199. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  2200. \t\t\t\t\t\t\t\t\t\t\t</tr>
  2201. \t\t\t\t\t\t\t\t\t\t";
  2202.             }
  2203.             // line 1662
  2204.             yield "\t\t\t\t\t\t\t\t\t\t";
  2205.             if ((($tmp CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "barcode", [], "any"falsefalsefalse1662)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  2206.                 // line 1663
  2207.                 yield "\t\t\t\t\t\t\t\t\t\t\t<tr>
  2208. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  2209. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>Code-barres</h5>
  2210. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  2211. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  2212. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>";
  2213.                 // line 1668
  2214.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "barcode", [], "any"falsefalsefalse1668), "html"nulltrue);
  2215.                 yield "</h5>
  2216. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  2217. \t\t\t\t\t\t\t\t\t\t\t</tr>
  2218. \t\t\t\t\t\t\t\t\t\t";
  2219.             }
  2220.             // line 1672
  2221.             yield "\t\t\t\t\t\t\t\t\t\t";
  2222.             if ((($tmp CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "brand", [], "any"falsefalsefalse1672)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  2223.                 // line 1673
  2224.                 yield "\t\t\t\t\t\t\t\t\t\t\t<tr>
  2225. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  2226. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>Marque</h5>
  2227. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  2228. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  2229. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>";
  2230.                 // line 1678
  2231.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "brand", [], "any"falsefalsefalse1678), "name", [], "any"falsefalsefalse1678), "html"nulltrue);
  2232.                 yield "</h5>
  2233. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  2234. \t\t\t\t\t\t\t\t\t\t\t</tr>
  2235. \t\t\t\t\t\t\t\t\t\t";
  2236.             }
  2237.             // line 1682
  2238.             yield "\t\t\t\t\t\t\t\t\t\t";
  2239.             if ((($tmp CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "category", [], "any"falsefalsefalse1682)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  2240.                 // line 1683
  2241.                 yield "\t\t\t\t\t\t\t\t\t\t\t<tr>
  2242. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  2243. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>Catégorie</h5>
  2244. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  2245. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  2246. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>";
  2247.                 // line 1688
  2248.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "category", [], "any"falsefalsefalse1688), "name", [], "any"falsefalsefalse1688), "html"nulltrue);
  2249.                 yield "</h5>
  2250. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  2251. \t\t\t\t\t\t\t\t\t\t\t</tr>
  2252. \t\t\t\t\t\t\t\t\t\t";
  2253.             }
  2254.             // line 1692
  2255.             yield "\t\t\t\t\t\t\t\t\t\t";
  2256.             if ((($tmp CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "weight", [], "any"falsefalsefalse1692)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  2257.                 // line 1693
  2258.                 yield "\t\t\t\t\t\t\t\t\t\t\t<tr>
  2259. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  2260. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>Poids</h5>
  2261. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  2262. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  2263. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>";
  2264.                 // line 1698
  2265.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "weight", [], "any"falsefalsefalse1698), "html"nulltrue);
  2266.                 yield "
  2267. \t\t\t\t\t\t\t\t\t\t\t\t\t\tkg</h5>
  2268. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  2269. \t\t\t\t\t\t\t\t\t\t\t</tr>
  2270. \t\t\t\t\t\t\t\t\t\t";
  2271.             }
  2272.             // line 1703
  2273.             yield "\t\t\t\t\t\t\t\t\t\t";
  2274.             if (((CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "length", [], "any"falsefalsefalse1703) || CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "width", [], "any"falsefalsefalse1703)) || CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "height", [], "any"falsefalsefalse1703))) {
  2275.                 // line 1704
  2276.                 yield "\t\t\t\t\t\t\t\t\t\t\t<tr>
  2277. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  2278. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>Dimensions</h5>
  2279. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  2280. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  2281. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>
  2282. \t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  2283.                 // line 1710
  2284.                 if ((($tmp CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "length", [], "any"falsefalsefalse1710)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  2285.                     // line 1711
  2286.                     yield "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  2287.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "length", [], "any"falsefalsefalse1711), "html"nulltrue);
  2288.                     yield "cm
  2289. \t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  2290.                 }
  2291.                 // line 1713
  2292.                 yield "\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  2293.                 if ((($tmp CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "width", [], "any"falsefalsefalse1713)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  2294.                     // line 1714
  2295.                     yield "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t×
  2296. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  2297.                     // line 1715
  2298.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "width", [], "any"falsefalsefalse1715), "html"nulltrue);
  2299.                     yield "cm
  2300. \t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  2301.                 }
  2302.                 // line 1717
  2303.                 yield "\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  2304.                 if ((($tmp CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "height", [], "any"falsefalsefalse1717)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  2305.                     // line 1718
  2306.                     yield "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t×
  2307. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  2308.                     // line 1719
  2309.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "height", [], "any"falsefalsefalse1719), "html"nulltrue);
  2310.                     yield "cm
  2311. \t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  2312.                 }
  2313.                 // line 1721
  2314.                 yield "\t\t\t\t\t\t\t\t\t\t\t\t\t</h5>
  2315. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  2316. \t\t\t\t\t\t\t\t\t\t\t</tr>
  2317. \t\t\t\t\t\t\t\t\t\t";
  2318.             }
  2319.             // line 1725
  2320.             yield "\t\t\t\t\t\t\t\t\t\t";
  2321.             if ((($tmp =  !(null === CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "stock", [], "any"falsefalsefalse1725))) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  2322.                 // line 1726
  2323.                 yield "\t\t\t\t\t\t\t\t\t\t\t<tr>
  2324. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  2325. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>Stock disponible</h5>
  2326. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  2327. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  2328. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>";
  2329.                 // line 1731
  2330.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "stock", [], "any"falsefalsefalse1731), "html"nulltrue);
  2331.                 yield "
  2332. \t\t\t\t\t\t\t\t\t\t\t\t\t\tunité(s)</h5>
  2333. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  2334. \t\t\t\t\t\t\t\t\t\t\t</tr>
  2335. \t\t\t\t\t\t\t\t\t\t";
  2336.             }
  2337.             // line 1736
  2338.             yield "\t\t\t\t\t\t\t\t\t\t";
  2339.             if ((CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "details", [], "any"truetruefalse1736) && (Twig\Extension\CoreExtension::length($this->env->getCharset(), CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "details", [], "any"falsefalsefalse1736)) > 0))) {
  2340.                 // line 1737
  2341.                 yield "\t\t\t\t\t\t\t\t\t\t\t";
  2342.                 $context['_parent'] = $context;
  2343.                 $context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "details", [], "any"falsefalsefalse1737));
  2344.                 foreach ($context['_seq'] as $context["_key"] => $context["detail"]) {
  2345.                     // line 1738
  2346.                     yield "\t\t\t\t\t\t\t\t\t\t\t\t";
  2347.                     if ((($tmp CoreExtension::getAttribute($this->env$this->source$context["detail"], "isActive", [], "any"falsefalsefalse1738)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  2348.                         // line 1739
  2349.                         yield "\t\t\t\t\t\t\t\t\t\t\t\t\t<tr>
  2350. \t\t\t\t\t\t\t\t\t\t\t\t\t\t<td>
  2351. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<h5>";
  2352.                         // line 1741
  2353.                         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["detail"], "label", [], "any"falsefalsefalse1741), "html"nulltrue);
  2354.                         yield "</h5>
  2355. \t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>
  2356. \t\t\t\t\t\t\t\t\t\t\t\t\t\t<td>
  2357. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<h5>";
  2358.                         // line 1744
  2359.                         yield CoreExtension::getAttribute($this->env$this->source$context["detail"], "value", [], "any"falsefalsefalse1744);
  2360.                         yield "</h5>
  2361. \t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>
  2362. \t\t\t\t\t\t\t\t\t\t\t\t\t</tr>
  2363. \t\t\t\t\t\t\t\t\t\t\t\t";
  2364.                     }
  2365.                     // line 1748
  2366.                     yield "\t\t\t\t\t\t\t\t\t\t\t";
  2367.                 }
  2368.                 $_parent $context['_parent'];
  2369.                 unset($context['_seq'], $context['_key'], $context['detail'], $context['_parent']);
  2370.                 $context array_intersect_key($context$_parent) + $_parent;
  2371.                 // line 1749
  2372.                 yield "\t\t\t\t\t\t\t\t\t\t";
  2373.             }
  2374.             // line 1750
  2375.             yield "\t\t\t\t\t\t\t\t\t\t";
  2376.             if ((($tmp CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "stockStatus", [], "any"falsefalsefalse1750)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  2377.                 // line 1751
  2378.                 yield "\t\t\t\t\t\t\t\t\t\t\t<tr>
  2379. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  2380. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>Statut</h5>
  2381. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  2382. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  2383. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>
  2384. \t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  2385.                 // line 1757
  2386.                 if ((CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "stockStatus", [], "any"falsefalsefalse1757) == "in_stock")) {
  2387.                     // line 1758
  2388.                     yield "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"badge bg-success\">En stock</span>
  2389. \t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  2390.                 } elseif ((CoreExtension::getAttribute($this->env$this->source,                 // line 1759
  2391. ($context["product"] ?? null), "stockStatus", [], "any"falsefalsefalse1759) == "out_of_stock")) {
  2392.                     // line 1760
  2393.                     yield "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"badge bg-danger\">Rupture de stock</span>
  2394. \t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  2395.                 } elseif ((CoreExtension::getAttribute($this->env$this->source,                 // line 1761
  2396. ($context["product"] ?? null), "stockStatus", [], "any"falsefalsefalse1761) == "backorder")) {
  2397.                     // line 1762
  2398.                     yield "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"badge bg-warning\">Sur commande</span>
  2399. \t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  2400.                 } else {
  2401.                     // line 1764
  2402.                     yield "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  2403.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "stockStatus", [], "any"falsefalsefalse1764), "html"nulltrue);
  2404.                     yield "
  2405. \t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  2406.                 }
  2407.                 // line 1766
  2408.                 yield "\t\t\t\t\t\t\t\t\t\t\t\t\t</h5>
  2409. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  2410. \t\t\t\t\t\t\t\t\t\t\t</tr>
  2411. \t\t\t\t\t\t\t\t\t\t";
  2412.             }
  2413.             // line 1770
  2414.             yield "\t\t\t\t\t\t\t\t\t\t";
  2415.             if ((($tmp CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "isDigital", [], "any"falsefalsefalse1770)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  2416.                 // line 1771
  2417.                 yield "\t\t\t\t\t\t\t\t\t\t\t<tr>
  2418. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  2419. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>Type</h5>
  2420. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  2421. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  2422. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>
  2423. \t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"badge bg-info\">Produit digital</span>
  2424. \t\t\t\t\t\t\t\t\t\t\t\t\t</h5>
  2425. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  2426. \t\t\t\t\t\t\t\t\t\t\t</tr>
  2427. \t\t\t\t\t\t\t\t\t\t";
  2428.             }
  2429.             // line 1782
  2430.             yield "\t\t\t\t\t\t\t\t\t\t";
  2431.             if ((($tmp =  !Twig\Extension\CoreExtension::testEmpty(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "attributes", [], "any"falsefalsefalse1782))) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  2432.                 // line 1783
  2433.                 yield "\t\t\t\t\t\t\t\t\t\t\t";
  2434.                 $context['_parent'] = $context;
  2435.                 $context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "attributes", [], "any"falsefalsefalse1783));
  2436.                 foreach ($context['_seq'] as $context["key"] => $context["value"]) {
  2437.                     // line 1784
  2438.                     yield "\t\t\t\t\t\t\t\t\t\t\t\t<tr>
  2439. \t\t\t\t\t\t\t\t\t\t\t\t\t<td>
  2440. \t\t\t\t\t\t\t\t\t\t\t\t\t\t<h5>";
  2441.                     // line 1786
  2442.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::titleCase($this->env->getCharset(), Twig\Extension\CoreExtension::replace($context["key"], ["_" => " "])), "html"nulltrue);
  2443.                     yield "</h5>
  2444. \t\t\t\t\t\t\t\t\t\t\t\t\t</td>
  2445. \t\t\t\t\t\t\t\t\t\t\t\t\t<td>
  2446. \t\t\t\t\t\t\t\t\t\t\t\t\t\t<h5>";
  2447.                     // line 1789
  2448.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($context["value"], "html"nulltrue);
  2449.                     yield "</h5>
  2450. \t\t\t\t\t\t\t\t\t\t\t\t\t</td>
  2451. \t\t\t\t\t\t\t\t\t\t\t\t</tr>
  2452. \t\t\t\t\t\t\t\t\t\t\t";
  2453.                 }
  2454.                 $_parent $context['_parent'];
  2455.                 unset($context['_seq'], $context['key'], $context['value'], $context['_parent']);
  2456.                 $context array_intersect_key($context$_parent) + $_parent;
  2457.                 // line 1793
  2458.                 yield "\t\t\t\t\t\t\t\t\t\t";
  2459.             }
  2460.             // line 1794
  2461.             yield "\t\t\t\t\t\t\t\t\t</tbody>
  2462. \t\t\t\t\t\t\t\t</table>
  2463. \t\t\t\t\t\t\t</div>
  2464. \t\t\t\t\t\t";
  2465.         } else {
  2466.             // line 1798
  2467.             yield "\t\t\t\t\t\t\t<p class=\"text-muted\">Aucune spécification disponible pour ce produit.</p>
  2468. \t\t\t\t\t\t";
  2469.         }
  2470.         // line 1800
  2471.         yield "\t\t\t\t\t</div>
  2472. \t\t\t\t</div>
  2473. \t\t\t\t<div class=\"tab-pane fade\" id=\"contact\" role=\"tabpanel\" aria-labelledby=\"contact-tab\">
  2474. \t\t\t\t\t<div class=\"comment-wrapper\">
  2475. \t\t\t\t\t\t<div class=\"alert alert-info\">
  2476. \t\t\t\t\t\t\t<i class=\"lnr lnr-info-circle\"></i>
  2477. \t\t\t\t\t\t\tLa fonctionnalité de commentaires sera bientôt disponible. Vous pourrez laisser des commentaires et poser des questions sur ce produit.
  2478. \t\t\t\t\t\t</div>
  2479. \t\t\t\t\t\t";
  2480.         // line 1808
  2481.         if ((($tmp CoreExtension::getAttribute($this->env$this->source, ($context["app"] ?? null), "user", [], "any"falsefalsefalse1808)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  2482.             // line 1809
  2483.             yield "\t\t\t\t\t\t\t<div class=\"review_box mt-4\">
  2484. \t\t\t\t\t\t\t\t<h4>Poser une question</h4>
  2485. \t\t\t\t\t\t\t\t<form class=\"row contact_form\" method=\"post\" novalidate=\"novalidate\">
  2486. \t\t\t\t\t\t\t\t\t<div class=\"col-md-12\">
  2487. \t\t\t\t\t\t\t\t\t\t<div class=\"form-group\">
  2488. \t\t\t\t\t\t\t\t\t\t\t<textarea class=\"form-control\" name=\"comment\" id=\"comment\" rows=\"3\" placeholder=\"Votre question ou commentaire...\" required></textarea>
  2489. \t\t\t\t\t\t\t\t\t\t</div>
  2490. \t\t\t\t\t\t\t\t\t</div>
  2491. \t\t\t\t\t\t\t\t\t<div class=\"col-md-12 text-right\">
  2492. \t\t\t\t\t\t\t\t\t\t<button type=\"submit\" class=\"btn primary-btn\">Envoyer</button>
  2493. \t\t\t\t\t\t\t\t\t</div>
  2494. \t\t\t\t\t\t\t\t</form>
  2495. \t\t\t\t\t\t\t</div>
  2496. \t\t\t\t\t\t";
  2497.         } else {
  2498.             // line 1823
  2499.             yield "\t\t\t\t\t\t\t<p class=\"text-center\">
  2500. \t\t\t\t\t\t\t\t<a href=\"";
  2501.             // line 1824
  2502.             yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("ui_app_login");
  2503.             yield "\" class=\"primary-btn\">Connectez-vous</a>
  2504. \t\t\t\t\t\t\t\tpour poser une question ou laisser un commentaire.
  2505. \t\t\t\t\t\t\t</p>
  2506. \t\t\t\t\t\t";
  2507.         }
  2508.         // line 1828
  2509.         yield "\t\t\t\t\t</div>
  2510. \t\t\t\t</div>
  2511. \t\t\t\t<div class=\"tab-pane fade\" id=\"review\" role=\"tabpanel\" aria-labelledby=\"review-tab\">
  2512. \t\t\t\t\t<div class=\"review-wrapper\">
  2513. \t\t\t\t\t\t<div class=\"row\">
  2514. \t\t\t\t\t\t\t<div class=\"col-lg-6\">
  2515. \t\t\t\t\t\t\t\t<div class=\"row total_rate\">
  2516. \t\t\t\t\t\t\t\t\t<div class=\"col-6\">
  2517. \t\t\t\t\t\t\t\t\t\t<div class=\"box_total\">
  2518. \t\t\t\t\t\t\t\t\t\t\t<h5>Note globale</h5>
  2519. \t\t\t\t\t\t\t\t\t\t\t<h4>";
  2520.         // line 1838
  2521.         yield (((($tmp CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "averageRating", [], "any"falsefalsefalse1838)) && $tmp instanceof Markup ? (string) $tmp $tmp)) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "averageRating", [], "any"falsefalsefalse1838), 1"."","), "html"nulltrue)) : ("0.0"));
  2522.         yield "</h4>
  2523. \t\t\t\t\t\t\t\t\t\t\t<h6>(";
  2524.         // line 1839
  2525.         yield (((CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "reviewCount", [], "any"truetruefalse1839) &&  !(null === CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "reviewCount", [], "any"falsefalsefalse1839)))) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "reviewCount", [], "any"falsefalsefalse1839), "html"nulltrue)) : (0));
  2526.         yield "
  2527. \t\t\t\t\t\t\t\t\t\t\t\tAvis)</h6>
  2528. \t\t\t\t\t\t\t\t\t\t</div>
  2529. \t\t\t\t\t\t\t\t\t</div>
  2530. \t\t\t\t\t\t\t\t\t<div class=\"col-6\">
  2531. \t\t\t\t\t\t\t\t\t\t<div class=\"rating_list\">
  2532. \t\t\t\t\t\t\t\t\t\t\t<h3>Basé sur
  2533. \t\t\t\t\t\t\t\t\t\t\t\t";
  2534.         // line 1846
  2535.         yield (((CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "reviewCount", [], "any"truetruefalse1846) &&  !(null === CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "reviewCount", [], "any"falsefalsefalse1846)))) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "reviewCount", [], "any"falsefalsefalse1846), "html"nulltrue)) : (0));
  2536.         yield "
  2537. \t\t\t\t\t\t\t\t\t\t\t\tavis</h3>
  2538. \t\t\t\t\t\t\t\t\t\t\t<div class=\"rating-summary\">
  2539. \t\t\t\t\t\t\t\t\t\t\t\t";
  2540.         // line 1849
  2541.         if ((($tmp CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "averageRating", [], "any"falsefalsefalse1849)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  2542.             // line 1850
  2543.             yield "\t\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"rating-display mb-3\">
  2544. \t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  2545.             // line 1851
  2546.             $context['_parent'] = $context;
  2547.             $context['_seq'] = CoreExtension::ensureTraversable(range(15));
  2548.             foreach ($context['_seq'] as $context["_key"] => $context["i"]) {
  2549.                 // line 1852
  2550.                 yield "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<i class=\"fa fa-star";
  2551.                 if (($context["i"] <= CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "averageRating", [], "any"falsefalsefalse1852))) {
  2552.                 } else {
  2553.                     yield "-o";
  2554.                 }
  2555.                 yield "\" style=\"color: #ffa200; font-size: 1.2rem;\"></i>
  2556. \t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  2557.             }
  2558.             $_parent $context['_parent'];
  2559.             unset($context['_seq'], $context['_key'], $context['i'], $context['_parent']);
  2560.             $context array_intersect_key($context$_parent) + $_parent;
  2561.             // line 1854
  2562.             yield "\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"ms-2\" style=\"font-size: 1.1rem; font-weight: bold;\">";
  2563.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "averageRating", [], "any"falsefalsefalse1854), 1"."","), "html"nulltrue);
  2564.             yield "
  2565. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/ 5.0</span>
  2566. \t\t\t\t\t\t\t\t\t\t\t\t\t</div>
  2567. \t\t\t\t\t\t\t\t\t\t\t\t";
  2568.         } else {
  2569.             // line 1858
  2570.             yield "\t\t\t\t\t\t\t\t\t\t\t\t\t<p class=\"text-muted\">Aucune note disponible</p>
  2571. \t\t\t\t\t\t\t\t\t\t\t\t";
  2572.         }
  2573.         // line 1860
  2574.         yield "\t\t\t\t\t\t\t\t\t\t\t</div>
  2575. \t\t\t\t\t\t\t\t\t\t</div>
  2576. \t\t\t\t\t\t\t\t\t</div>
  2577. \t\t\t\t\t\t\t\t</div>
  2578. \t\t\t\t\t\t\t\t<div class=\"review_list\">
  2579. \t\t\t\t\t\t\t\t\t";
  2580.         // line 1865
  2581.         if ((CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "reviewCount", [], "any"falsefalsefalse1865) && (CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "reviewCount", [], "any"falsefalsefalse1865) > 0))) {
  2582.             // line 1866
  2583.             yield "\t\t\t\t\t\t\t\t\t\t<div class=\"alert alert-info\">
  2584. \t\t\t\t\t\t\t\t\t\t\t<i class=\"lnr lnr-info-circle\"></i>
  2585. \t\t\t\t\t\t\t\t\t\t\tLe système d'affichage détaillé des avis sera disponible prochainement. 
  2586. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tNote actuelle :
  2587. \t\t\t\t\t\t\t\t\t\t\t";
  2588.             // line 1870
  2589.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "averageRating", [], "any"falsefalsefalse1870), 1"."","), "html"nulltrue);
  2590.             yield "
  2591. \t\t\t\t\t\t\t\t\t\t\t/ 5.0 basée sur
  2592. \t\t\t\t\t\t\t\t\t\t\t";
  2593.             // line 1872
  2594.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "reviewCount", [], "any"falsefalsefalse1872), "html"nulltrue);
  2595.             yield "
  2596. \t\t\t\t\t\t\t\t\t\t\tavis.
  2597. \t\t\t\t\t\t\t\t\t\t</div>
  2598. \t\t\t\t\t\t\t\t\t";
  2599.         } else {
  2600.             // line 1876
  2601.             yield "\t\t\t\t\t\t\t\t\t\t<div class=\"alert alert-info\">
  2602. \t\t\t\t\t\t\t\t\t\t\t<i class=\"lnr lnr-info-circle\"></i>
  2603. \t\t\t\t\t\t\t\t\t\t\tAucun avis pour ce produit pour le moment. Soyez le premier à laisser un avis après votre achat !
  2604. \t\t\t\t\t\t\t\t\t\t</div>
  2605. \t\t\t\t\t\t\t\t\t";
  2606.         }
  2607.         // line 1881
  2608.         yield "\t\t\t\t\t\t\t\t</div>
  2609. \t\t\t\t\t\t\t</div>
  2610. \t\t\t\t\t\t\t<div class=\"col-lg-6\">
  2611. \t\t\t\t\t\t\t\t<div class=\"review_box\">
  2612. \t\t\t\t\t\t\t\t\t<h4>Laisser un avis</h4>
  2613. \t\t\t\t\t\t\t\t\t";
  2614.         // line 1886
  2615.         if ((($tmp CoreExtension::getAttribute($this->env$this->source, ($context["app"] ?? null), "user", [], "any"falsefalsefalse1886)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  2616.             // line 1887
  2617.             yield "\t\t\t\t\t\t\t\t\t\t<p class=\"text-muted\">Vous pouvez laisser un avis après avoir acheté ce produit.</p>
  2618. \t\t\t\t\t\t\t\t\t\t<form class=\"row contact_form\" method=\"post\" novalidate=\"novalidate\">
  2619. \t\t\t\t\t\t\t\t\t\t\t<div class=\"col-md-12\">
  2620. \t\t\t\t\t\t\t\t\t\t\t\t<div class=\"form-group\">
  2621. \t\t\t\t\t\t\t\t\t\t\t\t\t<label>Votre note</label>
  2622. \t\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"rating-input mb-3\" style=\"display: flex; gap: 5px; flex-direction: row-reverse; justify-content: flex-end;\">
  2623. \t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  2624.             // line 1893
  2625.             $context['_parent'] = $context;
  2626.             $context['_seq'] = CoreExtension::ensureTraversable(range(51));
  2627.             foreach ($context['_seq'] as $context["_key"] => $context["i"]) {
  2628.                 // line 1894
  2629.                 yield "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<input type=\"radio\" name=\"rating\" id=\"rating";
  2630.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($context["i"], "html"nulltrue);
  2631.                 yield "\" value=\"";
  2632.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($context["i"], "html"nulltrue);
  2633.                 yield "\" required style=\"display: none;\">
  2634. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"rating";
  2635.                 // line 1895
  2636.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($context["i"], "html"nulltrue);
  2637.                 yield "\" class=\"star-label\" style=\"cursor: pointer;\">
  2638. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<i class=\"fa fa-star-o\" style=\"color: #ccc; font-size: 1.5rem;\"></i>
  2639. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</label>
  2640. \t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  2641.             }
  2642.             $_parent $context['_parent'];
  2643.             unset($context['_seq'], $context['_key'], $context['i'], $context['_parent']);
  2644.             $context array_intersect_key($context$_parent) + $_parent;
  2645.             // line 1899
  2646.             yield "\t\t\t\t\t\t\t\t\t\t\t\t\t</div>
  2647. \t\t\t\t\t\t\t\t\t\t\t\t</div>
  2648. \t\t\t\t\t\t\t\t\t\t\t</div>
  2649. \t\t\t\t\t\t\t\t\t\t\t<div class=\"col-md-12\">
  2650. \t\t\t\t\t\t\t\t\t\t\t\t<div class=\"form-group\">
  2651. \t\t\t\t\t\t\t\t\t\t\t\t\t<textarea class=\"form-control\" name=\"review\" id=\"review\" rows=\"5\" placeholder=\"Votre avis...\" required onfocus=\"this.placeholder = ''\" onblur=\"this.placeholder = 'Votre avis...'\"></textarea>
  2652. \t\t\t\t\t\t\t\t\t\t\t\t</div>
  2653. \t\t\t\t\t\t\t\t\t\t\t</div>
  2654. \t\t\t\t\t\t\t\t\t\t\t<div class=\"col-md-12 text-right\">
  2655. \t\t\t\t\t\t\t\t\t\t\t\t<button type=\"submit\" class=\"btn primary-btn\">Publier l'avis</button>
  2656. \t\t\t\t\t\t\t\t\t\t\t</div>
  2657. \t\t\t\t\t\t\t\t\t\t</form>
  2658. \t\t\t\t\t\t\t\t\t";
  2659.         } else {
  2660.             // line 1912
  2661.             yield "\t\t\t\t\t\t\t\t\t\t<p class=\"text-center\">
  2662. \t\t\t\t\t\t\t\t\t\t\t<a href=\"";
  2663.             // line 1913
  2664.             yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("ui_app_login");
  2665.             yield "\" class=\"primary-btn\">Connectez-vous</a>
  2666. \t\t\t\t\t\t\t\t\t\t\tpour laisser un avis sur ce produit.
  2667. \t\t\t\t\t\t\t\t\t\t</p>
  2668. \t\t\t\t\t\t\t\t\t";
  2669.         }
  2670.         // line 1917
  2671.         yield "\t\t\t\t\t\t\t\t</div>
  2672. \t\t\t\t\t\t\t</div>
  2673. \t\t\t\t\t\t</div>
  2674. \t\t\t\t\t</div>
  2675. \t\t\t\t</div>
  2676. \t\t\t</div>
  2677. \t\t</div>
  2678. \t</section>
  2679. \t<!--================End Product Description Area =================-->
  2680. \t<script>
  2681. \t\t// Données des variantes du produit
  2682. \t\tconst productVariants = ";
  2683.         // line 1929
  2684.         yield (((Twig\Extension\CoreExtension::length($this->env->getCharset(), CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "variants", [], "any"falsefalsefalse1929)) > 0)) ? (json_encode(Twig\Extension\CoreExtension::map($this->envCoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "variants", [], "any"falsefalsefalse1929), function ($__v__) use ($context$macros) { $context["v"] = $__v__; return ["id" => CoreExtension::getAttribute($this->env$this->source,         // line 1930
  2685. ($context["v"] ?? null), "id", [], "any"falsefalsefalse1930), "sku" => CoreExtension::getAttribute($this->env$this->source,         // line 1931
  2686. ($context["v"] ?? null), "sku", [], "any"falsefalsefalse1931), "price" => CoreExtension::getAttribute($this->env$this->source,         // line 1932
  2687. ($context["v"] ?? null), "price", [], "any"falsefalsefalse1932), "compareAtPrice" => CoreExtension::getAttribute($this->env$this->source,         // line 1933
  2688. ($context["v"] ?? null), "compareAtPrice", [], "any"falsefalsefalse1933), "stock" => CoreExtension::getAttribute($this->env$this->source,         // line 1934
  2689. ($context["v"] ?? null), "stock", [], "any"falsefalsefalse1934), "stockStatus" => CoreExtension::getAttribute($this->env$this->source,         // line 1935
  2690. ($context["v"] ?? null), "stockStatus", [], "any"falsefalsefalse1935), "isActive" => CoreExtension::getAttribute($this->env$this->source,         // line 1936
  2691. ($context["v"] ?? null), "isActive", [], "any"falsefalsefalse1936), "images" => CoreExtension::getAttribute($this->env$this->source,         // line 1937
  2692. ($context["v"] ?? null), "images", [], "any"falsefalsefalse1937), "attributeValues" => $this->extensions['App\Twig\ColorExtension']->toArray(Twig\Extension\CoreExtension::map($this->envCoreExtension::getAttribute($this->env$this->source,         // line 1938
  2693. ($context["v"] ?? null), "attributeValues", [], "any"falsefalsefalse1938), function ($__av__) use ($context$macros) { $context["av"] = $__av__; return ["attributeId" => CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source,         // line 1939
  2694. ($context["av"] ?? null), "attribute", [], "any"falsefalsefalse1939), "id", [], "any"falsefalsefalse1939), "attributeSlug" => CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source,         // line 1940
  2695. ($context["av"] ?? null), "attribute", [], "any"falsefalsefalse1940), "slug", [], "any"falsefalsefalse1940), "valueId" => CoreExtension::getAttribute($this->env$this->source,         // line 1941
  2696. ($context["av"] ?? null), "id", [], "any"falsefalsefalse1941), "value" => CoreExtension::getAttribute($this->env$this->source,         // line 1942
  2697. ($context["av"] ?? null), "value", [], "any"falsefalsefalse1942)]; }))]; }))) : ("[]"));
  2698.         // line 1944
  2699.         yield ";
  2700. \t\t// Gestion de la sélection de variantes
  2701. \t\tlet selectedAttributes = {};
  2702. \t\tlet currentVariant = null;
  2703. \t\t// Initialiser les onglets Bootstrap
  2704. document.addEventListener('DOMContentLoaded', function () { // Activer les onglets Bootstrap 5
  2705. const triggerTabList = document.querySelectorAll('#myTab button[data-bs-toggle=\"tab\"]');
  2706. triggerTabList.forEach(triggerEl => {
  2707. const tabTrigger = new bootstrap.Tab(triggerEl);
  2708. triggerEl.addEventListener('click', event => {
  2709. event.preventDefault();
  2710. tabTrigger.show();
  2711. });
  2712. });
  2713. // Gestion des étoiles pour les avis
  2714. const ratingInputs = document.querySelectorAll('.rating-input input[type=\"radio\"]');
  2715. const starLabels = document.querySelectorAll('.rating-input .star-label');
  2716. ratingInputs.forEach((input, index) => {
  2717. input.addEventListener('change', function () {
  2718. const rating = parseInt(this.value);
  2719. starLabels.forEach((label) => { // Trouver l'input associé à ce label
  2720. const labelInput = label.previousElementSibling;
  2721. if (labelInput && labelInput.type === 'radio') {
  2722. const starValue = parseInt(labelInput.value);
  2723. const star = label.querySelector('i');
  2724. if (starValue <= rating) {
  2725. star.style.color = '#ffa200';
  2726. star.classList.remove('fa-star-o');
  2727. star.classList.add('fa-star');
  2728. } else {
  2729. star.style.color = '#ccc';
  2730. star.classList.remove('fa-star');
  2731. star.classList.add('fa-star-o');
  2732. }
  2733. }
  2734. });
  2735. });
  2736. });
  2737. // Pré-remplir les étoiles au survol
  2738. starLabels.forEach((label) => {
  2739. label.addEventListener('mouseenter', function () { // Trouver l'input associé à ce label
  2740. const input = label.previousElementSibling;
  2741. if (input && input.type === 'radio') {
  2742. const rating = parseInt(input.value);
  2743. starLabels.forEach((l) => {
  2744. const lInput = l.previousElementSibling;
  2745. if (lInput && lInput.type === 'radio') {
  2746. const starValue = parseInt(lInput.value);
  2747. const star = l.querySelector('i');
  2748. if (starValue <= rating) {
  2749. star.style.color = '#ffa200';
  2750. star.classList.remove('fa-star-o');
  2751. star.classList.add('fa-star');
  2752. } else {
  2753. star.style.color = '#ccc';
  2754. star.classList.remove('fa-star');
  2755. star.classList.add('fa-star-o');
  2756. }
  2757. }
  2758. });
  2759. }
  2760. });
  2761. });
  2762. const ratingContainer = document.querySelector('.rating-input');
  2763. if (ratingContainer) {
  2764. ratingContainer.addEventListener('mouseleave', function () {
  2765. const checkedInput = document.querySelector('.rating-input input[type=\"radio\"]:checked');
  2766. if (checkedInput) {
  2767. checkedInput.dispatchEvent(new Event('change'));
  2768. } else {
  2769. starLabels.forEach(label => {
  2770. const star = label.querySelector('i');
  2771. star.style.color = '#ccc';
  2772. });
  2773. }
  2774. });
  2775. }
  2776. });
  2777. \t// Gestion de la sélection de variantes
  2778. \tif (typeof productVariants !== 'undefined' && productVariants.length > 0) {
  2779. \t\t// Initialiser avec la première variante active
  2780. \t\tconst firstVariant = productVariants.find(v => v.isActive);
  2781. \t\tif (firstVariant) {
  2782. \t\t\tfirstVariant.attributeValues.forEach(av => {
  2783. \t\t\t\tselectedAttributes[av.attributeSlug] = av.valueId;
  2784. \t\t\t});
  2785. \t\t\tupdateVariantDisplay(firstVariant);
  2786. \t\t} else {
  2787. \t\t\t// Si aucune variante active, afficher le prix de base
  2788. \t\t\tconst priceEl = document.getElementById('main-unit-price');
  2789. \t\t\tif (priceEl) {
  2790. \t\t\t\tpriceEl.textContent = '";
  2791.         // line 2042
  2792.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "price", [], "any"falsefalsefalse2042), 2"."" "), "html"nulltrue);
  2793.         yield "';
  2794. \t\t\t}
  2795. \t\t}
  2796. \t\t// Écouter les clics sur les options de variantes
  2797. \t\tdocument.querySelectorAll('.variant-option').forEach(option => {
  2798. \t\t\toption.addEventListener('click', function() {
  2799. \t\t\t\tconst attributeSlug = this.getAttribute('data-attribute');
  2800. \t\t\t\tconst valueId = parseInt(this.getAttribute('data-value-id'));
  2801. \t\t\t\tconst value = this.getAttribute('data-value');
  2802. \t\t\t\t// Mettre à jour la sélection visuelle
  2803. \t\t\t\tdocument.querySelectorAll(`[data-attribute=\"\${attributeSlug}\"]`).forEach(opt => {
  2804. \t\t\t\t\topt.classList.remove('selected', 'active');
  2805. \t\t\t\t\tif (opt.classList.contains('variant-color-option')) {
  2806. \t\t\t\t\t\topt.style.borderColor = '#ddd';
  2807. \t\t\t\t\t\tconst checkIcon = opt.querySelector('.check-icon');
  2808. \t\t\t\t\t\tif (checkIcon) checkIcon.remove();
  2809. \t\t\t\t\t}
  2810. \t\t\t\t});
  2811. \t\t\t\tthis.classList.add('selected', 'active');
  2812. \t\t\t\tif (this.classList.contains('variant-color-option')) {
  2813. \t\t\t\t\tthis.style.borderColor = '#007bff';
  2814. \t\t\t\t\tconst checkIcon = document.createElement('span');
  2815. \t\t\t\t\tcheckIcon.className = 'check-icon';
  2816. \t\t\t\t\tconst bgColor = this.style.backgroundColor || '';
  2817. \t\t\t\t\tconst isDark = bgColor && getContrastColor(bgColor) < 128;
  2818. \t\t\t\t\tcheckIcon.style.cssText = 'position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: ' + (isDark ? 'white' : 'black') + '; font-size: 18px;';
  2819. \t\t\t\t\tcheckIcon.textContent = '✓';
  2820. \t\t\t\t\tthis.appendChild(checkIcon);
  2821. \t\t\t\t}
  2822. \t\t\t\t// Mettre à jour les attributs sélectionnés
  2823. \t\t\t\tselectedAttributes[attributeSlug] = valueId;
  2824. \t\t\t\tconst selectedSpan = document.getElementById(`selected-\${attributeSlug}`);
  2825. \t\t\t\tif (selectedSpan) {
  2826. \t\t\t\t\tselectedSpan.textContent = value;
  2827. \t\t\t\t}
  2828. \t\t\t\t// Trouver la variante correspondante
  2829. \t\t\t\tconst matchingVariant = findMatchingVariant();
  2830. \t\t\t\tif (matchingVariant) {
  2831. \t\t\t\t\tupdateVariantDisplay(matchingVariant);
  2832. \t\t\t\t} else {
  2833. \t\t\t\t\t// Aucune variante correspondante trouvée - afficher le produit de base
  2834. \t\t\t\t\tresetToBaseProduct();
  2835. \t\t\t\t}
  2836. \t\t\t});
  2837. \t\t});
  2838. \t}
  2839. \tfunction findMatchingVariant() {
  2840. \t\tif (!productVariants || productVariants.length === 0) return null;
  2841. \t\t
  2842. \t\treturn productVariants.find(variant => {
  2843. \t\t\tif (!variant.isActive) return false;
  2844. \t\t\t
  2845. \t\t\tconst variantAttributes = {};
  2846. \t\t\tvariant.attributeValues.forEach(av => {
  2847. \t\t\t\tvariantAttributes[av.attributeSlug] = av.valueId;
  2848. \t\t\t});
  2849. \t\t\t// Vérifier si tous les attributs sélectionnés correspondent
  2850. \t\t\tfor (const [attrSlug, valueId] of Object.entries(selectedAttributes)) {
  2851. \t\t\t\tif (!variantAttributes[attrSlug] || variantAttributes[attrSlug] !== valueId) {
  2852. \t\t\t\t\treturn false;
  2853. \t\t\t\t}
  2854. \t\t\t}
  2855. \t\t\t// Vérifier que le nombre d'attributs correspond
  2856. \t\t\treturn Object.keys(variantAttributes).length === Object.keys(selectedAttributes).length;
  2857. \t\t});
  2858. \t}
  2859. \tfunction updateVariantDisplay(variant) {
  2860. \t\tcurrentVariant = variant;
  2861. \t\t
  2862. \t\t// Mettre à jour le prix
  2863. \t\tconst priceElement = document.getElementById('main-unit-price');
  2864. \t\tconst variantPriceElement = document.getElementById('variant-price');
  2865. \t\tif (priceElement) {
  2866. \t\t\tpriceElement.textContent = variant.price.toFixed(2).replace(/\\B(?=(\\d{3})+(?!\\d))/g, ' ');
  2867. \t\t}
  2868. \t\tif (variantPriceElement) {
  2869. \t\t\tvariantPriceElement.textContent = variant.price.toFixed(2).replace(/\\B(?=(\\d{3})+(?!\\d))/g, ' ') + ' HTG';
  2870. \t\t}
  2871. \t\t// Mettre à jour le stock
  2872. \t\tconst stockElement = document.getElementById('variant-stock');
  2873. \t\tif (stockElement) {
  2874. \t\t\tif (variant.stock > 0) {
  2875. \t\t\t\tstockElement.textContent = variant.stock + ' disponible(s)';
  2876. \t\t\t\tstockElement.className = 'variant-stock text-success';
  2877. \t\t\t} else {
  2878. \t\t\t\tstockElement.textContent = 'Rupture de stock';
  2879. \t\t\t\tstockElement.className = 'variant-stock text-danger';
  2880. \t\t\t}
  2881. \t\t}
  2882. \t\t// Mettre à jour les champs cachés
  2883. \t\tconst variantIdInput = document.getElementById('selected-variant-id');
  2884. \t\tconst variantSkuInput = document.getElementById('selected-variant-sku');
  2885. \t\tif (variantIdInput) variantIdInput.value = variant.id;
  2886. \t\tif (variantSkuInput) variantSkuInput.value = variant.sku;
  2887. \t\t// Mettre à jour les images si disponibles
  2888. \t\tif (variant.images && variant.images.length > 0) {
  2889. \t\t\tconst mainImage = document.getElementById('main-product-image');
  2890. \t\t\tif (mainImage && variant.images[0]) {
  2891. \t\t\t\tmainImage.src = variant.images[0];
  2892. \t\t\t}
  2893. \t\t}
  2894. \t\t// Afficher les informations de la variante
  2895. \t\tconst variantInfo = document.getElementById('variant-info');
  2896. \t\tif (variantInfo) variantInfo.style.display = 'block';
  2897. \t\t// Mettre à jour la quantité maximale
  2898. \t\tconst qtyInput = document.getElementById('sst');
  2899. \t\tif (qtyInput) {
  2900. \t\t\tqtyInput.max = variant.stock;
  2901. \t\t}
  2902. \t}
  2903. \tfunction getContrastColor(hexColor) {
  2904. \t\t// Convertir hex en RGB et calculer la luminosité
  2905. \t\tconst rgb = hexColor.match(/\\d+/g);
  2906. \t\tif (rgb && rgb.length >= 3) {
  2907. \t\t\tconst r = parseInt(rgb[0]);
  2908. \t\t\tconst g = parseInt(rgb[1]);
  2909. \t\tconst b = parseInt(rgb[2]);
  2910. \t\treturn (r * 299 + g * 587 + b * 114) / 1000;
  2911. \t}
  2912. \treturn 128;
  2913. }
  2914. function resetToBaseProduct() {
  2915. \tcurrentVariant = null;
  2916. \t
  2917. \t// Réinitialiser les attributs sélectionnés
  2918. \tselectedAttributes = {};
  2919. \t
  2920. \t// Masquer les informations de variante
  2921. \tconst variantInfo = document.getElementById('variant-info');
  2922. \tif (variantInfo) variantInfo.style.display = 'none';
  2923. \t
  2924. \t// Réinitialiser le prix au prix de base
  2925. \tconst priceEl = document.getElementById('main-unit-price');
  2926. \tif (priceEl) priceEl.textContent = '";
  2927.         // line 2190
  2928.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "price", [], "any"falsefalsefalse2190), 2"."" "), "html"nulltrue);
  2929.         yield "';
  2930. \t
  2931. \t// Réinitialiser les champs cachés
  2932. \tconst variantIdInput = document.getElementById('selected-variant-id');
  2933. \tconst variantSkuInput = document.getElementById('selected-variant-sku');
  2934. \tif (variantIdInput) variantIdInput.value = '';
  2935. \tif (variantSkuInput) variantSkuInput.value = '';
  2936. \t
  2937. \t// Réinitialiser les sélections visuelles
  2938. \tdocument.querySelectorAll('.variant-option').forEach(opt => {
  2939. \t\topt.classList.remove('selected', 'active');
  2940. \t\tif (opt.classList.contains('variant-color-option')) {
  2941. \t\t\topt.style.borderColor = '#ddd';
  2942. \t\t\tconst checkIcon = opt.querySelector('.check-icon');
  2943. \t\t\tif (checkIcon) checkIcon.remove();
  2944. \t\t}
  2945. \t});
  2946. \t
  2947. \t// Réinitialiser les labels de sélection
  2948. \tdocument.querySelectorAll('.selected-variant-value').forEach(span => {
  2949. \t\tspan.textContent = '';
  2950. \t});
  2951. \t
  2952. \t// Réinitialiser les images au produit de base
  2953. \tconst mainImage = document.getElementById('main-product-image');
  2954. \tif (mainImage && typeof productImages !== 'undefined' && productImages.length > 0) {
  2955. \t\tmainImage.src = productImages[0];
  2956. \t}
  2957. \t
  2958. \t// Réinitialiser la quantité maximale
  2959. \tconst qtyInput = document.getElementById('sst');
  2960. \tif (qtyInput) {
  2961. \t\tqtyInput.max = ";
  2962.         // line 2222
  2963.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "stock", [], "any"falsefalsefalse2222), "html"nulltrue);
  2964.         yield ";
  2965. \t}
  2966. }
  2967. </script>
  2968. \t";
  2969.         // line 2228
  2970.         if ((Twig\Extension\CoreExtension::length($this->env->getCharset(), ($context["youMightAlsoLike"] ?? null)) > 0)) {
  2971.             // line 2229
  2972.             yield "\t\t<section class=\"related-product-area section_gap_bottom py-5\" style=\"background: linear-gradient(to bottom, #f8f9fa 0%, #ffffff 100%);\">
  2973. \t\t\t<div class=\"container\">
  2974. \t\t\t\t<div class=\"row justify-content-center\">
  2975. \t\t\t\t\t<div class=\"col-lg-8 text-center\">
  2976. \t\t\t\t\t\t<div class=\"section-title\">
  2977. \t\t\t\t\t\t\t<h2 class=\"fw-bold mb-3\" style=\"font-size: 2.5rem; color: #2c3e50;\">Vous pourriez aussi aimer</h2>
  2978. \t\t\t\t\t\t\t<p class=\"text-muted\" style=\"font-size: 1.1rem;\">Produits sélectionnés pour vous en fonction de vos préférences</p>
  2979. \t\t\t\t\t\t</div>
  2980. \t\t\t\t\t</div>
  2981. \t\t\t\t</div>
  2982. \t\t\t\t<div class=\"row g-4\">
  2983. \t\t\t\t\t";
  2984.             // line 2240
  2985.             $context['_parent'] = $context;
  2986.             $context['_seq'] = CoreExtension::ensureTraversable(($context["youMightAlsoLike"] ?? null));
  2987.             foreach ($context['_seq'] as $context["_key"] => $context["relatedProduct"]) {
  2988.                 // line 2241
  2989.                 yield "\t\t\t\t\t\t<div class=\"col-6 col-md-4 col-lg-3 mb-3\">
  2990. \t\t\t\t\t\t\t<div class=\"modern-product-card\">
  2991. \t\t\t\t\t\t\t\t<div class=\"product-image-wrapper\">
  2992. \t\t\t\t\t\t\t\t\t<a href=\"";
  2993.                 // line 2244
  2994.                 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["relatedProduct"], "slug", [], "any"falsefalsefalse2244)]), "html"nulltrue);
  2995.                 yield "\" class=\"product-image-link\">
  2996. \t\t\t\t\t\t\t\t\t\t";
  2997.                 // line 2245
  2998.                 if ((CoreExtension::getAttribute($this->env$this->source$context["relatedProduct"], "images", [], "any"truetruefalse2245) && (Twig\Extension\CoreExtension::length($this->env->getCharset(), CoreExtension::getAttribute($this->env$this->source$context["relatedProduct"], "images", [], "any"falsefalsefalse2245)) > 0))) {
  2999.                     // line 2246
  3000.                     yield "\t\t\t\t\t\t\t\t\t\t\t<img src=\"";
  3001.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl((($_v4 CoreExtension::getAttribute($this->env$this->source$context["relatedProduct"], "images", [], "any"falsefalsefalse2246)) && is_array($_v4) || $_v4 instanceof ArrayAccess ? ($_v4[0] ?? null) : null)), "html"nulltrue);
  3002.                     yield "\" alt=\"";
  3003.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["relatedProduct"], "name", [], "any"falsefalsefalse2246), "html"nulltrue);
  3004.                     yield "\" class=\"product-image\">
  3005. \t\t\t\t\t\t\t\t\t\t";
  3006.                 } else {
  3007.                     // line 2248
  3008.                     yield "\t\t\t\t\t\t\t\t\t\t\t<img src=\"";
  3009.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl("ui/img/product/p1.jpg"), "html"nulltrue);
  3010.                     yield "\" alt=\"";
  3011.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["relatedProduct"], "name", [], "any"falsefalsefalse2248), "html"nulltrue);
  3012.                     yield "\" class=\"product-image\">
  3013. \t\t\t\t\t\t\t\t\t\t";
  3014.                 }
  3015.                 // line 2250
  3016.                 yield "\t\t\t\t\t\t\t\t\t\t<div class=\"product-overlay\">
  3017. \t\t\t\t\t\t\t\t\t\t\t<span class=\"view-product-btn\">
  3018. \t\t\t\t\t\t\t\t\t\t\t\t<i class=\"ti ti-eye\"></i> Voir
  3019. \t\t\t\t\t\t\t\t\t\t\t</span>
  3020. \t\t\t\t\t\t\t\t\t\t</div>
  3021. \t\t\t\t\t\t\t\t\t</a>
  3022. \t\t\t\t\t\t\t\t\t<div class=\"product-badge\">
  3023. \t\t\t\t\t\t\t\t\t\t";
  3024.                 // line 2257
  3025.                 if ((CoreExtension::getAttribute($this->env$this->source$context["relatedProduct"], "compareAtPrice", [], "any"falsefalsefalse2257) && (CoreExtension::getAttribute($this->env$this->source$context["relatedProduct"], "compareAtPrice", [], "any"falsefalsefalse2257) > CoreExtension::getAttribute($this->env$this->source$context["relatedProduct"], "price", [], "any"falsefalsefalse2257)))) {
  3026.                     // line 2258
  3027.                     yield "\t\t\t\t\t\t\t\t\t\t\t<span class=\"badge-discount\">
  3028. \t\t\t\t\t\t\t\t\t\t\t\t-";
  3029.                     // line 2259
  3030.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::round((((CoreExtension::getAttribute($this->env$this->source$context["relatedProduct"], "compareAtPrice", [], "any"falsefalsefalse2259) - CoreExtension::getAttribute($this->env$this->source$context["relatedProduct"], "price", [], "any"falsefalsefalse2259)) / CoreExtension::getAttribute($this->env$this->source$context["relatedProduct"], "compareAtPrice", [], "any"falsefalsefalse2259)) * 100)), "html"nulltrue);
  3031.                     yield "%
  3032. \t\t\t\t\t\t\t\t\t\t\t</span>
  3033. \t\t\t\t\t\t\t\t\t\t";
  3034.                 }
  3035.                 // line 2262
  3036.                 yield "\t\t\t\t\t\t\t\t\t</div>
  3037. \t\t\t\t\t\t\t\t</div>
  3038. \t\t\t\t\t\t\t\t<div class=\"product-info\">
  3039. \t\t\t\t\t\t\t\t\t<h6 class=\"product-title\">
  3040. \t\t\t\t\t\t\t\t\t\t<a href=\"";
  3041.                 // line 2266
  3042.                 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["relatedProduct"], "slug", [], "any"falsefalsefalse2266)]), "html"nulltrue);
  3043.                 yield "\">";
  3044.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["relatedProduct"], "name", [], "any"falsefalsefalse2266), "html"nulltrue);
  3045.                 yield "</a>
  3046. \t\t\t\t\t\t\t\t\t</h6>
  3047. \t\t\t\t\t\t\t\t\t";
  3048.                 // line 2268
  3049.                 if ((($tmp CoreExtension::getAttribute($this->env$this->source$context["relatedProduct"], "shop", [], "any"falsefalsefalse2268)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  3050.                     // line 2269
  3051.                     yield "\t\t\t\t\t\t\t\t\t\t<div class=\"product-shop\">
  3052. \t\t\t\t\t\t\t\t\t\t\t<i class=\"ti ti-store\"></i>
  3053. \t\t\t\t\t\t\t\t\t\t\t<a href=\"";
  3054.                     // line 2271
  3055.                     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->sourceCoreExtension::getAttribute($this->env$this->source$context["relatedProduct"], "shop", [], "any"falsefalsefalse2271), "slug", [], "any"falsefalsefalse2271)]), "html"nulltrue);
  3056.                     yield "\" class=\"shop-link\">";
  3057.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source$context["relatedProduct"], "shop", [], "any"falsefalsefalse2271), "name", [], "any"falsefalsefalse2271), "html"nulltrue);
  3058.                     yield "</a>
  3059. \t\t\t\t\t\t\t\t\t\t</div>
  3060. \t\t\t\t\t\t\t\t\t";
  3061.                 }
  3062.                 // line 2274
  3063.                 yield "\t\t\t\t\t\t\t\t\t<div class=\"product-price-wrapper\">
  3064. \t\t\t\t\t\t\t\t\t\t<span class=\"product-price\">";
  3065.                 // line 2275
  3066.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(CoreExtension::getAttribute($this->env$this->source$context["relatedProduct"], "price", [], "any"falsefalsefalse2275), 0"."" "), "html"nulltrue);
  3067.                 yield " HTG</span>
  3068. \t\t\t\t\t\t\t\t\t\t";
  3069.                 // line 2276
  3070.                 if ((CoreExtension::getAttribute($this->env$this->source$context["relatedProduct"], "compareAtPrice", [], "any"falsefalsefalse2276) && (CoreExtension::getAttribute($this->env$this->source$context["relatedProduct"], "compareAtPrice", [], "any"falsefalsefalse2276) > CoreExtension::getAttribute($this->env$this->source$context["relatedProduct"], "price", [], "any"falsefalsefalse2276)))) {
  3071.                     // line 2277
  3072.                     yield "\t\t\t\t\t\t\t\t\t\t\t<span class=\"product-compare-price\">";
  3073.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(CoreExtension::getAttribute($this->env$this->source$context["relatedProduct"], "compareAtPrice", [], "any"falsefalsefalse2277), 0"."" "), "html"nulltrue);
  3074.                     yield " HTG</span>
  3075. \t\t\t\t\t\t\t\t\t\t";
  3076.                 }
  3077.                 // line 2279
  3078.                 yield "\t\t\t\t\t\t\t\t\t</div>
  3079. \t\t\t\t\t\t\t\t\t<div class=\"product-actions\">
  3080. \t\t\t\t\t\t\t\t\t\t<a href=\"javascript:void(0)\" class=\"btn-add-to-cart\" data-product-id=\"";
  3081.                 // line 2281
  3082.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["relatedProduct"], "id", [], "any"falsefalsefalse2281), "html"nulltrue);
  3083.                 yield "\" data-qty=\"1\" title=\"Ajouter au panier\">
  3084. \t\t\t\t\t\t\t\t\t\t\t<i class=\"ti ti-shopping-cart\"></i>
  3085. \t\t\t\t\t\t\t\t\t\t\t<span>Ajouter</span>
  3086. \t\t\t\t\t\t\t\t\t\t</a>
  3087. \t\t\t\t\t\t\t\t\t</div>
  3088. \t\t\t\t\t\t\t\t</div>
  3089. \t\t\t\t\t\t\t</div>
  3090. \t\t\t\t\t\t</div>
  3091. \t\t\t\t\t";
  3092.             }
  3093.             $_parent $context['_parent'];
  3094.             unset($context['_seq'], $context['_key'], $context['relatedProduct'], $context['_parent']);
  3095.             $context array_intersect_key($context$_parent) + $_parent;
  3096.             // line 2290
  3097.             yield "\t\t\t\t</div>
  3098. \t\t\t</div>
  3099. \t\t</section>
  3100. \t\t<style>
  3101. \t\t\t.modern-product-card {
  3102. \t\t\t\tbackground: #ffffff;
  3103. \t\t\t\tborder-radius: 16px;
  3104. \t\t\t\toverflow: hidden;
  3105. \t\t\t\tbox-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  3106. \t\t\t\ttransition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  3107. \t\t\t\theight: 100%;
  3108. \t\t\t\tdisplay: flex;
  3109. \t\t\t\tflex-direction: column;
  3110. \t\t\t\tposition: relative;
  3111. \t\t\t}
  3112. \t\t\t.modern-product-card:hover {
  3113. \t\t\t\ttransform: translateY(-8px);
  3114. \t\t\t\tbox-shadow: 0 12px 24px rgba(0, 0, 0, 0.15);
  3115. \t\t\t}
  3116. \t\t\t.product-image-wrapper {
  3117. \t\t\t\tposition: relative;
  3118. \t\t\t\twidth: 100%;
  3119. \t\t\t\theight: 250px;
  3120. \t\t\t\toverflow: hidden;
  3121. \t\t\t\tbackground: #f8f9fa;
  3122. \t\t\t}
  3123. \t\t\t.product-image {
  3124. \t\t\t\twidth: 100%;
  3125. \t\t\t\theight: 100%;
  3126. \t\t\t\tobject-fit: cover !important;
  3127. \t\t\t\tobject-position: center !important;
  3128. \t\t\t\ttransition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1);
  3129. \t\t\t}
  3130. \t\t\t.modern-product-card:hover .product-image {
  3131. \t\t\t\ttransform: scale(1.1);
  3132. \t\t\t}
  3133. \t\t\t.product-overlay {
  3134. \t\t\t\tposition: absolute;
  3135. \t\t\t\ttop: 0;
  3136. \t\t\t\tleft: 0;
  3137. \t\t\t\tright: 0;
  3138. \t\t\t\tbottom: 0;
  3139. \t\t\t\tbackground: rgba(0, 0, 0, 0.5);
  3140. \t\t\t\tdisplay: flex;
  3141. \t\t\t\talign-items: center;
  3142. \t\t\t\tjustify-content: center;
  3143. \t\t\t\topacity: 0;
  3144. \t\t\t\ttransition: opacity 0.3s ease;
  3145. \t\t\t}
  3146. \t\t\t.modern-product-card:hover .product-overlay {
  3147. \t\t\t\topacity: 1;
  3148. \t\t\t}
  3149. \t\t\t.view-product-btn {
  3150. \t\t\t\tcolor: white;
  3151. \t\t\t\tpadding: 12px 24px;
  3152. \t\t\t\tbackground: rgba(255, 255, 255, 0.2);
  3153. \t\t\t\tbackdrop-filter: blur(10px);
  3154. \t\t\t\tborder-radius: 8px;
  3155. \t\t\t\tfont-weight: 600;
  3156. \t\t\t\tdisplay: inline-flex;
  3157. \t\t\t\talign-items: center;
  3158. \t\t\t\tgap: 8px;
  3159. \t\t\t\ttransition: all 0.3s ease;
  3160. \t\t\t}
  3161. \t\t\t.view-product-btn:hover {
  3162. \t\t\t\tbackground: rgba(255, 255, 255, 0.3);
  3163. \t\t\t\ttransform: scale(1.05);
  3164. \t\t\t}
  3165. \t\t\t.product-badge {
  3166. \t\t\t\tposition: absolute;
  3167. \t\t\t\ttop: 12px;
  3168. \t\t\t\tright: 12px;
  3169. \t\t\t\tz-index: 2;
  3170. \t\t\t}
  3171. \t\t\t.badge-discount {
  3172. \t\t\t\tbackground: linear-gradient(135deg, #ff6b6b 0%, #ee5a6f 100%);
  3173. \t\t\t\tcolor: white;
  3174. \t\t\t\tpadding: 6px 12px;
  3175. \t\t\t\tborder-radius: 20px;
  3176. \t\t\t\tfont-size: 0.75rem;
  3177. \t\t\t\tfont-weight: 700;
  3178. \t\t\t\tbox-shadow: 0 2px 8px rgba(238, 90, 111, 0.4);
  3179. \t\t\t}
  3180. \t\t\t.product-info {
  3181. \t\t\t\tpadding: 20px;
  3182. \t\t\t\tflex-grow: 1;
  3183. \t\t\t\tdisplay: flex;
  3184. \t\t\t\tflex-direction: column;
  3185. \t\t\t}
  3186. \t\t\t.product-title {
  3187. \t\t\t\tmargin: 0 0 8px 0;
  3188. \t\t\t\tfont-size: 1rem;
  3189. \t\t\t\tfont-weight: 600;
  3190. \t\t\t\tline-height: 1.4;
  3191. \t\t\t\theight: 2.8em;
  3192. \t\t\t\toverflow: hidden;
  3193. \t\t\t\tdisplay: -webkit-box;
  3194. \t\t\t\t-webkit-line-clamp: 2;
  3195. \t\t\t\t-webkit-box-orient: vertical;
  3196. \t\t\t}
  3197. \t\t\t.product-title a {
  3198. \t\t\t\tcolor: #2c3e50;
  3199. \t\t\t\ttext-decoration: none;
  3200. \t\t\t\ttransition: color 0.3s ease;
  3201. \t\t\t}
  3202. \t\t\t.product-title a:hover {
  3203. \t\t\t\tcolor: #ffa200;
  3204. \t\t\t}
  3205. \t\t\t.product-shop {
  3206. \t\t\t\tfont-size: 0.85rem;
  3207. \t\t\t\tcolor: #6c757d;
  3208. \t\t\t\tmargin-bottom: 12px;
  3209. \t\t\t\tdisplay: flex;
  3210. \t\t\t\talign-items: center;
  3211. \t\t\t\tgap: 6px;
  3212. \t\t\t}
  3213. \t\t\t.product-shop i {
  3214. \t\t\t\tfont-size: 0.9rem;
  3215. \t\t\t}
  3216. \t\t\t.shop-link {
  3217. \t\t\t\tcolor: #6c757d;
  3218. \t\t\t\ttext-decoration: none;
  3219. \t\t\t\ttransition: color 0.3s ease;
  3220. \t\t\t}
  3221. \t\t\t.shop-link:hover {
  3222. \t\t\t\tcolor: #ffa200;
  3223. \t\t\t}
  3224. \t\t\t.product-price-wrapper {
  3225. \t\t\t\tmargin-bottom: 16px;
  3226. \t\t\t\tdisplay: flex;
  3227. \t\t\t\talign-items: center;
  3228. \t\t\t\tgap: 8px;
  3229. \t\t\t\tflex-wrap: wrap;
  3230. \t\t\t}
  3231. \t\t\t.product-price {
  3232. \t\t\t\tfont-size: 1.25rem;
  3233. \t\t\t\tfont-weight: 700;
  3234. \t\t\t\tcolor: #ffa200;
  3235. \t\t\t}
  3236. \t\t\t.product-compare-price {
  3237. \t\t\t\tfont-size: 0.9rem;
  3238. \t\t\t\tcolor: #adb5bd;
  3239. \t\t\t\ttext-decoration: line-through;
  3240. \t\t\t}
  3241. \t\t\t.product-actions {
  3242. \t\t\t\tmargin-top: auto;
  3243. \t\t\t}
  3244. \t\t\t/* Styles pour les boutons de la section \"Vous pourriez aussi aimer\" uniquement */
  3245. \t\t\t.modern-product-card .btn-add-to-cart {
  3246. \t\t\t\twidth: 100%;
  3247. \t\t\t\tpadding: 12px;
  3248. \t\t\t\tbackground: linear-gradient(135deg, #ffa200 0%, #e8910a 100%);
  3249. \t\t\t\tcolor: white;
  3250. \t\t\t\tborder: none;
  3251. \t\t\t\tborder-radius: 10px;
  3252. \t\t\t\tfont-weight: 600;
  3253. \t\t\t\tdisplay: flex;
  3254. \t\t\t\talign-items: center;
  3255. \t\t\t\tjustify-content: center;
  3256. \t\t\t\tgap: 8px;
  3257. \t\t\t\ttext-decoration: none;
  3258. \t\t\t\ttransition: all 0.3s ease;
  3259. \t\t\t\tcursor: pointer;
  3260. \t\t\t}
  3261. \t\t\t.modern-product-card .btn-add-to-cart:hover {
  3262. \t\t\t\tbackground: linear-gradient(135deg, #e8910a 0%, #d6820a 100%);
  3263. \t\t\t\ttransform: translateY(-2px);
  3264. \t\t\t\tbox-shadow: 0 4px 12px rgba(255, 162, 0, 0.4);
  3265. \t\t\t\tcolor: white;
  3266. \t\t\t}
  3267. \t\t\t/* Le bouton principal garde son design original */
  3268. \t\t\t.card_area .btn-add-to-cart {
  3269. \t\t\t\twidth: auto;
  3270. \t\t\t\tdisplay: inline-flex;
  3271. \t\t\t}
  3272. \t\t\t.modern-product-card .btn-add-to-cart:active {
  3273. \t\t\t\ttransform: translateY(0);
  3274. \t\t\t}
  3275. \t\t\t.modern-product-card .btn-add-to-cart i {
  3276. \t\t\t\tfont-size: 1.1rem;
  3277. \t\t\t}
  3278. \t\t\t/* Responsive adjustments */
  3279. \t\t\t@media (max-width: 768px) {
  3280. \t\t\t\t.product-image-wrapper {
  3281. \t\t\t\t\theight: 200px;
  3282. \t\t\t\t}
  3283. \t\t\t\t.product-info {
  3284. \t\t\t\t\tpadding: 16px;
  3285. \t\t\t\t}
  3286. \t\t\t\t.product-title {
  3287. \t\t\t\t\tfont-size: 0.95rem;
  3288. \t\t\t\t}
  3289. \t\t\t\t.product-price {
  3290. \t\t\t\t\tfont-size: 1.1rem;
  3291. \t\t\t\t}
  3292. \t\t\t\t.section-title h2 {
  3293. \t\t\t\t\tfont-size: 2rem !important;
  3294. \t\t\t\t}
  3295. \t\t\t}
  3296. \t\t\t@media (max-width: 576px) {
  3297. \t\t\t\t.product-image-wrapper {
  3298. \t\t\t\t\theight: 190px;
  3299. \t\t\t\t}
  3300. \t\t\t\t.product-info {
  3301. \t\t\t\t\tpadding: 14px;
  3302. \t\t\t\t}
  3303. \t\t\t\t.btn-add-to-cart {
  3304. \t\t\t\t\tpadding: 10px;
  3305. \t\t\t\t\tfont-size: 0.9rem;
  3306. \t\t\t\t}
  3307. \t\t\t}
  3308. \t\t\t/* Ensure fixed height for cards */
  3309. \t\t\t.col-6.col-md-4.col-lg-3 {
  3310. \t\t\t\tdisplay: flex;
  3311. \t\t\t}
  3312. \t\t\t.modern-product-card {
  3313. \t\t\t\twidth: 100%;
  3314. \t\t\t}
  3315. \t\t\t/* Loading state for add to cart button */
  3316. \t\t\t.btn-add-to-cart.loading {
  3317. \t\t\t\topacity: 0.7;
  3318. \t\t\t\tpointer-events: none;
  3319. \t\t\t}
  3320. \t\t\t.btn-add-to-cart.loading i {
  3321. \t\t\t\tanimation: spin 1s linear infinite;
  3322. \t\t\t}
  3323. \t\t\t@keyframes spin {
  3324. \t\t\t\tfrom { transform: rotate(0deg); }
  3325. \t\t\t\tto { transform: rotate(360deg); }
  3326. \t\t\t}
  3327. \t\t\t/* Success state - vert pour tous les boutons */
  3328. \t\t\t.btn-add-to-cart.success {
  3329. \t\t\t\tbackground: linear-gradient(135deg, #28a745 0%, #20c997 100%) !important;
  3330. \t\t\t}
  3331. \t\t\t/* Le bouton principal garde son style original même en success */
  3332. \t\t\t.card_area .btn-add-to-cart.success {
  3333. \t\t\t\tbackground: linear-gradient(135deg, #28a745 0%, #20c997 100%) !important;
  3334. \t\t\t}
  3335. \t";
  3336.         }
  3337.         // line 2574
  3338.         yield "
  3339. \t<script src=\"/ui/js/vendor/jquery-2.2.4.min.js\"></script>
  3340. \t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js\" integrity=\"sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4\" crossorigin=\"anonymous\"></script>
  3341. \t<script src=\"/ui/js/vendor/bootstrap.min.js\"></script>
  3342. \t<script src=\"/ui/js/jquery.ajaxchimp.min.js\"></script>
  3343. \t<script src=\"/ui/js/jquery.nice-select.min.js\"></script>
  3344. \t<script src=\"/ui/js/jquery.sticky.js\"></script>
  3345. \t<script src=\"/ui/js/nouislider.min.js\"></script>
  3346. \t<script src=\"/ui/js/jquery.magnific-popup.min.js\"></script>
  3347. \t<script src=\"/ui/js/owl.carousel.min.js\"></script>
  3348. \t<!--gmaps Js-->
  3349. \t<script src=\"https://maps.googleapis.com/maps/api/js?key=AIzaSyCjCGmQ0Uq4exrzdcL6rvxywDDOvfAu6eE\"></script>
  3350. \t<script src=\"/ui/js/gmaps.min.js\"></script>
  3351. \t<script src=\"/ui/js/main.js\"></script>
  3352. \t
  3353. \t<!-- Product Image Navigation - Chargé en dernier pour éviter les conflits -->
  3354. \t<script src=\"/ui/js/product-image-navigation.js\"></script>
  3355. \t
  3356. \t<script>
  3357. // Variables globales pour la navigation des images (utilisées par le script externe)
  3358. window.productImages = [];
  3359. window.currentImageIndex = 0;
  3360. let mainImageElement, currentIndexElement, indicatorsElements;
  3361. // Test pour vérifier que les fonctions sont définies
  3362. window.testImageNavigation = function() {
  3363. console.log('Testing image navigation functions...');
  3364. if (window.productImageNav) {
  3365. console.log('productImageNav object:', window.productImageNav);
  3366. console.log('nextImage function:', typeof window.productImageNav.nextImage);
  3367. console.log('prevImage function:', typeof window.productImageNav.prevImage);
  3368. console.log('changeMainImageByIndex function:', typeof window.productImageNav.changeMainImageByIndex);
  3369. console.log('State:', window.productImageNav.getState());
  3370. } else {
  3371. console.warn('productImageNav not available');
  3372. }
  3373. };
  3374. // Fonction pour nettoyer le cache PWA et désenregistrer le Service Worker
  3375. window.clearPWACache = function() {
  3376. console.log('🧹 Nettoyage du cache PWA...');
  3377. // Désenregistrer tous les Service Workers
  3378. if ('serviceWorker' in navigator) {
  3379. navigator.serviceWorker.getRegistrations().then(function(registrations) {
  3380. for(let registration of registrations) {
  3381. console.log('Désenregistrement du Service Worker:', registration.scope);
  3382. registration.unregister().then(function(boolean) {
  3383. console.log('Service Worker désenregistré:', boolean);
  3384. });
  3385. }
  3386. });
  3387. }
  3388. // Vider tous les caches
  3389. if ('caches' in window) {
  3390. caches.keys().then(function(names) {
  3391. for (let name of names) {
  3392. console.log('Suppression du cache:', name);
  3393. caches.delete(name);
  3394. }
  3395. });
  3396. }
  3397. // Forcer le rechargement de la page après nettoyage
  3398. setTimeout(function() {
  3399. console.log('🔄 Rechargement de la page...');
  3400. window.location.reload(true);
  3401. }, 1000);
  3402. };
  3403. console.log('💡 Pour nettoyer le cache PWA, tapez: clearPWACache() dans la console');
  3404. // Fonction pour vérifier l'état du cache PWA
  3405. window.checkPWACache = function() {
  3406. console.log('🔍 Vérification de l\\'état PWA...');
  3407. if ('serviceWorker' in navigator) {
  3408. navigator.serviceWorker.getRegistrations().then(function(registrations) {
  3409. console.log('Service Workers enregistrés:', registrations.length);
  3410. registrations.forEach(function(registration, index) {
  3411. console.log(`SW \${index + 1}:`, registration.scope, registration.active ? 'ACTIF' : 'INACTIF');
  3412. });
  3413. });
  3414. } else {
  3415. console.log('Service Worker non supporté');
  3416. }
  3417. if ('caches' in window) {
  3418. caches.keys().then(function(names) {
  3419. console.log('Caches disponibles:', names.length);
  3420. names.forEach(function(name) {
  3421. console.log('- Cache:', name);
  3422. });
  3423. });
  3424. } else {
  3425. console.log('Cache API non supporté');
  3426. }
  3427. };
  3428. console.log('💡 Pour vérifier l\\'état PWA, tapez: checkPWACache() dans la console');
  3429. // Nettoyage automatique du cache PWA pour les tests (à supprimer en production)
  3430. if (window.location.search.includes('clearcache')) {
  3431. console.log('🧹 Nettoyage automatique du cache PWA demandé via URL');
  3432. clearPWACache();
  3433. }
  3434. // NOTE: La navigation des images principales est gérée par product-image-navigation.js
  3435. // Les fonctions sont exposées via window.productImageNav pour le débogage
  3436. // NOTE: La navigation des images principales est gérée par product-image-navigation.js
  3437. // Le script externe initialise automatiquement les images depuis les thumbnails
  3438. // Pas besoin de réinitialiser ici pour éviter les conflits
  3439. // Gestion du carrousel de miniatures avec taille fixe carrée
  3440. const navUpBtn = document.getElementById('thumbnail-nav-up');
  3441. const navDownBtn = document.getElementById('thumbnail-nav-down');
  3442. const thumbnailsContainer = document.getElementById('product-thumbnails');
  3443. const thumbnailsWrapper = document.getElementById('thumbnails-wrapper');
  3444. const thumbnailItems = Array.from(document.querySelectorAll('.thumbnail-item'));
  3445. let currentThumbnailOffset = 0;
  3446. const thumbnailHeight = 90;
  3447. // 80px (hauteur) + 10px (gap)
  3448. // Calculer la hauteur disponible pour les miniatures dynamiquement
  3449. const thumbnailsEl = document.getElementById('product-thumbnails');
  3450. let containerHeight = thumbnailsEl ? thumbnailsEl.clientHeight : 520; // Hauteur par défaut si non disponible
  3451. let visibleThumbnails = Math.floor(containerHeight / thumbnailHeight);
  3452. // Recalculer après le chargement pour avoir la vraie hauteur
  3453. setTimeout(() => {
  3454. if (thumbnailsEl) {
  3455. containerHeight = thumbnailsEl.clientHeight;
  3456. visibleThumbnails = Math.floor(containerHeight / thumbnailHeight);
  3457. updateThumbnailsPosition();
  3458. }
  3459. }, 100);
  3460. function getCurrentIndex() {
  3461. const current = document.querySelector('.thumbnail-item.permanently-active') || document.querySelector('.thumbnail-item.active');
  3462. if (! current)
  3463. return 0;
  3464. const idxAttr = current.getAttribute('data-index');
  3465. if (idxAttr !== null) {
  3466.     return parseInt(idxAttr, 10);
  3467. }
  3468. const index = thumbnailItems.indexOf(current);
  3469. return index >= 0 ? index : 0;
  3470. }
  3471. function selectThumbnailByIndex(newIndex) {
  3472. if (! thumbnailItems.length) 
  3473. return;
  3474. const total = thumbnailItems.length;
  3475. if (newIndex < 0) 
  3476. newIndex = 0;
  3477. if (newIndex > total - 1) 
  3478. newIndex = total - 1;
  3479. // Reset classes
  3480. thumbnailItems.forEach(t => t.classList.remove('active', 'permanently-active'));
  3481. const target = thumbnailItems[newIndex];
  3482. if (! target) 
  3483. return;
  3484. target.classList.add('active', 'permanently-active');
  3485. // Utiliser la fonction du script externe si disponible
  3486. if (window.productImageNav && typeof window.productImageNav.changeMainImageByIndex === 'function') {
  3487. window.productImageNav.changeMainImageByIndex(newIndex);
  3488. } else {
  3489. // Fallback : changer l'image directement
  3490. const imageUrl = target.getAttribute('data-image');
  3491. const mainImg = document.getElementById('main-product-image');
  3492. if (mainImg && imageUrl) {
  3493. mainImg.src = imageUrl;
  3494. }
  3495. }
  3496. // Ajuster le carrousel pour voir la miniature sélectionnée
  3497. ensureThumbnailVisible(newIndex);
  3498. }
  3499. function ensureThumbnailVisible(index) {
  3500. if (! thumbnailsWrapper || ! thumbnailItems.length) 
  3501. return;
  3502. const targetTop = index * thumbnailHeight;
  3503. const visibleTop = currentThumbnailOffset * thumbnailHeight;
  3504. const visibleBottom = visibleTop + containerHeight;
  3505. // Si la miniature est au-dessus de la zone visible
  3506. if (targetTop < visibleTop) {
  3507. currentThumbnailOffset = index;
  3508. updateThumbnailsPosition();
  3509. }
  3510. // Si la miniature est en-dessous de la zone visible else if (targetTop + thumbnailHeight > visibleBottom) {
  3511. currentThumbnailOffset = Math.max(0, index - visibleThumbnails + 1);
  3512. updateThumbnailsPosition();
  3513. }
  3514. }
  3515. function updateThumbnailsPosition() {
  3516. if (!thumbnailsWrapper) 
  3517. return;
  3518. const maxOffset = Math.max(0, thumbnailItems.length - visibleThumbnails);
  3519. currentThumbnailOffset = Math.max(0, Math.min(currentThumbnailOffset, maxOffset));
  3520. thumbnailsWrapper.style.transform = `translateY(-\${
  3521. currentThumbnailOffset * thumbnailHeight
  3522. }px)`;
  3523. updateNavButtons();
  3524. }
  3525. function updateNavButtons() {
  3526. if (!thumbnailItems.length) 
  3527. return;
  3528. const maxOffset = Math.max(0, thumbnailItems.length - visibleThumbnails);
  3529. const canScrollUp = currentThumbnailOffset > 0;
  3530. const canScrollDown = currentThumbnailOffset < maxOffset;
  3531. if (navUpBtn) {
  3532. navUpBtn.classList.toggle('disabled', ! canScrollUp);
  3533. }
  3534. if (navDownBtn) {
  3535. navDownBtn.classList.toggle('disabled', ! canScrollDown);
  3536. }
  3537. }
  3538. // Navigation avec les boutons
  3539. if(navUpBtn) {
  3540. navUpBtn.addEventListener('click', function (e) {
  3541. e.preventDefault();
  3542. if (currentThumbnailOffset > 0) {
  3543. currentThumbnailOffset --;
  3544. updateThumbnailsPosition();
  3545. }
  3546. });
  3547. }
  3548. if(navDownBtn) {
  3549. navDownBtn.addEventListener('click', function (e) {
  3550. e.preventDefault();
  3551. const maxOffset = Math.max(0, thumbnailItems.length - visibleThumbnails);
  3552. if (currentThumbnailOffset < maxOffset) {
  3553. currentThumbnailOffset ++;
  3554. updateThumbnailsPosition();
  3555. }
  3556. });
  3557. }
  3558. // Initialiser le carrousel
  3559. if(thumbnailsWrapper && thumbnailItems.length > 0) {
  3560. updateThumbnailsPosition();
  3561. // S'assurer que la première miniature est visible
  3562. ensureThumbnailVisible(0);
  3563. // Sélectionner la première image par défaut si aucune n'est sélectionnée
  3564. if (!document.querySelector('.thumbnail-item.permanently-active') && !document.querySelector('.thumbnail-item.active')) {
  3565.     selectThumbnailByIndex(0);
  3566. }
  3567. // Initialiser l'index actuel via le script externe si disponible
  3568. // Le script externe product-image-navigation.js gère déjà l'initialisation
  3569. if (window.productImageNav && typeof window.productImageNav.getState === 'function') {
  3570. const state = window.productImageNav.getState();
  3571. if (state.productImages && state.productImages.length > 0) {
  3572. window.productImageNav.changeMainImageByIndex(0);
  3573. }
  3574. }
  3575. }
  3576. // NOTE: La navigation des images principales est maintenant gérée par product-image-navigation.js
  3577. // Ce fichier externe évite les conflits avec cart-modal.js et autres scripts
  3578. }, 100); // Fin du setTimeout
  3579. }); // Fin du DOMContentLoaded
  3580. // --- Prix de gros : calcul du prix unitaire dynamique ---
  3581. (function () {
  3582. const bulk = document.getElementById('bulk-pricing');
  3583. const qtyInputEl = document.getElementById('sst');
  3584. const unitPriceSpan = document.getElementById('unit-price-value');
  3585. const mainUnitPriceSpan = document.getElementById('main-unit-price');
  3586. const totalPriceSpan = document.getElementById('total-price-value');
  3587. const savingsAmountSpan = document.getElementById('savings-amount');
  3588. const savingsPercentSpan = document.getElementById('savings-percent');
  3589. const unitPriceInput = document.getElementById('unit-price-input');
  3590. const tierRowsTbody = document.getElementById('bulk-tier-rows');
  3591. if (! bulk || ! qtyInputEl || ! unitPriceSpan || ! mainUnitPriceSpan || ! unitPriceInput) 
  3592. return;
  3593. let tiers = [];
  3594. try {
  3595. tiers = JSON.parse(bulk.getAttribute('data-tiers') || '[]');
  3596. } catch (e) {
  3597. tiers = [];
  3598. }
  3599. if (!Array.isArray(tiers) || tiers.length === 0) 
  3600. return;
  3601. tiers.sort(function (a, b) {
  3602. return(a.min || 0) - (b.min || 0);
  3603. });
  3604. const basePrice = (function () {
  3605. const one = tiers.find(t => (t.min || 0) <= 1);
  3606. return one ? parseFloat(one.price) : parseFloat(tiers[0].price);
  3607. })();
  3608. function getUnitPriceForQty(qty) {
  3609. let candidate = tiers[0] || null;
  3610. for (let i = 0; i < tiers.length; i++) {
  3611. if (qty >= (tiers[i].min || 1)) {
  3612. candidate = tiers[i];
  3613. }
  3614. }
  3615. return candidate ? parseFloat(candidate.price) : (tiers[0] ? parseFloat(tiers[0].price) : basePrice);
  3616. }
  3617. function formatPrice(val) {
  3618. return(parseFloat(val) || 0).toFixed(2);
  3619. }
  3620. function highlightActiveTier(qty) {
  3621. if (! tierRowsTbody) 
  3622. return;
  3623. const rows = tierRowsTbody.querySelectorAll('tr');
  3624. rows.forEach(r => r.classList.remove('table-warning'));
  3625. let activeRow = null;
  3626. rows.forEach(r => {
  3627. const m = parseInt(r.getAttribute('data-min'), 10) || 1;
  3628. if (qty >= m) 
  3629. activeRow = r;
  3630. });
  3631. if (activeRow) 
  3632. activeRow.classList.add('table-warning');
  3633. }
  3634. function refreshPrices() {
  3635. const qty = Math.max(1, parseInt(qtyInputEl.value, 10) || 1);
  3636. const unit = getUnitPriceForQty(qty);
  3637. const total = unit * qty;
  3638. const saveAmount = Math.max(0, (basePrice - unit) * qty);
  3639. const savePercent = Math.max(0, 100 * (basePrice - unit) / basePrice);
  3640. unitPriceSpan.textContent = formatPrice(unit) + ' HTG';
  3641. mainUnitPriceSpan.textContent = formatPrice(unit);
  3642. if (totalPriceSpan) 
  3643. totalPriceSpan.textContent = formatPrice(total);
  3644. if (savingsAmountSpan) 
  3645. savingsAmountSpan.textContent = formatPrice(saveAmount);
  3646. if (savingsPercentSpan) 
  3647. savingsPercentSpan.textContent = Math.round(savePercent);
  3648. unitPriceInput.value = formatPrice(unit);
  3649. highlightActiveTier(qty);
  3650. }
  3651. qtyInputEl.addEventListener('input', refreshPrices);
  3652. qtyInputEl.addEventListener('change', refreshPrices);
  3653. setTimeout(refreshPrices, 50);
  3654. setInterval(refreshPrices, 350);
  3655. })();
  3656. // --- /Prix de gros ---
  3657. // Améliorer les boutons de quantité avec gestion de l'état disabled
  3658. (function() {
  3659. const qtyInput = document.getElementById('sst');
  3660. const decreaseBtn = document.querySelector('.quantity-btn-decrease');
  3661. const increaseBtn = document.querySelector('.quantity-btn-increase');
  3662. if (!qtyInput || !decreaseBtn || !increaseBtn) return;
  3663. const maxStock = parseInt(qtyInput.getAttribute('max') || '99', 10);
  3664. function updateButtonStates() {
  3665. const currentValue = parseInt(qtyInput.value, 10) || 1;
  3666. // Désactiver le bouton decrease si la valeur est 1
  3667. if (currentValue <= 1) {
  3668. decreaseBtn.disabled = true;
  3669. } else {
  3670. decreaseBtn.disabled = false;
  3671. }
  3672. // Désactiver le bouton increase si la valeur est au maximum
  3673. if (currentValue >= maxStock) {
  3674. increaseBtn.disabled = true;
  3675. } else {
  3676. increaseBtn.disabled = false;
  3677. }
  3678. }
  3679. // Mettre à jour l'état des boutons au chargement
  3680. updateButtonStates();
  3681. // Mettre à jour l'état des boutons lors des changements
  3682. qtyInput.addEventListener('input', updateButtonStates);
  3683. qtyInput.addEventListener('change', updateButtonStates);
  3684. // Mettre à jour l'état après les clics sur les boutons
  3685. decreaseBtn.addEventListener('click', function() {
  3686. setTimeout(updateButtonStates, 10);
  3687. });
  3688. increaseBtn.addEventListener('click', function() {
  3689. setTimeout(updateButtonStates, 10);
  3690. });
  3691. })();
  3692. // Injection du prix unitaire dans l'ajout au panier
  3693. (function () {
  3694. const addToCartBtn = document.getElementById('add-to-cart-btn');
  3695. if (! addToCartBtn) 
  3696. return;
  3697. addToCartBtn.addEventListener('click', function () {
  3698. const unitPriceInput = document.getElementById('unit-price-input');
  3699. if (unitPriceInput) {
  3700. addToCartBtn.setAttribute('data-unit-price', unitPriceInput.value);
  3701. }
  3702. });
  3703. })();
  3704. // Fonction pour ouvrir le modal de zoom avec loader
  3705. function openImageZoom () {
  3706. const mainImage = document.getElementById('main-product-image');
  3707. const zoomModal = document.getElementById('image-zoom-modal');
  3708. const zoomImage = document.getElementById('zoom-modal-image');
  3709. const zoomLoader = document.getElementById('zoom-loader');
  3710. if (mainImage && zoomModal && zoomImage) { // Afficher le loader
  3711. if (zoomLoader) {
  3712. zoomLoader.style.display = 'flex';
  3713. }
  3714. // Masquer l'image et réinitialiser
  3715. zoomImage.classList.remove('loaded');
  3716. zoomImage.style.opacity = '0';
  3717. // Ouvrir le modal avec animation
  3718. zoomModal.classList.add('active');
  3719. document.body.style.overflow = 'hidden';
  3720. // Charger l'image
  3721. const imageUrl = mainImage.src;
  3722. const tempImage = new Image();
  3723. tempImage.onload = function () {
  3724. zoomImage.src = imageUrl;
  3725. // Masquer le loader et afficher l'image avec transition
  3726. setTimeout(function () {
  3727. if (zoomLoader) {
  3728. zoomLoader.style.display = 'none';
  3729. }
  3730. zoomImage.classList.add('loaded');
  3731. zoomImage.style.opacity = '1';
  3732. }, 200);
  3733. };
  3734. tempImage.onerror = function () {
  3735. if (zoomLoader) {
  3736. zoomLoader.style.display = 'none';
  3737. }
  3738. zoomImage.src = imageUrl;
  3739. zoomImage.classList.add('loaded');
  3740. };
  3741. tempImage.src = imageUrl;
  3742. }
  3743. }
  3744. // Fonction pour fermer le modal de zoom avec animation
  3745. function closeImageZoom () {
  3746. const zoomModal = document.getElementById('image-zoom-modal');
  3747. const zoomImage = document.getElementById('zoom-modal-image');
  3748. const zoomLoader = document.getElementById('zoom-loader');
  3749. if (zoomModal) { // Animation de fermeture
  3750. if (zoomImage) {
  3751. zoomImage.style.opacity = '0';
  3752. zoomImage.classList.remove('loaded');
  3753. }
  3754. setTimeout(function () {
  3755. zoomModal.classList.remove('active');
  3756. document.body.style.overflow = 'auto';
  3757. // Réinitialiser le loader pour la prochaine ouverture
  3758. if (zoomLoader) {
  3759. zoomLoader.style.display = 'none';
  3760. }
  3761. }, 200);
  3762. }
  3763. }
  3764. // Fermer le modal en cliquant en dehors
  3765. document.addEventListener('DOMContentLoaded', function () {
  3766. const zoomModal = document.getElementById('image-zoom-modal');
  3767. if (zoomModal) {
  3768. zoomModal.addEventListener('click', function (e) {
  3769. if (e.target === zoomModal) {
  3770. closeImageZoom();
  3771. }
  3772. });
  3773. }
  3774. });
  3775. \t</script>
  3776. \t<!-- Modal de zoom d'image -->
  3777. \t<div id=\"image-zoom-modal\" class=\"image-zoom-modal\">
  3778. \t\t<span class=\"close-zoom\" onclick=\"closeImageZoom()\" title=\"Fermer\">&times;</span>
  3779. \t\t<div
  3780. \t\t\tclass=\"zoom-modal-content\">
  3781. \t\t\t<!-- Loader -->
  3782. \t\t\t<div class=\"zoom-loader\" id=\"zoom-loader\" style=\"display: none;\">
  3783. \t\t\t\t<div class=\"zoom-loader-spinner\"></div>
  3784. \t\t\t\t<div class=\"zoom-loader-text\">Chargement...</div>
  3785. \t\t\t</div>
  3786. \t\t\t<!-- Image -->
  3787. \t\t\t<img id=\"zoom-modal-image\" src=\"\" alt=\"";
  3788.         // line 3129
  3789.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "name", [], "any"falsefalsefalse3129), "html"nulltrue);
  3790.         yield "\">
  3791. \t\t</div>
  3792. \t</div>
  3793. \t";
  3794.         // line 3133
  3795.         if ((($tmp = ($context["dropshipReferral"] ?? null)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  3796.             // line 3134
  3797.             yield "\t\t<!-- Modal d'affiliation -->
  3798. \t\t<div id=\"dropship-modal\" class=\"dropship-referral-modal\" style=\"display: none;\">
  3799. \t\t\t<div class=\"dropship-modal-overlay\"></div>
  3800. \t\t\t<div class=\"dropship-modal-content\">
  3801. \t\t\t\t<button type=\"button\" class=\"dropship-modal-close\" onclick=\"closeDropshipModal()\" aria-label=\"Fermer\">
  3802. \t\t\t\t\t&times;
  3803. \t\t\t\t</button>
  3804. \t\t\t\t<div class=\"dropship-modal-header\">
  3805. \t\t\t\t\t<div class=\"dropship-icon\">
  3806. \t\t\t\t\t\t<i class=\"fas fa-gift\"></i>
  3807. \t\t\t\t\t</div>
  3808. \t\t\t\t\t<h3>Produit recommandé par
  3809. \t\t\t\t\t\t";
  3810.             // line 3146
  3811.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["dropshipReferral"] ?? null), "affiliateName", [], "any"falsefalsefalse3146), "html"nulltrue);
  3812.             yield "</h3>
  3813. \t\t\t\t\t<p class=\"dropship-subtitle\">Vous avez été dirigé vers ce produit par un de nos partenaires</p>
  3814. \t\t\t\t</div>
  3815. \t\t\t\t<div class=\"dropship-modal-body\">
  3816. \t\t\t\t\t<div class=\"dropship-product-info\">
  3817. \t\t\t\t\t\t";
  3818.             // line 3151
  3819.             if ((Twig\Extension\CoreExtension::length($this->env->getCharset(), CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "images", [], "any"falsefalsefalse3151)) > 0)) {
  3820.                 // line 3152
  3821.                 yield "\t\t\t\t\t\t\t<img src=\"";
  3822.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl((($_v5 CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "images", [], "any"falsefalsefalse3152)) && is_array($_v5) || $_v5 instanceof ArrayAccess ? ($_v5[0] ?? null) : null)), "html"nulltrue);
  3823.                 yield "\" alt=\"";
  3824.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "name", [], "any"falsefalsefalse3152), "html"nulltrue);
  3825.                 yield "\" class=\"dropship-product-image\" onerror=\"this.style.display='none'; this.nextElementSibling.style.display='flex';\">
  3826. \t\t\t\t\t\t\t<div class=\"dropship-product-image-placeholder\" style=\"display: none; width: 100px; height: 100px; background: #f0f0f0; border-radius: 8px; align-items: center; justify-content: center; color: #999;\">
  3827. \t\t\t\t\t\t\t\t<i class=\"fas fa-image\" style=\"font-size: 32px;\"></i>
  3828. \t\t\t\t\t\t\t</div>
  3829. \t\t\t\t\t\t";
  3830.             } else {
  3831.                 // line 3157
  3832.                 yield "\t\t\t\t\t\t\t<div class=\"dropship-product-image-placeholder\" style=\"width: 100px; height: 100px; background: #f0f0f0; border-radius: 8px; display: flex; align-items: center; justify-content: center; color: #999;\">
  3833. \t\t\t\t\t\t\t\t<i class=\"fas fa-image\" style=\"font-size: 32px;\"></i>
  3834. \t\t\t\t\t\t\t</div>
  3835. \t\t\t\t\t\t";
  3836.             }
  3837.             // line 3161
  3838.             yield "\t\t\t\t\t\t<div class=\"dropship-product-details\">
  3839. \t\t\t\t\t\t\t<h4>";
  3840.             // line 3162
  3841.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "name", [], "any"falsefalsefalse3162), "html"nulltrue);
  3842.             yield "</h4>
  3843. \t\t\t\t\t\t\t<div class=\"dropship-product-price\">
  3844. \t\t\t\t\t\t\t\t<span class=\"price\">";
  3845.             // line 3164
  3846.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "price", [], "any"falsefalsefalse3164), 2","" "), "html"nulltrue);
  3847.             yield "
  3848. \t\t\t\t\t\t\t\t\tHTG</span>
  3849. \t\t\t\t\t\t\t</div>
  3850. \t\t\t\t\t\t</div>
  3851. \t\t\t\t\t</div>
  3852. \t\t\t\t\t<div class=\"dropship-message\">
  3853. \t\t\t\t\t\t<p>
  3854. \t\t\t\t\t\t\t<strong>";
  3855.             // line 3171
  3856.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["dropshipReferral"] ?? null), "affiliateName", [], "any"falsefalsefalse3171), "html"nulltrue);
  3857.             yield "</strong>
  3858. \t\t\t\t\t\t\tvous recommande ce produit. Souhaitez-vous l'ajouter à votre panier ?</p>
  3859. \t\t\t\t\t</div>
  3860. \t\t\t\t</div>
  3861. \t\t\t\t<div class=\"dropship-modal-footer\">
  3862. \t\t\t\t\t<button type=\"button\" class=\"btn btn-secondary\" onclick=\"closeDropshipModal()\">
  3863. \t\t\t\t\t\tParcourir d'abord
  3864. \t\t\t\t\t</button>
  3865. \t\t\t\t\t<button type=\"button\" class=\"btn btn-primary dropship-add-to-cart\" onclick=\"addToCartFromDropship()\">
  3866. \t\t\t\t\t\t<i class=\"fas fa-shopping-cart\"></i>
  3867. \t\t\t\t\t\tAjouter au panier
  3868. \t\t\t\t\t</button>
  3869. \t\t\t\t</div>
  3870. \t\t\t</div>
  3871. \t\t</div>
  3872. \t\t<style>
  3873. \t\t\t.dropship-referral-modal {
  3874. \t\t\t\tposition: fixed;
  3875. \t\t\t\ttop: 0;
  3876. \t\t\t\tleft: 0;
  3877. \t\t\t\twidth: 100%;
  3878. \t\t\t\theight: 100%;
  3879. \t\t\t\tz-index: 10000;
  3880. \t\t\t\tdisplay: flex;
  3881. \t\t\t\talign-items: center;
  3882. \t\t\t\tjustify-content: center;
  3883. \t\t\t}
  3884. \t\t\t.dropship-modal-overlay {
  3885. \t\t\t\tposition: absolute;
  3886. \t\t\t\ttop: 0;
  3887. \t\t\t\tleft: 0;
  3888. \t\t\t\twidth: 100%;
  3889. \t\t\t\theight: 100%;
  3890. \t\t\t\tbackground: rgba(0, 0, 0, 0.6);
  3891. \t\t\t\tbackdrop-filter: blur(4px);
  3892. \t\t\t}
  3893. \t\t\t.dropship-modal-content {
  3894. \t\t\t\tposition: relative;
  3895. \t\t\t\tbackground: white;
  3896. \t\t\t\tborder-radius: 16px;
  3897. \t\t\t\tbox-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
  3898. \t\t\t\tmax-width: 500px;
  3899. \t\t\t\twidth: 90%;
  3900. \t\t\t\tmax-height: 90vh;
  3901. \t\t\t\toverflow-y: auto;
  3902. \t\t\t\tz-index: 10001;
  3903. \t\t\t\tanimation: dropshipModalSlideIn 0.3s ease-out;
  3904. \t\t\t}
  3905. \t\t\t@keyframes dropshipModalSlideIn {
  3906. \t\t\t\tfrom {
  3907. \t\t\t\t\topacity: 0;
  3908. \t\t\t\t\ttransform: translateY(-30px) scale(0.95);
  3909. \t\t\t\t}
  3910. \t\t\t\tto {
  3911. \t\t\t\t\topacity: 1;
  3912. \t\t\t\t\ttransform: translateY(0) scale(1);
  3913. \t\t\t\t}
  3914. \t\t\t}
  3915. \t\t\t.dropship-modal-close {
  3916. \t\t\t\tposition: absolute;
  3917. \t\t\t\ttop: 15px;
  3918. \t\t\t\tright: 15px;
  3919. \t\t\t\tbackground: none;
  3920. \t\t\t\tborder: none;
  3921. \t\t\t\tfont-size: 28px;
  3922. \t\t\t\tcolor: #666;
  3923. \t\t\t\tcursor: pointer;
  3924. \t\t\t\twidth: 35px;
  3925. \t\t\t\theight: 35px;
  3926. \t\t\t\tdisplay: flex;
  3927. \t\t\t\talign-items: center;
  3928. \t\t\t\tjustify-content: center;
  3929. \t\t\t\tborder-radius: 50%;
  3930. \t\t\t\ttransition: all 0.2s;
  3931. \t\t\t\tz-index: 10;
  3932. \t\t\t}
  3933. \t\t\t.dropship-modal-close:hover {
  3934. \t\t\t\tbackground: #f0f0f0;
  3935. \t\t\t\tcolor: #333;
  3936. \t\t\t}
  3937. \t\t\t.dropship-modal-header {
  3938. \t\t\t\tpadding: 30px 30px 20px;
  3939. \t\t\t\ttext-align: center;
  3940. \t\t\t\tborder-bottom: 1px solid #f0f0f0;
  3941. \t\t\t}
  3942. \t\t\t.dropship-icon {
  3943. \t\t\t\twidth: 70px;
  3944. \t\t\t\theight: 70px;
  3945. \t\t\t\tmargin: 0 auto 15px;
  3946. \t\t\t\tbackground: linear-gradient(135deg, #ffa200 0%, #ff8c00 100%);
  3947. \t\t\t\tborder-radius: 50%;
  3948. \t\t\t\tdisplay: flex;
  3949. \t\t\t\talign-items: center;
  3950. \t\t\t\tjustify-content: center;
  3951. \t\t\t\tfont-size: 32px;
  3952. \t\t\t\tcolor: white;
  3953. \t\t\t\tbox-shadow: 0 4px 15px rgba(255, 162, 0, 0.3);
  3954. \t\t\t}
  3955. \t\t\t.dropship-modal-header h3 {
  3956. \t\t\t\tmargin: 0 0 8px;
  3957. \t\t\t\tfont-size: 22px;
  3958. \t\t\t\tfont-weight: 600;
  3959. \t\t\t\tcolor: #333;
  3960. \t\t\t}
  3961. \t\t\t.dropship-subtitle {
  3962. \t\t\t\tmargin: 0;
  3963. \t\t\t\tcolor: #666;
  3964. \t\t\t\tfont-size: 14px;
  3965. \t\t\t}
  3966. \t\t\t.dropship-modal-body {
  3967. \t\t\t\tpadding: 25px 30px;
  3968. \t\t\t}
  3969. \t\t\t.dropship-product-info {
  3970. \t\t\t\tdisplay: flex;
  3971. \t\t\t\tgap: 15px;
  3972. \t\t\t\tmargin-bottom: 20px;
  3973. \t\t\t\tpadding: 15px;
  3974. \t\t\t\tbackground: #f8f9fa;
  3975. \t\t\t\tborder-radius: 10px;
  3976. \t\t\t}
  3977. \t\t\t.dropship-product-image {
  3978. \t\t\t\twidth: 80px;
  3979. \t\t\t\theight: 80px;
  3980. \t\t\t\tobject-fit: cover;
  3981. \t\t\t\tborder-radius: 8px;
  3982. \t\t\t\tflex-shrink: 0;
  3983. \t\t\t}
  3984. \t\t\t.dropship-product-details {
  3985. \t\t\t\tflex: 1;
  3986. \t\t\t}
  3987. \t\t\t.dropship-product-details h4 {
  3988. \t\t\t\tmargin: 0 0 8px;
  3989. \t\t\t\tfont-size: 16px;
  3990. \t\t\t\tfont-weight: 600;
  3991. \t\t\t\tcolor: #333;
  3992. \t\t\t}
  3993. \t\t\t.dropship-product-price {
  3994. \t\t\t\tmargin-top: 5px;
  3995. \t\t\t}
  3996. \t\t\t.dropship-product-price .price {
  3997. \t\t\t\tfont-size: 20px;
  3998. \t\t\t\tfont-weight: 700;
  3999. \t\t\t\tcolor: #ffa200;
  4000. \t\t\t}
  4001. \t\t\t.dropship-message {
  4002. \t\t\t\tpadding: 15px;
  4003. \t\t\t\tbackground: #fff9e6;
  4004. \t\t\t\tborder-left: 4px solid #ffa200;
  4005. \t\t\t\tborder-radius: 6px;
  4006. \t\t\t}
  4007. \t\t\t.dropship-message p {
  4008. \t\t\t\tmargin: 0;
  4009. \t\t\t\tcolor: #666;
  4010. \t\t\t\tline-height: 1.6;
  4011. \t\t\t}
  4012. \t\t\t.dropship-modal-footer {
  4013. \t\t\t\tpadding: 20px 30px 30px;
  4014. \t\t\t\tdisplay: flex;
  4015. \t\t\t\tgap: 12px;
  4016. \t\t\t\tjustify-content: flex-end;
  4017. \t\t\t\tborder-top: 1px solid #f0f0f0;
  4018. \t\t\t}
  4019. \t\t\t.dropship-modal-footer .btn {
  4020. \t\t\t\tpadding: 12px 24px;
  4021. \t\t\t\tborder-radius: 8px;
  4022. \t\t\t\tfont-weight: 500;
  4023. \t\t\t\tborder: none;
  4024. \t\t\t\tcursor: pointer;
  4025. \t\t\t\ttransition: all 0.2s;
  4026. \t\t\t\tfont-size: 15px;
  4027. \t\t\t}
  4028. \t\t\t.dropship-modal-footer .btn-secondary {
  4029. \t\t\t\tbackground: #f0f0f0;
  4030. \t\t\t\tcolor: #666;
  4031. \t\t\t}
  4032. \t\t\t.dropship-modal-footer .btn-secondary:hover {
  4033. \t\t\t\tbackground: #e0e0e0;
  4034. \t\t\t}
  4035. \t\t\t.dropship-modal-footer .btn-primary {
  4036. \t\t\t\tbackground: #ffa200;
  4037. \t\t\t\tcolor: white;
  4038. \t\t\t}
  4039. \t\t\t.dropship-modal-footer .btn-primary:hover {
  4040. \t\t\t\tbackground: #e8910a;
  4041. \t\t\t\ttransform: translateY(-2px);
  4042. \t\t\t\tbox-shadow: 0 4px 12px rgba(255, 162, 0, 0.3);
  4043. \t\t\t}
  4044. \t\t\t.dropship-modal-footer .btn-primary:disabled {
  4045. \t\t\t\topacity: 0.6;
  4046. \t\t\t\tcursor: not-allowed;
  4047. \t\t\t\ttransform: none;
  4048. \t\t\t}
  4049. \t\t</style>
  4050. \t\t<script>
  4051. \t\t\t// Afficher le modal automatiquement au chargement de la page
  4052. document.addEventListener('DOMContentLoaded', function () {
  4053. const dropshipModal = document.getElementById('dropship-modal');
  4054. if (dropshipModal) {
  4055. setTimeout(function () {
  4056. dropshipModal.style.display = 'flex';
  4057. document.body.style.overflow = 'hidden';
  4058. }, 500); // Délai de 500ms pour une meilleure UX
  4059. }
  4060. });
  4061. function closeDropshipModal () {
  4062. const dropshipModal = document.getElementById('dropship-modal');
  4063. if (dropshipModal) {
  4064. dropshipModal.style.display = 'none';
  4065. document.body.style.overflow = 'auto';
  4066. }
  4067. }
  4068. function addToCartFromDropship () {
  4069. const addBtn = document.querySelector('.dropship-add-to-cart');
  4070. if (! addBtn) 
  4071. return;
  4072. // Désactiver le bouton pendant le traitement
  4073. addBtn.disabled = true;
  4074. addBtn.innerHTML = '<i class=\"fas fa-spinner fa-spin\"></i> Ajout en cours...';
  4075. const productId = ";
  4076.             // line 3422
  4077.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["product"] ?? null), "id", [], "any"falsefalsefalse3422), "html"nulltrue);
  4078.             yield ";
  4079. const qty = parseInt(document.getElementById('sst') ?. value || '1');
  4080. // Utiliser fetch pour ajouter au panier
  4081. fetch('";
  4082.             // line 3426
  4083.             yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("ui_cart_add");
  4084.             yield "', {
  4085. method: 'POST',
  4086. headers: {
  4087. 'Content-Type': 'application/x-www-form-urlencoded',
  4088. 'X-Requested-With': 'XMLHttpRequest'
  4089. },
  4090. body: new URLSearchParams(
  4091. {productId: productId, qty: qty}
  4092. )
  4093. }).then(response => response.json()).then(data => {
  4094. if (data.ok) { // Afficher un message de succès
  4095. const modalBody = document.querySelector('.dropship-modal-body');
  4096. if (modalBody) {
  4097. modalBody.innerHTML = `
  4098. \t\t\t\t\t\t\t\t<div style=\"text-align: center; padding: 30px 20px;\">
  4099. \t\t\t\t\t\t\t\t\t<div style=\"width: 80px; height: 80px; margin: 0 auto 20px; background: #d4edda; border-radius: 50%; display: flex; align-items: center; justify-content: center;\">
  4100. \t\t\t\t\t\t\t\t\t\t<i class=\"fas fa-check\" style=\"font-size: 40px; color: #28a745;\"></i>
  4101. \t\t\t\t\t\t\t\t\t</div>
  4102. \t\t\t\t\t\t\t\t\t<h3 style=\"color: #28a745; margin-bottom: 10px;\">Produit ajouté avec succès !</h3>
  4103. \t\t\t\t\t\t\t\t\t<p style=\"color: #666; margin-bottom: 20px;\">Merci d'avoir utilisé le lien de recommandation de <strong>";
  4104.             // line 3445
  4105.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, ($context["dropshipReferral"] ?? null), "affiliateName", [], "any"falsefalsefalse3445), "html"nulltrue);
  4106.             yield "</strong></p>
  4107. \t\t\t\t\t\t\t\t\t<p style=\"color: #666; font-size: 14px;\">Vous pouvez continuer vos achats ou aller directement au panier.</p>
  4108. \t\t\t\t\t\t\t\t</div>
  4109. \t\t\t\t\t\t\t`;
  4110. }
  4111. const modalFooter = document.querySelector('.dropship-modal-footer');
  4112. if (modalFooter) {
  4113. modalFooter.innerHTML = `
  4114. \t\t\t\t\t\t\t\t<button type=\"button\" class=\"btn btn-secondary\" onclick=\"closeDropshipModal()\">
  4115. \t\t\t\t\t\t\t\t\tContinuer les achats
  4116. \t\t\t\t\t\t\t\t</button>
  4117. \t\t\t\t\t\t\t\t<a href=\"";
  4118.             // line 3457
  4119.             yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("cart");
  4120.             yield "\" class=\"btn btn-primary\" style=\"text-decoration: none; display: inline-block;\">
  4121. \t\t\t\t\t\t\t\t\t<i class=\"fas fa-shopping-cart\"></i> Voir le panier
  4122. \t\t\t\t\t\t\t\t</a>
  4123. \t\t\t\t\t\t\t`;
  4124. }
  4125. // Mettre à jour le compteur du panier si présent
  4126. const cartCount = document.querySelector('.cart-count, .cart_count, [data-cart-count]');
  4127. if (cartCount) {
  4128. cartCount.textContent = data.totalQty || 0;
  4129. }
  4130. } else {
  4131. showCustomAlert('Erreur lors de l\\'ajout au panier. Veuillez réessayer.', 'error');
  4132. addBtn.disabled = false;
  4133. addBtn.innerHTML = '<i class=\"fas fa-shopping-cart\"></i> Ajouter au panier';
  4134. }
  4135. }).catch(error => {
  4136. console.error('Erreur:', error);
  4137. showCustomAlert('Une erreur est survenue. Veuillez réessayer.', 'error');
  4138. addBtn.disabled = false;
  4139. addBtn.innerHTML = '<i class=\"fas fa-shopping-cart\"></i> Ajouter au panier';
  4140. });
  4141. }
  4142. // Fermer le modal en cliquant sur l'overlay
  4143. document.addEventListener('DOMContentLoaded', function () {
  4144. const dropshipModal = document.getElementById('dropship-modal');
  4145. if (dropshipModal) {
  4146. const overlay = dropshipModal.querySelector('.dropship-modal-overlay');
  4147. if (overlay) {
  4148. overlay.addEventListener('click', function () {
  4149. closeDropshipModal();
  4150. });
  4151. }
  4152. }
  4153. });
  4154. \t\t</script>
  4155. \t";
  4156.         }
  4157.         // line 3495
  4158.         yield "
  4159. \t<!-- Modal personnalisé pour remplacer les alert -->
  4160. \t<div class=\"modal fade custom-alert-modal\" id=\"customAlertModal\" tabindex=\"-1\" aria-labelledby=\"customAlertModalLabel\" aria-hidden=\"true\">
  4161. \t\t<div class=\"modal-dialog modal-dialog-centered\">
  4162. \t\t\t<div class=\"modal-content\">
  4163. \t\t\t\t<div class=\"modal-header\">
  4164. \t\t\t\t\t<h5 class=\"modal-title text-white\" id=\"customAlertModalLabel\">Notification</h5>
  4165. \t\t\t\t\t<button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\" aria-label=\"Close\"></button>
  4166. \t\t\t\t</div>
  4167. \t\t\t\t<div class=\"modal-body\">
  4168. \t\t\t\t\t<div class=\"alert-icon\" id=\"alertIcon\">
  4169. \t\t\t\t\t\t<i class=\"lnr lnr-info-circle\"></i>
  4170. \t\t\t\t\t</div>
  4171. \t\t\t\t\t<p class=\"alert-message\" id=\"alertMessage\"></p>
  4172. \t\t\t\t</div>
  4173. \t\t\t\t<div class=\"modal-footer\">
  4174. \t\t\t\t\t<button type=\"button\" class=\"btn btn-primary\" data-bs-dismiss=\"modal\">OK</button>
  4175. \t\t\t\t</div>
  4176. \t\t\t</div>
  4177. \t\t</div>
  4178. \t</div>
  4179. \t<script>
  4180. \t\t// Fonction pour remplacer alert()
  4181. function showCustomAlert (message, type = 'info') {
  4182. const modal = new bootstrap.Modal(document.getElementById('customAlertModal'));
  4183. const alertMessage = document.getElementById('alertMessage');
  4184. const alertIcon = document.getElementById('alertIcon');
  4185. const modalTitle = document.getElementById('customAlertModalLabel');
  4186. alertMessage.textContent = message;
  4187. // Définir l'icône et le titre selon le type
  4188. let iconClass = 'lnr lnr-info-circle';
  4189. let title = 'Information';
  4190. switch (type) {
  4191. case 'success': iconClass = 'lnr lnr-checkmark-circle';
  4192. title = 'Succès';
  4193. alertIcon.className = 'alert-icon success';
  4194. break;
  4195. case 'error':
  4196. case 'danger': iconClass = 'lnr lnr-warning';
  4197. title = 'Erreur';
  4198. alertIcon.className = 'alert-icon error';
  4199. break;
  4200. case 'warning': iconClass = 'lnr lnr-warning';
  4201. title = 'Attention';
  4202. alertIcon.className = 'alert-icon warning';
  4203. break;
  4204. default: iconClass = 'lnr lnr-info-circle';
  4205. title = 'Information';
  4206. alertIcon.className = 'alert-icon info';
  4207. }
  4208. alertIcon.innerHTML = `<i class=\"\${iconClass}\"></i>`;
  4209. modalTitle.textContent = title;
  4210. modal.show();
  4211. }
  4212. // Remplacer window.alert par showCustomAlert
  4213. window.alert = showCustomAlert;
  4214. \t</script>
  4215. ";
  4216.         
  4217.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  4218.         
  4219.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  4220.         yield from [];
  4221.     }
  4222.     /**
  4223.      * @codeCoverageIgnore
  4224.      */
  4225.     public function getTemplateName(): string
  4226.     {
  4227.         return "home/single-product.html.twig";
  4228.     }
  4229.     /**
  4230.      * @codeCoverageIgnore
  4231.      */
  4232.     public function isTraitable(): bool
  4233.     {
  4234.         return false;
  4235.     }
  4236.     /**
  4237.      * @codeCoverageIgnore
  4238.      */
  4239.     public function getDebugInfo(): array
  4240.     {
  4241.         return array (  4523 => 3495,  4482 => 3457,  4467 => 3445,  4445 => 3426,  4438 => 3422,  4184 => 3171,  4174 => 3164,  4169 => 3162,  4166 => 3161,  4160 => 3157,  4149 => 3152,  4147 => 3151,  4139 => 3146,  4125 => 3134,  4123 => 3133,  4116 => 3129,  3559 => 2574,  3273 => 2290,  3258 => 2281,  3254 => 2279,  3248 => 2277,  3246 => 2276,  3242 => 2275,  3239 => 2274,  3231 => 2271,  3227 => 2269,  3225 => 2268,  3218 => 2266,  3212 => 2262,  3206 => 2259,  3203 => 2258,  3201 => 2257,  3192 => 2250,  3184 => 2248,  3176 => 2246,  3174 => 2245,  3170 => 2244,  3165 => 2241,  3161 => 2240,  3148 => 2229,  3146 => 2228,  3137 => 2222,  3102 => 2190,  2951 => 2042,  2851 => 1944,  2849 => 1942,  2848 => 1941,  2847 => 1940,  2846 => 1939,  2845 => 1938,  2844 => 1937,  2843 => 1936,  2842 => 1935,  2841 => 1934,  2840 => 1933,  2839 => 1932,  2838 => 1931,  2837 => 1930,  2836 => 1929,  2822 => 1917,  2815 => 1913,  2812 => 1912,  2797 => 1899,  2787 => 1895,  2780 => 1894,  2776 => 1893,  2768 => 1887,  2766 => 1886,  2759 => 1881,  2752 => 1876,  2745 => 1872,  2740 => 1870,  2734 => 1866,  2732 => 1865,  2725 => 1860,  2721 => 1858,  2713 => 1854,  2701 => 1852,  2697 => 1851,  2694 => 1850,  2692 => 1849,  2686 => 1846,  2676 => 1839,  2672 => 1838,  2660 => 1828,  2653 => 1824,  2650 => 1823,  2634 => 1809,  2632 => 1808,  2622 => 1800,  2618 => 1798,  2612 => 1794,  2609 => 1793,  2599 => 1789,  2593 => 1786,  2589 => 1784,  2584 => 1783,  2581 => 1782,  2568 => 1771,  2565 => 1770,  2559 => 1766,  2553 => 1764,  2549 => 1762,  2547 => 1761,  2544 => 1760,  2542 => 1759,  2539 => 1758,  2537 => 1757,  2529 => 1751,  2526 => 1750,  2523 => 1749,  2517 => 1748,  2510 => 1744,  2504 => 1741,  2500 => 1739,  2497 => 1738,  2492 => 1737,  2489 => 1736,  2481 => 1731,  2474 => 1726,  2471 => 1725,  2465 => 1721,  2460 => 1719,  2457 => 1718,  2454 => 1717,  2449 => 1715,  2446 => 1714,  2443 => 1713,  2437 => 1711,  2435 => 1710,  2427 => 1704,  2424 => 1703,  2416 => 1698,  2409 => 1693,  2406 => 1692,  2399 => 1688,  2392 => 1683,  2389 => 1682,  2382 => 1678,  2375 => 1673,  2372 => 1672,  2365 => 1668,  2358 => 1663,  2355 => 1662,  2348 => 1658,  2341 => 1653,  2339 => 1652,  2334 => 1649,  2332 => 1648,  2326 => 1644,  2322 => 1642,  2316 => 1639,  2313 => 1638,  2311 => 1637,  2302 => 1631,  2259 => 1599,  2245 => 1596,  2238 => 1592,  2234 => 1590,  2224 => 1583,  2215 => 1577,  2206 => 1571,  2200 => 1567,  2198 => 1566,  2194 => 1564,  2188 => 1561,  2185 => 1560,  2183 => 1559,  2179 => 1557,  2160 => 1541,  2152 => 1535,  2136 => 1532,  2132 => 1530,  2126 => 1528,  2124 => 1527,  2119 => 1525,  2115 => 1524,  2106 => 1523,  2103 => 1522,  2086 => 1521,  2071 => 1509,  2064 => 1505,  2061 => 1504,  2055 => 1503,  2052 => 1502,  2047 => 1501,  2044 => 1500,  2041 => 1499,  2036 => 1496,  2026 => 1489,  2022 => 1488,  2011 => 1479,  2007 => 1477,  2001 => 1474,  1996 => 1473,  1994 => 1472,  1986 => 1466,  1968 => 1450,  1960 => 1447,  1946 => 1446,  1943 => 1445,  1937 => 1442,  1933 => 1441,  1929 => 1440,  1925 => 1439,  1919 => 1438,  1916 => 1437,  1912 => 1435,  1902 => 1433,  1900 => 1432,  1886 => 1431,  1882 => 1430,  1878 => 1429,  1874 => 1428,  1870 => 1427,  1864 => 1426,  1861 => 1425,  1858 => 1424,  1855 => 1423,  1838 => 1422,  1832 => 1419,  1828 => 1418,  1822 => 1416,  1818 => 1415,  1815 => 1414,  1809 => 1413,  1806 => 1412,  1800 => 1411,  1797 => 1410,  1794 => 1409,  1791 => 1408,  1788 => 1407,  1785 => 1406,  1782 => 1405,  1779 => 1404,  1774 => 1403,  1771 => 1402,  1766 => 1401,  1764 => 1400,  1759 => 1399,  1757 => 1398,  1751 => 1395,  1745 => 1392,  1736 => 1386,  1725 => 1378,  1720 => 1376,  1712 => 1370,  1699 => 1368,  1694 => 1367,  1691 => 1366,  1685 => 1365,  1682 => 1364,  1676 => 1363,  1673 => 1362,  1668 => 1361,  1665 => 1360,  1660 => 1359,  1657 => 1358,  1655 => 1357,  1646 => 1352,  1643 => 1351,  1637 => 1350,  1634 => 1349,  1628 => 1348,  1625 => 1347,  1620 => 1346,  1617 => 1345,  1612 => 1344,  1609 => 1343,  1607 => 1342,  1576 => 1322,  1568 => 1316,  1560 => 1314,  1552 => 1312,  1549 => 1311,  1546 => 1310,  1540 => 1309,  1537 => 1308,  1531 => 1307,  1528 => 1306,  1523 => 1305,  1520 => 1304,  1515 => 1303,  1512 => 1302,  1510 => 1301,  1498 => 1291,  1490 => 1288,  1485 => 1287,  1482 => 1286,  1461 => 1283,  1450 => 1282,  1432 => 1281,  1429 => 1280,  1426 => 1279,  1420 => 1278,  1417 => 1277,  1411 => 1276,  1408 => 1275,  1403 => 1274,  1400 => 1273,  1395 => 1272,  1392 => 1271,  1390 => 1270,  1355 => 1237,  1342 => 1236,  106 => 9,  93 => 8,  78 => 4,  65 => 3,  42 => 1,);
  4242.     }
  4243.     public function getSourceContext(): Source
  4244.     {
  4245.         return new Source("{% extends 'base_home.html.twig' %}
  4246. {% block title %}
  4247. \t{{ product.name }}
  4248. \t| MaketOu
  4249. {% endblock %}
  4250. {% block stylesheets %}
  4251. \t<style>
  4252. \t\t/* Styles pour l'affichage de la boutique */
  4253. \t\t.shop-info {
  4254. \t\t\tpadding: 10px 0;
  4255. \t\t\tborder-bottom: 1px solid #f0f0f0;
  4256. \t\t\tmargin-bottom: 15px;
  4257. \t\t}
  4258. \t\t.shop-link {
  4259. \t\t\tcolor: #ffa200;
  4260. \t\t\ttext-decoration: none;
  4261. \t\t\tfont-weight: 500;
  4262. \t\t}
  4263. \t\t.shop-link:hover {
  4264. \t\t\tcolor: #e8910a;
  4265. \t\t\ttext-decoration: underline;
  4266. \t\t}
  4267. \t\t/* Styles pour les statistiques du produit */
  4268. \t\t.product-stats {
  4269. \t\t\tbackground: #f8f9fa;
  4270. \t\t\tpadding: 15px;
  4271. \t\t\tborder-radius: 8px;
  4272. \t\t\tborder: 1px solid #e9ecef;
  4273. \t\t}
  4274. \t\t.product-stats .stat-item {
  4275. \t\t\ttext-align: center;
  4276. \t\t}
  4277. \t\t.product-stats .stat-number {
  4278. \t\t\tdisplay: block;
  4279. \t\t\tfont-size: 1.2rem;
  4280. \t\t\tfont-weight: bold;
  4281. \t\t\tcolor: #ffa200;
  4282. \t\t}
  4283. \t\t.product-stats .stat-label {
  4284. \t\t\tcolor: #666;
  4285. \t\t\tfont-size: 0.8rem;
  4286. \t\t\ttext-transform: uppercase;
  4287. \t\t\tletter-spacing: 0.5px;
  4288. \t\t}
  4289. \t\t/* Message de confirmation */
  4290. \t\t#cart-message {
  4291. \t\t\tborder: none;
  4292. \t\t\tbackground: #d4edda;
  4293. \t\t\tcolor: #155724;
  4294. \t\t\tborder-radius: 6px;
  4295. \t\t\tpadding: 12px 16px;
  4296. \t\t\tmargin-top: 15px;
  4297. \t\t}
  4298. \t\t/* Amélioration des boutons */
  4299. \t\t.card_area .primary-btn {
  4300. \t\t\tbackground: #ffa200;
  4301. \t\t\tborder: none;
  4302. \t\t\tpadding: 12px 24px;
  4303. \t\t\tborder-radius: 6px;
  4304. \t\t\tcolor: white;
  4305. \t\t\tfont-weight: 500;
  4306. \t\t\ttransition: all 0.3s ease;
  4307. \t\t}
  4308. \t\t.card_area .primary-btn:hover {
  4309. \t\t\tbackground: #e8910a;
  4310. \t\t\ttransform: translateY(-2px);
  4311. \t\t\tbox-shadow: 0 4px 12px rgba(255, 162, 0, 0.3);
  4312. \t\t}
  4313. \t\t.icon_btn:hover {
  4314. \t\t\tbackground: #ffa200;
  4315. \t\t\tcolor: white;
  4316. \t\t\tborder-color: #ffa200;
  4317. \t\t}
  4318. \t\t/* Styles pour la galerie moderne de produits */
  4319. \t\t.product-gallery-modern {
  4320. \t\t\tdisplay: flex;
  4321. \t\t\tgap: 15px;
  4322. \t\t\tposition: relative;
  4323. \t\t}
  4324. \t\t.thumbnails-container {
  4325. \t\t\tposition: relative;
  4326. \t\t\tdisplay: flex;
  4327. \t\t\tflex-direction: column;
  4328. \t\t\talign-items: center;
  4329. \t\t\twidth: 80px;
  4330. \t\t\tflex-shrink: 0;
  4331. \t\t}
  4332. \t\t/* Cacher les boutons jusqu'au survol */
  4333. \t\t.thumbnails-container .thumbnail-nav-btn {
  4334. \t\t\topacity: 0;
  4335. \t\t\tvisibility: hidden;
  4336. \t\t\ttransition: opacity 0.2s ease, visibility 0.2s ease;
  4337. \t\t}
  4338. \t\t.thumbnails-container:hover .thumbnail-nav-btn {
  4339. \t\t\topacity: 1;
  4340. \t\t\tvisibility: visible;
  4341. \t\t}
  4342. \t\t.product-thumbnails {
  4343. \t\t\tdisplay: flex;
  4344. \t\t\tflex-direction: column;
  4345. \t\t\tgap: 10px;
  4346. \t\t\twidth: 100%;
  4347. \t\t\theight: 400px;
  4348. \t\t\toverflow: hidden;
  4349. \t\t\tposition: relative;
  4350. \t\t}
  4351. \t\t.thumbnails-wrapper {
  4352. \t\t\tdisplay: flex;
  4353. \t\t\tflex-direction: column;
  4354. \t\t\tgap: 10px;
  4355. \t\t\ttransition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
  4356. \t\t\twill-change: transform;
  4357. \t\t}
  4358. \t\t.thumbnail-nav-btn {
  4359. \t\t\twidth: 30px;
  4360. \t\t\theight: 30px;
  4361. \t\t\tborder-radius: 50%;
  4362. \t\t\tbackground: white;
  4363. \t\t\tborder: 2px solid #e0e0e0;
  4364. \t\t\tdisplay: flex !important;
  4365. \t\t\talign-items: center;
  4366. \t\t\tjustify-content: center;
  4367. \t\t\tcursor: pointer;
  4368. \t\t\ttransition: all 0.3s ease;
  4369. \t\t\tmargin: 0;
  4370. \t\t\tcolor: #666;
  4371. \t\t\tz-index: 10;
  4372. \t\t\tbox-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  4373. \t\t\tposition: relative;
  4374. \t\t\tflex-shrink: 0;
  4375. \t\t}
  4376. \t\t.thumbnail-nav-btn:hover {
  4377. \t\t\tbackground: #ffa200;
  4378. \t\t\tborder-color: #ffa200;
  4379. \t\t\tcolor: white;
  4380. \t\t\ttransform: scale(1.1);
  4381. \t\t\tbox-shadow: 0 4px 12px rgba(255, 162, 0, 0.3);
  4382. \t\t}
  4383. \t\t.thumbnail-nav-btn:active {
  4384. \t\t\ttransform: scale(0.95);
  4385. \t\t}
  4386. \t\t.thumbnail-nav-btn.disabled {
  4387. \t\t\topacity: 0.3;
  4388. \t\t\tcursor: not-allowed;
  4389. \t\t\tpointer-events: none;
  4390. \t\t\tfilter: grayscale(1);
  4391. \t\t}
  4392. \t\t.thumbnail-nav-btn i {
  4393. \t\t\tfont-size: 20px;
  4394. \t\t\tfont-weight: bold;
  4395. \t\t}
  4396. \t\t.thumbnail-item {
  4397. \t\t\twidth: 80px;
  4398. \t\t\theight: 80px;
  4399. \t\t\tmin-width: 80px;
  4400. \t\t\tmin-height: 80px;
  4401. \t\t\tmax-width: 80px;
  4402. \t\t\tmax-height: 80px;
  4403. \t\t\tborder: 2px solid #e0e0e0;
  4404. \t\t\tborder-radius: 8px;
  4405. \t\t\toverflow: hidden;
  4406. \t\t\tcursor: pointer;
  4407. \t\t\ttransition: border-color 0.3s ease, border-width 0.3s ease, box-shadow 0.3s ease;
  4408. \t\t\tposition: relative;
  4409. \t\t\tbackground: #f8f9fa;
  4410. \t\t\tborder-bottom: 2px solid #e0e0e0;
  4411. \t\t\tflex-shrink: 0;
  4412. \t\t\tdisplay: flex;
  4413. \t\t\talign-items: center;
  4414. \t\t\tjustify-content: center;
  4415. \t\t}
  4416. \t\t.thumbnail-item:hover {
  4417. \t\t\tborder-color: #ffa200;
  4418. \t\t\tborder-bottom-color: #ffa200;
  4419. \t\t\tborder-width: 3px;
  4420. \t\t\tbox-shadow: 0 0 0 2px rgba(255, 162, 0, 0.2);
  4421. \t\t}
  4422. \t\t.thumbnail-item.active {
  4423. \t\t\tborder-color: #ffa200 !important;
  4424. \t\t\tborder-bottom-color: #ffa200 !important;
  4425. \t\t\tborder-width: 3px !important;
  4426. \t\t\tbox-shadow: 0 0 0 2px rgba(255, 162, 0, 0.2) !important;
  4427. \t\t}
  4428. \t\t.thumbnail-item::after,
  4429. \t\t.thumbnail-item::before {
  4430. \t\t\tdisplay: none !important;
  4431. \t\t\tcontent: none !important;
  4432. \t\t}
  4433. \t\t.thumbnail-item img {
  4434. \t\t\twidth: 100%;
  4435. \t\t\theight: 100%;
  4436. \t\t\tobject-fit: cover !important;
  4437. \t\t\tobject-position: center !important;
  4438. \t\t\ttransition: transform 0.3s ease;
  4439. \t\t}
  4440. \t\t.thumbnail-item:hover img {
  4441. \t\t\ttransform: scale(1.05);
  4442. \t\t}
  4443. \t\t.thumbnail-item.active img {
  4444. \t\t\ttransform: scale(1.05);
  4445. \t\t}
  4446. \t\t.product-main-image-wrapper {
  4447. \t\t\tflex: 1;
  4448. \t\t\tposition: relative;
  4449. \t\t\tbackground: #fff;
  4450. \t\t\theight: 400px;
  4451. \t\t\tborder-radius: 12px;
  4452. \t\t\toverflow: visible;
  4453. \t\t\tborder: 1px solid #e0e0e0;
  4454. \t\t\tz-index: 1;
  4455. \t\t}
  4456. \t\t.product-main-image {
  4457. \t\t\tposition: relative;
  4458. \t\t\twidth: 100%;
  4459. \t\t\tpadding-top: 100%;
  4460. \t\t\toverflow: visible;
  4461. \t\t\tbackground: #f8f9fa;
  4462. \t\t\tdisplay: flex;
  4463. \t\t\talign-items: center;
  4464. \t\t\tjustify-content: center;
  4465. \t\t\tz-index: 1;
  4466. \t\t}
  4467. \t\t.product-main-image img {
  4468. \t\t\tposition: absolute;
  4469. \t\t\ttop: 0;
  4470. \t\t\tleft: 0;
  4471. \t\t\twidth: 100%;
  4472. \t\t\theight: 100%;
  4473. \t\t\tobject-fit: contain !important;
  4474. \t\t\tobject-position: center !important;
  4475. \t\t\ttransition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease;
  4476. \t\t\topacity: 1;
  4477. \t\t}
  4478. \t\t.product-main-image img.loading {
  4479. \t\t\topacity: 0.5;
  4480. \t\t}
  4481. \t\t.product-main-image:hover img {
  4482. \t\t\ttransform: scale(1.08);
  4483. \t\t}
  4484. \t\t.product-main-image img.fade-in {
  4485. \t\t\tanimation: fadeInImage 0.4s ease;
  4486. \t\t}
  4487. \t\t@keyframes fadeInImage {
  4488. \t\t\tfrom {
  4489. \t\t\t\topacity: 0;
  4490. \t\t\t\ttransform: scale(0.95);
  4491. \t\t\t}
  4492. \t\t\tto {
  4493. \t\t\t\topacity: 1;
  4494. \t\t\t\ttransform: scale(1);
  4495. \t\t\t}
  4496. \t\t}
  4497. \t\t.image-overlay-icons {
  4498. \t\t\tposition: absolute !important;
  4499. \t\t\ttop: 20px !important;
  4500. \t\t\tright: 20px !important;
  4501. \t\t\tdisplay: flex !important;
  4502. \t\t\tflex-direction: column !important;
  4503. \t\t\tgap: 12px !important;
  4504. \t\t\tz-index: 10 !important;
  4505. \t\t\topacity: 0 !important;
  4506. \t\t\ttransition: opacity 0.3s ease, transform 0.3s ease !important;
  4507. \t\t\ttransform: translateX(10px) !important;
  4508. \t\t}
  4509. \t\t.product-main-image-wrapper:hover .image-overlay-icons {
  4510. \t\t\topacity: 1 !important;
  4511. \t\t\ttransform: translateX(0) !important;
  4512. \t\t}
  4513. \t\t.product-main-image-wrapper .icon-btn,
  4514. \t\t.image-overlay-icons .icon-btn {
  4515. \t\t\twidth: 48px !important;
  4516. \t\t\theight: 48px !important;
  4517. \t\t\tmin-width: 48px !important;
  4518. \t\t\tmin-height: 48px !important;
  4519. \t\t\tmax-width: 48px !important;
  4520. \t\t\tmax-height: 48px !important;
  4521. \t\t\tborder-radius: 50% !important;
  4522. \t\t\tbackground: rgba(255, 255, 255, 0.95) !important;
  4523. \t\t\tbackdrop-filter: blur(10px) !important;
  4524. \t\t\tborder: 2px solid rgba(255, 255, 255, 0.8) !important;
  4525. \t\t\tdisplay: flex !important;
  4526. \t\t\talign-items: center !important;
  4527. \t\t\tjustify-content: center !important;
  4528. \t\t\tcursor: pointer !important;
  4529. \t\t\ttransition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
  4530. \t\t\tbox-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important;
  4531. \t\t\tcolor: #333 !important;
  4532. \t\t\tposition: relative !important;
  4533. \t\t\toverflow: hidden !important;
  4534. \t\t\tpadding: 0 !important;
  4535. \t\t\tmargin: 0 !important;
  4536. \t\t\tfont-size: inherit !important;
  4537. \t\t\tfont-weight: normal !important;
  4538. \t\t\tline-height: 1 !important;
  4539. \t\t\ttext-align: center !important;
  4540. \t\t\ttext-decoration: none !important;
  4541. \t\t\twhite-space: nowrap !important;
  4542. \t\t\tvertical-align: middle !important;
  4543. \t\t\tfont-family: inherit !important;
  4544. \t\t\ttext-transform: none !important;
  4545. \t\t\tletter-spacing: normal !important;
  4546. \t\t}
  4547. \t\t.product-main-image-wrapper .icon-btn::before,
  4548. \t\t.image-overlay-icons .icon-btn::before {
  4549. \t\t\tcontent: '' !important;
  4550. \t\t\tposition: absolute !important;
  4551. \t\t\ttop: 50% !important;
  4552. \t\t\tleft: 50% !important;
  4553. \t\t\twidth: 0 !important;
  4554. \t\t\theight: 0 !important;
  4555. \t\t\tborder-radius: 50% !important;
  4556. \t\t\tbackground: rgba(255, 162, 0, 0.2) !important;
  4557. \t\t\ttransform: translate(-50%, -50%) !important;
  4558. \t\t\ttransition: width 0.4s ease, height 0.4s ease !important;
  4559. \t\t}
  4560. \t\t.product-main-image-wrapper .icon-btn:hover::before,
  4561. \t\t.image-overlay-icons .icon-btn:hover::before {
  4562. \t\t\twidth: 100% !important;
  4563. \t\t\theight: 100% !important;
  4564. \t\t}
  4565. \t\t.product-main-image-wrapper .icon-btn:hover,
  4566. \t\t.image-overlay-icons .icon-btn:hover {
  4567. \t\t\tbackground: #ffa200 !important;
  4568. \t\t\tborder-color: #ffa200 !important;
  4569. \t\t\tcolor: white !important;
  4570. \t\t\ttransform: scale(1.15) rotate(5deg) !important;
  4571. \t\t\tbox-shadow: 0 6px 20px rgba(255, 162, 0, 0.5) !important;
  4572. \t\t}
  4573. \t\t.product-main-image-wrapper .icon-btn:active,
  4574. \t\t.image-overlay-icons .icon-btn:active {
  4575. \t\t\ttransform: scale(1.05) rotate(0deg) !important;
  4576. \t\t}
  4577. \t\t.product-main-image-wrapper .icon-btn i,
  4578. \t\t.image-overlay-icons .icon-btn i {
  4579. \t\t\tfont-size: 20px !important;
  4580. \t\t\tposition: relative !important;
  4581. \t\t\tz-index: 1 !important;
  4582. \t\t\ttransition: transform 0.3s ease !important;
  4583. \t\t\tmargin: 0 !important;
  4584. \t\t\tdisplay: block !important;
  4585. \t\t}
  4586. \t\t.product-main-image-wrapper .icon-btn:hover i,
  4587. \t\t.image-overlay-icons .icon-btn:hover i {
  4588. \t\t\ttransform: scale(1.1) !important;
  4589. \t\t}
  4590. \t\t.product-main-image-wrapper .favorite-btn.active,
  4591. \t\t.image-overlay-icons .favorite-btn.active {
  4592. \t\t\tbackground: linear-gradient(135deg, #ff6b6b 0%, #ee5a6f 100%) !important;
  4593. \t\t\tborder-color: #ff6b6b !important;
  4594. \t\t\tcolor: white !important;
  4595. \t\t\tbox-shadow: 0 4px 15px rgba(255, 107, 107, 0.4) !important;
  4596. \t\t}
  4597. \t\t.product-main-image-wrapper .favorite-btn.active:hover,
  4598. \t\t.image-overlay-icons .favorite-btn.active:hover {
  4599. \t\t\tbackground: linear-gradient(135deg, #ee5a6f 0%, #dd4a5f 100%) !important;
  4600. \t\t\ttransform: scale(1.15) rotate(-5deg) !important;
  4601. \t\t}
  4602. \t\t.product-main-image-wrapper .image-counter,
  4603. \t\t.image-counter {
  4604. \t\t\tposition: absolute !important;
  4605. \t\t\tbottom: 20px !important;
  4606. \t\t\tright: 20px !important;
  4607. \t\t\tbackground: rgba(0, 0, 0, 0.75) !important;
  4608. \t\t\tbackdrop-filter: blur(8px) !important;
  4609. \t\t\tcolor: white !important;
  4610. \t\t\tpadding: 8px 16px !important;
  4611. \t\t\tborder-radius: 25px !important;
  4612. \t\t\tfont-size: 14px !important;
  4613. \t\t\tfont-weight: 600 !important;
  4614. \t\t\tbox-shadow: 0 2px 10px rgba(0, 0, 0, 0.3) !important;
  4615. \t\t\tz-index: 5 !important;
  4616. \t\t\tdisplay: flex !important;
  4617. \t\t\talign-items: center !important;
  4618. \t\t\tgap: 6px !important;
  4619. \t\t}
  4620. \t\t.product-main-image-wrapper .image-counter span,
  4621. \t\t.image-counter span {
  4622. \t\t\tfont-weight: 700 !important;
  4623. \t\t\tcolor: #ffa200 !important;
  4624. \t\t}
  4625. \t\t.product-main-image-wrapper .image-indicators,
  4626. \t\t#image-indicators {
  4627. \t\t\tposition: absolute !important;
  4628. \t\t\tbottom: 20px !important;
  4629. \t\t\tleft: 50% !important;
  4630. \t\t\ttransform: translateX(-50%) !important;
  4631. \t\t\tdisplay: flex !important;
  4632. \t\t\talign-items: center !important;
  4633. \t\t\tjustify-content: center !important;
  4634. \t\t\tgap: 10px !important;
  4635. \t\t\tbackground: rgba(0, 0, 0, 0.4) !important;
  4636. \t\t\tbackdrop-filter: blur(8px) !important;
  4637. \t\t\tpadding: 8px 16px !important;
  4638. \t\t\tborder-radius: 25px !important;
  4639. \t\t\tz-index: 5 !important;
  4640. \t\t}
  4641. \t\t.product-main-image-wrapper .indicator,
  4642. \t\t#image-indicators .indicator,
  4643. \t\t.image-indicators .indicator {
  4644. \t\t\twidth: 12px !important;
  4645. \t\t\theight: 12px !important;
  4646. \t\t\tmin-width: 12px !important;
  4647. \t\t\tmin-height: 12px !important;
  4648. \t\t\tmax-width: 12px !important;
  4649. \t\t\tmax-height: 12px !important;
  4650. \t\t\tborder-radius: 50% !important;
  4651. \t\t\tborder: 2px solid rgba(255, 255, 255, 0.6) !important;
  4652. \t\t\tbackground: rgba(255, 255, 255, 0.3) !important;
  4653. \t\t\tcursor: pointer !important;
  4654. \t\t\ttransition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
  4655. \t\t\tpadding: 0 !important;
  4656. \t\t\tmargin: 0 !important;
  4657. \t\t\tposition: relative !important;
  4658. \t\t\tdisplay: block !important;
  4659. \t\t\ttext-align: center !important;
  4660. \t\t\ttext-decoration: none !important;
  4661. \t\t\twhite-space: nowrap !important;
  4662. \t\t\tvertical-align: middle !important;
  4663. \t\t\tfont-size: 0 !important;
  4664. \t\t\tline-height: 0 !important;
  4665. \t\t\tbox-sizing: border-box !important;
  4666. \t\t}
  4667. \t\t.product-main-image-wrapper .indicator::before,
  4668. \t\t#image-indicators .indicator::before,
  4669. \t\t.image-indicators .indicator::before {
  4670. \t\t\tcontent: '' !important;
  4671. \t\t\tposition: absolute !important;
  4672. \t\t\ttop: 50% !important;
  4673. \t\t\tleft: 50% !important;
  4674. \t\t\ttransform: translate(-50%, -50%) scale(0) !important;
  4675. \t\t\twidth: 20px !important;
  4676. \t\t\theight: 20px !important;
  4677. \t\t\tborder-radius: 50% !important;
  4678. \t\t\tbackground: rgba(255, 162, 0, 0.3) !important;
  4679. \t\t\ttransition: transform 0.3s ease !important;
  4680. \t\t}
  4681. \t\t.product-main-image-wrapper .indicator:hover,
  4682. \t\t#image-indicators .indicator:hover,
  4683. \t\t.image-indicators .indicator:hover {
  4684. \t\t\tborder-color: #ffa200 !important;
  4685. \t\t\tbackground: rgba(255, 162, 0, 0.6) !important;
  4686. \t\t\ttransform: scale(1.2) !important;
  4687. \t\t}
  4688. \t\t.product-main-image-wrapper .indicator:hover::before,
  4689. \t\t#image-indicators .indicator:hover::before,
  4690. \t\t.image-indicators .indicator:hover::before {
  4691. \t\t\ttransform: translate(-50%, -50%) scale(1) !important;
  4692. \t\t}
  4693. \t\t.product-main-image-wrapper .indicator.active,
  4694. \t\t#image-indicators .indicator.active,
  4695. \t\t.image-indicators .indicator.active {
  4696. \t\t\tborder-color: #ffa200 !important;
  4697. \t\t\tbackground: #ffa200 !important;
  4698. \t\t\tbox-shadow: 0 0 0 3px rgba(255, 162, 0, 0.3), 0 2px 8px rgba(255, 162, 0, 0.5) !important;
  4699. \t\t\ttransform: scale(1.3) !important;
  4700. \t\t}
  4701. \t\t.product-main-image-wrapper .indicator.active::before,
  4702. \t\t#image-indicators .indicator.active::before,
  4703. \t\t.image-indicators .indicator.active::before {
  4704. \t\t\ttransform: translate(-50%, -50%) scale(1) !important;
  4705. \t\t\tbackground: rgba(255, 162, 0, 0.4) !important;
  4706. \t\t}
  4707. \t\t/* Modal de zoom d'image avec transitions modernes */
  4708. \t\t.image-zoom-modal {
  4709. \t\t\tdisplay: none;
  4710. \t\t\tposition: fixed;
  4711. \t\t\tz-index: 9999;
  4712. \t\t\tleft: 0;
  4713. \t\t\ttop: 0;
  4714. \t\t\twidth: 100%;
  4715. \t\t\theight: 100%;
  4716. \t\t\tbackground: rgba(0, 0, 0, 0);
  4717. \t\t\toverflow: auto;
  4718. \t\t\topacity: 0;
  4719. \t\t\ttransition: opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1), background 0.3s ease;
  4720. \t\t\tbackdrop-filter: blur(0px);
  4721. \t\t}
  4722. \t\t.image-zoom-modal.active {
  4723. \t\t\tdisplay: flex;
  4724. \t\t\talign-items: center;
  4725. \t\t\tjustify-content: center;
  4726. \t\t\topacity: 1;
  4727. \t\t\tbackground: rgba(0, 0, 0, 0.95);
  4728. \t\t\tbackdrop-filter: blur(10px);
  4729. \t\t}
  4730. \t\t.zoom-modal-content {
  4731. \t\t\tposition: relative;
  4732. \t\t\tmax-width: 90%;
  4733. \t\t\tmax-height: 90%;
  4734. \t\t\tmargin: auto;
  4735. \t\t\topacity: 0;
  4736. \t\t\ttransform: scale(0.8);
  4737. \t\t\ttransition: opacity 0.4s cubic-bezier(0.4, 0, 0.2, 1), transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
  4738. \t\t}
  4739. \t\t.image-zoom-modal.active .zoom-modal-content {
  4740. \t\t\topacity: 1;
  4741. \t\t\ttransform: scale(1);
  4742. \t\t}
  4743. \t\t.zoom-modal-content img {
  4744. \t\t\twidth: 100%;
  4745. \t\t\theight: auto;
  4746. \t\t\tmax-height: 90vh;
  4747. \t\t\tobject-fit: contain !important;
  4748. \t\t\tobject-position: center !important;
  4749. \t\t\tborder-radius: 8px;
  4750. \t\t\tbox-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
  4751. \t\t\topacity: 0;
  4752. \t\t\ttransition: opacity 0.3s ease;
  4753. \t\t}
  4754. \t\t.zoom-modal-content img.loaded {
  4755. \t\t\topacity: 1;
  4756. \t\t}
  4757. \t\t/* Loader moderne */
  4758. \t\t.zoom-loader {
  4759. \t\t\tposition: absolute;
  4760. \t\t\ttop: 50%;
  4761. \t\t\tleft: 50%;
  4762. \t\t\ttransform: translate(-50%, -50%);
  4763. \t\t\tz-index: 1;
  4764. \t\t\tdisplay: flex;
  4765. \t\t\tflex-direction: column;
  4766. \t\t\talign-items: center;
  4767. \t\t\tjustify-content: center;
  4768. \t\t}
  4769. \t\t.zoom-loader-spinner {
  4770. \t\t\twidth: 60px;
  4771. \t\t\theight: 60px;
  4772. \t\t\tborder: 4px solid rgba(255, 255, 255, 0.1);
  4773. \t\t\tborder-top-color: #ffa200;
  4774. \t\t\tborder-radius: 50%;
  4775. \t\t\tanimation: spin 1s linear infinite;
  4776. \t\t}
  4777. \t\t@keyframes spin {
  4778. \t\t\tto {
  4779. \t\t\t\ttransform: rotate(360deg);
  4780. \t\t\t}
  4781. \t\t}
  4782. \t\t.zoom-loader-text {
  4783. \t\t\tcolor: white;
  4784. \t\t\tmargin-top: 15px;
  4785. \t\t\ttext-align: center;
  4786. \t\t\tfont-size: 14px;
  4787. \t\t\tfont-weight: 500;
  4788. \t\t}
  4789. \t\t.close-zoom {
  4790. \t\t\tposition: absolute;
  4791. \t\t\ttop: 30px;
  4792. \t\t\tright: 30px;
  4793. \t\t\tcolor: white;
  4794. \t\t\tfont-size: 32px;
  4795. \t\t\tfont-weight: 300;
  4796. \t\t\tcursor: pointer;
  4797. \t\t\tz-index: 10000;
  4798. \t\t\twidth: 50px;
  4799. \t\t\theight: 50px;
  4800. \t\t\tdisplay: flex;
  4801. \t\t\talign-items: center;
  4802. \t\t\tjustify-content: center;
  4803. \t\t\tbackground: rgba(255, 255, 255, 0.1);
  4804. \t\t\tborder: 2px solid rgba(255, 255, 255, 0.2);
  4805. \t\t\tborder-radius: 50%;
  4806. \t\t\ttransition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  4807. \t\t\topacity: 0;
  4808. \t\t\ttransform: scale(0.8);
  4809. \t\t}
  4810. \t\t.image-zoom-modal.active .close-zoom {
  4811. \t\t\topacity: 1;
  4812. \t\t\ttransform: scale(1);
  4813. \t\t\ttransition-delay: 0.2s;
  4814. \t\t}
  4815. \t\t.close-zoom:hover {
  4816. \t\t\tbackground: rgba(255, 162, 0, 0.9);
  4817. \t\t\tborder-color: #ffa200;
  4818. \t\t\ttransform: scale(1.1) rotate(90deg);
  4819. \t\t\tbox-shadow: 0 4px 20px rgba(255, 162, 0, 0.4);
  4820. \t\t}
  4821. \t\t
  4822. \t\t/* Styles pour le contrôle de quantité amélioré */
  4823. \t\t.product_count {
  4824. \t\t\tdisplay: flex !important;
  4825. \t\t\talign-items: center !important;
  4826. \t\t\tgap: 15px !important;
  4827. \t\t\tmargin-bottom: 24px !important;
  4828. \t\t\tposition: relative !important;
  4829. \t\t}
  4830. \t\t
  4831. \t\t.product_count label {
  4832. \t\t\tfont-size: 14px !important;
  4833. \t\t\tcolor: #777777 !important;
  4834. \t\t\tfont-family: \"Roboto\", sans-serif !important;
  4835. \t\t\tfont-weight: normal !important;
  4836. \t\t\tmargin-bottom: 0 !important;
  4837. \t\t\twhite-space: nowrap !important;
  4838. \t\t\tpadding-right: 10px !important;
  4839. \t\t}
  4840. \t\t
  4841. \t\t.quantity-controls-wrapper {
  4842. \t\t\tdisplay: flex !important;
  4843. \t\t\talign-items: center !important;
  4844. \t\t\tborder: 1px solid #eeeeee !important;
  4845. \t\t\tborder-radius: 4px !important;
  4846. \t\t\toverflow: hidden !important;
  4847. \t\t\tbackground: #fff !important;
  4848. \t\t\tposition: relative !important;
  4849. \t\t}
  4850. \t\t
  4851. \t\t.quantity-btn {
  4852. \t\t\tdisplay: flex !important;
  4853. \t\t\talign-items: center !important;
  4854. \t\t\tjustify-content: center !important;
  4855. \t\t\twidth: 40px !important;
  4856. \t\t\theight: 40px !important;
  4857. \t\t\tborder: none !important;
  4858. \t\t\tbackground: #f8f9fa !important;
  4859. \t\t\tcolor: #666 !important;
  4860. \t\t\tcursor: pointer !important;
  4861. \t\t\ttransition: all 0.3s ease !important;
  4862. \t\t\tfont-size: 16px !important;
  4863. \t\t\tpadding: 0 !important;
  4864. \t\t\tmargin: 0 !important;
  4865. \t\t\tposition: relative !important;
  4866. \t\t\ttop: auto !important;
  4867. \t\t\tbottom: auto !important;
  4868. \t\t\tright: auto !important;
  4869. \t\t\tleft: auto !important;
  4870. \t\t}
  4871. \t\t
  4872. \t\t.quantity-btn:hover {
  4873. \t\t\tbackground: #e9ecef !important;
  4874. \t\t\tcolor: #ffa200 !important;
  4875. \t\t}
  4876. \t\t
  4877. \t\t.quantity-btn:active {
  4878. \t\t\tbackground: #dee2e6 !important;
  4879. \t\t\ttransform: scale(0.95) !important;
  4880. \t\t}
  4881. \t\t
  4882. \t\t.quantity-btn i {
  4883. \t\t\tfont-size: 14px !important;
  4884. \t\t}
  4885. \t\t
  4886. \t\t.quantity-input {
  4887. \t\t\twidth: 60px !important;
  4888. \t\t\theight: 40px !important;
  4889. \t\t\tborder: none !important;
  4890. \t\t\tborder-left: 1px solid #eeeeee !important;
  4891. \t\t\tborder-right: 1px solid #eeeeee !important;
  4892. \t\t\ttext-align: center !important;
  4893. \t\t\tfont-size: 14px !important;
  4894. \t\t\tfont-weight: 500 !important;
  4895. \t\t\tpadding: 0 !important;
  4896. \t\t\tmargin: 0 !important;
  4897. \t\t\toutline: none !important;
  4898. \t\t\tbackground: #fff !important;
  4899. \t\t\tposition: relative !important;
  4900. \t\t}
  4901. \t\t
  4902. \t\t.quantity-input:focus {
  4903. \t\t\tborder-left-color: #ffa200 !important;
  4904. \t\t\tborder-right-color: #ffa200 !important;
  4905. \t\t}
  4906. \t\t
  4907. \t\t/* Surcharger les styles existants pour les boutons */
  4908. \t\t.product_count .quantity-btn {
  4909. \t\t\tposition: relative !important;
  4910. \t\t\tdisplay: flex !important;
  4911. \t\t\talign-items: center !important;
  4912. \t\t\tjustify-content: center !important;
  4913. \t\t\twidth: 40px !important;
  4914. \t\t\theight: 40px !important;
  4915. \t\t\tborder: none !important;
  4916. \t\t\tbackground: #f8f9fa !important;
  4917. \t\t\tcolor: #666 !important;
  4918. \t\t\tcursor: pointer !important;
  4919. \t\t\ttransition: all 0.3s ease !important;
  4920. \t\t\tfont-size: 16px !important;
  4921. \t\t\tpadding: 0 !important;
  4922. \t\t\tmargin: 0 !important;
  4923. \t\t\ttop: auto !important;
  4924. \t\t\tbottom: auto !important;
  4925. \t\t\tright: auto !important;
  4926. \t\t\tleft: auto !important;
  4927. \t\t}
  4928. \t\t
  4929. \t\t.product_count .quantity-btn:hover {
  4930. \t\t\tbackground: #e9ecef !important;
  4931. \t\t\tcolor: #ffa200 !important;
  4932. \t\t}
  4933. \t\t
  4934. \t\t.product_count .quantity-btn:active {
  4935. \t\t\tbackground: #dee2e6 !important;
  4936. \t\t\ttransform: scale(0.95) !important;
  4937. \t\t}
  4938. \t\t
  4939. \t\t.product_count .quantity-btn i,
  4940. \t\t.product_count .quantity-btn .quantity-icon {
  4941. \t\t\tfont-size: 20px !important;
  4942. \t\t\tfont-weight: 300 !important;
  4943. \t\t\tline-height: 1 !important;
  4944. \t\t\tdisplay: inline-block !important;
  4945. \t\t}
  4946. \t\t
  4947. \t\t.product_count .quantity-btn .quantity-icon {
  4948. \t\t\tfont-size: 24px !important;
  4949. \t\t\tfont-weight: 300 !important;
  4950. \t\t\tline-height: 1 !important;
  4951. \t\t}
  4952. \t\t
  4953. \t\t/* Désactiver les boutons si nécessaire */
  4954. \t\t.quantity-btn:disabled {
  4955. \t\t\topacity: 0.5 !important;
  4956. \t\t\tcursor: not-allowed !important;
  4957. \t\t}
  4958. \t\t
  4959. \t\t.quantity-btn:disabled:hover {
  4960. \t\t\tbackground: #f8f9fa !important;
  4961. \t\t\tcolor: #666 !important;
  4962. \t\t}
  4963. \t\t
  4964. \t\t/* Surcharger les styles pour le wrapper */
  4965. \t\t.product_count .quantity-controls-wrapper {
  4966. \t\t\tdisplay: flex !important;
  4967. \t\t\talign-items: center !important;
  4968. \t\t\tborder: 1px solid #eeeeee !important;
  4969. \t\t\tborder-radius: 4px !important;
  4970. \t\t\toverflow: hidden !important;
  4971. \t\t\tbackground: #fff !important;
  4972. \t\t\tposition: relative !important;
  4973. \t\t}
  4974. \t\t
  4975. \t\t/* Surcharger tous les styles de main.css pour les boutons dans product_count */
  4976. \t\t.product_count button.quantity-btn,
  4977. \t\t.product_count .quantity-btn {
  4978. \t\t\tdisplay: flex !important;
  4979. \t\t\tposition: relative !important;
  4980. \t\t\ttop: auto !important;
  4981. \t\t\tbottom: auto !important;
  4982. \t\t\tright: auto !important;
  4983. \t\t\tleft: auto !important;
  4984. \t\t\twidth: 40px !important;
  4985. \t\t\theight: 40px !important;
  4986. \t\t\tbackground: #f8f9fa !important;
  4987. \t\t\tcolor: #666 !important;
  4988. \t\t\tborder: none !important;
  4989. \t\t\tbox-shadow: none !important;
  4990. \t\t}
  4991. \t\t
  4992. \t\t.product_count button.quantity-btn:hover,
  4993. \t\t.product_count .quantity-btn:hover {
  4994. \t\t\tbackground: #e9ecef !important;
  4995. \t\t\tcolor: #ffa200 !important;
  4996. \t\t}
  4997. \t\t
  4998. \t\t/* Surcharger les styles pour l'input */
  4999. \t\t.product_count .quantity-input,
  5000. \t\t.product_count input.quantity-input {
  5001. \t\t\twidth: 60px !important;
  5002. \t\t\theight: 40px !important;
  5003. \t\t\tborder: none !important;
  5004. \t\t\tborder-left: 1px solid #eeeeee !important;
  5005. \t\t\tborder-right: 1px solid #eeeeee !important;
  5006. \t\t\ttext-align: center !important;
  5007. \t\t\tpadding: 0 !important;
  5008. \t\t\tpadding-left: 0 !important;
  5009. \t\t\tposition: relative !important;
  5010. \t\t}
  5011. \t\t/* Boutons de navigation sur l'image principale */
  5012. \t\t.main-image-nav {
  5013. \t\t\tposition: absolute;
  5014. \t\t\ttop: 50%;
  5015. \t\t\tleft: 0;
  5016. \t\t\tright: 0;
  5017. \t\t\ttransform: translateY(-50%);
  5018. \t\t\tdisplay: flex;
  5019. \t\t\tjustify-content: space-between;
  5020. \t\t\tpadding: 0 12px;
  5021. \t\t\tpointer-events: none !important;
  5022. \t\t\tz-index: 10 !important;
  5023. \t\t}
  5024. \t\t.main-image-nav .main-image-nav-btn,
  5025. \t\t.main-image-nav-btn {
  5026. \t\t\tpointer-events: all !important;
  5027. \t\t\tz-index: 1000 !important;
  5028. \t\t\tposition: relative !important;
  5029. \t\t\tcursor: pointer !important;
  5030. \t\t\t-webkit-user-select: none !important;
  5031. \t\t\t-moz-user-select: none !important;
  5032. \t\t\t-ms-user-select: none !important;
  5033. \t\t\tuser-select: none !important;
  5034. \t\t\tuser-select: none !important;
  5035. \t\t\t-webkit-user-select: none !important;
  5036. \t\t\t-moz-user-select: none !important;
  5037. \t\t\t-ms-user-select: none !important;
  5038. \t\t\twidth: 48px !important;
  5039. \t\t\theight: 48px !important;
  5040. \t\t\tmin-width: 48px !important;
  5041. \t\t\tmin-height: 48px !important;
  5042. \t\t\tmax-width: 48px !important;
  5043. \t\t\tmax-height: 48px !important;
  5044. \t\t\tborder-radius: 50% !important;
  5045. \t\t\tbackground: rgba(255, 255, 255, 0.95) !important;
  5046. \t\t\tbackdrop-filter: blur(10px) !important;
  5047. \t\t\tborder: 2px solid rgba(255, 255, 255, 0.8) !important;
  5048. \t\t\tdisplay: flex !important;
  5049. \t\t\talign-items: center !important;
  5050. \t\t\tjustify-content: center !important;
  5051. \t\t\tbox-shadow: 0 4px 15px rgba(0, 0, 0, 0.2) !important;
  5052. \t\t\tcolor: #333 !important;
  5053. \t\t\ttransition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
  5054. \t\t\tcursor: pointer !important;
  5055. \t\t\toverflow: hidden !important;
  5056. \t\t\tpadding: 0 !important;
  5057. \t\t\tmargin: 0 !important;
  5058. \t\t\tfont-size: inherit !important;
  5059. \t\t\tfont-weight: normal !important;
  5060. \t\t\tline-height: 1 !important;
  5061. \t\t\ttext-align: center !important;
  5062. \t\t\ttext-decoration: none !important;
  5063. \t\t\twhite-space: nowrap !important;
  5064. \t\t\tvertical-align: middle !important;
  5065. \t\t\tfont-family: inherit !important;
  5066. \t\t\ttext-transform: none !important;
  5067. \t\t\tletter-spacing: normal !important;
  5068. \t\t\t-webkit-tap-highlight-color: transparent !important;
  5069. \t\t\ttouch-action: manipulation !important;
  5070. \t\t}
  5071. \t\t.main-image-nav .main-image-nav-btn::before,
  5072. \t\t.main-image-nav-btn::before {
  5073. \t\t\tcontent: '' !important;
  5074. \t\t\tposition: absolute !important;
  5075. \t\t\ttop: 50% !important;
  5076. \t\t\tleft: 50% !important;
  5077. \t\t\twidth: 0 !important;
  5078. \t\t\theight: 0 !important;
  5079. \t\t\tborder-radius: 50% !important;
  5080. \t\t\tbackground: rgba(255, 162, 0, 0.2) !important;
  5081. \t\t\ttransform: translate(-50%, -50%) !important;
  5082. \t\t\ttransition: width 0.4s ease, height 0.4s ease !important;
  5083. \t\t}
  5084. \t\t.main-image-nav .main-image-nav-btn:hover::before,
  5085. \t\t.main-image-nav-btn:hover::before {
  5086. \t\t\twidth: 100% !important;
  5087. \t\t\theight: 100% !important;
  5088. \t\t}
  5089. \t\t.main-image-nav .main-image-nav-btn:hover,
  5090. \t\t.main-image-nav-btn:hover {
  5091. \t\t\tbackground: #ffa200 !important;
  5092. \t\t\tborder-color: #ffa200 !important;
  5093. \t\t\tcolor: #fff !important;
  5094. \t\t\ttransform: scale(1.15) !important;
  5095. \t\t\tbox-shadow: 0 6px 20px rgba(255, 162, 0, 0.5) !important;
  5096. \t\t}
  5097. \t\t.main-image-nav .main-image-nav-btn:active,
  5098. \t\t.main-image-nav-btn:active {
  5099. \t\t\ttransform: scale(1.05) !important;
  5100. \t\t}
  5101. \t\t.main-image-nav .main-image-nav-btn i,
  5102. \t\t.main-image-nav-btn i {
  5103. \t\t\tposition: relative !important;
  5104. \t\t\tz-index: 1 !important;
  5105. \t\t\tfont-size: 20px !important;
  5106. \t\t\ttransition: transform 0.3s ease !important;
  5107. \t\t\tmargin: 0 !important;
  5108. \t\t\tdisplay: block !important;
  5109. \t\t}
  5110. \t\t.main-image-nav .main-image-nav-btn:hover i,
  5111. \t\t.main-image-nav-btn:hover i {
  5112. \t\t\ttransform: scale(1.2) !important;
  5113. \t\t}
  5114. \t\t.main-image-nav .main-image-nav-btn.disabled,
  5115. \t\t.main-image-nav-btn.disabled {
  5116. \t\t\topacity: 0.4 !important;
  5117. \t\t\tcursor: not-allowed !important;
  5118. \t\t\tpointer-events: none !important;
  5119. \t\t}
  5120. \t\t/* Modal personnalisé pour remplacer les alert */
  5121. \t\t.custom-alert-modal .modal-content {
  5122. \t\t\tborder-radius: 12px;
  5123. \t\t\tborder: none;
  5124. \t\t\tbox-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
  5125. \t\t}
  5126. \t\t.custom-alert-modal .modal-header {
  5127. \t\t\tborder-bottom: none;
  5128. \t\t\tpadding: 1.5rem 1.5rem 0.5rem;
  5129. \t\t\tbackground: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  5130. \t\t\tcolor: white;
  5131. \t\t\tborder-radius: 12px 12px 0 0;
  5132. \t\t}
  5133. \t\t.custom-alert-modal .modal-header .btn-close {
  5134. \t\t\tfilter: brightness(0) invert(1);
  5135. \t\t\topacity: 0.8;
  5136. \t\t}
  5137. \t\t.custom-alert-modal .modal-header .btn-close:hover {
  5138. \t\t\topacity: 1;
  5139. \t\t}
  5140. \t\t.custom-alert-modal .modal-body {
  5141. \t\t\tpadding: 1.5rem;
  5142. \t\t\ttext-align: center;
  5143. \t\t}
  5144. \t\t.custom-alert-modal .modal-body .alert-icon {
  5145. \t\t\tfont-size: 3rem;
  5146. \t\t\tmargin-bottom: 1rem;
  5147. \t\t}
  5148. \t\t.custom-alert-modal .modal-body .alert-icon.success {
  5149. \t\t\tcolor: #28a745;
  5150. \t\t}
  5151. \t\t.custom-alert-modal .modal-body .alert-icon.error {
  5152. \t\t\tcolor: #dc3545;
  5153. \t\t}
  5154. \t\t.custom-alert-modal .modal-body .alert-icon.warning {
  5155. \t\t\tcolor: #ffc107;
  5156. \t\t}
  5157. \t\t.custom-alert-modal .modal-body .alert-icon.info {
  5158. \t\t\tcolor: #17a2b8;
  5159. \t\t}
  5160. \t\t.custom-alert-modal .modal-body .alert-message {
  5161. \t\t\tfont-size: 1.1rem;
  5162. \t\t\tcolor: #333;
  5163. \t\t\tmargin-bottom: 1rem;
  5164. \t\t\tline-height: 1.6;
  5165. \t\t}
  5166. \t\t.custom-alert-modal .modal-footer {
  5167. \t\t\tborder-top: none;
  5168. \t\t\tpadding: 0.5rem 1.5rem 1.5rem;
  5169. \t\t\tjustify-content: center;
  5170. \t\t}
  5171. \t\t.custom-alert-modal .modal-footer .btn {
  5172. \t\t\tmin-width: 120px;
  5173. \t\t\tpadding: 0.6rem 1.5rem;
  5174. \t\t\tborder-radius: 8px;
  5175. \t\t\tfont-weight: 500;
  5176. \t\t}
  5177. \t\t/* Responsive pour single-product */
  5178. \t\t@media(max-width: 991.98px) {
  5179. \t\t\t.product-gallery-modern {
  5180. \t\t\t\tflex-direction: column;
  5181. \t\t\t}
  5182. \t\t\t.thumbnails-container {
  5183. \t\t\t\tflex-direction: row;
  5184. \t\t\t\twidth: 100%;
  5185. \t\t\t\toverflow-x: auto;
  5186. \t\t\t\tpadding: 10px 0;
  5187. \t\t\t}
  5188. \t\t\t.thumbnail-item {
  5189. \t\t\t\tflex-shrink: 0;
  5190. \t\t\t}
  5191. \t\t\t.main-image-container {
  5192. \t\t\t\twidth: 100%;
  5193. \t\t\t}
  5194. \t\t}
  5195. \t\t@media(max-width: 768px) {
  5196. \t\t\t.product-gallery-modern {
  5197. \t\t\t\tflex-direction: column;
  5198. \t\t\t}
  5199. \t\t\t.thumbnails-container {
  5200. \t\t\t\twidth: 100%;
  5201. \t\t\t\tflex-direction: row;
  5202. \t\t\t\talign-items: center;
  5203. \t\t\t}
  5204. \t\t\t.product-thumbnails {
  5205. \t\t\t\tflex-direction: row;
  5206. \t\t\t\twidth: 100%;
  5207. \t\t\t\tmax-height: 100px;
  5208. \t\t\t\toverflow-x: auto;
  5209. \t\t\t\toverflow-y: hidden;
  5210. \t\t\t}
  5211. \t\t\t.thumbnail-item {
  5212. \t\t\t\tflex-shrink: 0;
  5213. \t\t\t}
  5214. \t\t\t.thumbnail-nav-btn {
  5215. \t\t\t\tmargin: 0 5px;
  5216. \t\t\t}
  5217. \t\t\t.thumbnail-nav-up {
  5218. \t\t\t\torder: 1;
  5219. \t\t\t}
  5220. \t\t\t.product-thumbnails {
  5221. \t\t\t\torder: 2;
  5222. \t\t\t}
  5223. \t\t\t.thumbnail-nav-down {
  5224. \t\t\t\torder: 3;
  5225. \t\t\t}
  5226. \t\t\t.product-main-image-wrapper .image-overlay-icons,
  5227. \t\t\t.image-overlay-icons {
  5228. \t\t\t\topacity: 1 !important;
  5229. \t\t\t\ttop: 10px !important;
  5230. \t\t\t\tright: 10px !important;
  5231. \t\t\t}
  5232. \t\t\t.product-main-image-wrapper .icon-btn,
  5233. \t\t\t.image-overlay-icons .icon-btn {
  5234. \t\t\t\twidth: 40px !important;
  5235. \t\t\t\theight: 40px !important;
  5236. \t\t\t\tmin-width: 40px !important;
  5237. \t\t\t\tmin-height: 40px !important;
  5238. \t\t\t\tmax-width: 40px !important;
  5239. \t\t\t\tmax-height: 40px !important;
  5240. \t\t\t}
  5241. \t\t\t.product-main-image-wrapper .icon-btn i,
  5242. \t\t\t.image-overlay-icons .icon-btn i {
  5243. \t\t\t\tfont-size: 18px !important;
  5244. \t\t\t}
  5245. \t\t\t.product-main-image-wrapper .image-indicators,
  5246. \t\t\t#image-indicators {
  5247. \t\t\t\tbottom: 15px !important;
  5248. \t\t\t\tpadding: 6px 12px !important;
  5249. \t\t\t\tgap: 8px !important;
  5250. \t\t\t}
  5251. \t\t\t.product-main-image-wrapper .indicator,
  5252. \t\t\t#image-indicators .indicator {
  5253. \t\t\t\twidth: 10px !important;
  5254. \t\t\t\theight: 10px !important;
  5255. \t\t\t\tmin-width: 10px !important;
  5256. \t\t\t\tmin-height: 10px !important;
  5257. \t\t\t\tmax-width: 10px !important;
  5258. \t\t\t\tmax-height: 10px !important;
  5259. \t\t\t}
  5260. \t\t\t.product-main-image-wrapper .image-counter,
  5261. \t\t\t.image-counter {
  5262. \t\t\t\tbottom: 15px !important;
  5263. \t\t\t\tright: 15px !important;
  5264. \t\t\t\tpadding: 6px 12px !important;
  5265. \t\t\t\tfont-size: 12px !important;
  5266. \t\t\t}
  5267. \t\t\t.main-image-nav .main-image-nav-btn,
  5268. \t\t\t.main-image-nav-btn {
  5269. \t\t\t\twidth: 40px !important;
  5270. \t\t\t\theight: 40px !important;
  5271. \t\t\t\tmin-width: 40px !important;
  5272. \t\t\t\tmin-height: 40px !important;
  5273. \t\t\t\tmax-width: 40px !important;
  5274. \t\t\t\tmax-height: 40px !important;
  5275. \t\t\t}
  5276. \t\t\t.main-image-nav .main-image-nav-btn i,
  5277. \t\t\t.main-image-nav-btn i {
  5278. \t\t\t\tfont-size: 18px !important;
  5279. \t\t\t}
  5280. \t\t}
  5281. \t\t@media(max-width: 576px) {
  5282. \t\t\t.product-main-image-wrapper .image-indicators,
  5283. \t\t\t#image-indicators {
  5284. \t\t\t\tbottom: 10px !important;
  5285. \t\t\t\tpadding: 5px 10px !important;
  5286. \t\t\t\tgap: 6px !important;
  5287. \t\t\t}
  5288. \t\t\t.product-main-image-wrapper .indicator,
  5289. \t\t\t#image-indicators .indicator {
  5290. \t\t\t\twidth: 8px !important;
  5291. \t\t\t\theight: 8px !important;
  5292. \t\t\t\tmin-width: 8px !important;
  5293. \t\t\t\tmin-height: 8px !important;
  5294. \t\t\t\tmax-width: 8px !important;
  5295. \t\t\t\tmax-height: 8px !important;
  5296. \t\t\t}
  5297. \t\t\t.product-main-image-wrapper .image-counter,
  5298. \t\t\t.image-counter {
  5299. \t\t\t\tbottom: 10px !important;
  5300. \t\t\t\tright: 10px !important;
  5301. \t\t\t\tpadding: 5px 10px !important;
  5302. \t\t\t\tfont-size: 11px !important;
  5303. \t\t\t}
  5304. \t\t\t.product-main-image-wrapper .icon-btn,
  5305. \t\t\t.image-overlay-icons .icon-btn {
  5306. \t\t\t\twidth: 36px !important;
  5307. \t\t\t\theight: 36px !important;
  5308. \t\t\t\tmin-width: 36px !important;
  5309. \t\t\t\tmin-height: 36px !important;
  5310. \t\t\t\tmax-width: 36px !important;
  5311. \t\t\t\tmax-height: 36px !important;
  5312. \t\t\t}
  5313. \t\t\t.product-main-image-wrapper .icon-btn i,
  5314. \t\t\t.image-overlay-icons .icon-btn i {
  5315. \t\t\t\tfont-size: 16px !important;
  5316. \t\t\t}
  5317. \t\t\t.main-image-nav .main-image-nav-btn,
  5318. \t\t\t.main-image-nav-btn {
  5319. \t\t\t\twidth: 36px !important;
  5320. \t\t\t\theight: 36px !important;
  5321. \t\t\t\tmin-width: 36px !important;
  5322. \t\t\t\tmin-height: 36px !important;
  5323. \t\t\t\tmax-width: 36px !important;
  5324. \t\t\t\tmax-height: 36px !important;
  5325. \t\t\t}
  5326. \t\t\t.main-image-nav .main-image-nav-btn i,
  5327. \t\t\t.main-image-nav-btn i {
  5328. \t\t\t\tfont-size: 16px !important;
  5329. \t\t\t}
  5330. \t\t}
  5331. \t\t
  5332. \t\t/* Styles finaux pour forcer l'affichage des boutons de quantité */
  5333. \t\t.product_count .quantity-controls-wrapper button.quantity-btn,
  5334. \t\t.product_count button.quantity-btn-decrease,
  5335. \t\t.product_count button.quantity-btn-increase {
  5336. \t\t\tdisplay: flex !important;
  5337. \t\t\tvisibility: visible !important;
  5338. \t\t\topacity: 1 !important;
  5339. \t\t\tposition: relative !important;
  5340. \t\t\ttop: auto !important;
  5341. \t\t\tbottom: auto !important;
  5342. \t\t\tright: auto !important;
  5343. \t\t\tleft: auto !important;
  5344. \t\t\twidth: 40px !important;
  5345. \t\t\theight: 40px !important;
  5346. \t\t\tbackground: #f8f9fa !important;
  5347. \t\t\tcolor: #666 !important;
  5348. \t\t\tborder: none !important;
  5349. \t\t\tbox-shadow: none !important;
  5350. \t\t\tmargin: 0 !important;
  5351. \t\t\tpadding: 0 !important;
  5352. \t\t}
  5353. \t\t
  5354. \t\t.product_count .quantity-controls-wrapper {
  5355. \t\t\tdisplay: flex !important;
  5356. \t\t\tvisibility: visible !important;
  5357. \t\t\topacity: 1 !important;
  5358. \t\t}
  5359. \t</style>
  5360. {% endblock %}
  5361. {% block body %}
  5362. \t<!-- Start Banner Area -->
  5363. \t<section class=\"banner-area organic-breadcrumb\">
  5364. \t\t<div class=\"container\">
  5365. \t\t\t<div class=\"breadcrumb-banner d-flex flex-wrap align-items-center justify-content-end\">
  5366. \t\t\t\t<div class=\"col-first\">
  5367. \t\t\t\t\t<h1>Product Details Page</h1>
  5368. \t\t\t\t\t<nav class=\"d-flex align-items-center\">
  5369. \t\t\t\t\t\t<a href=\"index.html\">Home<span class=\"lnr lnr-arrow-right\"></span>
  5370. \t\t\t\t\t\t</a>
  5371. \t\t\t\t\t\t<a href=\"#\">Shop<span class=\"lnr lnr-arrow-right\"></span>
  5372. \t\t\t\t\t\t</a>
  5373. \t\t\t\t\t\t<a href=\"single-product.html\">product-details</a>
  5374. \t\t\t\t\t</nav>
  5375. \t\t\t\t</div>
  5376. \t\t\t</div>
  5377. \t\t</div>
  5378. \t</section>
  5379. \t<!-- End Banner Area -->
  5380. \t<!--================Single Product Area =================-->
  5381. \t<div class=\"product_image_area\">
  5382. \t\t<div class=\"container\">
  5383. \t\t\t<div class=\"row s_product_inner\">
  5384. \t\t\t\t<div class=\"col-lg-6\">
  5385. \t\t\t\t\t<div
  5386. \t\t\t\t\t\tclass=\"product-gallery-modern\">
  5387. \t\t\t\t\t\t<!-- Colonne de miniatures à gauche avec navigation -->
  5388. \t\t\t\t\t\t<div class=\"thumbnails-container\">
  5389. \t\t\t\t\t\t\t<button class=\"thumbnail-nav-btn thumbnail-nav-up\" id=\"thumbnail-nav-up\" title=\"Image précédente\">
  5390. \t\t\t\t\t\t\t\t<i class=\"lnr lnr-chevron-up\"></i>
  5391. \t\t\t\t\t\t\t</button>
  5392. \t\t\t\t\t\t\t<div class=\"product-thumbnails\" id=\"product-thumbnails\">
  5393. \t\t\t\t\t\t\t\t<div class=\"thumbnails-wrapper\" id=\"thumbnails-wrapper\">
  5394. \t\t\t\t\t\t\t\t\t{% set allProductImages = product.images|default([]) %}
  5395. \t\t\t\t\t\t\t\t\t{% if product.variants is defined %}
  5396. \t\t\t\t\t\t\t\t\t\t{% for variant in product.variants %}
  5397. \t\t\t\t\t\t\t\t\t\t\t{% if variant.isActive and variant.images is defined %}
  5398. \t\t\t\t\t\t\t\t\t\t\t\t{% for variantImg in variant.images %}
  5399. \t\t\t\t\t\t\t\t\t\t\t\t\t{% set allProductImages = allProductImages|merge([variantImg]) %}
  5400. \t\t\t\t\t\t\t\t\t\t\t\t{% endfor %}
  5401. \t\t\t\t\t\t\t\t\t\t\t{% endif %}
  5402. \t\t\t\t\t\t\t\t\t\t{% endfor %}
  5403. \t\t\t\t\t\t\t\t\t{% endif %}
  5404. \t\t\t\t\t\t\t\t\t{% if allProductImages|length > 0 %}
  5405. \t\t\t\t\t\t\t\t\t\t{% for img in allProductImages %}
  5406. \t\t\t\t\t\t\t\t\t\t\t<div class=\"thumbnail-item {% if loop.first %}active permanently-active{% endif %}\" data-image=\"{{ asset(img) }}\" data-index=\"{{ loop.index0 }}\">
  5407. \t\t\t\t\t\t\t\t\t\t\t\t<img src=\"{{ asset(img) }}\" alt=\"{{ product.name }} - Image {{ loop.index }}\">
  5408. \t\t\t\t\t\t\t\t\t\t\t</div>
  5409. \t\t\t\t\t\t\t\t\t\t{% endfor %}
  5410. \t\t\t\t\t\t\t\t\t{% else %}
  5411. \t\t\t\t\t\t\t\t\t\t<div class=\"thumbnail-item active permanently-active\" data-image=\"{{ asset('ui/img/category/s-p1.jpg') }}\" data-index=\"0\">
  5412. \t\t\t\t\t\t\t\t\t\t\t<img src=\"{{ asset('ui/img/category/s-p1.jpg') }}\" alt=\"{{ product.name }}\">
  5413. \t\t\t\t\t\t\t\t\t\t</div>
  5414. \t\t\t\t\t\t\t\t\t{% endif %}
  5415. \t\t\t\t\t\t\t\t</div>
  5416. \t\t\t\t\t\t\t</div>
  5417. \t\t\t\t\t\t\t<button class=\"thumbnail-nav-btn thumbnail-nav-down\" id=\"thumbnail-nav-down\" title=\"Image suivante\">
  5418. \t\t\t\t\t\t\t\t<i class=\"lnr lnr-chevron-down\"></i>
  5419. \t\t\t\t\t\t\t</button>
  5420. \t\t\t\t\t\t</div>
  5421. \t\t\t\t\t\t<!-- Grande image principale -->
  5422. \t\t\t\t\t\t<div class=\"product-main-image-wrapper\">
  5423. \t\t\t\t\t\t\t<div class=\"product-main-image\">
  5424. \t\t\t\t\t\t\t\t{% set allProductImages = product.images|default([]) %}
  5425. \t\t\t\t\t\t\t\t{% if product.variants is defined %}
  5426. \t\t\t\t\t\t\t\t\t{% for variant in product.variants %}
  5427. \t\t\t\t\t\t\t\t\t\t{% if variant.isActive and variant.images is defined %}
  5428. \t\t\t\t\t\t\t\t\t\t\t{% for variantImg in variant.images %}
  5429. \t\t\t\t\t\t\t\t\t\t\t\t{% set allProductImages = allProductImages|merge([variantImg]) %}
  5430. \t\t\t\t\t\t\t\t\t\t\t{% endfor %}
  5431. \t\t\t\t\t\t\t\t\t\t{% endif %}
  5432. \t\t\t\t\t\t\t\t\t{% endfor %}
  5433. \t\t\t\t\t\t\t\t{% endif %}
  5434. \t\t\t\t\t\t\t\t{% if allProductImages|length > 0 %}
  5435. \t\t\t\t\t\t\t\t\t<img id=\"main-product-image\" src=\"{{ asset(allProductImages[0]) }}\" alt=\"{{ product.name }}\">
  5436. \t\t\t\t\t\t\t\t{% else %}
  5437. \t\t\t\t\t\t\t\t\t<img id=\"main-product-image\" src=\"{{ asset('ui/img/category/s-p1.jpg') }}\" alt=\"{{ product.name }}\">
  5438. \t\t\t\t\t\t\t\t{% endif %}
  5439. \t\t\t\t\t\t\t\t<!-- Overlay avec icônes -->
  5440. \t\t\t\t\t\t\t\t<div class=\"image-overlay-icons\">
  5441. \t\t\t\t\t\t\t\t\t<button class=\"icon-btn zoom-btn\" onclick=\"openImageZoom()\" title=\"Agrandir l'image\">
  5442. \t\t\t\t\t\t\t\t\t\t<i class=\"lnr lnr-magnifier\"></i>
  5443. \t\t\t\t\t\t\t\t\t</button>
  5444. \t\t\t\t\t\t\t\t\t<button class=\"icon-btn favorite-btn\" {% if app.user %} onclick=\"toggleWishlist({{ product.id }}, this); return false;\" {% else %} onclick=\"showCustomAlert('Vous devez être connecté pour ajouter aux favoris', 'warning'); return false;\" {% endif %} title=\"Ajouter aux favoris\" data-product-id=\"{{ product.id }}\">
  5445. \t\t\t\t\t\t\t\t\t\t<i class=\"lnr lnr-heart\"></i>
  5446. \t\t\t\t\t\t\t\t\t</button>
  5447. \t\t\t\t\t\t\t\t</div>
  5448. \t\t\t\t\t\t\t\t<!-- Navigation sur l'image principale -->
  5449. \t\t\t\t\t\t\t\t<div class=\"main-image-nav\">
  5450. \t\t\t\t\t\t\t\t\t<button type=\"button\" class=\"main-image-nav-btn\" id=\"main-image-prev\" title=\"Image précédente\">
  5451. \t\t\t\t\t\t\t\t\t\t<i class=\"lnr lnr-chevron-left\"></i>
  5452. \t\t\t\t\t\t\t\t\t</button>
  5453. \t\t\t\t\t\t\t\t\t<button type=\"button\" class=\"main-image-nav-btn\" id=\"main-image-next\" title=\"Image suivante\">
  5454. \t\t\t\t\t\t\t\t\t\t<i class=\"lnr lnr-chevron-right\"></i>
  5455. \t\t\t\t\t\t\t\t\t</button>
  5456. \t\t\t\t\t\t\t\t</div>
  5457. \t\t\t\t\t\t\t</div>
  5458. \t\t\t\t\t\t\t<!-- Indicateur d'image active -->
  5459. \t\t\t\t\t\t\t<div class=\"image-counter\">
  5460. \t\t\t\t\t\t\t\t<span id=\"current-image-index\">1</span>
  5461. \t\t\t\t\t\t\t\t/
  5462. \t\t\t\t\t\t\t\t{% set allProductImages = product.images|default([]) %}
  5463. \t\t\t\t\t\t\t\t{% if product.variants is defined %}
  5464. \t\t\t\t\t\t\t\t\t{% for variant in product.variants %}
  5465. \t\t\t\t\t\t\t\t\t\t{% if variant.isActive and variant.images is defined %}
  5466. \t\t\t\t\t\t\t\t\t\t\t{% for variantImg in variant.images %}
  5467. \t\t\t\t\t\t\t\t\t\t\t\t{% set allProductImages = allProductImages|merge([variantImg]) %}
  5468. \t\t\t\t\t\t\t\t\t\t\t{% endfor %}
  5469. \t\t\t\t\t\t\t\t\t\t{% endif %}
  5470. \t\t\t\t\t\t\t\t\t{% endfor %}
  5471. \t\t\t\t\t\t\t\t{% endif %}
  5472. \t\t\t\t\t\t\t\t<span id=\"total-images\">{{ (allProductImages|length) ?: 1 }}</span>
  5473. \t\t\t\t\t\t\t</div>
  5474. \t\t\t\t\t\t\t<!-- Indicateurs d'images (points) -->
  5475. \t\t\t\t\t\t\t<div class=\"image-indicators\" id=\"image-indicators\">
  5476. \t\t\t\t\t\t\t\t{% set allProductImages = product.images|default([]) %}
  5477. \t\t\t\t\t\t\t\t{% if product.variants is defined %}
  5478. \t\t\t\t\t\t\t\t\t{% for variant in product.variants %}
  5479. \t\t\t\t\t\t\t\t\t\t{% if variant.isActive and variant.images is defined %}
  5480. \t\t\t\t\t\t\t\t\t\t\t{% for variantImg in variant.images %}
  5481. \t\t\t\t\t\t\t\t\t\t\t\t{% set allProductImages = allProductImages|merge([variantImg]) %}
  5482. \t\t\t\t\t\t\t\t\t\t\t{% endfor %}
  5483. \t\t\t\t\t\t\t\t\t\t{% endif %}
  5484. \t\t\t\t\t\t\t\t\t{% endfor %}
  5485. \t\t\t\t\t\t\t\t{% endif %}
  5486. \t\t\t\t\t\t\t\t{% for i in 0..((allProductImages|length) ?: 1) - 1 %}
  5487. \t\t\t\t\t\t\t\t<button class=\"indicator {{ i == 0 ? 'active' : '' }}\" data-index=\"{{ i }}\" title=\"Image {{ i + 1 }}\"></button>
  5488. \t\t\t\t\t\t\t\t{% endfor %}
  5489. \t\t\t\t\t\t\t</div>
  5490. \t\t\t\t\t\t</div>
  5491. \t\t\t\t\t</div>
  5492. \t\t\t\t</div>
  5493. \t\t\t\t<div class=\"col-lg-5 offset-lg-1\">
  5494. \t\t\t\t\t<div class=\"s_product_text\">
  5495. \t\t\t\t\t\t<h3>{{ product.name }}</h3>
  5496. \t\t\t\t\t\t<h2>
  5497. \t\t\t\t\t\t\t<span id=\"main-unit-price\">{{ product.price|number_format(2, '.', ' ') }}</span>
  5498. \t\t\t\t\t\t\tHTG
  5499. \t\t\t\t\t\t</h2>
  5500. \t\t\t\t\t\t<ul class=\"list\">
  5501. \t\t\t\t\t\t\t<li>
  5502. \t\t\t\t\t\t\t\t<a class=\"active\" href=\"#\">
  5503. \t\t\t\t\t\t\t\t\t<span>Category</span>
  5504. \t\t\t\t\t\t\t\t\t:
  5505. \t\t\t\t\t\t\t\t\t{{ product.category.name }}</a>
  5506. \t\t\t\t\t\t\t</li>
  5507. \t\t\t\t\t\t\t<li>
  5508. \t\t\t\t\t\t\t\t<a href=\"#\">
  5509. \t\t\t\t\t\t\t\t\t<span>Disponibilité</span>
  5510. \t\t\t\t\t\t\t\t\t:
  5511. \t\t\t\t\t\t\t\t\t{{ product.stockStatus }}</a>
  5512. \t\t\t\t\t\t\t</li>
  5513. \t\t\t\t\t\t</ul>
  5514. \t\t\t\t\t\t<div class=\"product-description-preview\">{{ product.description|striptags|length > 150 ? product.description|striptags|slice(0, 150) ~ '...' : product.description|striptags }}</div>
  5515. \t\t\t\t\t\t<!-- Sélection de variantes (Couleurs, Tailles, etc.) -->
  5516. \t\t\t\t\t\t{% if product.variants is defined and product.variants|length > 0 %}
  5517. \t\t\t\t\t\t\t<div class=\"product-variants mb-4\" id=\"product-variants\" data-product-id=\"{{ product.id }}\">
  5518. \t\t\t\t\t\t\t\t{% set variantAttributes = {} %}
  5519. \t\t\t\t\t\t\t\t{% for variant in product.variants %}
  5520. \t\t\t\t\t\t\t\t\t{% if variant.isActive %}
  5521. \t\t\t\t\t\t\t\t\t\t{% for attrValue in variant.attributeValues %}
  5522. \t\t\t\t\t\t\t\t\t\t\t{% set attrName = attrValue.attribute.name|lower %}
  5523. \t\t\t\t\t\t\t\t\t\t\t{% if variantAttributes[attrName] is not defined %}
  5524. \t\t\t\t\t\t\t\t\t\t\t\t{% set variantAttributes = variantAttributes|merge({(attrName): {'attribute': attrValue.attribute, 'values': []}}) %}
  5525. \t\t\t\t\t\t\t\t\t\t\t{% endif %}
  5526. \t\t\t\t\t\t\t\t\t\t\t{% if attrValue not in variantAttributes[attrName].values %}
  5527. \t\t\t\t\t\t\t\t\t\t\t\t{% set variantAttributes = variantAttributes|merge({(attrName): variantAttributes[attrName]|merge({'values': variantAttributes[attrName].values|merge([attrValue])})}) %}
  5528. \t\t\t\t\t\t\t\t\t\t\t{% endif %}
  5529. \t\t\t\t\t\t\t\t\t\t{% endfor %}
  5530. \t\t\t\t\t\t\t\t\t{% endif %}
  5531. \t\t\t\t\t\t\t\t{% endfor %}
  5532. \t\t\t\t\t\t\t\t{% for attrName, attrData in variantAttributes %}
  5533. \t\t\t\t\t\t\t\t\t<div class=\"variant-selector mb-3\" data-attribute=\"{{ attrData.attribute.slug }}\">
  5534. \t\t\t\t\t\t\t\t\t\t<label class=\"variant-label mb-2\">
  5535. \t\t\t\t\t\t\t\t\t\t\t<strong>{{ attrData.attribute.name }}:</strong>
  5536. \t\t\t\t\t\t\t\t\t\t\t<span class=\"selected-variant-value\" id=\"selected-{{ attrData.attribute.slug }}\"></span>
  5537. \t\t\t\t\t\t\t\t\t\t</label>
  5538. \t\t\t\t\t\t\t\t\t\t<div class=\"variant-options d-flex flex-wrap gap-2\">
  5539. \t\t\t\t\t\t\t\t\t\t\t{% for attrValue in attrData.values %}
  5540. \t\t\t\t\t\t\t\t\t\t\t\t{% if attrValue.isActive %}
  5541. \t\t\t\t\t\t\t\t\t\t\t\t\t{% if attrData.attribute.type == 'color' %}
  5542. \t\t\t\t\t\t\t\t\t\t\t\t\t\t<button type=\"button\" 
  5543. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclass=\"variant-option variant-color-option {% if loop.first %}selected{% endif %}\" 
  5544. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata-value-id=\"{{ attrValue.id }}\"
  5545. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata-value=\"{{ attrValue.value }}\"
  5546. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata-attribute=\"{{ attrData.attribute.slug }}\"
  5547. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle=\"{{ attrValue.value }}\"
  5548. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstyle=\"{% if attrValue.colorCode %}background-color: {{ attrValue.colorCode }};{% endif %} width: 40px; height: 40px; border-radius: 50%; border: 2px solid {% if loop.first %}#007bff{% else %}#ddd{% endif %}; cursor: pointer; position: relative;\">
  5549. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{% if loop.first %}
  5550. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"check-icon\" style=\"position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: {% if attrValue.colorCode and attrValue.colorCode|is_dark_color %}white{% else %}black{% endif %}; font-size: 18px;\">✓</span>
  5551. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{% endif %}
  5552. \t\t\t\t\t\t\t\t\t\t\t\t\t\t</button>
  5553. \t\t\t\t\t\t\t\t\t\t\t\t\t{% else %}
  5554. \t\t\t\t\t\t\t\t\t\t\t\t\t\t<button type=\"button\" 
  5555. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclass=\"variant-option variant-text-option btn btn-outline-secondary {% if loop.first %}active{% endif %}\" 
  5556. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata-value-id=\"{{ attrValue.id }}\"
  5557. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata-value=\"{{ attrValue.value }}\"
  5558. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata-attribute=\"{{ attrData.attribute.slug }}\">
  5559. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{{ attrValue.value }}
  5560. \t\t\t\t\t\t\t\t\t\t\t\t\t\t</button>
  5561. \t\t\t\t\t\t\t\t\t\t\t\t\t{% endif %}
  5562. \t\t\t\t\t\t\t\t\t\t\t\t{% endif %}
  5563. \t\t\t\t\t\t\t\t\t\t\t{% endfor %}
  5564. \t\t\t\t\t\t\t\t\t\t</div>
  5565. \t\t\t\t\t\t\t\t\t</div>
  5566. \t\t\t\t\t\t\t\t{% endfor %}
  5567. \t\t\t\t\t\t\t\t<!-- Affichage du stock et du prix de la variante sélectionnée -->
  5568. \t\t\t\t\t\t\t\t<div class=\"variant-info mt-3 p-3 bg-light rounded\" id=\"variant-info\" style=\"display: none;\">
  5569. \t\t\t\t\t\t\t\t\t<div class=\"d-flex justify-content-between align-items-center mb-2\">
  5570. \t\t\t\t\t\t\t\t\t\t<span><strong>Prix:</strong></span>
  5571. \t\t\t\t\t\t\t\t\t\t<span class=\"variant-price text-primary fw-bold\" id=\"variant-price\"></span>
  5572. \t\t\t\t\t\t\t\t\t</div>
  5573. \t\t\t\t\t\t\t\t\t<div class=\"d-flex justify-content-between align-items-center\">
  5574. \t\t\t\t\t\t\t\t\t\t<span><strong>Stock:</strong></span>
  5575. \t\t\t\t\t\t\t\t\t\t<span class=\"variant-stock\" id=\"variant-stock\"></span>
  5576. \t\t\t\t\t\t\t\t\t</div>
  5577. \t\t\t\t\t\t\t\t\t<input type=\"hidden\" id=\"selected-variant-id\" value=\"\">
  5578. \t\t\t\t\t\t\t\t\t<input type=\"hidden\" id=\"selected-variant-sku\" value=\"\">
  5579. \t\t\t\t\t\t\t\t</div>
  5580. \t\t\t\t\t\t\t</div>
  5581. \t\t\t\t\t\t{% endif %}
  5582. \t\t\t\t\t\t<!-- Informations sur la boutique -->
  5583. \t\t\t\t\t\t<div class=\"shop-info mb-3\">
  5584. \t\t\t\t\t\t\t<small class=\"text-muted\">
  5585. \t\t\t\t\t\t\t\t<i class=\"lnr lnr-store\"></i>
  5586. \t\t\t\t\t\t\t\tVendu par :
  5587. \t\t\t\t\t\t\t\t{% if product.shop is defined and product.shop %}
  5588. \t\t\t\t\t\t\t\t\t<a href=\"{{ path('ui_shop_show', {'slug': product.shop.slug}) }}\" class=\"shop-link\">
  5589. \t\t\t\t\t\t\t\t\t\t{{ product.shop.name }}
  5590. \t\t\t\t\t\t\t\t\t</a>
  5591. \t\t\t\t\t\t\t\t{% else %}
  5592. \t\t\t\t\t\t\t\t\t<span class=\"text-muted\">Boutique inconnue</span>
  5593. \t\t\t\t\t\t\t\t{% endif %}
  5594. \t\t\t\t\t\t\t</small>
  5595. \t\t\t\t\t\t</div>
  5596. \t\t\t\t\t\t<div class=\"product_count\">
  5597. \t\t\t\t\t\t\t<label for=\"qty\">Quantité :</label>
  5598. \t\t\t\t\t\t\t<div class=\"quantity-controls-wrapper\">
  5599. \t\t\t\t\t\t\t\t<button onclick=\"var result = document.getElementById('sst'); var sst = result.value; if( !isNaN( sst ) && sst > 1 ) result.value--;return false;\" class=\"quantity-btn quantity-btn-decrease\" type=\"button\" title=\"Diminuer\">
  5600. \t\t\t\t\t\t\t\t\t<span class=\"quantity-icon\">−</span>
  5601. \t\t\t\t\t\t\t\t</button>
  5602. \t\t\t\t\t\t\t\t<input type=\"text\" name=\"qty\" id=\"sst\" maxlength=\"12\" value=\"1\" title=\"Quantité:\" class=\"input-text qty quantity-input\" max=\"{{ product.stock ?? 99 }}\">
  5603. \t\t\t\t\t\t\t\t<button onclick=\"var result = document.getElementById('sst'); var sst = result.value; if( !isNaN( sst ) && sst < {{ product.stock ?? 99 }}) result.value++;return false;\" class=\"quantity-btn quantity-btn-increase\" type=\"button\" title=\"Augmenter\">
  5604. \t\t\t\t\t\t\t\t\t<span class=\"quantity-icon\">+</span>
  5605. \t\t\t\t\t\t\t\t</button>
  5606. \t\t\t\t\t\t\t</div>
  5607. \t\t\t\t\t\t</div>
  5608. \t\t\t\t\t\t<input
  5609. \t\t\t\t\t\ttype=\"hidden\" id=\"unit-price-input\" value=\"{{ product.price|number_format(2, '.', '') }}\"/>
  5610. \t\t\t\t\t\t{# Prix de gros (bulk pricing) - Affiché uniquement si activé par le vendeur #}
  5611. \t\t\t\t\t\t{% if product.hasTierPricing and product.tierPrices is defined and product.tierPrices|length > 0 %}
  5612. \t\t\t\t\t\t{% set tierPrices = [] %}
  5613. \t\t\t\t\t\t\t{% for tier in product.tierPrices %}
  5614. \t\t\t\t\t\t\t\t{% set tierPrices = tierPrices|merge([{ 'min': tier.min, 'price': tier.price }]) %}
  5615. \t\t\t\t\t\t\t{% endfor %}
  5616. \t\t\t\t\t\t\t<div id=\"bulk-pricing\" class=\"mt-4 p-3 bg-light rounded\" data-tiers='{{ tierPrices|json_encode|e('html_attr') }}'>
  5617. \t\t\t\t\t\t\t\t<div class=\"d-flex align-items-center mb-3\">
  5618. \t\t\t\t\t\t\t\t\t<i class=\"lnr lnr-tag text-primary me-2\" style=\"font-size: 1.2rem;\"></i>
  5619. \t\t\t\t\t\t\t\t\t<strong class=\"me-2\">Prix de gros disponible</strong>
  5620. \t\t\t\t\t\t\t\t\t<span id=\"unit-price-value\" class=\"badge bg-primary ms-2 text-white p-2\">{{ product.price|number_format(2, '.', ' ') }} HTG</span>
  5621. \t\t\t\t\t\t\t</div>
  5622. \t\t\t\t\t\t\t<div class=\"table-responsive\">
  5623. \t\t\t\t\t\t\t\t\t<table class=\"table table-sm mb-3\" style=\"border:1px solid #dee2e6; background: white;\">
  5624. \t\t\t\t\t\t\t\t\t\t<thead class=\"table-primary\">
  5625. \t\t\t\t\t\t\t\t\t\t<tr>
  5626. \t\t\t\t\t\t\t\t\t\t\t\t<th style=\"font-weight: 600;\">Quantité minimale</th>
  5627. \t\t\t\t\t\t\t\t\t\t\t\t<th style=\"font-weight: 600;\">Prix unitaire (HTG)</th>
  5628. \t\t\t\t\t\t\t\t\t\t\t\t<th style=\"font-weight: 600;\">Économie</th>
  5629. \t\t\t\t\t\t\t\t\t\t</tr>
  5630. \t\t\t\t\t\t\t\t\t</thead>
  5631. \t\t\t\t\t\t\t\t\t<tbody id=\"bulk-tier-rows\">
  5632. \t\t\t\t\t\t\t\t\t\t{% for tier in tierPrices|sort((a,b)=> a.min <=> b.min) %}
  5633. \t\t\t\t\t\t\t\t\t\t\t\t{% set savings = ((product.price - tier.price) / product.price * 100)|round(1) %}
  5634. \t\t\t\t\t\t\t\t\t\t\t\t<tr data-min=\"{{ tier.min }}\" class=\"{% if loop.first %}table-active{% endif %}\">
  5635. \t\t\t\t\t\t\t\t\t\t\t\t\t<td><strong>≥ {{ tier.min }}</strong></td>
  5636. \t\t\t\t\t\t\t\t\t\t\t\t\t<td><strong class=\"text-primary\">{{ tier.price|number_format(2, '.', ' ') }}</strong></td>
  5637. \t\t\t\t\t\t\t\t\t\t\t\t\t<td>
  5638. \t\t\t\t\t\t\t\t\t\t\t\t\t\t{% if savings > 0 %}
  5639. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"badge bg-success text-white p-2\">-{{ savings }}%</span>
  5640. \t\t\t\t\t\t\t\t\t\t\t\t\t\t{% else %}
  5641. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"text-muted\">-</span>
  5642. \t\t\t\t\t\t\t\t\t\t\t\t\t\t{% endif %}
  5643. \t\t\t\t\t\t\t\t\t\t\t\t\t</td>
  5644. \t\t\t\t\t\t\t\t\t\t\t</tr>
  5645. \t\t\t\t\t\t\t\t\t\t{% endfor %}
  5646. \t\t\t\t\t\t\t\t\t</tbody>
  5647. \t\t\t\t\t\t\t\t</table>
  5648. \t\t\t\t\t\t\t</div>
  5649. \t\t\t\t\t\t\t\t<div class=\"d-flex flex-wrap gap-3 align-items-baseline mb-2 p-2 bg-white rounded\">
  5650. \t\t\t\t\t\t\t\t<div>
  5651. \t\t\t\t\t\t\t\t\t<strong>Total:</strong>
  5652. \t\t\t\t\t\t\t\t\t\t<span id=\"total-price-value\" class=\"text-primary fs-5\">{{ product.price|number_format(2, '.', ' ') }}</span>
  5653. \t\t\t\t\t\t\t\t\tHTG
  5654. \t\t\t\t\t\t\t\t</div>
  5655. \t\t\t\t\t\t\t\t<div class=\"text-success\">
  5656. \t\t\t\t\t\t\t\t\t<strong>Économies:</strong>
  5657. \t\t\t\t\t\t\t\t\t<span id=\"savings-amount\">0.00</span>
  5658. \t\t\t\t\t\t\t\t\tHTG
  5659. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(<span id=\"savings-percent\">0</span>%)
  5660. \t\t\t\t\t\t\t\t</div>
  5661. \t\t\t\t\t\t\t</div>
  5662. \t\t\t\t\t\t\t\t<small class=\"text-muted d-block mt-2\">
  5663. \t\t\t\t\t\t\t\t\t<i class=\"lnr lnr-info-circle me-1\"></i>
  5664. \t\t\t\t\t\t\t\t\tLe prix et le total s'adaptent automatiquement selon la quantité sélectionnée.
  5665. \t\t\t\t\t\t\t\t</small>
  5666. \t\t\t\t\t\t</div>
  5667. \t\t\t\t\t\t{% endif %}
  5668. \t\t\t\t\t\t<!-- Stock disponible -->
  5669. \t\t\t\t\t\t{% if product.stock is defined %}
  5670. \t\t\t\t\t\t\t<small class=\"text-muted\">Stock disponible :
  5671. \t\t\t\t\t\t\t\t{{ product.stock }}
  5672. \t\t\t\t\t\t\t\tunités</small>
  5673. \t\t\t\t\t\t{% endif %}
  5674. \t\t\t\t\t\t<!-- Statistiques du produit -->
  5675. \t\t\t\t\t\t{% if productStats is defined %}
  5676. \t\t\t\t\t\t\t<div class=\"product-stats mt-3\">
  5677. \t\t\t\t\t\t\t\t<div class=\"row text-center\">
  5678. \t\t\t\t\t\t\t\t\t<div class=\"col-4\">
  5679. \t\t\t\t\t\t\t\t\t\t<div class=\"stat-item\">
  5680. \t\t\t\t\t\t\t\t\t\t\t<span class=\"stat-number\">{{ productStats.totalViews }}</span>
  5681. \t\t\t\t\t\t\t\t\t\t\t<small class=\"stat-label\">Vues</small>
  5682. \t\t\t\t\t\t\t\t\t\t</div>
  5683. \t\t\t\t\t\t\t\t\t</div>
  5684. \t\t\t\t\t\t\t\t\t<div class=\"col-4\">
  5685. \t\t\t\t\t\t\t\t\t\t<div class=\"stat-item\">
  5686. \t\t\t\t\t\t\t\t\t\t\t<span class=\"stat-number\">{{ productStats.salesCount }}</span>
  5687. \t\t\t\t\t\t\t\t\t\t\t<small class=\"stat-label\">Ventes</small>
  5688. \t\t\t\t\t\t\t\t\t\t</div>
  5689. \t\t\t\t\t\t\t\t\t</div>
  5690. \t\t\t\t\t\t\t\t\t<div class=\"col-4\">
  5691. \t\t\t\t\t\t\t\t\t\t<div class=\"stat-item\">
  5692. \t\t\t\t\t\t\t\t\t\t\t<span class=\"stat-number\">{{ productStats.conversionRate }}%</span>
  5693. \t\t\t\t\t\t\t\t\t\t\t<small class=\"stat-label\">Conversion</small>
  5694. \t\t\t\t\t\t\t\t\t\t</div>
  5695. \t\t\t\t\t\t\t\t\t</div>
  5696. \t\t\t\t\t\t\t\t</div>
  5697. \t\t\t\t\t\t\t</div>
  5698. \t\t\t\t\t\t{% endif %}
  5699. \t\t\t\t\t\t<div class=\"card_area d-flex align-items-center\">
  5700. \t\t\t\t\t\t\t<a class=\"primary-btn btn-add-to-cart\" href=\"javascript:void(0);\" id=\"add-to-cart-btn\" data-product-id=\"{{ product.id }}\" data-qty=\"1\">
  5701. \t\t\t\t\t\t\t\t<i class=\"lnr lnr-cart\"></i>
  5702. \t\t\t\t\t\t\t\tAjouter au panier
  5703. \t\t\t\t\t\t\t</a>
  5704. \t\t\t\t\t\t\t<a class=\"icon_btn wishlist-btn\" href=\"#\" title=\"Ajouter aux favoris\" data-product-id=\"{{ product.id }}\" {% if app.user %} onclick=\"toggleWishlist({{ product.id }}, this); return false;\" {% else %} onclick=\"showCustomAlert('Vous devez être connecté pour ajouter aux favoris', 'warning'); return false;\" {% endif %}>
  5705. \t\t\t\t\t\t\t\t<i class=\"lnr lnr-heart\"></i>
  5706. \t\t\t\t\t\t\t</a>
  5707. \t\t\t\t\t\t\t<a class=\"icon_btn comparison-btn\" href=\"#\" title=\"Comparer\" data-product-id=\"{{ product.id }}\" {% if app.user %} onclick=\"toggleComparison({{ product.id }}, this); return false;\" {% else %} onclick=\"showCustomAlert('Vous devez être connecté pour comparer des produits', 'warning'); return false;\" {% endif %}>
  5708. \t\t\t\t\t\t\t\t<i class=\"lnr lnr-sync\"></i>
  5709. \t\t\t\t\t\t\t</a>
  5710. \t\t\t\t\t\t</div>
  5711. \t\t\t\t\t\t<!-- Message de confirmation -->
  5712. \t\t\t\t\t\t<div id=\"cart-message\" class=\"alert alert-success mt-3\" style=\"display: none;\">
  5713. \t\t\t\t\t\t\t<i class=\"lnr lnr-checkmark-circle\"></i>
  5714. \t\t\t\t\t\t\tProduit ajouté au panier avec succès !
  5715. \t\t\t\t\t\t</div>
  5716. \t\t\t\t\t\t<!-- ... existing code ... -->
  5717. \t\t\t\t\t</div>
  5718. \t\t\t\t</div>
  5719. \t\t\t</div>
  5720. \t\t</div>
  5721. \t</div>
  5722. \t<!--================End Single Product Area =================-->
  5723. \t<!--================Product Description Area =================-->
  5724. \t<section class=\"product_description_area\">
  5725. \t\t<div class=\"container\">
  5726. \t\t\t<ul class=\"nav nav-tabs\" id=\"myTab\" role=\"tablist\">
  5727. \t\t\t\t<li class=\"nav-item\">
  5728. \t\t\t\t\t<a class=\"nav-link active\" id=\"home-tab\" data-bs-toggle=\"tab\" href=\"#home\" role=\"tab\" aria-controls=\"home\" aria-selected=\"true\">Description</a>
  5729. \t\t\t\t</li>
  5730. \t\t\t\t<li class=\"nav-item\">
  5731. \t\t\t\t\t<a class=\"nav-link\" id=\"profile-tab\" data-bs-toggle=\"tab\" href=\"#profile\" role=\"tab\" aria-controls=\"profile\" aria-selected=\"false\">Spécifications</a>
  5732. \t\t\t\t</li>
  5733. \t\t\t\t<li class=\"nav-item\">
  5734. \t\t\t\t\t<a class=\"nav-link\" id=\"contact-tab\" data-bs-toggle=\"tab\" href=\"#contact\" role=\"tab\" aria-controls=\"contact\" aria-selected=\"false\">Commentaires</a>
  5735. \t\t\t\t</li>
  5736. \t\t\t\t<li class=\"nav-item\">
  5737. \t\t\t\t\t<a class=\"nav-link\" id=\"review-tab\" data-bs-toggle=\"tab\" href=\"#review\" role=\"tab\" aria-controls=\"review\" aria-selected=\"false\">Avis ({{ product.reviewCount ?? 0 }})</a>
  5738. \t\t\t\t</li>
  5739. \t\t\t</ul>
  5740. \t\t\t<div class=\"tab-content\" id=\"myTabContent\">
  5741. \t\t\t\t<div class=\"tab-pane fade show active\" id=\"home\" role=\"tabpanel\" aria-labelledby=\"home-tab\">
  5742. \t\t\t\t\t<div class=\"description\">
  5743. \t\t\t\t\t\t{% if product.description %}
  5744. \t\t\t\t\t\t\t<div class=\"product-description-content\">
  5745. \t\t\t\t\t\t\t\t{{ product.description|raw }}
  5746. \t\t\t\t\t\t\t</div>
  5747. \t\t\t\t\t\t{% else %}
  5748. \t\t\t\t\t\t\t<p class=\"text-muted\">Aucune description disponible pour ce produit.</p>
  5749. \t\t\t\t\t\t{% endif %}
  5750. \t\t\t\t\t</div>
  5751. \t\t\t\t</div>
  5752. \t\t\t\t<div class=\"tab-pane fade\" id=\"profile\" role=\"tabpanel\" aria-labelledby=\"profile-tab\">
  5753. \t\t\t\t\t<div class=\"specification-table\">
  5754. \t\t\t\t\t\t{% if product.weight or product.length or product.width or product.height or product.attributes %}
  5755. \t\t\t\t\t\t\t<div class=\"table-responsive\">
  5756. \t\t\t\t\t\t\t\t<table class=\"table\">
  5757. \t\t\t\t\t\t\t\t\t<tbody>
  5758. \t\t\t\t\t\t\t\t\t\t{% if product.sku %}
  5759. \t\t\t\t\t\t\t\t\t\t\t<tr>
  5760. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  5761. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>Référence (SKU)</h5>
  5762. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  5763. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  5764. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>{{ product.sku }}</h5>
  5765. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  5766. \t\t\t\t\t\t\t\t\t\t\t</tr>
  5767. \t\t\t\t\t\t\t\t\t\t{% endif %}
  5768. \t\t\t\t\t\t\t\t\t\t{% if product.barcode %}
  5769. \t\t\t\t\t\t\t\t\t\t\t<tr>
  5770. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  5771. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>Code-barres</h5>
  5772. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  5773. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  5774. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>{{ product.barcode }}</h5>
  5775. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  5776. \t\t\t\t\t\t\t\t\t\t\t</tr>
  5777. \t\t\t\t\t\t\t\t\t\t{% endif %}
  5778. \t\t\t\t\t\t\t\t\t\t{% if product.brand %}
  5779. \t\t\t\t\t\t\t\t\t\t\t<tr>
  5780. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  5781. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>Marque</h5>
  5782. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  5783. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  5784. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>{{ product.brand.name }}</h5>
  5785. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  5786. \t\t\t\t\t\t\t\t\t\t\t</tr>
  5787. \t\t\t\t\t\t\t\t\t\t{% endif %}
  5788. \t\t\t\t\t\t\t\t\t\t{% if product.category %}
  5789. \t\t\t\t\t\t\t\t\t\t\t<tr>
  5790. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  5791. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>Catégorie</h5>
  5792. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  5793. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  5794. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>{{ product.category.name }}</h5>
  5795. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  5796. \t\t\t\t\t\t\t\t\t\t\t</tr>
  5797. \t\t\t\t\t\t\t\t\t\t{% endif %}
  5798. \t\t\t\t\t\t\t\t\t\t{% if product.weight %}
  5799. \t\t\t\t\t\t\t\t\t\t\t<tr>
  5800. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  5801. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>Poids</h5>
  5802. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  5803. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  5804. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>{{ product.weight }}
  5805. \t\t\t\t\t\t\t\t\t\t\t\t\t\tkg</h5>
  5806. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  5807. \t\t\t\t\t\t\t\t\t\t\t</tr>
  5808. \t\t\t\t\t\t\t\t\t\t{% endif %}
  5809. \t\t\t\t\t\t\t\t\t\t{% if product.length or product.width or product.height %}
  5810. \t\t\t\t\t\t\t\t\t\t\t<tr>
  5811. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  5812. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>Dimensions</h5>
  5813. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  5814. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  5815. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>
  5816. \t\t\t\t\t\t\t\t\t\t\t\t\t\t{% if product.length %}
  5817. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{{ product.length }}cm
  5818. \t\t\t\t\t\t\t\t\t\t\t\t\t\t{% endif %}
  5819. \t\t\t\t\t\t\t\t\t\t\t\t\t\t{% if product.width %}
  5820. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t×
  5821. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{{ product.width }}cm
  5822. \t\t\t\t\t\t\t\t\t\t\t\t\t\t{% endif %}
  5823. \t\t\t\t\t\t\t\t\t\t\t\t\t\t{% if product.height %}
  5824. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t×
  5825. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{{ product.height }}cm
  5826. \t\t\t\t\t\t\t\t\t\t\t\t\t\t{% endif %}
  5827. \t\t\t\t\t\t\t\t\t\t\t\t\t</h5>
  5828. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  5829. \t\t\t\t\t\t\t\t\t\t\t</tr>
  5830. \t\t\t\t\t\t\t\t\t\t{% endif %}
  5831. \t\t\t\t\t\t\t\t\t\t{% if product.stock is not null %}
  5832. \t\t\t\t\t\t\t\t\t\t\t<tr>
  5833. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  5834. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>Stock disponible</h5>
  5835. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  5836. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  5837. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>{{ product.stock }}
  5838. \t\t\t\t\t\t\t\t\t\t\t\t\t\tunité(s)</h5>
  5839. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  5840. \t\t\t\t\t\t\t\t\t\t\t</tr>
  5841. \t\t\t\t\t\t\t\t\t\t{% endif %}
  5842. \t\t\t\t\t\t\t\t\t\t{% if product.details is defined and product.details|length > 0 %}
  5843. \t\t\t\t\t\t\t\t\t\t\t{% for detail in product.details %}
  5844. \t\t\t\t\t\t\t\t\t\t\t\t{% if detail.isActive %}
  5845. \t\t\t\t\t\t\t\t\t\t\t\t\t<tr>
  5846. \t\t\t\t\t\t\t\t\t\t\t\t\t\t<td>
  5847. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<h5>{{ detail.label }}</h5>
  5848. \t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>
  5849. \t\t\t\t\t\t\t\t\t\t\t\t\t\t<td>
  5850. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<h5>{{ detail.value|raw }}</h5>
  5851. \t\t\t\t\t\t\t\t\t\t\t\t\t\t</td>
  5852. \t\t\t\t\t\t\t\t\t\t\t\t\t</tr>
  5853. \t\t\t\t\t\t\t\t\t\t\t\t{% endif %}
  5854. \t\t\t\t\t\t\t\t\t\t\t{% endfor %}
  5855. \t\t\t\t\t\t\t\t\t\t{% endif %}
  5856. \t\t\t\t\t\t\t\t\t\t{% if product.stockStatus %}
  5857. \t\t\t\t\t\t\t\t\t\t\t<tr>
  5858. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  5859. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>Statut</h5>
  5860. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  5861. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  5862. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>
  5863. \t\t\t\t\t\t\t\t\t\t\t\t\t\t{% if product.stockStatus == 'in_stock' %}
  5864. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"badge bg-success\">En stock</span>
  5865. \t\t\t\t\t\t\t\t\t\t\t\t\t\t{% elseif product.stockStatus == 'out_of_stock' %}
  5866. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"badge bg-danger\">Rupture de stock</span>
  5867. \t\t\t\t\t\t\t\t\t\t\t\t\t\t{% elseif product.stockStatus == 'backorder' %}
  5868. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"badge bg-warning\">Sur commande</span>
  5869. \t\t\t\t\t\t\t\t\t\t\t\t\t\t{% else %}
  5870. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{{ product.stockStatus }}
  5871. \t\t\t\t\t\t\t\t\t\t\t\t\t\t{% endif %}
  5872. \t\t\t\t\t\t\t\t\t\t\t\t\t</h5>
  5873. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  5874. \t\t\t\t\t\t\t\t\t\t\t</tr>
  5875. \t\t\t\t\t\t\t\t\t\t{% endif %}
  5876. \t\t\t\t\t\t\t\t\t\t{% if product.isDigital %}
  5877. \t\t\t\t\t\t\t\t\t\t\t<tr>
  5878. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  5879. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>Type</h5>
  5880. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  5881. \t\t\t\t\t\t\t\t\t\t\t\t<td>
  5882. \t\t\t\t\t\t\t\t\t\t\t\t\t<h5>
  5883. \t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"badge bg-info\">Produit digital</span>
  5884. \t\t\t\t\t\t\t\t\t\t\t\t\t</h5>
  5885. \t\t\t\t\t\t\t\t\t\t\t\t</td>
  5886. \t\t\t\t\t\t\t\t\t\t\t</tr>
  5887. \t\t\t\t\t\t\t\t\t\t{% endif %}
  5888. \t\t\t\t\t\t\t\t\t\t{% if product.attributes is not empty %}
  5889. \t\t\t\t\t\t\t\t\t\t\t{% for key, value in product.attributes %}
  5890. \t\t\t\t\t\t\t\t\t\t\t\t<tr>
  5891. \t\t\t\t\t\t\t\t\t\t\t\t\t<td>
  5892. \t\t\t\t\t\t\t\t\t\t\t\t\t\t<h5>{{ key|replace({'_': ' '})|title }}</h5>
  5893. \t\t\t\t\t\t\t\t\t\t\t\t\t</td>
  5894. \t\t\t\t\t\t\t\t\t\t\t\t\t<td>
  5895. \t\t\t\t\t\t\t\t\t\t\t\t\t\t<h5>{{ value }}</h5>
  5896. \t\t\t\t\t\t\t\t\t\t\t\t\t</td>
  5897. \t\t\t\t\t\t\t\t\t\t\t\t</tr>
  5898. \t\t\t\t\t\t\t\t\t\t\t{% endfor %}
  5899. \t\t\t\t\t\t\t\t\t\t{% endif %}
  5900. \t\t\t\t\t\t\t\t\t</tbody>
  5901. \t\t\t\t\t\t\t\t</table>
  5902. \t\t\t\t\t\t\t</div>
  5903. \t\t\t\t\t\t{% else %}
  5904. \t\t\t\t\t\t\t<p class=\"text-muted\">Aucune spécification disponible pour ce produit.</p>
  5905. \t\t\t\t\t\t{% endif %}
  5906. \t\t\t\t\t</div>
  5907. \t\t\t\t</div>
  5908. \t\t\t\t<div class=\"tab-pane fade\" id=\"contact\" role=\"tabpanel\" aria-labelledby=\"contact-tab\">
  5909. \t\t\t\t\t<div class=\"comment-wrapper\">
  5910. \t\t\t\t\t\t<div class=\"alert alert-info\">
  5911. \t\t\t\t\t\t\t<i class=\"lnr lnr-info-circle\"></i>
  5912. \t\t\t\t\t\t\tLa fonctionnalité de commentaires sera bientôt disponible. Vous pourrez laisser des commentaires et poser des questions sur ce produit.
  5913. \t\t\t\t\t\t</div>
  5914. \t\t\t\t\t\t{% if app.user %}
  5915. \t\t\t\t\t\t\t<div class=\"review_box mt-4\">
  5916. \t\t\t\t\t\t\t\t<h4>Poser une question</h4>
  5917. \t\t\t\t\t\t\t\t<form class=\"row contact_form\" method=\"post\" novalidate=\"novalidate\">
  5918. \t\t\t\t\t\t\t\t\t<div class=\"col-md-12\">
  5919. \t\t\t\t\t\t\t\t\t\t<div class=\"form-group\">
  5920. \t\t\t\t\t\t\t\t\t\t\t<textarea class=\"form-control\" name=\"comment\" id=\"comment\" rows=\"3\" placeholder=\"Votre question ou commentaire...\" required></textarea>
  5921. \t\t\t\t\t\t\t\t\t\t</div>
  5922. \t\t\t\t\t\t\t\t\t</div>
  5923. \t\t\t\t\t\t\t\t\t<div class=\"col-md-12 text-right\">
  5924. \t\t\t\t\t\t\t\t\t\t<button type=\"submit\" class=\"btn primary-btn\">Envoyer</button>
  5925. \t\t\t\t\t\t\t\t\t</div>
  5926. \t\t\t\t\t\t\t\t</form>
  5927. \t\t\t\t\t\t\t</div>
  5928. \t\t\t\t\t\t{% else %}
  5929. \t\t\t\t\t\t\t<p class=\"text-center\">
  5930. \t\t\t\t\t\t\t\t<a href=\"{{ path('ui_app_login') }}\" class=\"primary-btn\">Connectez-vous</a>
  5931. \t\t\t\t\t\t\t\tpour poser une question ou laisser un commentaire.
  5932. \t\t\t\t\t\t\t</p>
  5933. \t\t\t\t\t\t{% endif %}
  5934. \t\t\t\t\t</div>
  5935. \t\t\t\t</div>
  5936. \t\t\t\t<div class=\"tab-pane fade\" id=\"review\" role=\"tabpanel\" aria-labelledby=\"review-tab\">
  5937. \t\t\t\t\t<div class=\"review-wrapper\">
  5938. \t\t\t\t\t\t<div class=\"row\">
  5939. \t\t\t\t\t\t\t<div class=\"col-lg-6\">
  5940. \t\t\t\t\t\t\t\t<div class=\"row total_rate\">
  5941. \t\t\t\t\t\t\t\t\t<div class=\"col-6\">
  5942. \t\t\t\t\t\t\t\t\t\t<div class=\"box_total\">
  5943. \t\t\t\t\t\t\t\t\t\t\t<h5>Note globale</h5>
  5944. \t\t\t\t\t\t\t\t\t\t\t<h4>{{ product.averageRating ? product.averageRating|number_format(1, '.', ',') : '0.0' }}</h4>
  5945. \t\t\t\t\t\t\t\t\t\t\t<h6>({{ product.reviewCount ?? 0 }}
  5946. \t\t\t\t\t\t\t\t\t\t\t\tAvis)</h6>
  5947. \t\t\t\t\t\t\t\t\t\t</div>
  5948. \t\t\t\t\t\t\t\t\t</div>
  5949. \t\t\t\t\t\t\t\t\t<div class=\"col-6\">
  5950. \t\t\t\t\t\t\t\t\t\t<div class=\"rating_list\">
  5951. \t\t\t\t\t\t\t\t\t\t\t<h3>Basé sur
  5952. \t\t\t\t\t\t\t\t\t\t\t\t{{ product.reviewCount ?? 0 }}
  5953. \t\t\t\t\t\t\t\t\t\t\t\tavis</h3>
  5954. \t\t\t\t\t\t\t\t\t\t\t<div class=\"rating-summary\">
  5955. \t\t\t\t\t\t\t\t\t\t\t\t{% if product.averageRating %}
  5956. \t\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"rating-display mb-3\">
  5957. \t\t\t\t\t\t\t\t\t\t\t\t\t\t{% for i in 1..5 %}
  5958. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<i class=\"fa fa-star{% if i <= product.averageRating %}{% else %}-o{% endif %}\" style=\"color: #ffa200; font-size: 1.2rem;\"></i>
  5959. \t\t\t\t\t\t\t\t\t\t\t\t\t\t{% endfor %}
  5960. \t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"ms-2\" style=\"font-size: 1.1rem; font-weight: bold;\">{{ product.averageRating|number_format(1, '.', ',') }}
  5961. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/ 5.0</span>
  5962. \t\t\t\t\t\t\t\t\t\t\t\t\t</div>
  5963. \t\t\t\t\t\t\t\t\t\t\t\t{% else %}
  5964. \t\t\t\t\t\t\t\t\t\t\t\t\t<p class=\"text-muted\">Aucune note disponible</p>
  5965. \t\t\t\t\t\t\t\t\t\t\t\t{% endif %}
  5966. \t\t\t\t\t\t\t\t\t\t\t</div>
  5967. \t\t\t\t\t\t\t\t\t\t</div>
  5968. \t\t\t\t\t\t\t\t\t</div>
  5969. \t\t\t\t\t\t\t\t</div>
  5970. \t\t\t\t\t\t\t\t<div class=\"review_list\">
  5971. \t\t\t\t\t\t\t\t\t{% if product.reviewCount and product.reviewCount > 0 %}
  5972. \t\t\t\t\t\t\t\t\t\t<div class=\"alert alert-info\">
  5973. \t\t\t\t\t\t\t\t\t\t\t<i class=\"lnr lnr-info-circle\"></i>
  5974. \t\t\t\t\t\t\t\t\t\t\tLe système d'affichage détaillé des avis sera disponible prochainement. 
  5975. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tNote actuelle :
  5976. \t\t\t\t\t\t\t\t\t\t\t{{ product.averageRating|number_format(1, '.', ',') }}
  5977. \t\t\t\t\t\t\t\t\t\t\t/ 5.0 basée sur
  5978. \t\t\t\t\t\t\t\t\t\t\t{{ product.reviewCount }}
  5979. \t\t\t\t\t\t\t\t\t\t\tavis.
  5980. \t\t\t\t\t\t\t\t\t\t</div>
  5981. \t\t\t\t\t\t\t\t\t{% else %}
  5982. \t\t\t\t\t\t\t\t\t\t<div class=\"alert alert-info\">
  5983. \t\t\t\t\t\t\t\t\t\t\t<i class=\"lnr lnr-info-circle\"></i>
  5984. \t\t\t\t\t\t\t\t\t\t\tAucun avis pour ce produit pour le moment. Soyez le premier à laisser un avis après votre achat !
  5985. \t\t\t\t\t\t\t\t\t\t</div>
  5986. \t\t\t\t\t\t\t\t\t{% endif %}
  5987. \t\t\t\t\t\t\t\t</div>
  5988. \t\t\t\t\t\t\t</div>
  5989. \t\t\t\t\t\t\t<div class=\"col-lg-6\">
  5990. \t\t\t\t\t\t\t\t<div class=\"review_box\">
  5991. \t\t\t\t\t\t\t\t\t<h4>Laisser un avis</h4>
  5992. \t\t\t\t\t\t\t\t\t{% if app.user %}
  5993. \t\t\t\t\t\t\t\t\t\t<p class=\"text-muted\">Vous pouvez laisser un avis après avoir acheté ce produit.</p>
  5994. \t\t\t\t\t\t\t\t\t\t<form class=\"row contact_form\" method=\"post\" novalidate=\"novalidate\">
  5995. \t\t\t\t\t\t\t\t\t\t\t<div class=\"col-md-12\">
  5996. \t\t\t\t\t\t\t\t\t\t\t\t<div class=\"form-group\">
  5997. \t\t\t\t\t\t\t\t\t\t\t\t\t<label>Votre note</label>
  5998. \t\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"rating-input mb-3\" style=\"display: flex; gap: 5px; flex-direction: row-reverse; justify-content: flex-end;\">
  5999. \t\t\t\t\t\t\t\t\t\t\t\t\t\t{% for i in 5..1 %}
  6000. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<input type=\"radio\" name=\"rating\" id=\"rating{{ i }}\" value=\"{{ i }}\" required style=\"display: none;\">
  6001. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"rating{{ i }}\" class=\"star-label\" style=\"cursor: pointer;\">
  6002. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<i class=\"fa fa-star-o\" style=\"color: #ccc; font-size: 1.5rem;\"></i>
  6003. \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</label>
  6004. \t\t\t\t\t\t\t\t\t\t\t\t\t\t{% endfor %}
  6005. \t\t\t\t\t\t\t\t\t\t\t\t\t</div>
  6006. \t\t\t\t\t\t\t\t\t\t\t\t</div>
  6007. \t\t\t\t\t\t\t\t\t\t\t</div>
  6008. \t\t\t\t\t\t\t\t\t\t\t<div class=\"col-md-12\">
  6009. \t\t\t\t\t\t\t\t\t\t\t\t<div class=\"form-group\">
  6010. \t\t\t\t\t\t\t\t\t\t\t\t\t<textarea class=\"form-control\" name=\"review\" id=\"review\" rows=\"5\" placeholder=\"Votre avis...\" required onfocus=\"this.placeholder = ''\" onblur=\"this.placeholder = 'Votre avis...'\"></textarea>
  6011. \t\t\t\t\t\t\t\t\t\t\t\t</div>
  6012. \t\t\t\t\t\t\t\t\t\t\t</div>
  6013. \t\t\t\t\t\t\t\t\t\t\t<div class=\"col-md-12 text-right\">
  6014. \t\t\t\t\t\t\t\t\t\t\t\t<button type=\"submit\" class=\"btn primary-btn\">Publier l'avis</button>
  6015. \t\t\t\t\t\t\t\t\t\t\t</div>
  6016. \t\t\t\t\t\t\t\t\t\t</form>
  6017. \t\t\t\t\t\t\t\t\t{% else %}
  6018. \t\t\t\t\t\t\t\t\t\t<p class=\"text-center\">
  6019. \t\t\t\t\t\t\t\t\t\t\t<a href=\"{{ path('ui_app_login') }}\" class=\"primary-btn\">Connectez-vous</a>
  6020. \t\t\t\t\t\t\t\t\t\t\tpour laisser un avis sur ce produit.
  6021. \t\t\t\t\t\t\t\t\t\t</p>
  6022. \t\t\t\t\t\t\t\t\t{% endif %}
  6023. \t\t\t\t\t\t\t\t</div>
  6024. \t\t\t\t\t\t\t</div>
  6025. \t\t\t\t\t\t</div>
  6026. \t\t\t\t\t</div>
  6027. \t\t\t\t</div>
  6028. \t\t\t</div>
  6029. \t\t</div>
  6030. \t</section>
  6031. \t<!--================End Product Description Area =================-->
  6032. \t<script>
  6033. \t\t// Données des variantes du produit
  6034. \t\tconst productVariants = {{ product.variants|length > 0 ? product.variants|map(v => {
  6035. \t\t\t'id': v.id,
  6036. \t\t\t'sku': v.sku,
  6037. \t\t\t'price': v.price,
  6038. \t\t\t'compareAtPrice': v.compareAtPrice,
  6039. \t\t\t'stock': v.stock,
  6040. \t\t\t'stockStatus': v.stockStatus,
  6041. \t\t\t'isActive': v.isActive,
  6042. \t\t\t'images': v.images,
  6043. \t\t\t'attributeValues': v.attributeValues|map(av => {
  6044. \t\t\t\t'attributeId': av.attribute.id,
  6045. \t\t\t\t'attributeSlug': av.attribute.slug,
  6046. \t\t\t\t'valueId': av.id,
  6047. \t\t\t\t'value': av.value
  6048. \t\t\t})|to_array
  6049. \t\t})|json_encode|raw : '[]' }};
  6050. \t\t// Gestion de la sélection de variantes
  6051. \t\tlet selectedAttributes = {};
  6052. \t\tlet currentVariant = null;
  6053. \t\t// Initialiser les onglets Bootstrap
  6054. document.addEventListener('DOMContentLoaded', function () { // Activer les onglets Bootstrap 5
  6055. const triggerTabList = document.querySelectorAll('#myTab button[data-bs-toggle=\"tab\"]');
  6056. triggerTabList.forEach(triggerEl => {
  6057. const tabTrigger = new bootstrap.Tab(triggerEl);
  6058. triggerEl.addEventListener('click', event => {
  6059. event.preventDefault();
  6060. tabTrigger.show();
  6061. });
  6062. });
  6063. // Gestion des étoiles pour les avis
  6064. const ratingInputs = document.querySelectorAll('.rating-input input[type=\"radio\"]');
  6065. const starLabels = document.querySelectorAll('.rating-input .star-label');
  6066. ratingInputs.forEach((input, index) => {
  6067. input.addEventListener('change', function () {
  6068. const rating = parseInt(this.value);
  6069. starLabels.forEach((label) => { // Trouver l'input associé à ce label
  6070. const labelInput = label.previousElementSibling;
  6071. if (labelInput && labelInput.type === 'radio') {
  6072. const starValue = parseInt(labelInput.value);
  6073. const star = label.querySelector('i');
  6074. if (starValue <= rating) {
  6075. star.style.color = '#ffa200';
  6076. star.classList.remove('fa-star-o');
  6077. star.classList.add('fa-star');
  6078. } else {
  6079. star.style.color = '#ccc';
  6080. star.classList.remove('fa-star');
  6081. star.classList.add('fa-star-o');
  6082. }
  6083. }
  6084. });
  6085. });
  6086. });
  6087. // Pré-remplir les étoiles au survol
  6088. starLabels.forEach((label) => {
  6089. label.addEventListener('mouseenter', function () { // Trouver l'input associé à ce label
  6090. const input = label.previousElementSibling;
  6091. if (input && input.type === 'radio') {
  6092. const rating = parseInt(input.value);
  6093. starLabels.forEach((l) => {
  6094. const lInput = l.previousElementSibling;
  6095. if (lInput && lInput.type === 'radio') {
  6096. const starValue = parseInt(lInput.value);
  6097. const star = l.querySelector('i');
  6098. if (starValue <= rating) {
  6099. star.style.color = '#ffa200';
  6100. star.classList.remove('fa-star-o');
  6101. star.classList.add('fa-star');
  6102. } else {
  6103. star.style.color = '#ccc';
  6104. star.classList.remove('fa-star');
  6105. star.classList.add('fa-star-o');
  6106. }
  6107. }
  6108. });
  6109. }
  6110. });
  6111. });
  6112. const ratingContainer = document.querySelector('.rating-input');
  6113. if (ratingContainer) {
  6114. ratingContainer.addEventListener('mouseleave', function () {
  6115. const checkedInput = document.querySelector('.rating-input input[type=\"radio\"]:checked');
  6116. if (checkedInput) {
  6117. checkedInput.dispatchEvent(new Event('change'));
  6118. } else {
  6119. starLabels.forEach(label => {
  6120. const star = label.querySelector('i');
  6121. star.style.color = '#ccc';
  6122. });
  6123. }
  6124. });
  6125. }
  6126. });
  6127. \t// Gestion de la sélection de variantes
  6128. \tif (typeof productVariants !== 'undefined' && productVariants.length > 0) {
  6129. \t\t// Initialiser avec la première variante active
  6130. \t\tconst firstVariant = productVariants.find(v => v.isActive);
  6131. \t\tif (firstVariant) {
  6132. \t\t\tfirstVariant.attributeValues.forEach(av => {
  6133. \t\t\t\tselectedAttributes[av.attributeSlug] = av.valueId;
  6134. \t\t\t});
  6135. \t\t\tupdateVariantDisplay(firstVariant);
  6136. \t\t} else {
  6137. \t\t\t// Si aucune variante active, afficher le prix de base
  6138. \t\t\tconst priceEl = document.getElementById('main-unit-price');
  6139. \t\t\tif (priceEl) {
  6140. \t\t\t\tpriceEl.textContent = '{{ product.price|number_format(2, '.', ' ') }}';
  6141. \t\t\t}
  6142. \t\t}
  6143. \t\t// Écouter les clics sur les options de variantes
  6144. \t\tdocument.querySelectorAll('.variant-option').forEach(option => {
  6145. \t\t\toption.addEventListener('click', function() {
  6146. \t\t\t\tconst attributeSlug = this.getAttribute('data-attribute');
  6147. \t\t\t\tconst valueId = parseInt(this.getAttribute('data-value-id'));
  6148. \t\t\t\tconst value = this.getAttribute('data-value');
  6149. \t\t\t\t// Mettre à jour la sélection visuelle
  6150. \t\t\t\tdocument.querySelectorAll(`[data-attribute=\"\${attributeSlug}\"]`).forEach(opt => {
  6151. \t\t\t\t\topt.classList.remove('selected', 'active');
  6152. \t\t\t\t\tif (opt.classList.contains('variant-color-option')) {
  6153. \t\t\t\t\t\topt.style.borderColor = '#ddd';
  6154. \t\t\t\t\t\tconst checkIcon = opt.querySelector('.check-icon');
  6155. \t\t\t\t\t\tif (checkIcon) checkIcon.remove();
  6156. \t\t\t\t\t}
  6157. \t\t\t\t});
  6158. \t\t\t\tthis.classList.add('selected', 'active');
  6159. \t\t\t\tif (this.classList.contains('variant-color-option')) {
  6160. \t\t\t\t\tthis.style.borderColor = '#007bff';
  6161. \t\t\t\t\tconst checkIcon = document.createElement('span');
  6162. \t\t\t\t\tcheckIcon.className = 'check-icon';
  6163. \t\t\t\t\tconst bgColor = this.style.backgroundColor || '';
  6164. \t\t\t\t\tconst isDark = bgColor && getContrastColor(bgColor) < 128;
  6165. \t\t\t\t\tcheckIcon.style.cssText = 'position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: ' + (isDark ? 'white' : 'black') + '; font-size: 18px;';
  6166. \t\t\t\t\tcheckIcon.textContent = '✓';
  6167. \t\t\t\t\tthis.appendChild(checkIcon);
  6168. \t\t\t\t}
  6169. \t\t\t\t// Mettre à jour les attributs sélectionnés
  6170. \t\t\t\tselectedAttributes[attributeSlug] = valueId;
  6171. \t\t\t\tconst selectedSpan = document.getElementById(`selected-\${attributeSlug}`);
  6172. \t\t\t\tif (selectedSpan) {
  6173. \t\t\t\t\tselectedSpan.textContent = value;
  6174. \t\t\t\t}
  6175. \t\t\t\t// Trouver la variante correspondante
  6176. \t\t\t\tconst matchingVariant = findMatchingVariant();
  6177. \t\t\t\tif (matchingVariant) {
  6178. \t\t\t\t\tupdateVariantDisplay(matchingVariant);
  6179. \t\t\t\t} else {
  6180. \t\t\t\t\t// Aucune variante correspondante trouvée - afficher le produit de base
  6181. \t\t\t\t\tresetToBaseProduct();
  6182. \t\t\t\t}
  6183. \t\t\t});
  6184. \t\t});
  6185. \t}
  6186. \tfunction findMatchingVariant() {
  6187. \t\tif (!productVariants || productVariants.length === 0) return null;
  6188. \t\t
  6189. \t\treturn productVariants.find(variant => {
  6190. \t\t\tif (!variant.isActive) return false;
  6191. \t\t\t
  6192. \t\t\tconst variantAttributes = {};
  6193. \t\t\tvariant.attributeValues.forEach(av => {
  6194. \t\t\t\tvariantAttributes[av.attributeSlug] = av.valueId;
  6195. \t\t\t});
  6196. \t\t\t// Vérifier si tous les attributs sélectionnés correspondent
  6197. \t\t\tfor (const [attrSlug, valueId] of Object.entries(selectedAttributes)) {
  6198. \t\t\t\tif (!variantAttributes[attrSlug] || variantAttributes[attrSlug] !== valueId) {
  6199. \t\t\t\t\treturn false;
  6200. \t\t\t\t}
  6201. \t\t\t}
  6202. \t\t\t// Vérifier que le nombre d'attributs correspond
  6203. \t\t\treturn Object.keys(variantAttributes).length === Object.keys(selectedAttributes).length;
  6204. \t\t});
  6205. \t}
  6206. \tfunction updateVariantDisplay(variant) {
  6207. \t\tcurrentVariant = variant;
  6208. \t\t
  6209. \t\t// Mettre à jour le prix
  6210. \t\tconst priceElement = document.getElementById('main-unit-price');
  6211. \t\tconst variantPriceElement = document.getElementById('variant-price');
  6212. \t\tif (priceElement) {
  6213. \t\t\tpriceElement.textContent = variant.price.toFixed(2).replace(/\\B(?=(\\d{3})+(?!\\d))/g, ' ');
  6214. \t\t}
  6215. \t\tif (variantPriceElement) {
  6216. \t\t\tvariantPriceElement.textContent = variant.price.toFixed(2).replace(/\\B(?=(\\d{3})+(?!\\d))/g, ' ') + ' HTG';
  6217. \t\t}
  6218. \t\t// Mettre à jour le stock
  6219. \t\tconst stockElement = document.getElementById('variant-stock');
  6220. \t\tif (stockElement) {
  6221. \t\t\tif (variant.stock > 0) {
  6222. \t\t\t\tstockElement.textContent = variant.stock + ' disponible(s)';
  6223. \t\t\t\tstockElement.className = 'variant-stock text-success';
  6224. \t\t\t} else {
  6225. \t\t\t\tstockElement.textContent = 'Rupture de stock';
  6226. \t\t\t\tstockElement.className = 'variant-stock text-danger';
  6227. \t\t\t}
  6228. \t\t}
  6229. \t\t// Mettre à jour les champs cachés
  6230. \t\tconst variantIdInput = document.getElementById('selected-variant-id');
  6231. \t\tconst variantSkuInput = document.getElementById('selected-variant-sku');
  6232. \t\tif (variantIdInput) variantIdInput.value = variant.id;
  6233. \t\tif (variantSkuInput) variantSkuInput.value = variant.sku;
  6234. \t\t// Mettre à jour les images si disponibles
  6235. \t\tif (variant.images && variant.images.length > 0) {
  6236. \t\t\tconst mainImage = document.getElementById('main-product-image');
  6237. \t\t\tif (mainImage && variant.images[0]) {
  6238. \t\t\t\tmainImage.src = variant.images[0];
  6239. \t\t\t}
  6240. \t\t}
  6241. \t\t// Afficher les informations de la variante
  6242. \t\tconst variantInfo = document.getElementById('variant-info');
  6243. \t\tif (variantInfo) variantInfo.style.display = 'block';
  6244. \t\t// Mettre à jour la quantité maximale
  6245. \t\tconst qtyInput = document.getElementById('sst');
  6246. \t\tif (qtyInput) {
  6247. \t\t\tqtyInput.max = variant.stock;
  6248. \t\t}
  6249. \t}
  6250. \tfunction getContrastColor(hexColor) {
  6251. \t\t// Convertir hex en RGB et calculer la luminosité
  6252. \t\tconst rgb = hexColor.match(/\\d+/g);
  6253. \t\tif (rgb && rgb.length >= 3) {
  6254. \t\t\tconst r = parseInt(rgb[0]);
  6255. \t\t\tconst g = parseInt(rgb[1]);
  6256. \t\tconst b = parseInt(rgb[2]);
  6257. \t\treturn (r * 299 + g * 587 + b * 114) / 1000;
  6258. \t}
  6259. \treturn 128;
  6260. }
  6261. function resetToBaseProduct() {
  6262. \tcurrentVariant = null;
  6263. \t
  6264. \t// Réinitialiser les attributs sélectionnés
  6265. \tselectedAttributes = {};
  6266. \t
  6267. \t// Masquer les informations de variante
  6268. \tconst variantInfo = document.getElementById('variant-info');
  6269. \tif (variantInfo) variantInfo.style.display = 'none';
  6270. \t
  6271. \t// Réinitialiser le prix au prix de base
  6272. \tconst priceEl = document.getElementById('main-unit-price');
  6273. \tif (priceEl) priceEl.textContent = '{{ product.price|number_format(2, '.', ' ') }}';
  6274. \t
  6275. \t// Réinitialiser les champs cachés
  6276. \tconst variantIdInput = document.getElementById('selected-variant-id');
  6277. \tconst variantSkuInput = document.getElementById('selected-variant-sku');
  6278. \tif (variantIdInput) variantIdInput.value = '';
  6279. \tif (variantSkuInput) variantSkuInput.value = '';
  6280. \t
  6281. \t// Réinitialiser les sélections visuelles
  6282. \tdocument.querySelectorAll('.variant-option').forEach(opt => {
  6283. \t\topt.classList.remove('selected', 'active');
  6284. \t\tif (opt.classList.contains('variant-color-option')) {
  6285. \t\t\topt.style.borderColor = '#ddd';
  6286. \t\t\tconst checkIcon = opt.querySelector('.check-icon');
  6287. \t\t\tif (checkIcon) checkIcon.remove();
  6288. \t\t}
  6289. \t});
  6290. \t
  6291. \t// Réinitialiser les labels de sélection
  6292. \tdocument.querySelectorAll('.selected-variant-value').forEach(span => {
  6293. \t\tspan.textContent = '';
  6294. \t});
  6295. \t
  6296. \t// Réinitialiser les images au produit de base
  6297. \tconst mainImage = document.getElementById('main-product-image');
  6298. \tif (mainImage && typeof productImages !== 'undefined' && productImages.length > 0) {
  6299. \t\tmainImage.src = productImages[0];
  6300. \t}
  6301. \t
  6302. \t// Réinitialiser la quantité maximale
  6303. \tconst qtyInput = document.getElementById('sst');
  6304. \tif (qtyInput) {
  6305. \t\tqtyInput.max = {{ product.stock }};
  6306. \t}
  6307. }
  6308. </script>
  6309. \t{% if youMightAlsoLike|length > 0 %}
  6310. \t\t<section class=\"related-product-area section_gap_bottom py-5\" style=\"background: linear-gradient(to bottom, #f8f9fa 0%, #ffffff 100%);\">
  6311. \t\t\t<div class=\"container\">
  6312. \t\t\t\t<div class=\"row justify-content-center\">
  6313. \t\t\t\t\t<div class=\"col-lg-8 text-center\">
  6314. \t\t\t\t\t\t<div class=\"section-title\">
  6315. \t\t\t\t\t\t\t<h2 class=\"fw-bold mb-3\" style=\"font-size: 2.5rem; color: #2c3e50;\">Vous pourriez aussi aimer</h2>
  6316. \t\t\t\t\t\t\t<p class=\"text-muted\" style=\"font-size: 1.1rem;\">Produits sélectionnés pour vous en fonction de vos préférences</p>
  6317. \t\t\t\t\t\t</div>
  6318. \t\t\t\t\t</div>
  6319. \t\t\t\t</div>
  6320. \t\t\t\t<div class=\"row g-4\">
  6321. \t\t\t\t\t{% for relatedProduct in youMightAlsoLike %}
  6322. \t\t\t\t\t\t<div class=\"col-6 col-md-4 col-lg-3 mb-3\">
  6323. \t\t\t\t\t\t\t<div class=\"modern-product-card\">
  6324. \t\t\t\t\t\t\t\t<div class=\"product-image-wrapper\">
  6325. \t\t\t\t\t\t\t\t\t<a href=\"{{ path('ui_product_show', { slug: relatedProduct.slug }) }}\" class=\"product-image-link\">
  6326. \t\t\t\t\t\t\t\t\t\t{% if relatedProduct.images is defined and relatedProduct.images|length > 0 %}
  6327. \t\t\t\t\t\t\t\t\t\t\t<img src=\"{{ asset(relatedProduct.images[0]) }}\" alt=\"{{ relatedProduct.name }}\" class=\"product-image\">
  6328. \t\t\t\t\t\t\t\t\t\t{% else %}
  6329. \t\t\t\t\t\t\t\t\t\t\t<img src=\"{{ asset('ui/img/product/p1.jpg') }}\" alt=\"{{ relatedProduct.name }}\" class=\"product-image\">
  6330. \t\t\t\t\t\t\t\t\t\t{% endif %}
  6331. \t\t\t\t\t\t\t\t\t\t<div class=\"product-overlay\">
  6332. \t\t\t\t\t\t\t\t\t\t\t<span class=\"view-product-btn\">
  6333. \t\t\t\t\t\t\t\t\t\t\t\t<i class=\"ti ti-eye\"></i> Voir
  6334. \t\t\t\t\t\t\t\t\t\t\t</span>
  6335. \t\t\t\t\t\t\t\t\t\t</div>
  6336. \t\t\t\t\t\t\t\t\t</a>
  6337. \t\t\t\t\t\t\t\t\t<div class=\"product-badge\">
  6338. \t\t\t\t\t\t\t\t\t\t{% if relatedProduct.compareAtPrice and relatedProduct.compareAtPrice > relatedProduct.price %}
  6339. \t\t\t\t\t\t\t\t\t\t\t<span class=\"badge-discount\">
  6340. \t\t\t\t\t\t\t\t\t\t\t\t-{{ ((relatedProduct.compareAtPrice - relatedProduct.price) / relatedProduct.compareAtPrice * 100)|round }}%
  6341. \t\t\t\t\t\t\t\t\t\t\t</span>
  6342. \t\t\t\t\t\t\t\t\t\t{% endif %}
  6343. \t\t\t\t\t\t\t\t\t</div>
  6344. \t\t\t\t\t\t\t\t</div>
  6345. \t\t\t\t\t\t\t\t<div class=\"product-info\">
  6346. \t\t\t\t\t\t\t\t\t<h6 class=\"product-title\">
  6347. \t\t\t\t\t\t\t\t\t\t<a href=\"{{ path('ui_product_show', { slug: relatedProduct.slug }) }}\">{{ relatedProduct.name }}</a>
  6348. \t\t\t\t\t\t\t\t\t</h6>
  6349. \t\t\t\t\t\t\t\t\t{% if relatedProduct.shop %}
  6350. \t\t\t\t\t\t\t\t\t\t<div class=\"product-shop\">
  6351. \t\t\t\t\t\t\t\t\t\t\t<i class=\"ti ti-store\"></i>
  6352. \t\t\t\t\t\t\t\t\t\t\t<a href=\"{{ path('ui_shop_show', {'slug': relatedProduct.shop.slug}) }}\" class=\"shop-link\">{{ relatedProduct.shop.name }}</a>
  6353. \t\t\t\t\t\t\t\t\t\t</div>
  6354. \t\t\t\t\t\t\t\t\t{% endif %}
  6355. \t\t\t\t\t\t\t\t\t<div class=\"product-price-wrapper\">
  6356. \t\t\t\t\t\t\t\t\t\t<span class=\"product-price\">{{ relatedProduct.price|number_format(0, '.', ' ') }} HTG</span>
  6357. \t\t\t\t\t\t\t\t\t\t{% if relatedProduct.compareAtPrice and relatedProduct.compareAtPrice > relatedProduct.price %}
  6358. \t\t\t\t\t\t\t\t\t\t\t<span class=\"product-compare-price\">{{ relatedProduct.compareAtPrice|number_format(0, '.', ' ') }} HTG</span>
  6359. \t\t\t\t\t\t\t\t\t\t{% endif %}
  6360. \t\t\t\t\t\t\t\t\t</div>
  6361. \t\t\t\t\t\t\t\t\t<div class=\"product-actions\">
  6362. \t\t\t\t\t\t\t\t\t\t<a href=\"javascript:void(0)\" class=\"btn-add-to-cart\" data-product-id=\"{{ relatedProduct.id }}\" data-qty=\"1\" title=\"Ajouter au panier\">
  6363. \t\t\t\t\t\t\t\t\t\t\t<i class=\"ti ti-shopping-cart\"></i>
  6364. \t\t\t\t\t\t\t\t\t\t\t<span>Ajouter</span>
  6365. \t\t\t\t\t\t\t\t\t\t</a>
  6366. \t\t\t\t\t\t\t\t\t</div>
  6367. \t\t\t\t\t\t\t\t</div>
  6368. \t\t\t\t\t\t\t</div>
  6369. \t\t\t\t\t\t</div>
  6370. \t\t\t\t\t{% endfor %}
  6371. \t\t\t\t</div>
  6372. \t\t\t</div>
  6373. \t\t</section>
  6374. \t\t<style>
  6375. \t\t\t.modern-product-card {
  6376. \t\t\t\tbackground: #ffffff;
  6377. \t\t\t\tborder-radius: 16px;
  6378. \t\t\t\toverflow: hidden;
  6379. \t\t\t\tbox-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  6380. \t\t\t\ttransition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  6381. \t\t\t\theight: 100%;
  6382. \t\t\t\tdisplay: flex;
  6383. \t\t\t\tflex-direction: column;
  6384. \t\t\t\tposition: relative;
  6385. \t\t\t}
  6386. \t\t\t.modern-product-card:hover {
  6387. \t\t\t\ttransform: translateY(-8px);
  6388. \t\t\t\tbox-shadow: 0 12px 24px rgba(0, 0, 0, 0.15);
  6389. \t\t\t}
  6390. \t\t\t.product-image-wrapper {
  6391. \t\t\t\tposition: relative;
  6392. \t\t\t\twidth: 100%;
  6393. \t\t\t\theight: 250px;
  6394. \t\t\t\toverflow: hidden;
  6395. \t\t\t\tbackground: #f8f9fa;
  6396. \t\t\t}
  6397. \t\t\t.product-image {
  6398. \t\t\t\twidth: 100%;
  6399. \t\t\t\theight: 100%;
  6400. \t\t\t\tobject-fit: cover !important;
  6401. \t\t\t\tobject-position: center !important;
  6402. \t\t\t\ttransition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1);
  6403. \t\t\t}
  6404. \t\t\t.modern-product-card:hover .product-image {
  6405. \t\t\t\ttransform: scale(1.1);
  6406. \t\t\t}
  6407. \t\t\t.product-overlay {
  6408. \t\t\t\tposition: absolute;
  6409. \t\t\t\ttop: 0;
  6410. \t\t\t\tleft: 0;
  6411. \t\t\t\tright: 0;
  6412. \t\t\t\tbottom: 0;
  6413. \t\t\t\tbackground: rgba(0, 0, 0, 0.5);
  6414. \t\t\t\tdisplay: flex;
  6415. \t\t\t\talign-items: center;
  6416. \t\t\t\tjustify-content: center;
  6417. \t\t\t\topacity: 0;
  6418. \t\t\t\ttransition: opacity 0.3s ease;
  6419. \t\t\t}
  6420. \t\t\t.modern-product-card:hover .product-overlay {
  6421. \t\t\t\topacity: 1;
  6422. \t\t\t}
  6423. \t\t\t.view-product-btn {
  6424. \t\t\t\tcolor: white;
  6425. \t\t\t\tpadding: 12px 24px;
  6426. \t\t\t\tbackground: rgba(255, 255, 255, 0.2);
  6427. \t\t\t\tbackdrop-filter: blur(10px);
  6428. \t\t\t\tborder-radius: 8px;
  6429. \t\t\t\tfont-weight: 600;
  6430. \t\t\t\tdisplay: inline-flex;
  6431. \t\t\t\talign-items: center;
  6432. \t\t\t\tgap: 8px;
  6433. \t\t\t\ttransition: all 0.3s ease;
  6434. \t\t\t}
  6435. \t\t\t.view-product-btn:hover {
  6436. \t\t\t\tbackground: rgba(255, 255, 255, 0.3);
  6437. \t\t\t\ttransform: scale(1.05);
  6438. \t\t\t}
  6439. \t\t\t.product-badge {
  6440. \t\t\t\tposition: absolute;
  6441. \t\t\t\ttop: 12px;
  6442. \t\t\t\tright: 12px;
  6443. \t\t\t\tz-index: 2;
  6444. \t\t\t}
  6445. \t\t\t.badge-discount {
  6446. \t\t\t\tbackground: linear-gradient(135deg, #ff6b6b 0%, #ee5a6f 100%);
  6447. \t\t\t\tcolor: white;
  6448. \t\t\t\tpadding: 6px 12px;
  6449. \t\t\t\tborder-radius: 20px;
  6450. \t\t\t\tfont-size: 0.75rem;
  6451. \t\t\t\tfont-weight: 700;
  6452. \t\t\t\tbox-shadow: 0 2px 8px rgba(238, 90, 111, 0.4);
  6453. \t\t\t}
  6454. \t\t\t.product-info {
  6455. \t\t\t\tpadding: 20px;
  6456. \t\t\t\tflex-grow: 1;
  6457. \t\t\t\tdisplay: flex;
  6458. \t\t\t\tflex-direction: column;
  6459. \t\t\t}
  6460. \t\t\t.product-title {
  6461. \t\t\t\tmargin: 0 0 8px 0;
  6462. \t\t\t\tfont-size: 1rem;
  6463. \t\t\t\tfont-weight: 600;
  6464. \t\t\t\tline-height: 1.4;
  6465. \t\t\t\theight: 2.8em;
  6466. \t\t\t\toverflow: hidden;
  6467. \t\t\t\tdisplay: -webkit-box;
  6468. \t\t\t\t-webkit-line-clamp: 2;
  6469. \t\t\t\t-webkit-box-orient: vertical;
  6470. \t\t\t}
  6471. \t\t\t.product-title a {
  6472. \t\t\t\tcolor: #2c3e50;
  6473. \t\t\t\ttext-decoration: none;
  6474. \t\t\t\ttransition: color 0.3s ease;
  6475. \t\t\t}
  6476. \t\t\t.product-title a:hover {
  6477. \t\t\t\tcolor: #ffa200;
  6478. \t\t\t}
  6479. \t\t\t.product-shop {
  6480. \t\t\t\tfont-size: 0.85rem;
  6481. \t\t\t\tcolor: #6c757d;
  6482. \t\t\t\tmargin-bottom: 12px;
  6483. \t\t\t\tdisplay: flex;
  6484. \t\t\t\talign-items: center;
  6485. \t\t\t\tgap: 6px;
  6486. \t\t\t}
  6487. \t\t\t.product-shop i {
  6488. \t\t\t\tfont-size: 0.9rem;
  6489. \t\t\t}
  6490. \t\t\t.shop-link {
  6491. \t\t\t\tcolor: #6c757d;
  6492. \t\t\t\ttext-decoration: none;
  6493. \t\t\t\ttransition: color 0.3s ease;
  6494. \t\t\t}
  6495. \t\t\t.shop-link:hover {
  6496. \t\t\t\tcolor: #ffa200;
  6497. \t\t\t}
  6498. \t\t\t.product-price-wrapper {
  6499. \t\t\t\tmargin-bottom: 16px;
  6500. \t\t\t\tdisplay: flex;
  6501. \t\t\t\talign-items: center;
  6502. \t\t\t\tgap: 8px;
  6503. \t\t\t\tflex-wrap: wrap;
  6504. \t\t\t}
  6505. \t\t\t.product-price {
  6506. \t\t\t\tfont-size: 1.25rem;
  6507. \t\t\t\tfont-weight: 700;
  6508. \t\t\t\tcolor: #ffa200;
  6509. \t\t\t}
  6510. \t\t\t.product-compare-price {
  6511. \t\t\t\tfont-size: 0.9rem;
  6512. \t\t\t\tcolor: #adb5bd;
  6513. \t\t\t\ttext-decoration: line-through;
  6514. \t\t\t}
  6515. \t\t\t.product-actions {
  6516. \t\t\t\tmargin-top: auto;
  6517. \t\t\t}
  6518. \t\t\t/* Styles pour les boutons de la section \"Vous pourriez aussi aimer\" uniquement */
  6519. \t\t\t.modern-product-card .btn-add-to-cart {
  6520. \t\t\t\twidth: 100%;
  6521. \t\t\t\tpadding: 12px;
  6522. \t\t\t\tbackground: linear-gradient(135deg, #ffa200 0%, #e8910a 100%);
  6523. \t\t\t\tcolor: white;
  6524. \t\t\t\tborder: none;
  6525. \t\t\t\tborder-radius: 10px;
  6526. \t\t\t\tfont-weight: 600;
  6527. \t\t\t\tdisplay: flex;
  6528. \t\t\t\talign-items: center;
  6529. \t\t\t\tjustify-content: center;
  6530. \t\t\t\tgap: 8px;
  6531. \t\t\t\ttext-decoration: none;
  6532. \t\t\t\ttransition: all 0.3s ease;
  6533. \t\t\t\tcursor: pointer;
  6534. \t\t\t}
  6535. \t\t\t.modern-product-card .btn-add-to-cart:hover {
  6536. \t\t\t\tbackground: linear-gradient(135deg, #e8910a 0%, #d6820a 100%);
  6537. \t\t\t\ttransform: translateY(-2px);
  6538. \t\t\t\tbox-shadow: 0 4px 12px rgba(255, 162, 0, 0.4);
  6539. \t\t\t\tcolor: white;
  6540. \t\t\t}
  6541. \t\t\t/* Le bouton principal garde son design original */
  6542. \t\t\t.card_area .btn-add-to-cart {
  6543. \t\t\t\twidth: auto;
  6544. \t\t\t\tdisplay: inline-flex;
  6545. \t\t\t}
  6546. \t\t\t.modern-product-card .btn-add-to-cart:active {
  6547. \t\t\t\ttransform: translateY(0);
  6548. \t\t\t}
  6549. \t\t\t.modern-product-card .btn-add-to-cart i {
  6550. \t\t\t\tfont-size: 1.1rem;
  6551. \t\t\t}
  6552. \t\t\t/* Responsive adjustments */
  6553. \t\t\t@media (max-width: 768px) {
  6554. \t\t\t\t.product-image-wrapper {
  6555. \t\t\t\t\theight: 200px;
  6556. \t\t\t\t}
  6557. \t\t\t\t.product-info {
  6558. \t\t\t\t\tpadding: 16px;
  6559. \t\t\t\t}
  6560. \t\t\t\t.product-title {
  6561. \t\t\t\t\tfont-size: 0.95rem;
  6562. \t\t\t\t}
  6563. \t\t\t\t.product-price {
  6564. \t\t\t\t\tfont-size: 1.1rem;
  6565. \t\t\t\t}
  6566. \t\t\t\t.section-title h2 {
  6567. \t\t\t\t\tfont-size: 2rem !important;
  6568. \t\t\t\t}
  6569. \t\t\t}
  6570. \t\t\t@media (max-width: 576px) {
  6571. \t\t\t\t.product-image-wrapper {
  6572. \t\t\t\t\theight: 190px;
  6573. \t\t\t\t}
  6574. \t\t\t\t.product-info {
  6575. \t\t\t\t\tpadding: 14px;
  6576. \t\t\t\t}
  6577. \t\t\t\t.btn-add-to-cart {
  6578. \t\t\t\t\tpadding: 10px;
  6579. \t\t\t\t\tfont-size: 0.9rem;
  6580. \t\t\t\t}
  6581. \t\t\t}
  6582. \t\t\t/* Ensure fixed height for cards */
  6583. \t\t\t.col-6.col-md-4.col-lg-3 {
  6584. \t\t\t\tdisplay: flex;
  6585. \t\t\t}
  6586. \t\t\t.modern-product-card {
  6587. \t\t\t\twidth: 100%;
  6588. \t\t\t}
  6589. \t\t\t/* Loading state for add to cart button */
  6590. \t\t\t.btn-add-to-cart.loading {
  6591. \t\t\t\topacity: 0.7;
  6592. \t\t\t\tpointer-events: none;
  6593. \t\t\t}
  6594. \t\t\t.btn-add-to-cart.loading i {
  6595. \t\t\t\tanimation: spin 1s linear infinite;
  6596. \t\t\t}
  6597. \t\t\t@keyframes spin {
  6598. \t\t\t\tfrom { transform: rotate(0deg); }
  6599. \t\t\t\tto { transform: rotate(360deg); }
  6600. \t\t\t}
  6601. \t\t\t/* Success state - vert pour tous les boutons */
  6602. \t\t\t.btn-add-to-cart.success {
  6603. \t\t\t\tbackground: linear-gradient(135deg, #28a745 0%, #20c997 100%) !important;
  6604. \t\t\t}
  6605. \t\t\t/* Le bouton principal garde son style original même en success */
  6606. \t\t\t.card_area .btn-add-to-cart.success {
  6607. \t\t\t\tbackground: linear-gradient(135deg, #28a745 0%, #20c997 100%) !important;
  6608. \t\t\t}
  6609. \t{% endif %}
  6610. \t<script src=\"/ui/js/vendor/jquery-2.2.4.min.js\"></script>
  6611. \t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js\" integrity=\"sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4\" crossorigin=\"anonymous\"></script>
  6612. \t<script src=\"/ui/js/vendor/bootstrap.min.js\"></script>
  6613. \t<script src=\"/ui/js/jquery.ajaxchimp.min.js\"></script>
  6614. \t<script src=\"/ui/js/jquery.nice-select.min.js\"></script>
  6615. \t<script src=\"/ui/js/jquery.sticky.js\"></script>
  6616. \t<script src=\"/ui/js/nouislider.min.js\"></script>
  6617. \t<script src=\"/ui/js/jquery.magnific-popup.min.js\"></script>
  6618. \t<script src=\"/ui/js/owl.carousel.min.js\"></script>
  6619. \t<!--gmaps Js-->
  6620. \t<script src=\"https://maps.googleapis.com/maps/api/js?key=AIzaSyCjCGmQ0Uq4exrzdcL6rvxywDDOvfAu6eE\"></script>
  6621. \t<script src=\"/ui/js/gmaps.min.js\"></script>
  6622. \t<script src=\"/ui/js/main.js\"></script>
  6623. \t
  6624. \t<!-- Product Image Navigation - Chargé en dernier pour éviter les conflits -->
  6625. \t<script src=\"/ui/js/product-image-navigation.js\"></script>
  6626. \t
  6627. \t<script>
  6628. // Variables globales pour la navigation des images (utilisées par le script externe)
  6629. window.productImages = [];
  6630. window.currentImageIndex = 0;
  6631. let mainImageElement, currentIndexElement, indicatorsElements;
  6632. // Test pour vérifier que les fonctions sont définies
  6633. window.testImageNavigation = function() {
  6634. console.log('Testing image navigation functions...');
  6635. if (window.productImageNav) {
  6636. console.log('productImageNav object:', window.productImageNav);
  6637. console.log('nextImage function:', typeof window.productImageNav.nextImage);
  6638. console.log('prevImage function:', typeof window.productImageNav.prevImage);
  6639. console.log('changeMainImageByIndex function:', typeof window.productImageNav.changeMainImageByIndex);
  6640. console.log('State:', window.productImageNav.getState());
  6641. } else {
  6642. console.warn('productImageNav not available');
  6643. }
  6644. };
  6645. // Fonction pour nettoyer le cache PWA et désenregistrer le Service Worker
  6646. window.clearPWACache = function() {
  6647. console.log('🧹 Nettoyage du cache PWA...');
  6648. // Désenregistrer tous les Service Workers
  6649. if ('serviceWorker' in navigator) {
  6650. navigator.serviceWorker.getRegistrations().then(function(registrations) {
  6651. for(let registration of registrations) {
  6652. console.log('Désenregistrement du Service Worker:', registration.scope);
  6653. registration.unregister().then(function(boolean) {
  6654. console.log('Service Worker désenregistré:', boolean);
  6655. });
  6656. }
  6657. });
  6658. }
  6659. // Vider tous les caches
  6660. if ('caches' in window) {
  6661. caches.keys().then(function(names) {
  6662. for (let name of names) {
  6663. console.log('Suppression du cache:', name);
  6664. caches.delete(name);
  6665. }
  6666. });
  6667. }
  6668. // Forcer le rechargement de la page après nettoyage
  6669. setTimeout(function() {
  6670. console.log('🔄 Rechargement de la page...');
  6671. window.location.reload(true);
  6672. }, 1000);
  6673. };
  6674. console.log('💡 Pour nettoyer le cache PWA, tapez: clearPWACache() dans la console');
  6675. // Fonction pour vérifier l'état du cache PWA
  6676. window.checkPWACache = function() {
  6677. console.log('🔍 Vérification de l\\'état PWA...');
  6678. if ('serviceWorker' in navigator) {
  6679. navigator.serviceWorker.getRegistrations().then(function(registrations) {
  6680. console.log('Service Workers enregistrés:', registrations.length);
  6681. registrations.forEach(function(registration, index) {
  6682. console.log(`SW \${index + 1}:`, registration.scope, registration.active ? 'ACTIF' : 'INACTIF');
  6683. });
  6684. });
  6685. } else {
  6686. console.log('Service Worker non supporté');
  6687. }
  6688. if ('caches' in window) {
  6689. caches.keys().then(function(names) {
  6690. console.log('Caches disponibles:', names.length);
  6691. names.forEach(function(name) {
  6692. console.log('- Cache:', name);
  6693. });
  6694. });
  6695. } else {
  6696. console.log('Cache API non supporté');
  6697. }
  6698. };
  6699. console.log('💡 Pour vérifier l\\'état PWA, tapez: checkPWACache() dans la console');
  6700. // Nettoyage automatique du cache PWA pour les tests (à supprimer en production)
  6701. if (window.location.search.includes('clearcache')) {
  6702. console.log('🧹 Nettoyage automatique du cache PWA demandé via URL');
  6703. clearPWACache();
  6704. }
  6705. // NOTE: La navigation des images principales est gérée par product-image-navigation.js
  6706. // Les fonctions sont exposées via window.productImageNav pour le débogage
  6707. // NOTE: La navigation des images principales est gérée par product-image-navigation.js
  6708. // Le script externe initialise automatiquement les images depuis les thumbnails
  6709. // Pas besoin de réinitialiser ici pour éviter les conflits
  6710. // Gestion du carrousel de miniatures avec taille fixe carrée
  6711. const navUpBtn = document.getElementById('thumbnail-nav-up');
  6712. const navDownBtn = document.getElementById('thumbnail-nav-down');
  6713. const thumbnailsContainer = document.getElementById('product-thumbnails');
  6714. const thumbnailsWrapper = document.getElementById('thumbnails-wrapper');
  6715. const thumbnailItems = Array.from(document.querySelectorAll('.thumbnail-item'));
  6716. let currentThumbnailOffset = 0;
  6717. const thumbnailHeight = 90;
  6718. // 80px (hauteur) + 10px (gap)
  6719. // Calculer la hauteur disponible pour les miniatures dynamiquement
  6720. const thumbnailsEl = document.getElementById('product-thumbnails');
  6721. let containerHeight = thumbnailsEl ? thumbnailsEl.clientHeight : 520; // Hauteur par défaut si non disponible
  6722. let visibleThumbnails = Math.floor(containerHeight / thumbnailHeight);
  6723. // Recalculer après le chargement pour avoir la vraie hauteur
  6724. setTimeout(() => {
  6725. if (thumbnailsEl) {
  6726. containerHeight = thumbnailsEl.clientHeight;
  6727. visibleThumbnails = Math.floor(containerHeight / thumbnailHeight);
  6728. updateThumbnailsPosition();
  6729. }
  6730. }, 100);
  6731. function getCurrentIndex() {
  6732. const current = document.querySelector('.thumbnail-item.permanently-active') || document.querySelector('.thumbnail-item.active');
  6733. if (! current)
  6734. return 0;
  6735. const idxAttr = current.getAttribute('data-index');
  6736. if (idxAttr !== null) {
  6737.     return parseInt(idxAttr, 10);
  6738. }
  6739. const index = thumbnailItems.indexOf(current);
  6740. return index >= 0 ? index : 0;
  6741. }
  6742. function selectThumbnailByIndex(newIndex) {
  6743. if (! thumbnailItems.length) 
  6744. return;
  6745. const total = thumbnailItems.length;
  6746. if (newIndex < 0) 
  6747. newIndex = 0;
  6748. if (newIndex > total - 1) 
  6749. newIndex = total - 1;
  6750. // Reset classes
  6751. thumbnailItems.forEach(t => t.classList.remove('active', 'permanently-active'));
  6752. const target = thumbnailItems[newIndex];
  6753. if (! target) 
  6754. return;
  6755. target.classList.add('active', 'permanently-active');
  6756. // Utiliser la fonction du script externe si disponible
  6757. if (window.productImageNav && typeof window.productImageNav.changeMainImageByIndex === 'function') {
  6758. window.productImageNav.changeMainImageByIndex(newIndex);
  6759. } else {
  6760. // Fallback : changer l'image directement
  6761. const imageUrl = target.getAttribute('data-image');
  6762. const mainImg = document.getElementById('main-product-image');
  6763. if (mainImg && imageUrl) {
  6764. mainImg.src = imageUrl;
  6765. }
  6766. }
  6767. // Ajuster le carrousel pour voir la miniature sélectionnée
  6768. ensureThumbnailVisible(newIndex);
  6769. }
  6770. function ensureThumbnailVisible(index) {
  6771. if (! thumbnailsWrapper || ! thumbnailItems.length) 
  6772. return;
  6773. const targetTop = index * thumbnailHeight;
  6774. const visibleTop = currentThumbnailOffset * thumbnailHeight;
  6775. const visibleBottom = visibleTop + containerHeight;
  6776. // Si la miniature est au-dessus de la zone visible
  6777. if (targetTop < visibleTop) {
  6778. currentThumbnailOffset = index;
  6779. updateThumbnailsPosition();
  6780. }
  6781. // Si la miniature est en-dessous de la zone visible else if (targetTop + thumbnailHeight > visibleBottom) {
  6782. currentThumbnailOffset = Math.max(0, index - visibleThumbnails + 1);
  6783. updateThumbnailsPosition();
  6784. }
  6785. }
  6786. function updateThumbnailsPosition() {
  6787. if (!thumbnailsWrapper) 
  6788. return;
  6789. const maxOffset = Math.max(0, thumbnailItems.length - visibleThumbnails);
  6790. currentThumbnailOffset = Math.max(0, Math.min(currentThumbnailOffset, maxOffset));
  6791. thumbnailsWrapper.style.transform = `translateY(-\${
  6792. currentThumbnailOffset * thumbnailHeight
  6793. }px)`;
  6794. updateNavButtons();
  6795. }
  6796. function updateNavButtons() {
  6797. if (!thumbnailItems.length) 
  6798. return;
  6799. const maxOffset = Math.max(0, thumbnailItems.length - visibleThumbnails);
  6800. const canScrollUp = currentThumbnailOffset > 0;
  6801. const canScrollDown = currentThumbnailOffset < maxOffset;
  6802. if (navUpBtn) {
  6803. navUpBtn.classList.toggle('disabled', ! canScrollUp);
  6804. }
  6805. if (navDownBtn) {
  6806. navDownBtn.classList.toggle('disabled', ! canScrollDown);
  6807. }
  6808. }
  6809. // Navigation avec les boutons
  6810. if(navUpBtn) {
  6811. navUpBtn.addEventListener('click', function (e) {
  6812. e.preventDefault();
  6813. if (currentThumbnailOffset > 0) {
  6814. currentThumbnailOffset --;
  6815. updateThumbnailsPosition();
  6816. }
  6817. });
  6818. }
  6819. if(navDownBtn) {
  6820. navDownBtn.addEventListener('click', function (e) {
  6821. e.preventDefault();
  6822. const maxOffset = Math.max(0, thumbnailItems.length - visibleThumbnails);
  6823. if (currentThumbnailOffset < maxOffset) {
  6824. currentThumbnailOffset ++;
  6825. updateThumbnailsPosition();
  6826. }
  6827. });
  6828. }
  6829. // Initialiser le carrousel
  6830. if(thumbnailsWrapper && thumbnailItems.length > 0) {
  6831. updateThumbnailsPosition();
  6832. // S'assurer que la première miniature est visible
  6833. ensureThumbnailVisible(0);
  6834. // Sélectionner la première image par défaut si aucune n'est sélectionnée
  6835. if (!document.querySelector('.thumbnail-item.permanently-active') && !document.querySelector('.thumbnail-item.active')) {
  6836.     selectThumbnailByIndex(0);
  6837. }
  6838. // Initialiser l'index actuel via le script externe si disponible
  6839. // Le script externe product-image-navigation.js gère déjà l'initialisation
  6840. if (window.productImageNav && typeof window.productImageNav.getState === 'function') {
  6841. const state = window.productImageNav.getState();
  6842. if (state.productImages && state.productImages.length > 0) {
  6843. window.productImageNav.changeMainImageByIndex(0);
  6844. }
  6845. }
  6846. }
  6847. // NOTE: La navigation des images principales est maintenant gérée par product-image-navigation.js
  6848. // Ce fichier externe évite les conflits avec cart-modal.js et autres scripts
  6849. }, 100); // Fin du setTimeout
  6850. }); // Fin du DOMContentLoaded
  6851. // --- Prix de gros : calcul du prix unitaire dynamique ---
  6852. (function () {
  6853. const bulk = document.getElementById('bulk-pricing');
  6854. const qtyInputEl = document.getElementById('sst');
  6855. const unitPriceSpan = document.getElementById('unit-price-value');
  6856. const mainUnitPriceSpan = document.getElementById('main-unit-price');
  6857. const totalPriceSpan = document.getElementById('total-price-value');
  6858. const savingsAmountSpan = document.getElementById('savings-amount');
  6859. const savingsPercentSpan = document.getElementById('savings-percent');
  6860. const unitPriceInput = document.getElementById('unit-price-input');
  6861. const tierRowsTbody = document.getElementById('bulk-tier-rows');
  6862. if (! bulk || ! qtyInputEl || ! unitPriceSpan || ! mainUnitPriceSpan || ! unitPriceInput) 
  6863. return;
  6864. let tiers = [];
  6865. try {
  6866. tiers = JSON.parse(bulk.getAttribute('data-tiers') || '[]');
  6867. } catch (e) {
  6868. tiers = [];
  6869. }
  6870. if (!Array.isArray(tiers) || tiers.length === 0) 
  6871. return;
  6872. tiers.sort(function (a, b) {
  6873. return(a.min || 0) - (b.min || 0);
  6874. });
  6875. const basePrice = (function () {
  6876. const one = tiers.find(t => (t.min || 0) <= 1);
  6877. return one ? parseFloat(one.price) : parseFloat(tiers[0].price);
  6878. })();
  6879. function getUnitPriceForQty(qty) {
  6880. let candidate = tiers[0] || null;
  6881. for (let i = 0; i < tiers.length; i++) {
  6882. if (qty >= (tiers[i].min || 1)) {
  6883. candidate = tiers[i];
  6884. }
  6885. }
  6886. return candidate ? parseFloat(candidate.price) : (tiers[0] ? parseFloat(tiers[0].price) : basePrice);
  6887. }
  6888. function formatPrice(val) {
  6889. return(parseFloat(val) || 0).toFixed(2);
  6890. }
  6891. function highlightActiveTier(qty) {
  6892. if (! tierRowsTbody) 
  6893. return;
  6894. const rows = tierRowsTbody.querySelectorAll('tr');
  6895. rows.forEach(r => r.classList.remove('table-warning'));
  6896. let activeRow = null;
  6897. rows.forEach(r => {
  6898. const m = parseInt(r.getAttribute('data-min'), 10) || 1;
  6899. if (qty >= m) 
  6900. activeRow = r;
  6901. });
  6902. if (activeRow) 
  6903. activeRow.classList.add('table-warning');
  6904. }
  6905. function refreshPrices() {
  6906. const qty = Math.max(1, parseInt(qtyInputEl.value, 10) || 1);
  6907. const unit = getUnitPriceForQty(qty);
  6908. const total = unit * qty;
  6909. const saveAmount = Math.max(0, (basePrice - unit) * qty);
  6910. const savePercent = Math.max(0, 100 * (basePrice - unit) / basePrice);
  6911. unitPriceSpan.textContent = formatPrice(unit) + ' HTG';
  6912. mainUnitPriceSpan.textContent = formatPrice(unit);
  6913. if (totalPriceSpan) 
  6914. totalPriceSpan.textContent = formatPrice(total);
  6915. if (savingsAmountSpan) 
  6916. savingsAmountSpan.textContent = formatPrice(saveAmount);
  6917. if (savingsPercentSpan) 
  6918. savingsPercentSpan.textContent = Math.round(savePercent);
  6919. unitPriceInput.value = formatPrice(unit);
  6920. highlightActiveTier(qty);
  6921. }
  6922. qtyInputEl.addEventListener('input', refreshPrices);
  6923. qtyInputEl.addEventListener('change', refreshPrices);
  6924. setTimeout(refreshPrices, 50);
  6925. setInterval(refreshPrices, 350);
  6926. })();
  6927. // --- /Prix de gros ---
  6928. // Améliorer les boutons de quantité avec gestion de l'état disabled
  6929. (function() {
  6930. const qtyInput = document.getElementById('sst');
  6931. const decreaseBtn = document.querySelector('.quantity-btn-decrease');
  6932. const increaseBtn = document.querySelector('.quantity-btn-increase');
  6933. if (!qtyInput || !decreaseBtn || !increaseBtn) return;
  6934. const maxStock = parseInt(qtyInput.getAttribute('max') || '99', 10);
  6935. function updateButtonStates() {
  6936. const currentValue = parseInt(qtyInput.value, 10) || 1;
  6937. // Désactiver le bouton decrease si la valeur est 1
  6938. if (currentValue <= 1) {
  6939. decreaseBtn.disabled = true;
  6940. } else {
  6941. decreaseBtn.disabled = false;
  6942. }
  6943. // Désactiver le bouton increase si la valeur est au maximum
  6944. if (currentValue >= maxStock) {
  6945. increaseBtn.disabled = true;
  6946. } else {
  6947. increaseBtn.disabled = false;
  6948. }
  6949. }
  6950. // Mettre à jour l'état des boutons au chargement
  6951. updateButtonStates();
  6952. // Mettre à jour l'état des boutons lors des changements
  6953. qtyInput.addEventListener('input', updateButtonStates);
  6954. qtyInput.addEventListener('change', updateButtonStates);
  6955. // Mettre à jour l'état après les clics sur les boutons
  6956. decreaseBtn.addEventListener('click', function() {
  6957. setTimeout(updateButtonStates, 10);
  6958. });
  6959. increaseBtn.addEventListener('click', function() {
  6960. setTimeout(updateButtonStates, 10);
  6961. });
  6962. })();
  6963. // Injection du prix unitaire dans l'ajout au panier
  6964. (function () {
  6965. const addToCartBtn = document.getElementById('add-to-cart-btn');
  6966. if (! addToCartBtn) 
  6967. return;
  6968. addToCartBtn.addEventListener('click', function () {
  6969. const unitPriceInput = document.getElementById('unit-price-input');
  6970. if (unitPriceInput) {
  6971. addToCartBtn.setAttribute('data-unit-price', unitPriceInput.value);
  6972. }
  6973. });
  6974. })();
  6975. // Fonction pour ouvrir le modal de zoom avec loader
  6976. function openImageZoom () {
  6977. const mainImage = document.getElementById('main-product-image');
  6978. const zoomModal = document.getElementById('image-zoom-modal');
  6979. const zoomImage = document.getElementById('zoom-modal-image');
  6980. const zoomLoader = document.getElementById('zoom-loader');
  6981. if (mainImage && zoomModal && zoomImage) { // Afficher le loader
  6982. if (zoomLoader) {
  6983. zoomLoader.style.display = 'flex';
  6984. }
  6985. // Masquer l'image et réinitialiser
  6986. zoomImage.classList.remove('loaded');
  6987. zoomImage.style.opacity = '0';
  6988. // Ouvrir le modal avec animation
  6989. zoomModal.classList.add('active');
  6990. document.body.style.overflow = 'hidden';
  6991. // Charger l'image
  6992. const imageUrl = mainImage.src;
  6993. const tempImage = new Image();
  6994. tempImage.onload = function () {
  6995. zoomImage.src = imageUrl;
  6996. // Masquer le loader et afficher l'image avec transition
  6997. setTimeout(function () {
  6998. if (zoomLoader) {
  6999. zoomLoader.style.display = 'none';
  7000. }
  7001. zoomImage.classList.add('loaded');
  7002. zoomImage.style.opacity = '1';
  7003. }, 200);
  7004. };
  7005. tempImage.onerror = function () {
  7006. if (zoomLoader) {
  7007. zoomLoader.style.display = 'none';
  7008. }
  7009. zoomImage.src = imageUrl;
  7010. zoomImage.classList.add('loaded');
  7011. };
  7012. tempImage.src = imageUrl;
  7013. }
  7014. }
  7015. // Fonction pour fermer le modal de zoom avec animation
  7016. function closeImageZoom () {
  7017. const zoomModal = document.getElementById('image-zoom-modal');
  7018. const zoomImage = document.getElementById('zoom-modal-image');
  7019. const zoomLoader = document.getElementById('zoom-loader');
  7020. if (zoomModal) { // Animation de fermeture
  7021. if (zoomImage) {
  7022. zoomImage.style.opacity = '0';
  7023. zoomImage.classList.remove('loaded');
  7024. }
  7025. setTimeout(function () {
  7026. zoomModal.classList.remove('active');
  7027. document.body.style.overflow = 'auto';
  7028. // Réinitialiser le loader pour la prochaine ouverture
  7029. if (zoomLoader) {
  7030. zoomLoader.style.display = 'none';
  7031. }
  7032. }, 200);
  7033. }
  7034. }
  7035. // Fermer le modal en cliquant en dehors
  7036. document.addEventListener('DOMContentLoaded', function () {
  7037. const zoomModal = document.getElementById('image-zoom-modal');
  7038. if (zoomModal) {
  7039. zoomModal.addEventListener('click', function (e) {
  7040. if (e.target === zoomModal) {
  7041. closeImageZoom();
  7042. }
  7043. });
  7044. }
  7045. });
  7046. \t</script>
  7047. \t<!-- Modal de zoom d'image -->
  7048. \t<div id=\"image-zoom-modal\" class=\"image-zoom-modal\">
  7049. \t\t<span class=\"close-zoom\" onclick=\"closeImageZoom()\" title=\"Fermer\">&times;</span>
  7050. \t\t<div
  7051. \t\t\tclass=\"zoom-modal-content\">
  7052. \t\t\t<!-- Loader -->
  7053. \t\t\t<div class=\"zoom-loader\" id=\"zoom-loader\" style=\"display: none;\">
  7054. \t\t\t\t<div class=\"zoom-loader-spinner\"></div>
  7055. \t\t\t\t<div class=\"zoom-loader-text\">Chargement...</div>
  7056. \t\t\t</div>
  7057. \t\t\t<!-- Image -->
  7058. \t\t\t<img id=\"zoom-modal-image\" src=\"\" alt=\"{{ product.name }}\">
  7059. \t\t</div>
  7060. \t</div>
  7061. \t{% if dropshipReferral %}
  7062. \t\t<!-- Modal d'affiliation -->
  7063. \t\t<div id=\"dropship-modal\" class=\"dropship-referral-modal\" style=\"display: none;\">
  7064. \t\t\t<div class=\"dropship-modal-overlay\"></div>
  7065. \t\t\t<div class=\"dropship-modal-content\">
  7066. \t\t\t\t<button type=\"button\" class=\"dropship-modal-close\" onclick=\"closeDropshipModal()\" aria-label=\"Fermer\">
  7067. \t\t\t\t\t&times;
  7068. \t\t\t\t</button>
  7069. \t\t\t\t<div class=\"dropship-modal-header\">
  7070. \t\t\t\t\t<div class=\"dropship-icon\">
  7071. \t\t\t\t\t\t<i class=\"fas fa-gift\"></i>
  7072. \t\t\t\t\t</div>
  7073. \t\t\t\t\t<h3>Produit recommandé par
  7074. \t\t\t\t\t\t{{ dropshipReferral.affiliateName }}</h3>
  7075. \t\t\t\t\t<p class=\"dropship-subtitle\">Vous avez été dirigé vers ce produit par un de nos partenaires</p>
  7076. \t\t\t\t</div>
  7077. \t\t\t\t<div class=\"dropship-modal-body\">
  7078. \t\t\t\t\t<div class=\"dropship-product-info\">
  7079. \t\t\t\t\t\t{% if product.images|length > 0 %}
  7080. \t\t\t\t\t\t\t<img src=\"{{ asset(product.images[0]) }}\" alt=\"{{ product.name }}\" class=\"dropship-product-image\" onerror=\"this.style.display='none'; this.nextElementSibling.style.display='flex';\">
  7081. \t\t\t\t\t\t\t<div class=\"dropship-product-image-placeholder\" style=\"display: none; width: 100px; height: 100px; background: #f0f0f0; border-radius: 8px; align-items: center; justify-content: center; color: #999;\">
  7082. \t\t\t\t\t\t\t\t<i class=\"fas fa-image\" style=\"font-size: 32px;\"></i>
  7083. \t\t\t\t\t\t\t</div>
  7084. \t\t\t\t\t\t{% else %}
  7085. \t\t\t\t\t\t\t<div class=\"dropship-product-image-placeholder\" style=\"width: 100px; height: 100px; background: #f0f0f0; border-radius: 8px; display: flex; align-items: center; justify-content: center; color: #999;\">
  7086. \t\t\t\t\t\t\t\t<i class=\"fas fa-image\" style=\"font-size: 32px;\"></i>
  7087. \t\t\t\t\t\t\t</div>
  7088. \t\t\t\t\t\t{% endif %}
  7089. \t\t\t\t\t\t<div class=\"dropship-product-details\">
  7090. \t\t\t\t\t\t\t<h4>{{ product.name }}</h4>
  7091. \t\t\t\t\t\t\t<div class=\"dropship-product-price\">
  7092. \t\t\t\t\t\t\t\t<span class=\"price\">{{ product.price|number_format(2, ',', ' ') }}
  7093. \t\t\t\t\t\t\t\t\tHTG</span>
  7094. \t\t\t\t\t\t\t</div>
  7095. \t\t\t\t\t\t</div>
  7096. \t\t\t\t\t</div>
  7097. \t\t\t\t\t<div class=\"dropship-message\">
  7098. \t\t\t\t\t\t<p>
  7099. \t\t\t\t\t\t\t<strong>{{ dropshipReferral.affiliateName }}</strong>
  7100. \t\t\t\t\t\t\tvous recommande ce produit. Souhaitez-vous l'ajouter à votre panier ?</p>
  7101. \t\t\t\t\t</div>
  7102. \t\t\t\t</div>
  7103. \t\t\t\t<div class=\"dropship-modal-footer\">
  7104. \t\t\t\t\t<button type=\"button\" class=\"btn btn-secondary\" onclick=\"closeDropshipModal()\">
  7105. \t\t\t\t\t\tParcourir d'abord
  7106. \t\t\t\t\t</button>
  7107. \t\t\t\t\t<button type=\"button\" class=\"btn btn-primary dropship-add-to-cart\" onclick=\"addToCartFromDropship()\">
  7108. \t\t\t\t\t\t<i class=\"fas fa-shopping-cart\"></i>
  7109. \t\t\t\t\t\tAjouter au panier
  7110. \t\t\t\t\t</button>
  7111. \t\t\t\t</div>
  7112. \t\t\t</div>
  7113. \t\t</div>
  7114. \t\t<style>
  7115. \t\t\t.dropship-referral-modal {
  7116. \t\t\t\tposition: fixed;
  7117. \t\t\t\ttop: 0;
  7118. \t\t\t\tleft: 0;
  7119. \t\t\t\twidth: 100%;
  7120. \t\t\t\theight: 100%;
  7121. \t\t\t\tz-index: 10000;
  7122. \t\t\t\tdisplay: flex;
  7123. \t\t\t\talign-items: center;
  7124. \t\t\t\tjustify-content: center;
  7125. \t\t\t}
  7126. \t\t\t.dropship-modal-overlay {
  7127. \t\t\t\tposition: absolute;
  7128. \t\t\t\ttop: 0;
  7129. \t\t\t\tleft: 0;
  7130. \t\t\t\twidth: 100%;
  7131. \t\t\t\theight: 100%;
  7132. \t\t\t\tbackground: rgba(0, 0, 0, 0.6);
  7133. \t\t\t\tbackdrop-filter: blur(4px);
  7134. \t\t\t}
  7135. \t\t\t.dropship-modal-content {
  7136. \t\t\t\tposition: relative;
  7137. \t\t\t\tbackground: white;
  7138. \t\t\t\tborder-radius: 16px;
  7139. \t\t\t\tbox-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
  7140. \t\t\t\tmax-width: 500px;
  7141. \t\t\t\twidth: 90%;
  7142. \t\t\t\tmax-height: 90vh;
  7143. \t\t\t\toverflow-y: auto;
  7144. \t\t\t\tz-index: 10001;
  7145. \t\t\t\tanimation: dropshipModalSlideIn 0.3s ease-out;
  7146. \t\t\t}
  7147. \t\t\t@keyframes dropshipModalSlideIn {
  7148. \t\t\t\tfrom {
  7149. \t\t\t\t\topacity: 0;
  7150. \t\t\t\t\ttransform: translateY(-30px) scale(0.95);
  7151. \t\t\t\t}
  7152. \t\t\t\tto {
  7153. \t\t\t\t\topacity: 1;
  7154. \t\t\t\t\ttransform: translateY(0) scale(1);
  7155. \t\t\t\t}
  7156. \t\t\t}
  7157. \t\t\t.dropship-modal-close {
  7158. \t\t\t\tposition: absolute;
  7159. \t\t\t\ttop: 15px;
  7160. \t\t\t\tright: 15px;
  7161. \t\t\t\tbackground: none;
  7162. \t\t\t\tborder: none;
  7163. \t\t\t\tfont-size: 28px;
  7164. \t\t\t\tcolor: #666;
  7165. \t\t\t\tcursor: pointer;
  7166. \t\t\t\twidth: 35px;
  7167. \t\t\t\theight: 35px;
  7168. \t\t\t\tdisplay: flex;
  7169. \t\t\t\talign-items: center;
  7170. \t\t\t\tjustify-content: center;
  7171. \t\t\t\tborder-radius: 50%;
  7172. \t\t\t\ttransition: all 0.2s;
  7173. \t\t\t\tz-index: 10;
  7174. \t\t\t}
  7175. \t\t\t.dropship-modal-close:hover {
  7176. \t\t\t\tbackground: #f0f0f0;
  7177. \t\t\t\tcolor: #333;
  7178. \t\t\t}
  7179. \t\t\t.dropship-modal-header {
  7180. \t\t\t\tpadding: 30px 30px 20px;
  7181. \t\t\t\ttext-align: center;
  7182. \t\t\t\tborder-bottom: 1px solid #f0f0f0;
  7183. \t\t\t}
  7184. \t\t\t.dropship-icon {
  7185. \t\t\t\twidth: 70px;
  7186. \t\t\t\theight: 70px;
  7187. \t\t\t\tmargin: 0 auto 15px;
  7188. \t\t\t\tbackground: linear-gradient(135deg, #ffa200 0%, #ff8c00 100%);
  7189. \t\t\t\tborder-radius: 50%;
  7190. \t\t\t\tdisplay: flex;
  7191. \t\t\t\talign-items: center;
  7192. \t\t\t\tjustify-content: center;
  7193. \t\t\t\tfont-size: 32px;
  7194. \t\t\t\tcolor: white;
  7195. \t\t\t\tbox-shadow: 0 4px 15px rgba(255, 162, 0, 0.3);
  7196. \t\t\t}
  7197. \t\t\t.dropship-modal-header h3 {
  7198. \t\t\t\tmargin: 0 0 8px;
  7199. \t\t\t\tfont-size: 22px;
  7200. \t\t\t\tfont-weight: 600;
  7201. \t\t\t\tcolor: #333;
  7202. \t\t\t}
  7203. \t\t\t.dropship-subtitle {
  7204. \t\t\t\tmargin: 0;
  7205. \t\t\t\tcolor: #666;
  7206. \t\t\t\tfont-size: 14px;
  7207. \t\t\t}
  7208. \t\t\t.dropship-modal-body {
  7209. \t\t\t\tpadding: 25px 30px;
  7210. \t\t\t}
  7211. \t\t\t.dropship-product-info {
  7212. \t\t\t\tdisplay: flex;
  7213. \t\t\t\tgap: 15px;
  7214. \t\t\t\tmargin-bottom: 20px;
  7215. \t\t\t\tpadding: 15px;
  7216. \t\t\t\tbackground: #f8f9fa;
  7217. \t\t\t\tborder-radius: 10px;
  7218. \t\t\t}
  7219. \t\t\t.dropship-product-image {
  7220. \t\t\t\twidth: 80px;
  7221. \t\t\t\theight: 80px;
  7222. \t\t\t\tobject-fit: cover;
  7223. \t\t\t\tborder-radius: 8px;
  7224. \t\t\t\tflex-shrink: 0;
  7225. \t\t\t}
  7226. \t\t\t.dropship-product-details {
  7227. \t\t\t\tflex: 1;
  7228. \t\t\t}
  7229. \t\t\t.dropship-product-details h4 {
  7230. \t\t\t\tmargin: 0 0 8px;
  7231. \t\t\t\tfont-size: 16px;
  7232. \t\t\t\tfont-weight: 600;
  7233. \t\t\t\tcolor: #333;
  7234. \t\t\t}
  7235. \t\t\t.dropship-product-price {
  7236. \t\t\t\tmargin-top: 5px;
  7237. \t\t\t}
  7238. \t\t\t.dropship-product-price .price {
  7239. \t\t\t\tfont-size: 20px;
  7240. \t\t\t\tfont-weight: 700;
  7241. \t\t\t\tcolor: #ffa200;
  7242. \t\t\t}
  7243. \t\t\t.dropship-message {
  7244. \t\t\t\tpadding: 15px;
  7245. \t\t\t\tbackground: #fff9e6;
  7246. \t\t\t\tborder-left: 4px solid #ffa200;
  7247. \t\t\t\tborder-radius: 6px;
  7248. \t\t\t}
  7249. \t\t\t.dropship-message p {
  7250. \t\t\t\tmargin: 0;
  7251. \t\t\t\tcolor: #666;
  7252. \t\t\t\tline-height: 1.6;
  7253. \t\t\t}
  7254. \t\t\t.dropship-modal-footer {
  7255. \t\t\t\tpadding: 20px 30px 30px;
  7256. \t\t\t\tdisplay: flex;
  7257. \t\t\t\tgap: 12px;
  7258. \t\t\t\tjustify-content: flex-end;
  7259. \t\t\t\tborder-top: 1px solid #f0f0f0;
  7260. \t\t\t}
  7261. \t\t\t.dropship-modal-footer .btn {
  7262. \t\t\t\tpadding: 12px 24px;
  7263. \t\t\t\tborder-radius: 8px;
  7264. \t\t\t\tfont-weight: 500;
  7265. \t\t\t\tborder: none;
  7266. \t\t\t\tcursor: pointer;
  7267. \t\t\t\ttransition: all 0.2s;
  7268. \t\t\t\tfont-size: 15px;
  7269. \t\t\t}
  7270. \t\t\t.dropship-modal-footer .btn-secondary {
  7271. \t\t\t\tbackground: #f0f0f0;
  7272. \t\t\t\tcolor: #666;
  7273. \t\t\t}
  7274. \t\t\t.dropship-modal-footer .btn-secondary:hover {
  7275. \t\t\t\tbackground: #e0e0e0;
  7276. \t\t\t}
  7277. \t\t\t.dropship-modal-footer .btn-primary {
  7278. \t\t\t\tbackground: #ffa200;
  7279. \t\t\t\tcolor: white;
  7280. \t\t\t}
  7281. \t\t\t.dropship-modal-footer .btn-primary:hover {
  7282. \t\t\t\tbackground: #e8910a;
  7283. \t\t\t\ttransform: translateY(-2px);
  7284. \t\t\t\tbox-shadow: 0 4px 12px rgba(255, 162, 0, 0.3);
  7285. \t\t\t}
  7286. \t\t\t.dropship-modal-footer .btn-primary:disabled {
  7287. \t\t\t\topacity: 0.6;
  7288. \t\t\t\tcursor: not-allowed;
  7289. \t\t\t\ttransform: none;
  7290. \t\t\t}
  7291. \t\t</style>
  7292. \t\t<script>
  7293. \t\t\t// Afficher le modal automatiquement au chargement de la page
  7294. document.addEventListener('DOMContentLoaded', function () {
  7295. const dropshipModal = document.getElementById('dropship-modal');
  7296. if (dropshipModal) {
  7297. setTimeout(function () {
  7298. dropshipModal.style.display = 'flex';
  7299. document.body.style.overflow = 'hidden';
  7300. }, 500); // Délai de 500ms pour une meilleure UX
  7301. }
  7302. });
  7303. function closeDropshipModal () {
  7304. const dropshipModal = document.getElementById('dropship-modal');
  7305. if (dropshipModal) {
  7306. dropshipModal.style.display = 'none';
  7307. document.body.style.overflow = 'auto';
  7308. }
  7309. }
  7310. function addToCartFromDropship () {
  7311. const addBtn = document.querySelector('.dropship-add-to-cart');
  7312. if (! addBtn) 
  7313. return;
  7314. // Désactiver le bouton pendant le traitement
  7315. addBtn.disabled = true;
  7316. addBtn.innerHTML = '<i class=\"fas fa-spinner fa-spin\"></i> Ajout en cours...';
  7317. const productId = {{ product.id }};
  7318. const qty = parseInt(document.getElementById('sst') ?. value || '1');
  7319. // Utiliser fetch pour ajouter au panier
  7320. fetch('{{ path(\"ui_cart_add\") }}', {
  7321. method: 'POST',
  7322. headers: {
  7323. 'Content-Type': 'application/x-www-form-urlencoded',
  7324. 'X-Requested-With': 'XMLHttpRequest'
  7325. },
  7326. body: new URLSearchParams(
  7327. {productId: productId, qty: qty}
  7328. )
  7329. }).then(response => response.json()).then(data => {
  7330. if (data.ok) { // Afficher un message de succès
  7331. const modalBody = document.querySelector('.dropship-modal-body');
  7332. if (modalBody) {
  7333. modalBody.innerHTML = `
  7334. \t\t\t\t\t\t\t\t<div style=\"text-align: center; padding: 30px 20px;\">
  7335. \t\t\t\t\t\t\t\t\t<div style=\"width: 80px; height: 80px; margin: 0 auto 20px; background: #d4edda; border-radius: 50%; display: flex; align-items: center; justify-content: center;\">
  7336. \t\t\t\t\t\t\t\t\t\t<i class=\"fas fa-check\" style=\"font-size: 40px; color: #28a745;\"></i>
  7337. \t\t\t\t\t\t\t\t\t</div>
  7338. \t\t\t\t\t\t\t\t\t<h3 style=\"color: #28a745; margin-bottom: 10px;\">Produit ajouté avec succès !</h3>
  7339. \t\t\t\t\t\t\t\t\t<p style=\"color: #666; margin-bottom: 20px;\">Merci d'avoir utilisé le lien de recommandation de <strong>{{ dropshipReferral.affiliateName }}</strong></p>
  7340. \t\t\t\t\t\t\t\t\t<p style=\"color: #666; font-size: 14px;\">Vous pouvez continuer vos achats ou aller directement au panier.</p>
  7341. \t\t\t\t\t\t\t\t</div>
  7342. \t\t\t\t\t\t\t`;
  7343. }
  7344. const modalFooter = document.querySelector('.dropship-modal-footer');
  7345. if (modalFooter) {
  7346. modalFooter.innerHTML = `
  7347. \t\t\t\t\t\t\t\t<button type=\"button\" class=\"btn btn-secondary\" onclick=\"closeDropshipModal()\">
  7348. \t\t\t\t\t\t\t\t\tContinuer les achats
  7349. \t\t\t\t\t\t\t\t</button>
  7350. \t\t\t\t\t\t\t\t<a href=\"{{ path('cart') }}\" class=\"btn btn-primary\" style=\"text-decoration: none; display: inline-block;\">
  7351. \t\t\t\t\t\t\t\t\t<i class=\"fas fa-shopping-cart\"></i> Voir le panier
  7352. \t\t\t\t\t\t\t\t</a>
  7353. \t\t\t\t\t\t\t`;
  7354. }
  7355. // Mettre à jour le compteur du panier si présent
  7356. const cartCount = document.querySelector('.cart-count, .cart_count, [data-cart-count]');
  7357. if (cartCount) {
  7358. cartCount.textContent = data.totalQty || 0;
  7359. }
  7360. } else {
  7361. showCustomAlert('Erreur lors de l\\'ajout au panier. Veuillez réessayer.', 'error');
  7362. addBtn.disabled = false;
  7363. addBtn.innerHTML = '<i class=\"fas fa-shopping-cart\"></i> Ajouter au panier';
  7364. }
  7365. }).catch(error => {
  7366. console.error('Erreur:', error);
  7367. showCustomAlert('Une erreur est survenue. Veuillez réessayer.', 'error');
  7368. addBtn.disabled = false;
  7369. addBtn.innerHTML = '<i class=\"fas fa-shopping-cart\"></i> Ajouter au panier';
  7370. });
  7371. }
  7372. // Fermer le modal en cliquant sur l'overlay
  7373. document.addEventListener('DOMContentLoaded', function () {
  7374. const dropshipModal = document.getElementById('dropship-modal');
  7375. if (dropshipModal) {
  7376. const overlay = dropshipModal.querySelector('.dropship-modal-overlay');
  7377. if (overlay) {
  7378. overlay.addEventListener('click', function () {
  7379. closeDropshipModal();
  7380. });
  7381. }
  7382. }
  7383. });
  7384. \t\t</script>
  7385. \t{% endif %}
  7386. \t<!-- Modal personnalisé pour remplacer les alert -->
  7387. \t<div class=\"modal fade custom-alert-modal\" id=\"customAlertModal\" tabindex=\"-1\" aria-labelledby=\"customAlertModalLabel\" aria-hidden=\"true\">
  7388. \t\t<div class=\"modal-dialog modal-dialog-centered\">
  7389. \t\t\t<div class=\"modal-content\">
  7390. \t\t\t\t<div class=\"modal-header\">
  7391. \t\t\t\t\t<h5 class=\"modal-title text-white\" id=\"customAlertModalLabel\">Notification</h5>
  7392. \t\t\t\t\t<button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\" aria-label=\"Close\"></button>
  7393. \t\t\t\t</div>
  7394. \t\t\t\t<div class=\"modal-body\">
  7395. \t\t\t\t\t<div class=\"alert-icon\" id=\"alertIcon\">
  7396. \t\t\t\t\t\t<i class=\"lnr lnr-info-circle\"></i>
  7397. \t\t\t\t\t</div>
  7398. \t\t\t\t\t<p class=\"alert-message\" id=\"alertMessage\"></p>
  7399. \t\t\t\t</div>
  7400. \t\t\t\t<div class=\"modal-footer\">
  7401. \t\t\t\t\t<button type=\"button\" class=\"btn btn-primary\" data-bs-dismiss=\"modal\">OK</button>
  7402. \t\t\t\t</div>
  7403. \t\t\t</div>
  7404. \t\t</div>
  7405. \t</div>
  7406. \t<script>
  7407. \t\t// Fonction pour remplacer alert()
  7408. function showCustomAlert (message, type = 'info') {
  7409. const modal = new bootstrap.Modal(document.getElementById('customAlertModal'));
  7410. const alertMessage = document.getElementById('alertMessage');
  7411. const alertIcon = document.getElementById('alertIcon');
  7412. const modalTitle = document.getElementById('customAlertModalLabel');
  7413. alertMessage.textContent = message;
  7414. // Définir l'icône et le titre selon le type
  7415. let iconClass = 'lnr lnr-info-circle';
  7416. let title = 'Information';
  7417. switch (type) {
  7418. case 'success': iconClass = 'lnr lnr-checkmark-circle';
  7419. title = 'Succès';
  7420. alertIcon.className = 'alert-icon success';
  7421. break;
  7422. case 'error':
  7423. case 'danger': iconClass = 'lnr lnr-warning';
  7424. title = 'Erreur';
  7425. alertIcon.className = 'alert-icon error';
  7426. break;
  7427. case 'warning': iconClass = 'lnr lnr-warning';
  7428. title = 'Attention';
  7429. alertIcon.className = 'alert-icon warning';
  7430. break;
  7431. default: iconClass = 'lnr lnr-info-circle';
  7432. title = 'Information';
  7433. alertIcon.className = 'alert-icon info';
  7434. }
  7435. alertIcon.innerHTML = `<i class=\"\${iconClass}\"></i>`;
  7436. modalTitle.textContent = title;
  7437. modal.show();
  7438. }
  7439. // Remplacer window.alert par showCustomAlert
  7440. window.alert = showCustomAlert;
  7441. \t</script>
  7442. {% endblock %}
  7443. ""home/single-product.html.twig""/home/u540977899/domains/maketou-ht.com/public_html/templates/home/single-product.html.twig");
  7444.     }
  7445. }