feat: wishlist view

This commit is contained in:
2025-01-02 12:17:24 +01:00
parent 7ef4d58ffa
commit 63f01db7ba
8 changed files with 118 additions and 7 deletions
+2
View File
@@ -135,6 +135,8 @@ STATIC_ROOT = BASE_DIR / "static"
MEDIA_URL = "/media/"
MEDIA_ROOT = BASE_DIR / "media"
LOGIN_REDIRECT_URL = "/login/"
STORAGES = {
"default": {
"BACKEND": "django.core.files.storage.FileSystemStorage",
@@ -4,7 +4,7 @@
<input type="hidden" name="product" value="{{ product.pk }}">
{% csrf_token %}
<button class="flex items-center justify-center py-2.5 px-5 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded-lg border border-gray-200 hover:bg-gray-100 hover:text-primary-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700">
{% include 'components/icons/like.svg' %}
{% include 'components/icons/x.svg' %}
{% translate 'Quitar de la lista de deseados' %}
</button>
</form>
@@ -19,7 +19,7 @@
</a>
</li>
<li>
<a href="#" title=""
<a href="{% url 'web:wishlist' %}" title=""
class="inline-flex w-full items-center gap-2 rounded-md px-3 py-2 text-sm hover:bg-gray-100 dark:hover:bg-gray-600">
{% translate 'Lista de deseados' %}
</a>
+31
View File
@@ -0,0 +1,31 @@
{% extends 'theme/base.html' %}
{% load static i18n %}
{% block main %}
{% include 'components/generic/navbar.html' %}
<div>
<section
class="p-8"
hx-get="{% url 'web:list_wishlisted_products' %}"
hx-trigger="load, updated-wishlist"
hx-target="#products"
hx-swap="innerHTML"
>
<h1
class="text-xl font-semibold text-gray-900 dark:text-white sm:text-2xl my-4"
>
{% translate 'Lista de deseados' %}
</h1>
<div>
<section id="products">
</section>
<div class="w-full text-center">
</div>
</div>
</section>
</div>
{% endblock %}
+28 -3
View File
@@ -38,10 +38,12 @@ class TestWishlist(TestCase, CreateProductsMixin):
reverse("web:add_to_wishlist"),
{
"product": self.product.pk,
}
},
)
assert response.status_code == 201
assert WishlistedProduct.objects.filter(user=self.user, product=self.product).exists()
assert WishlistedProduct.objects.filter(
user=self.user, product=self.product
).exists()
def test_logged_user_delete_wishlisted_product(self):
wishlisted = WishlistedProduct.objects.create(
@@ -53,4 +55,27 @@ class TestWishlist(TestCase, CreateProductsMixin):
reverse("web:delete_from_wishlist", kwargs={"pk": wishlisted.pk})
)
assert response.status_code == 204
assert not WishlistedProduct.objects.filter(user=self.user, product=self.product).exists()
assert not WishlistedProduct.objects.filter(
user=self.user, product=self.product
).exists()
def test_logged_user_wishlist(self):
WishlistedProduct.objects.create(
user=self.user,
product=self.product,
)
self.client.force_login(self.user)
response = self.client.get(
reverse("web:wishlist")
)
assert response.status_code == 200
def test_not_logged_user_wishlist(self):
WishlistedProduct.objects.create(
user=self.user,
product=self.product,
)
response = self.client.get(
reverse("web:wishlist")
)
assert response.status_code == 302
+15 -2
View File
@@ -1,6 +1,12 @@
from django.urls import path
from web.views.components import cart, cart_dropdown, list_products, wishlist_button
from django.contrib.auth.decorators import login_required
from web.views.components import (
cart,
cart_dropdown,
list_products,
wishlist_button,
list_wishlisted_products,
)
from web.views.users import login, logout, my_account, register, reset_password
from web.views.web import (
add_cart_item,
@@ -12,12 +18,14 @@ from web.views.web import (
index,
manifest,
product_detail,
wishlist,
)
app_name = "web"
urlpatterns = [
path("", index, name="index"),
path("wishlist", login_required(wishlist, login_url="/login/"), name="wishlist"),
path("categories/<str:slug>/", category_view, name="category_view"),
path("products/<int:pk>/<str:slug>/", product_detail, name="product_detail"),
path("cart/", cart_detail, name="cart_detail"),
@@ -29,6 +37,11 @@ urlpatterns = [
path("my-account/", my_account, name="my_account"),
# components
path("web/components/products/", list_products, name="list_products"),
path(
"web/components/wishlist/",
list_wishlisted_products,
name="list_wishlisted_products",
),
path("web/components/cart-dropdown/", cart_dropdown, name="cart_dropdown"),
path("web/components/cart/", cart, name="cart"),
path(
+27
View File
@@ -28,6 +28,32 @@ class ListProducts(TemplateView, FilteredQuerysetMixin, PaginatedQuerysetMixin):
}
class ListWishlistedProducts(
TemplateView, FilteredQuerysetMixin, PaginatedQuerysetMixin
):
template_name = "web/list_products.html"
queryset = Product.objects.filter(hidden=False).prefetch_related(
"images",
)
filter_class = ProductFilter
def get_queryset(self):
product_ids = WishlistedProduct.objects.filter(
user=self.request.user
).values_list("product", flat=True)
return super().get_queryset().filter(pk__in=product_ids).distinct()
def get_context_data(self, **kwargs):
qs = self.get_queryset()
page = self.get_paginated_queryset(qs)
return {
"page": page,
"has_next_page": page.has_next(),
"has_previous_page": page.has_previous(),
}
def cart_dropdown(request, *args, **kwargs):
cart, created = get_or_create_cart(request)
@@ -91,4 +117,5 @@ class WishlistButton(TemplateView):
list_products = ListProducts.as_view()
list_wishlisted_products = ListWishlistedProducts.as_view()
wishlist_button = WishlistButton.as_view()
+13
View File
@@ -71,6 +71,18 @@ class CartDetail(TemplateView):
}
class WishlistView(TemplateView):
template_name = "web/wishlist.html"
def get_context_data(self, **kwargs):
settings = WebSettings.load()
return {
"title": settings.web_title,
"web_title": settings.web_title,
"description": settings.web_description,
}
@require_http_methods(
[
"POST",
@@ -188,3 +200,4 @@ index = IndexView.as_view()
category_view = CategoryView.as_view()
product_detail = ProductDetail.as_view()
cart_detail = CartDetail.as_view()
wishlist = WishlistView.as_view()