templates/shop/index.html.twig line 1

Open in your IDE?
  1. {% extends 'nav.html.twig' %}
  2. {% block title %}Магазин{% endblock %}
  3. {% block content %}
  4.     <aside id="filterProducts" class="bd-aside sticky-xl-top text-muted align-self-start mb-3 mb-xl-5 px-2">
  5.         <form style="padding-left: 30px; margin-bottom: 30px !important; width: 300px" id="formFilter">
  6.             <h5 style="padding-left: 10px" class="pt-4 pb-3 mb-4 border-bottom">Фильтры</h5>
  7.             <nav style="width: 300px" class="small">
  8.                     <h5 class="type-filter">Тип изделия</h5>
  9.                     {% for groupProducts in groupsProducts %}
  10.                         <label class="filter-label cursor-pointer">
  11.                             {{ groupProducts.title }}
  12.                             <input class="checkboxFilter cursor-pointer" onchange="filter()" id="{{ groupProducts.name }}" name="{{ groupProducts.name }}" type="checkbox">
  13.                         </label><br>
  14.                     {% endfor %}
  15.                     <br>
  16.                     <h5 class="type-filter">Материал</h5>
  17.                     {% for materialProducts in materialsProducts %}
  18.                         <label class="filter-label cursor-pointer">
  19.                             {{ materialProducts.title }}
  20.                             <input class="checkboxFilter cursor-pointer" onchange="filter()" id="{{ materialProducts.name }}" name="{{ materialProducts.name }}" type="checkbox">
  21.                         </label><br>
  22.                     {% endfor %}
  23.                     <div style="padding-top: 30px; padding-left: 30px">
  24.                         <label for="priceRange" class="form-label">Цена: до </label>
  25.                         <span id="priceValue">{{ maxPrice }}</span><span>₽</span><br>
  26.                         <span style="margin-right: 10px">0₽</span><input onchange="filter()" oninput="updatePriceValue(this.value)" name = "price" type="range" min="0" max="{{ maxPrice }}" class="form-range" id="priceRange" style="cursor: pointer"><span style="margin-left: 10px">{{ maxPrice }}₽</span>
  27.                     </div>
  28.             </nav>
  29.             <h5 style="padding-left: 10px; margin-top: 530px;" class="pt-4 pb-3 mb-4 border-bottom">Сортировка</h5>
  30.             <select id = "selectSort" onchange="filter()" style="background: none; border: none; cursor: pointer; width: 260px" class="form-select" aria-label="Default select example">
  31.                 <option class="cursor-pointer" value="0" selected>По умолчанию</option>
  32.                 <option class="cursor-pointer" value="1">Убыванию цены</option>
  33.                 <option class="cursor-pointer" value="2">Возрастанию цены</option>
  34.                 <option class="cursor-pointer" value="3">Количеству просмотров</option>
  35.                 <option class="cursor-pointer" value="4">Количеству продаж</option>
  36.             </select>
  37.         </form>
  38.     </aside>
  39.     <div class="card-table">
  40.         {% for product in products %}
  41.             <div class="card" style="width: 18rem;">
  42.                 <a onclick="openProductCard('{{ product.id }}');" style="cursor: pointer">
  43.                     {% if product.images is not null and product.images|length > 0 %}
  44.                     <img class="card-img-top" height="350" src="../assets/images/{{ product.images[0].path }}">
  45.                     {% endif %}
  46.                 </a>
  47.                 <div class="card-body">
  48.                     <a onclick="openProductCard('{{ product.id }}');" style="cursor: pointer">
  49.                     <h6 class="card-title">{{ product.title }}</h6>
  50.                     <p style="height: 70px; font-size: 12px" class="card-text">
  51.                         {% if product.description | length > 30 %}
  52.                             {{ product.description | slice (0, 30) ~ '...' }}
  53.                         {% else %}
  54.                             {{ product.description }}
  55.                         {% endif %}
  56.                     </p>
  57.                     </a>
  58.                         <button type="button" class="btn btn-primary buttonsCard" onclick="addProductToCart('grid', {{ product.id }})">
  59.                             <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-cart" viewBox="0 0 16 16">
  60.                                 <path d="M0 1.5A.5.5 0 0 1 .5 1H2a.5.5 0 0 1 .485.379L2.89 3H14.5a.5.5 0 0 1 .491.592l-1.5 8A.5.5 0 0 1 13 12H4a.5.5 0 0 1-.491-.408L2.01 3.607 1.61 2H.5a.5.5 0 0 1-.5-.5zM3.102 4l1.313 7h8.17l1.313-7H3.102zM5 12a2 2 0 1 0 0 4 2 2 0 0 0 0-4zm7 0a2 2 0 1 0 0 4 2 2 0 0 0 0-4zm-7 1a1 1 0 1 1 0 2 1 1 0 0 1 0-2zm7 0a1 1 0 1 1 0 2 1 1 0 0 1 0-2z"></path>
  61.                             </svg>
  62.                         </button>
  63.                     <button type="button" class="btn btn-primary buttonsCard">
  64.                         <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-heart" viewBox="0 0 16 13">
  65.                             <path d="m8 2.748-.717-.737C5.6.281 2.514.878 1.4 3.053c-.523 1.023-.641 2.5.314 4.385.92 1.815 2.834 3.989 6.286 6.357 3.452-2.368 5.365-4.542 6.286-6.357.955-1.886.838-3.362.314-4.385C13.486.878 10.4.28 8.717 2.01L8 2.748zM8 15C-7.333 4.868 3.279-3.04 7.824 1.143c.06.055.119.112.176.171a3.12 3.12 0 0 1 .176-.17C12.72-3.042 23.333 4.867 8 15z"></path>
  66.                         </svg>
  67.                     </button>
  68.                     <span style="right: 20px; position: absolute; font-size: 20px">{{ product.price }}₽</span>
  69.                     <br><span class="master-name">{{ product.seller.lastname }} {{ product.seller.name }}</span>
  70.                     <div style="text-align: right">
  71.                         <small>{{ product.views }}<svg xmlns="http://www.w3.org/2000/svg" width="16" height="18" fill="currentColor" class="bi bi-eye" viewBox="0 0 16 10">
  72.                                 <path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.133 13.133 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.133 13.133 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5c-2.12 0-3.879-1.168-5.168-2.457A13.134 13.134 0 0 1 1.172 8z"></path>
  73.                                 <path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0z"></path>
  74.                             </svg>
  75.                         </small>
  76.                         <small>{{ product.bought }}<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="bi bi-bag" viewBox="0 0 16 15">
  77.                                 <path d="M8 1a2.5 2.5 0 0 1 2.5 2.5V4h-5v-.5A2.5 2.5 0 0 1 8 1zm3.5 3v-.5a3.5 3.5 0 1 0-7 0V4H1v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V4h-3.5zM2 5h12v9a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V5z"/>
  78.                             </svg>
  79.                         </small>
  80.                     </div>
  81.                 </div>
  82.             </div>
  83.         {% endfor %}
  84.     </div>
  85.     <!-- Modal -->
  86.     <button type="button" class="btn btn-primary" data-toggle="modal" data-target=".bd-example-modal-lg">Large modal</button>
  87.     <div class="modal fade bd-example-modal-lg" id="productCardModal" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true">
  88.         <div class="modal-dialog modal-lg" style="max-width: 1000px">
  89.             <div class="modal-content" id="productCardModalContainer">
  90.                 ...
  91.             </div>
  92.         </div>
  93.     </div>
  94. {% endblock %}
  95. {% block pagescripts %}
  96.     <script>
  97.         var descriptionProductCardVisible = false;
  98.         document.addEventListener('DOMContentLoaded', function () {
  99.             var urlParams = new URLSearchParams(window.location.search);
  100.             var productIdParam = urlParams.get('product_id');
  101.             var priceRange = document.getElementById('priceRange');
  102.             var priceValue = document.getElementById('priceValue');
  103.             var priceParam = urlParams.get('price');
  104.             priceRange.value = priceParam ? priceParam : priceRange.max;
  105.             priceValue.textContent = priceRange.value
  106.             if (productIdParam) {
  107.                 openProductCard(productIdParam);
  108.             }
  109.         });
  110.         function filter() {
  111.             event.preventDefault();
  112.             let spinner = document.getElementById('loadingSpinner');
  113.             let form = document.getElementById('formFilter');
  114.             let inputs = form.getElementsByTagName('input');
  115.             let sort = form.getElementsByTagName('select');
  116.             let formSearch = document.getElementById('searchFilter');
  117.             let search = formSearch.querySelector('input[name="search"]').value;
  118.             sort = sort[0].value;
  119.             let price = inputs['price'].value;
  120.             let numberOfInputs = inputs.length;
  121.             let url = "?";
  122.             if (search !== "")
  123.                 url = url + "search=" + search + "&";
  124.             url = url + "price=" + price + "&";
  125.             for (let i = 0; i < numberOfInputs; i++) {
  126.                 if (!inputs[i].checked) continue;
  127.                 url = url + inputs[i].name + "=" + inputs[i].checked + "&";
  128.             }
  129.             url = url + "sort=" + sort;
  130.             window.history.pushState('page2', 'Title', url);
  131.             spinner.style.display = 'block';
  132.             sendGetRequest(url)
  133.                 .then(function (response) {
  134.                     document.body.innerHTML = response;
  135.                     for (let i = 0; i < numberOfInputs; i++) {
  136.                         if (inputs[i].checked) {
  137.                             document.getElementById(inputs[i].id).checked = true;
  138.                         }
  139.                     }
  140.                     document.getElementById('priceRange').value = price;
  141.                     document.getElementById('selectSort').value = sort;
  142.                     document.getElementById('searchBar').value = search;
  143.                     document.getElementById('priceValue').textContent = price;
  144.                     let clearSearchIcon = document.getElementById('clearSearch');
  145.                     clearSearchIcon.style.visibility = document.getElementById('searchBar').value ? 'inherit' : 'hidden';
  146.                     spinner.style.display = 'none';
  147.                 })
  148.                 .catch(function () {
  149.                     spinner.style.display = 'none';
  150.                 })
  151.         }
  152.         /**
  153.          * Функция для отображения текущего значения слайдера фильтра цены во время его изменения
  154.          *
  155.          * @param value
  156.          */
  157.         function updatePriceValue(value) {
  158.             document.getElementById('priceValue').textContent = value;
  159.         }
  160.         /**
  161.          * Функция, которая меняет стиль отображения крестика в поле поиска при вводе текста
  162.          */
  163.         function showCross() {
  164.             let clearSearchIcon = document.getElementById('clearSearch');
  165.             clearSearchIcon.style.visibility = document.getElementById('searchBar').value ? 'inherit' : 'hidden';
  166.         }
  167.         /**
  168.          * Функция, которая очищает поле поиска по нажатию на крестик и сбрасывает имеющийся поиск товаров
  169.          */
  170.         function clearSearch() {
  171.             document.getElementById('searchBar').value = '';
  172.             filter();
  173.         }
  174.         /**
  175.          * Отображает модальное окно карты товара и отслеживает его состояние
  176.          *
  177.          * @param productId
  178.          */
  179.         function openProductCard(productId) {
  180.             let productModal = document.getElementById('productCardModalContainer');
  181.             let responseUrl = '/get-product/' + productId;
  182.             let url = '?product_id=' + productId;
  183.             let originalUrl = window.location.href;
  184.             $('#productCardModal').on('hidden.bs.modal', function () {
  185.                 window.history.replaceState('page2', 'Title', originalUrl);
  186.             });
  187.             descriptionProductCardVisible = false;
  188.             window.history.pushState('page2', 'Title', url);
  189.             sendGetRequest(responseUrl)
  190.                 .then(function (response) {
  191.                     productModal.innerHTML = response;
  192.                     $('#productCardModal').modal('show');
  193.                     document.getElementById('addProductToCartBtn').disabled = false
  194.                 })
  195.         }
  196.         /**
  197.          * Отвечает за логику работы кнопки "Посмотреть полностью" в модальном окне карты товара
  198.          */
  199.         function toggleProductCardDescription() {
  200.             let container = document.getElementById('descriptionProductCard');
  201.             descriptionProductCardVisible = !descriptionProductCardVisible;
  202.             container.classList.toggle('collapsed');
  203.             container.classList.toggle('expanded')
  204.         }
  205.         /**
  206.          * Отправляет запрос на добавление товара в корзину и
  207.          * выводит сообщение, если он успешно добавлен.
  208.          *
  209.          * @param from
  210.          * @param product
  211.          */
  212.         function addProductToCart(from, product) {
  213.             let Data;
  214.             if (from === 'Form'){
  215.                 Data = new FormData(document.getElementById('modalProductCardForm'));
  216.             } else {
  217.                 Data = new FormData();
  218.                 Data.append('product', product);
  219.                 Data.append('count', '1');
  220.                 Data.append('sizeOption', 'anyone');
  221.             }
  222.             let url = 'addProductToCart';
  223.             sendPostRequest(url, Data)
  224.                 .then(function (response) {
  225.                     let responseData = JSON.parse(response);
  226.                     if (responseData.guest) {
  227.                         addToLocalCart(responseData.item);
  228.                         showSuccessAlert('Товар успешно добавлен в корзину');
  229.                     } else {
  230.                         showSuccessAlert('Товар успешно добавлен в корзину');
  231.                     }
  232.                 })
  233.         }
  234.         /**
  235.          * Добавляет товар в localStorage
  236.          *
  237.          * @param cartItem
  238.          */
  239.         function addToLocalCart(cartItem) {
  240.             let found = false;
  241.             let cart = JSON.parse(localStorage.getItem('cart')) || [];
  242.             cart.forEach(function(item) {
  243.                 if (item['product_id'] === cartItem['product_id'] && item['size'] === cartItem['size']) {
  244.                     item['count'] += cartItem['count'];
  245.                     found = true
  246.                 }
  247.             })
  248.             if (!found) cart.push(cartItem);
  249.             localStorage.setItem('cart', JSON.stringify(cart));
  250.         }
  251.     </script>
  252. {% endblock %}