feat: wishlist view
This commit is contained in:
@@ -135,6 +135,8 @@ STATIC_ROOT = BASE_DIR / "static"
|
|||||||
MEDIA_URL = "/media/"
|
MEDIA_URL = "/media/"
|
||||||
MEDIA_ROOT = BASE_DIR / "media"
|
MEDIA_ROOT = BASE_DIR / "media"
|
||||||
|
|
||||||
|
LOGIN_REDIRECT_URL = "/login/"
|
||||||
|
|
||||||
STORAGES = {
|
STORAGES = {
|
||||||
"default": {
|
"default": {
|
||||||
"BACKEND": "django.core.files.storage.FileSystemStorage",
|
"BACKEND": "django.core.files.storage.FileSystemStorage",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<input type="hidden" name="product" value="{{ product.pk }}">
|
<input type="hidden" name="product" value="{{ product.pk }}">
|
||||||
{% csrf_token %}
|
{% 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">
|
<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' %}
|
{% translate 'Quitar de la lista de deseados' %}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<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">
|
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' %}
|
{% translate 'Lista de deseados' %}
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -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 %}
|
||||||
@@ -38,10 +38,12 @@ class TestWishlist(TestCase, CreateProductsMixin):
|
|||||||
reverse("web:add_to_wishlist"),
|
reverse("web:add_to_wishlist"),
|
||||||
{
|
{
|
||||||
"product": self.product.pk,
|
"product": self.product.pk,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
assert response.status_code == 201
|
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):
|
def test_logged_user_delete_wishlisted_product(self):
|
||||||
wishlisted = WishlistedProduct.objects.create(
|
wishlisted = WishlistedProduct.objects.create(
|
||||||
@@ -53,4 +55,27 @@ class TestWishlist(TestCase, CreateProductsMixin):
|
|||||||
reverse("web:delete_from_wishlist", kwargs={"pk": wishlisted.pk})
|
reverse("web:delete_from_wishlist", kwargs={"pk": wishlisted.pk})
|
||||||
)
|
)
|
||||||
assert response.status_code == 204
|
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
@@ -1,6 +1,12 @@
|
|||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
from web.views.components import cart, cart_dropdown, list_products, wishlist_button
|
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.users import login, logout, my_account, register, reset_password
|
||||||
from web.views.web import (
|
from web.views.web import (
|
||||||
add_cart_item,
|
add_cart_item,
|
||||||
@@ -12,12 +18,14 @@ from web.views.web import (
|
|||||||
index,
|
index,
|
||||||
manifest,
|
manifest,
|
||||||
product_detail,
|
product_detail,
|
||||||
|
wishlist,
|
||||||
)
|
)
|
||||||
|
|
||||||
app_name = "web"
|
app_name = "web"
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", index, name="index"),
|
path("", index, name="index"),
|
||||||
|
path("wishlist", login_required(wishlist, login_url="/login/"), name="wishlist"),
|
||||||
path("categories/<str:slug>/", category_view, name="category_view"),
|
path("categories/<str:slug>/", category_view, name="category_view"),
|
||||||
path("products/<int:pk>/<str:slug>/", product_detail, name="product_detail"),
|
path("products/<int:pk>/<str:slug>/", product_detail, name="product_detail"),
|
||||||
path("cart/", cart_detail, name="cart_detail"),
|
path("cart/", cart_detail, name="cart_detail"),
|
||||||
@@ -29,6 +37,11 @@ urlpatterns = [
|
|||||||
path("my-account/", my_account, name="my_account"),
|
path("my-account/", my_account, name="my_account"),
|
||||||
# components
|
# components
|
||||||
path("web/components/products/", list_products, name="list_products"),
|
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-dropdown/", cart_dropdown, name="cart_dropdown"),
|
||||||
path("web/components/cart/", cart, name="cart"),
|
path("web/components/cart/", cart, name="cart"),
|
||||||
path(
|
path(
|
||||||
|
|||||||
@@ -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):
|
def cart_dropdown(request, *args, **kwargs):
|
||||||
cart, created = get_or_create_cart(request)
|
cart, created = get_or_create_cart(request)
|
||||||
|
|
||||||
@@ -91,4 +117,5 @@ class WishlistButton(TemplateView):
|
|||||||
|
|
||||||
|
|
||||||
list_products = ListProducts.as_view()
|
list_products = ListProducts.as_view()
|
||||||
|
list_wishlisted_products = ListWishlistedProducts.as_view()
|
||||||
wishlist_button = WishlistButton.as_view()
|
wishlist_button = WishlistButton.as_view()
|
||||||
|
|||||||
@@ -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(
|
@require_http_methods(
|
||||||
[
|
[
|
||||||
"POST",
|
"POST",
|
||||||
@@ -188,3 +200,4 @@ index = IndexView.as_view()
|
|||||||
category_view = CategoryView.as_view()
|
category_view = CategoryView.as_view()
|
||||||
product_detail = ProductDetail.as_view()
|
product_detail = ProductDetail.as_view()
|
||||||
cart_detail = CartDetail.as_view()
|
cart_detail = CartDetail.as_view()
|
||||||
|
wishlist = WishlistView.as_view()
|
||||||
|
|||||||
Reference in New Issue
Block a user