sforkowany z mtyton/comfy
added possibility to remove product from cart
rodzic
20ea20fa79
commit
4a588bf8ea
|
@ -23,7 +23,9 @@ RUN apt-get update --yes --quiet && apt-get install --yes --quiet --no-install-r
|
||||||
|
|
||||||
# Install the project requirements.
|
# Install the project requirements.
|
||||||
COPY requirements.txt /
|
COPY requirements.txt /
|
||||||
|
COPY requirements_dev.txt /
|
||||||
RUN pip install -r /requirements.txt
|
RUN pip install -r /requirements.txt
|
||||||
|
RUN pip install -r /requirements_dev.txt
|
||||||
|
|
||||||
# Use /app folder as a directory where the source code is stored.
|
# Use /app folder as a directory where the source code is stored.
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash" viewBox="0 0 16 16">
|
||||||
|
<path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5Zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5Zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6Z"/>
|
||||||
|
<path d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1ZM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118ZM2.5 3h11V2h-11v1Z"/>
|
||||||
|
</svg>
|
Po Szerokość: | Wysokość: | Rozmiar: 553 B |
|
@ -51,7 +51,7 @@
|
||||||
<script type="text/javascript" src="{% static 'js/jquery-3.6.4.min.js' %}"></script>
|
<script type="text/javascript" src="{% static 'js/jquery-3.6.4.min.js' %}"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.14.7/dist/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
|
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.14.7/dist/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
|
||||||
<script type="text/javascript" src="{% static 'bootstrap/js/bootstrap.bundle.min.js' %}"></script>
|
<script type="text/javascript" src="{% static 'bootstrap/js/bootstrap.bundle.min.js' %}"></script>
|
||||||
|
<script src="{% static 'js/cart.js' %}"></script>
|
||||||
{% block extra_js %}
|
{% block extra_js %}
|
||||||
{# Override this in templates to add extra javascript #}
|
{# Override this in templates to add extra javascript #}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -13,6 +13,8 @@ services:
|
||||||
- DATABASE_URL
|
- DATABASE_URL
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
|
stdin_open: true
|
||||||
|
tty: true
|
||||||
db:
|
db:
|
||||||
image: postgres
|
image: postgres
|
||||||
restart: always
|
restart: always
|
||||||
|
|
|
@ -2,3 +2,4 @@ FLAKE8>=6.0.0
|
||||||
pre-commit>=3.3.1
|
pre-commit>=3.3.1
|
||||||
isort>=5.12
|
isort>=5.12
|
||||||
black>=23.3.0
|
black>=23.3.0
|
||||||
|
ipdb==0.12.3
|
||||||
|
|
|
@ -51,9 +51,9 @@ class SessionCart(BaseCart):
|
||||||
self.validate_item_id(item_id)
|
self.validate_item_id(item_id)
|
||||||
quantity = int(quantity)
|
quantity = int(quantity)
|
||||||
item_id = int(item_id)
|
item_id = int(item_id)
|
||||||
|
if not self.session[settings.CART_SESSION_ID].get(str(item_id)):
|
||||||
if not self.session[settings.CART_SESSION_ID].get(item_id):
|
|
||||||
self.session[settings.CART_SESSION_ID][item_id] = quantity
|
self.session[settings.CART_SESSION_ID][item_id] = quantity
|
||||||
|
self.session.modified = True
|
||||||
else:
|
else:
|
||||||
self.update_item_quantity(item_id, quantity)
|
self.update_item_quantity(item_id, quantity)
|
||||||
|
|
||||||
|
@ -61,6 +61,7 @@ class SessionCart(BaseCart):
|
||||||
self.validate_item_id(item_id)
|
self.validate_item_id(item_id)
|
||||||
try:
|
try:
|
||||||
self.session[settings.CART_SESSION_ID].pop(item_id)
|
self.session[settings.CART_SESSION_ID].pop(item_id)
|
||||||
|
self.session.modified = True
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# TODO - add logging
|
# TODO - add logging
|
||||||
...
|
...
|
||||||
|
@ -68,7 +69,8 @@ class SessionCart(BaseCart):
|
||||||
def update_item_quantity(self, item_id: int, change: int) -> None:
|
def update_item_quantity(self, item_id: int, change: int) -> None:
|
||||||
self.validate_item_id(item_id)
|
self.validate_item_id(item_id)
|
||||||
try:
|
try:
|
||||||
self.session[settings.CART_SESSION_ID][item_id] += change
|
self.session[settings.CART_SESSION_ID][str(item_id)] += change
|
||||||
|
self.session.modified = True
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# TODO - add logging
|
# TODO - add logging
|
||||||
self.add_item(item_id, change)
|
self.add_item(item_id, change)
|
||||||
|
|
|
@ -28,10 +28,10 @@ class CartProductAddSerializer(serializers.Serializer):
|
||||||
|
|
||||||
def validate_product_id(self, value):
|
def validate_product_id(self, value):
|
||||||
try:
|
try:
|
||||||
self.product = Product.obejcts.get(id=value)
|
Product.objects.get(id=value)
|
||||||
except Product.objects.DoesNotExist:
|
except Product.DoesNotExist:
|
||||||
raise serializers.ValidationError("Unable to add not existing product")
|
raise serializers.ValidationError("Unable to add not existing product")
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def save(self, cart):
|
def save(self, cart):
|
||||||
cart.add_item(self.product, self.validated_data["quantity"])
|
cart.add_item(self.validated_data["product_id"], self.validated_data["quantity"])
|
||||||
|
|
|
@ -4,10 +4,11 @@ $(document).on('click', '.add-to-cart-button', function(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const button = $(this);
|
const button = $(this);
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
const productID = $(this).data('product-id');
|
const productID = parseInt($(this).data('product-id'));
|
||||||
const quantity = $('#quantity'+productID).val();
|
const quantity = parseInt($('#quantity'+productID).val());
|
||||||
const addToCartURL = $(this).data('add-to-cart-url');
|
const addToCartURL = $(this).data('add-to-cart-url');
|
||||||
const csrfToken = $(this).data('csrf-token');
|
const csrfToken = $(this).data('csrf-token');
|
||||||
|
console.log(productID);
|
||||||
formData.append('product_id', productID);
|
formData.append('product_id', productID);
|
||||||
formData.append('quantity', quantity); // Serialize the form data correctly
|
formData.append('quantity', quantity); // Serialize the form data correctly
|
||||||
button.prop('disabled', true);
|
button.prop('disabled', true);
|
||||||
|
@ -107,15 +108,16 @@ $(document).on('click', '.add-to-cart-button', function(event) {
|
||||||
const button = $(this);
|
const button = $(this);
|
||||||
const productId = button.data('product-id');
|
const productId = button.data('product-id');
|
||||||
const csrfToken = button.data('csrf-token');
|
const csrfToken = button.data('csrf-token');
|
||||||
|
const url = button.data('remove-from-cart-url');
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: 'DELETE',
|
type: 'POST',
|
||||||
url: '/cart/item/' + parseInt(productId) + '/',
|
url: url,
|
||||||
|
data: {"product_id": productId},
|
||||||
headers: { 'X-CSRFToken': csrfToken },
|
headers: { 'X-CSRFToken': csrfToken },
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
success: function(data) {
|
success: function(data) {
|
||||||
alert(data.message);
|
alert("Item has been removed");
|
||||||
fetchCartItems(csrfToken);
|
location.reload();
|
||||||
},
|
},
|
||||||
error: function() {
|
error: function() {
|
||||||
alert("Error occurred while removing the item from the cart.");
|
alert("Error occurred while removing the item from the cart.");
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
|
||||||
<script src="{% static 'js/cart.js' %}"></script>
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<section class="h-100">
|
<section class="h-100">
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
<div class="card rounded-3 mb-4">
|
<div class="card rounded-3 mb-4">
|
||||||
<div class="card-body p-4">
|
<div class="card-body p-4">
|
||||||
<div class="row d-flex justify-content-between align-items-center">
|
<div class="row d-flex justify-content-between align-items-center">
|
||||||
|
@ -27,7 +29,12 @@
|
||||||
<h5 class="mb-0">{{item.product.price}} ZŁ</h5>
|
<h5 class="mb-0">{{item.product.price}} ZŁ</h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-1 col-lg-1 col-xl-1 text-end">
|
<div class="col-md-1 col-lg-1 col-xl-1 text-end">
|
||||||
<a href="#!" class="text-danger"><i class="fas fa-trash fa-lg"></i></a>
|
<a href="#!" class="text-danger remove-from-cart-button"
|
||||||
|
data-product-id="{{item.product.id}}"
|
||||||
|
data-csrf-token="{{csrf_token}}"
|
||||||
|
data-remove-from-cart-url={% url "cart-action-remove-product" %}>
|
||||||
|
<img src="{% static 'images/icons/trash.svg'%}" />
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
{% load static %}
|
{% load static %}
|
||||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
|
||||||
<script src="{% static 'js/cart.js' %}"></script>
|
|
||||||
|
|
||||||
<div class="card h-100" style="width: 15rem;">
|
<div class="card h-100" style="width: 15rem;">
|
||||||
<div class="card-header">{{item.title}}</div>
|
<div class="card-header">{{item.title}}</div>
|
||||||
|
@ -13,8 +11,10 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col text-end">
|
<div class="col text-end">
|
||||||
<a href="#" class="btn btn-outline-success add-to-cart-button"
|
<a href="#" class="btn btn-outline-success add-to-cart-button"
|
||||||
data-product-id="{{ item.id }}"
|
data-product-id="{{item.id}}"
|
||||||
data-csrf-token="{{ csrf_token }}">
|
data-csrf-token="{{csrf_token}}"
|
||||||
|
data-add-to-cart-url={% url "cart-action-add-product" %}
|
||||||
|
>
|
||||||
<img src="{% static 'images/icons/cart.svg' %}" alt="Koszyk"/>
|
<img src="{% static 'images/icons/cart.svg' %}" alt="Koszyk"/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
{% extends 'base.html'%}
|
{% extends 'base.html'%}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
<script src="{% static 'js/cart.js' %}"></script>
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
|
|
|
@ -34,19 +34,27 @@ class CartActionView(ViewSet):
|
||||||
# get cart items
|
# get cart items
|
||||||
cart = SessionCart(self.request)
|
cart = SessionCart(self.request)
|
||||||
items = cart.get_items()
|
items = cart.get_items()
|
||||||
serialzier = CartProductSerializer(instance=items, many=True)
|
serializer = CartProductSerializer(instance=items, many=True)
|
||||||
return Response(serialzier.data)
|
return Response(serializer.data)
|
||||||
|
|
||||||
@action(detail=False, methods=["post"])
|
@action(detail=False, methods=["post"])
|
||||||
def add_product(self, request):
|
def add_product(self, request):
|
||||||
cart = SessionCart(self.request)
|
cart = SessionCart(self.request)
|
||||||
serializer = CartProductAddSerializer(data=request.POST)
|
serializer = CartProductAddSerializer(data=request.POST)
|
||||||
if serializer.is_valid():
|
if not serializer.is_valid():
|
||||||
return Response(serializer.errors, status=400)
|
return Response(serializer.errors, status=400)
|
||||||
serializer.save(cart)
|
serializer.save(cart)
|
||||||
|
|
||||||
items = cart.get_items()
|
items = cart.get_items()
|
||||||
serialzier = CartProductSerializer(instance=items, many=True)
|
serializer = CartProductSerializer(instance=items, many=True)
|
||||||
return Response(serialzier.data, status=201)
|
return Response(serializer.data, status=201)
|
||||||
|
|
||||||
# TODO - same for remove product
|
@action(detail=False, methods=["post"])
|
||||||
|
def remove_product(self, request):
|
||||||
|
cart = SessionCart(self.request)
|
||||||
|
product_id = request.POST.get("product_id")
|
||||||
|
cart.remove_item(product_id)
|
||||||
|
|
||||||
|
items = cart.get_items()
|
||||||
|
serializer = CartProductSerializer(instance=items, many=True)
|
||||||
|
return Response(serializer.data, status=201)
|
||||||
|
|
Ładowanie…
Reference in New Issue