feat: add favorites feature for users
All checks were successful
Build and Push Docker Image / build (push) Successful in 51s
All checks were successful
Build and Push Docker Image / build (push) Successful in 51s
- Implemented `Favorite` model with unique user-item constraint and timestamped records - Added `favorites:index` and `favorites:toggle` views with AJAX support for toggling favorites - Built templates and front-end assets for the favorites page and integration with item grids - Extended header with favorites link and dynamic counter - Added tests covering models, views, and templates for the favorites functionality - Updated admin to enable management of favorites via Django admin interface
This commit is contained in:
@@ -7,19 +7,19 @@
|
||||
<div class="footer-col">
|
||||
<h4>ПОКУПАТЕЛЮ</h4>
|
||||
<ul>
|
||||
<li><a href="#">Каталог</a></li>
|
||||
<li><a href="#">Услуги</a></li>
|
||||
<li><a href="#">Акции</a></li>
|
||||
<li><a href="#">Новинки</a></li>
|
||||
<li><a href="/catalog/">Каталог</a></li>
|
||||
<li><a href="{% url 'services' %}">Услуги</a></li>
|
||||
<li><a href="/catalog/">Акции</a></li>
|
||||
<li><a href="/catalog/">Новинки</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer-col">
|
||||
<h4>ПОМОЩЬ</h4>
|
||||
<ul>
|
||||
<li><a href="#">Доставка и оплата</a></li>
|
||||
<li><a href="#">Гарантия и возврат</a></li>
|
||||
<li>Ответы на вопросы</li>
|
||||
<li><a href="#">Контакты</a></li>
|
||||
<li><a href="{% url 'shipping' %}">Доставка и оплата</a></li>
|
||||
<li><a href="{% url 'warranty' %}">Гарантия и возврат</a></li>
|
||||
<li><a href="{% url 'home' %}#faq-section">Ответы на вопросы</a></li>
|
||||
<li><a href="{% url 'contacts' %}">Контакты</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer-col">
|
||||
|
||||
@@ -5,13 +5,67 @@
|
||||
<div class="logo"><a href="/">SantehRay</a></div>
|
||||
<form action="">
|
||||
<div class="search-wrap">
|
||||
<label>
|
||||
<select>
|
||||
<option>Все категории</option>
|
||||
<option>Сантехника</option>
|
||||
<option>Декор</option>
|
||||
</select>
|
||||
</label>
|
||||
<div class="search-select-wrap">
|
||||
<div class="search-category-dropdown" data-category-dropdown>
|
||||
<button
|
||||
type="button"
|
||||
class="search-category-trigger"
|
||||
aria-label="Выбор категории"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
data-category-trigger
|
||||
>
|
||||
<span class="search-category-label"
|
||||
data-selected-label>{{ navigation_selected_label }}</span>
|
||||
<svg class="search-select-arrow" xmlns="http://www.w3.org/2000/svg" width="14"
|
||||
height="14"
|
||||
viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false">
|
||||
<path d="M3.2 6.2 8 11l4.8-4.8" stroke="currentColor" stroke-width="1.8"
|
||||
stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<input type="hidden" name="category" value="{{ navigation_selected_value }}"
|
||||
data-category-value>
|
||||
<div class="search-category-menu" role="listbox" aria-label="Категории и подкатегории"
|
||||
data-category-menu>
|
||||
<button
|
||||
type="button"
|
||||
class="search-category-option search-category-option--all"
|
||||
data-category-option
|
||||
data-label="Все категории"
|
||||
data-value=""
|
||||
>
|
||||
Все категории
|
||||
</button>
|
||||
{% for category in navigation_categories %}
|
||||
<div class="search-category-group">
|
||||
<div class="search-category-sublist">
|
||||
<button
|
||||
type="button"
|
||||
class="search-category-option search-category-option--category"
|
||||
data-category-option
|
||||
data-label="{{ category.name }}"
|
||||
data-value="category:{{ category.slug }}"
|
||||
>
|
||||
{{ category.name }}
|
||||
</button>
|
||||
{% for subcategory in category.subcategories.all %}
|
||||
<button
|
||||
type="button"
|
||||
class="search-category-option search-category-option--subcategory"
|
||||
data-category-option
|
||||
data-label="{{ category.name }} / {{ subcategory.name }}"
|
||||
data-value="subcategory:{{ category.slug }}:{{ subcategory.slug }}"
|
||||
>
|
||||
{{ subcategory.name }}
|
||||
</button>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<label>
|
||||
<input class="search-input" type="text" placeholder="Кто ищет, тот найдет...">
|
||||
</label>
|
||||
@@ -24,7 +78,8 @@
|
||||
</div>
|
||||
</form>
|
||||
<div class="header-icons">
|
||||
<a href="">
|
||||
<a href="{% if request.user.is_authenticated %}{% url 'favorites:index' %}{% else %}{% url 'users:login' %}{% endif %}"
|
||||
aria-label="Избранное">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
|
||||
class="bi bi-heart" viewBox="0 0 16 16">
|
||||
<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.01zM8 15C-7.333 4.868 3.279-3.04 7.824 1.143q.09.083.176.171a3 3 0 0 1 .176-.17C12.72-3.042 23.333 4.867 8 15"></path>
|
||||
|
||||
7
templates/_fragments/item-grid.html
Normal file
7
templates/_fragments/item-grid.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<div class="items-grid"{% if favorites_grid %} data-favorites-grid data-empty-message="{{ empty_message|escape }}"{% endif %}>
|
||||
{% for item in items %}
|
||||
{% include "catalog/_fragments/item-card.html" with item=item %}
|
||||
{% empty %}
|
||||
<p class="item-list-empty">{{ empty_message }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
Reference in New Issue
Block a user