feat: refine price formatting and enable dynamic color updates in cart
All checks were successful
Build and Push Docker Image / build (push) Successful in 25s
All checks were successful
Build and Push Docker Image / build (push) Successful in 25s
- Updated price slider and backend formatting to round values instead of showing decimals - Enhanced product detail page with active color selection display and automatic cart updates - Adjusted swatch behavior to dynamically update the selected color in the cart via AJAX - Improved consistency in slider steps and price formatting throughout templates and views
This commit is contained in:
@@ -8,6 +8,7 @@ from django.shortcuts import redirect, render
|
|||||||
|
|
||||||
from favorites.services import get_user_favorite_item_ids
|
from favorites.services import get_user_favorite_item_ids
|
||||||
from items.models import Category, Color, Item, Subcategory
|
from items.models import Category, Color, Item, Subcategory
|
||||||
|
from orders.models import CartItem
|
||||||
from orders.services import get_user_cart_item_ids
|
from orders.services import get_user_cart_item_ids
|
||||||
|
|
||||||
|
|
||||||
@@ -90,7 +91,7 @@ def _resolve_catalog_scope(scope_value: str | None) -> tuple[str | None, str | N
|
|||||||
|
|
||||||
|
|
||||||
def _format_price_value(value: Decimal) -> str:
|
def _format_price_value(value: Decimal) -> str:
|
||||||
return format(value, "f")
|
return str(int(value))
|
||||||
|
|
||||||
|
|
||||||
def index(request: HttpRequest, category: str | None = None) -> HttpResponse:
|
def index(request: HttpRequest, category: str | None = None) -> HttpResponse:
|
||||||
@@ -322,11 +323,20 @@ def detail(request: HttpRequest, category: str, slug: str) -> HttpResponse:
|
|||||||
|
|
||||||
images = list(item.images.all())
|
images = list(item.images.all())
|
||||||
|
|
||||||
|
cart_color_id = None
|
||||||
|
if request.user.is_authenticated:
|
||||||
|
cart_item = CartItem.objects.filter(
|
||||||
|
cart__user=request.user, item=item
|
||||||
|
).select_related('selected_color').first()
|
||||||
|
if cart_item and cart_item.selected_color_id:
|
||||||
|
cart_color_id = cart_item.selected_color_id
|
||||||
|
|
||||||
return render(request, 'catalog/detail.html', {
|
return render(request, 'catalog/detail.html', {
|
||||||
'categories': Category.objects.order_by('name'),
|
'categories': Category.objects.order_by('name'),
|
||||||
'item': item,
|
'item': item,
|
||||||
'images': images,
|
'images': images,
|
||||||
'primary_image': images[0] if images else None,
|
'primary_image': images[0] if images else None,
|
||||||
'cart_item_ids': get_user_cart_item_ids(request.user),
|
'cart_item_ids': get_user_cart_item_ids(request.user),
|
||||||
|
'cart_color_id': cart_color_id,
|
||||||
'favorite_item_ids': get_user_favorite_item_ids(request.user),
|
'favorite_item_ids': get_user_favorite_item_ids(request.user),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
document.addEventListener('DOMContentLoaded', function () {
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
const priceFormatter = new Intl.NumberFormat('ru-RU', {
|
const priceFormatter = new Intl.NumberFormat('ru-RU', {
|
||||||
minimumFractionDigits: 2,
|
minimumFractionDigits: 0,
|
||||||
maximumFractionDigits: 2,
|
maximumFractionDigits: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
const formatQueryValue = function (value) {
|
const formatQueryValue = function (value) {
|
||||||
return value.toFixed(2).replace(/\.?0+$/, '');
|
return Math.round(value).toString();
|
||||||
};
|
};
|
||||||
|
|
||||||
document.querySelectorAll('[data-price-slider]').forEach(function (slider) {
|
document.querySelectorAll('[data-price-slider]').forEach(function (slider) {
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
type="range"
|
type="range"
|
||||||
min="{{ price_slider_min_bound }}"
|
min="{{ price_slider_min_bound }}"
|
||||||
max="{{ price_slider_max_bound }}"
|
max="{{ price_slider_max_bound }}"
|
||||||
step="0.01"
|
step="1"
|
||||||
value="{{ price_slider_selected_min }}"
|
value="{{ price_slider_selected_min }}"
|
||||||
class="catalog-price-slider__range"
|
class="catalog-price-slider__range"
|
||||||
aria-label="Минимальная цена"
|
aria-label="Минимальная цена"
|
||||||
@@ -74,7 +74,7 @@
|
|||||||
type="range"
|
type="range"
|
||||||
min="{{ price_slider_min_bound }}"
|
min="{{ price_slider_min_bound }}"
|
||||||
max="{{ price_slider_max_bound }}"
|
max="{{ price_slider_max_bound }}"
|
||||||
step="0.01"
|
step="1"
|
||||||
value="{{ price_slider_selected_max }}"
|
value="{{ price_slider_selected_max }}"
|
||||||
class="catalog-price-slider__range"
|
class="catalog-price-slider__range"
|
||||||
aria-label="Максимальная цена"
|
aria-label="Максимальная цена"
|
||||||
|
|||||||
@@ -61,13 +61,14 @@
|
|||||||
<div class="product-summary__swatches" aria-label="Цвета товара">
|
<div class="product-summary__swatches" aria-label="Цвета товара">
|
||||||
{% for color in colors %}
|
{% for color in colors %}
|
||||||
<span
|
<span
|
||||||
class="product-summary__swatch"
|
class="product-summary__swatch{% if color.id == cart_color_id %} product-summary__swatch--active{% endif %}"
|
||||||
style="background: {{ color.hex_code }};"
|
style="background: {{ color.hex_code }};"
|
||||||
title="{{ color.name }}"
|
title="{{ color.name }}"
|
||||||
data-color-id="{{ color.id }}"
|
data-color-id="{{ color.id }}"
|
||||||
></span>
|
></span>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
<p class="product-summary__color-name" data-color-name>{% for color in colors %}{% if color.id == cart_color_id %}Цвет: {{ color.name }}{% endif %}{% endfor %}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
|
|
||||||
@@ -77,6 +78,12 @@
|
|||||||
|
|
||||||
<div class="product-summary__actions">
|
<div class="product-summary__actions">
|
||||||
{% if item.id in cart_item_ids %}
|
{% if item.id in cart_item_ids %}
|
||||||
|
<form method="post" action="{% url 'orders:add' %}" class="product-summary__cart-form" id="update-color-form" style="display:none;">
|
||||||
|
{% csrf_token %}
|
||||||
|
<input type="hidden" name="item_id" value="{{ item.id }}">
|
||||||
|
<input type="hidden" name="next" value="{{ request.get_full_path }}">
|
||||||
|
<input type="hidden" name="color_id" id="selected-color-id" value="">
|
||||||
|
</form>
|
||||||
<a class="product-summary__button product-summary__button--primary product-summary__button--link" href="{% url 'orders:cart' %}">
|
<a class="product-summary__button product-summary__button--primary product-summary__button--link" href="{% url 'orders:cart' %}">
|
||||||
Перейти в корзину
|
Перейти в корзину
|
||||||
</a>
|
</a>
|
||||||
@@ -115,18 +122,29 @@
|
|||||||
(function () {
|
(function () {
|
||||||
var swatches = document.querySelectorAll('.product-summary__swatch[data-color-id]');
|
var swatches = document.querySelectorAll('.product-summary__swatch[data-color-id]');
|
||||||
var colorInput = document.getElementById('selected-color-id');
|
var colorInput = document.getElementById('selected-color-id');
|
||||||
|
var colorNameEl = document.querySelector('[data-color-name]');
|
||||||
|
var updateForm = document.getElementById('update-color-form');
|
||||||
var cartBtn = document.querySelector('.product-summary__button--primary[type="submit"]');
|
var cartBtn = document.querySelector('.product-summary__button--primary[type="submit"]');
|
||||||
|
|
||||||
if (!swatches.length || !colorInput) { return; }
|
if (!swatches.length || !colorInput) { return; }
|
||||||
|
|
||||||
if (cartBtn) { cartBtn.disabled = true; }
|
if (!updateForm && cartBtn) { cartBtn.disabled = true; }
|
||||||
|
|
||||||
swatches.forEach(function (swatch) {
|
swatches.forEach(function (swatch) {
|
||||||
swatch.addEventListener('click', function () {
|
swatch.addEventListener('click', function () {
|
||||||
swatches.forEach(function (s) { s.classList.remove('product-summary__swatch--active'); });
|
swatches.forEach(function (s) { s.classList.remove('product-summary__swatch--active'); });
|
||||||
this.classList.add('product-summary__swatch--active');
|
this.classList.add('product-summary__swatch--active');
|
||||||
colorInput.value = this.dataset.colorId || '';
|
colorInput.value = this.dataset.colorId || '';
|
||||||
if (cartBtn) { cartBtn.disabled = false; }
|
|
||||||
|
if (colorNameEl) {
|
||||||
|
colorNameEl.textContent = 'Цвет: ' + this.title;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateForm) {
|
||||||
|
updateForm.submit();
|
||||||
|
} else if (cartBtn) {
|
||||||
|
cartBtn.disabled = false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}());
|
}());
|
||||||
|
|||||||
Reference in New Issue
Block a user