Small fixes
All checks were successful
Build and Push Docker Image / build (push) Successful in 29s

This commit is contained in:
2026-06-24 21:27:50 +02:00
parent aca8f56b9a
commit 068e5190c2
4 changed files with 58 additions and 10 deletions

View File

@@ -3,7 +3,7 @@ from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from favorites.models import Favorite from favorites.models import Favorite
from items.models import Category, Item, ItemImage, Subcategory from items.models import Category, Color, Item, ItemImage, Subcategory
from orders.models import Cart, CartItem from orders.models import Cart, CartItem
@@ -406,6 +406,44 @@ class CatalogViewTests(TestCase):
self.assertContains(response, 'href="/orders/cart/"', html=False) self.assertContains(response, 'href="/orders/cart/"', html=False)
self.assertContains(response, "Перейти в корзину") self.assertContains(response, "Перейти в корзину")
def test_detail_page_selects_first_color_by_default(self):
white = Color.objects.create(name="Белый", hex_code="#ffffff")
black = Color.objects.create(name="Черный", hex_code="#000000")
self.sink.colors.add(black, white)
user = get_user_model().objects.create_user(
username="default-color-user",
email="default-color-user@example.com",
password="StrongPassword123",
is_active=True,
)
self.client.force_login(user)
response = self.client.get("/catalog/plumbing/kitchen-sink/")
self.assertEqual(response.context["selected_color_id"], white.id)
self.assertContains(response, f'value="{white.id}"', html=False)
self.assertContains(response, "Цвет: Белый")
def test_detail_page_keeps_cart_selected_color(self):
white = Color.objects.create(name="Белый", hex_code="#ffffff")
black = Color.objects.create(name="Черный", hex_code="#000000")
self.sink.colors.add(black, white)
user = get_user_model().objects.create_user(
username="color-cart-user",
email="color-cart-user@example.com",
password="StrongPassword123",
is_active=True,
)
cart = Cart.objects.create(user=user)
CartItem.objects.create(cart=cart, item=self.sink, quantity=1, selected_color=black)
self.client.force_login(user)
response = self.client.get("/catalog/plumbing/kitchen-sink/")
self.assertEqual(response.context["selected_color_id"], black.id)
self.assertContains(response, f'value="{black.id}"', html=False)
self.assertContains(response, "Цвет: Черный")
def test_detail_page_guest_cart_cta_redirects_to_login(self): def test_detail_page_guest_cart_cta_redirects_to_login(self):
response = self.client.get("/catalog/plumbing/kitchen-sink/") response = self.client.get("/catalog/plumbing/kitchen-sink/")

View File

@@ -334,6 +334,7 @@ def detail(request: HttpRequest, category: str, slug: str) -> HttpResponse:
raise Http404() raise Http404()
images = list(item.images.all()) images = list(item.images.all())
colors = list(item.colors.all())
cart_color_id = None cart_color_id = None
if request.user.is_authenticated: if request.user.is_authenticated:
@@ -343,12 +344,17 @@ def detail(request: HttpRequest, category: str, slug: str) -> HttpResponse:
if cart_item and cart_item.selected_color_id: if cart_item and cart_item.selected_color_id:
cart_color_id = cart_item.selected_color_id cart_color_id = cart_item.selected_color_id
selected_color_id = cart_color_id
if selected_color_id is None and colors:
selected_color_id = colors[0].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,
'colors': colors,
'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, 'selected_color_id': selected_color_id,
'favorite_item_ids': get_user_favorite_item_ids(request.user), 'favorite_item_ids': get_user_favorite_item_ids(request.user),
}) })

View File

@@ -7,6 +7,7 @@
.icon { .icon {
width: 59px; width: 59px;
height: 59px; height: 59px;
flex: 0 0 59px;
border-radius: 100%; border-radius: 100%;
background: #ffffff; background: #ffffff;
@@ -58,6 +59,11 @@
} }
} }
.top-box:first-child > p {
font-size: 12px;
line-height: 1.35;
}
.large { .large {
margin-top: 40px; margin-top: 40px;
margin-bottom: 130px; margin-bottom: 130px;
@@ -97,4 +103,4 @@
color: #63768d; color: #63768d;
} }
} }

View File

@@ -56,21 +56,19 @@
</span> </span>
</div> </div>
{% with colors=item.colors.all %}
{% if colors %} {% if colors %}
<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{% if color.id == cart_color_id %} product-summary__swatch--active{% endif %}" class="product-summary__swatch{% if color.id == selected_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> <p class="product-summary__color-name" data-color-name>{% for color in colors %}{% if color.id == selected_color_id %}Цвет: {{ color.name }}{% endif %}{% endfor %}</p>
{% endif %} {% endif %}
{% endwith %}
{% if item.description %} {% if item.description %}
<div class="product-summary__description">{{ item.description|linebreaksbr }}</div> <div class="product-summary__description">{{ item.description|linebreaksbr }}</div>
@@ -82,7 +80,7 @@
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="item_id" value="{{ item.id }}"> <input type="hidden" name="item_id" value="{{ item.id }}">
<input type="hidden" name="next" value="{{ request.get_full_path }}"> <input type="hidden" name="next" value="{{ request.get_full_path }}">
<input type="hidden" name="color_id" id="selected-color-id" value=""> <input type="hidden" name="color_id" id="selected-color-id" value="{{ selected_color_id|default:'' }}">
</form> </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' %}">
Перейти в корзину Перейти в корзину
@@ -92,7 +90,7 @@
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="item_id" value="{{ item.id }}"> <input type="hidden" name="item_id" value="{{ item.id }}">
<input type="hidden" name="next" value="{{ request.get_full_path }}"> <input type="hidden" name="next" value="{{ request.get_full_path }}">
<input type="hidden" name="color_id" id="selected-color-id" value=""> <input type="hidden" name="color_id" id="selected-color-id" value="{{ selected_color_id|default:'' }}">
<button class="product-summary__button product-summary__button--primary" type="submit" {% if not item.is_available %}disabled{% endif %}> <button class="product-summary__button product-summary__button--primary" type="submit" {% if not item.is_available %}disabled{% endif %}>
В корзину В корзину
</button> </button>
@@ -134,7 +132,7 @@
if (!swatches.length || !colorInput) { return; } if (!swatches.length || !colorInput) { return; }
if (!updateForm && cartBtn) { cartBtn.disabled = true; } if (!updateForm && cartBtn && !colorInput.value) { cartBtn.disabled = true; }
swatches.forEach(function (swatch) { swatches.forEach(function (swatch) {
swatch.addEventListener('click', function () { swatch.addEventListener('click', function () {