diff --git a/media/products/WhatsApp_Image_2025-03-02_at_12.02.15_cfPyazE.jpeg b/media/products/WhatsApp_Image_2025-03-02_at_12.02.15_cfPyazE.jpeg new file mode 100644 index 0000000..8b3fdee Binary files /dev/null and b/media/products/WhatsApp_Image_2025-03-02_at_12.02.15_cfPyazE.jpeg differ diff --git a/shop/admin.py b/shop/admin.py index ede1402..842c8fa 100644 --- a/shop/admin.py +++ b/shop/admin.py @@ -3,7 +3,7 @@ from .models import Product, Color, Size @admin.register(Product) class ProductAdmin(admin.ModelAdmin): - list_display = ("title", "price") + list_display = ("title", "order", "price", "cut") @admin.register(Color) class ColorAdmin(admin.ModelAdmin): diff --git a/shop/cart.py b/shop/cart.py index 2df32fd..9d8e720 100644 --- a/shop/cart.py +++ b/shop/cart.py @@ -1,4 +1,4 @@ -from .models import CartItem, Product +from .models import CartItem, Product, Color, Size def get_or_create_cart_id(request): """Get the cart ID from the session or create a new one""" @@ -11,7 +11,7 @@ def get_cart_items(request): cart_id = get_or_create_cart_id(request) return CartItem.objects.filter(session_id=cart_id) -def add_to_cart(request, product_id, quantity=1): +def add_to_cart(request, product_id, quantity=1, color_id=None, size_id=None): """Add a product to the cart or update its quantity""" product = Product.objects.get(id=product_id) cart_id = get_or_create_cart_id(request) @@ -23,10 +23,14 @@ def add_to_cart(request, product_id, quantity=1): cart_item.save() except CartItem.DoesNotExist: # Create new cart item + color = Color.objects.get(id=color_id) if color_id else None + size = Size.objects.get(id=size_id) if size_id else None cart_item = CartItem.objects.create( product=product, quantity=quantity, - session_id=cart_id + session_id=cart_id, + color=color, + size=size ) return cart_item @@ -50,3 +54,8 @@ def update_cart_item(request, product_id, quantity): def get_cart_total(request): """Calculate the total price of all items in the cart""" return sum(item.product.price * item.quantity for item in get_cart_items(request)) + +def clear_cart(request): + """Clear the cart""" + cart_id = get_or_create_cart_id(request) + CartItem.objects.filter(session_id=cart_id).delete() diff --git a/shop/migrations/0004_cartitem_color_cartitem_size.py b/shop/migrations/0004_cartitem_color_cartitem_size.py new file mode 100644 index 0000000..889c712 --- /dev/null +++ b/shop/migrations/0004_cartitem_color_cartitem_size.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.11 on 2025-03-18 08:00 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('shop', '0003_rename_productcolor_color_rename_productsize_size_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='cartitem', + name='color', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='shop.color'), + ), + migrations.AddField( + model_name='cartitem', + name='size', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='shop.size'), + ), + ] diff --git a/shop/migrations/0005_alter_color_name_alter_size_name.py b/shop/migrations/0005_alter_color_name_alter_size_name.py new file mode 100644 index 0000000..63c8369 --- /dev/null +++ b/shop/migrations/0005_alter_color_name_alter_size_name.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.11 on 2025-03-18 08:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('shop', '0004_cartitem_color_cartitem_size'), + ] + + operations = [ + migrations.AlterField( + model_name='color', + name='name', + field=models.CharField(choices=[('Red', 'Red'), ('Blue', 'Blue'), ('Green', 'Green'), ('Black', 'Black'), ('White', 'White')], max_length=20, unique=True), + ), + migrations.AlterField( + model_name='size', + name='name', + field=models.CharField(choices=[('S', 'Small'), ('M', 'Medium'), ('L', 'Large'), ('XL', 'X-Large'), ('SINGLE', 'Unique')], max_length=20, unique=True), + ), + ] diff --git a/shop/migrations/0006_alter_product_options_product_order.py b/shop/migrations/0006_alter_product_options_product_order.py new file mode 100644 index 0000000..4c68f84 --- /dev/null +++ b/shop/migrations/0006_alter_product_options_product_order.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2.11 on 2025-03-18 13:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('shop', '0005_alter_color_name_alter_size_name'), + ] + + operations = [ + migrations.AlterModelOptions( + name='product', + options={'ordering': ['order']}, + ), + migrations.AddField( + model_name='product', + name='order', + field=models.IntegerField(default=0), + ), + ] diff --git a/shop/migrations/0007_product_cut.py b/shop/migrations/0007_product_cut.py new file mode 100644 index 0000000..905a6bf --- /dev/null +++ b/shop/migrations/0007_product_cut.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.11 on 2025-03-18 13:49 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('shop', '0006_alter_product_options_product_order'), + ] + + operations = [ + migrations.AddField( + model_name='product', + name='cut', + field=models.IntegerField(choices=[(1, 'Women'), (2, 'Men'), (3, 'Kids')], default=2), + ), + ] diff --git a/shop/models.py b/shop/models.py index 38ab895..f3c49ba 100644 --- a/shop/models.py +++ b/shop/models.py @@ -14,15 +14,21 @@ class SizeChoices(models.TextChoices): MEDIUM = "M", "Medium" LARGE = "L", "Large" XLARGE = "XL", "X-Large" + SINGLE = "SINGLE", "Unique" + +class CutChoices(models.IntegerChoices): + WOMEN = 1, 'Women' + MEN = 2, 'Men' + KIDS = 3, 'Kids' class Color(models.Model): - name = models.CharField(max_length=10, choices=ColorChoices.choices, unique=True) + name = models.CharField(max_length=20, choices=ColorChoices.choices, unique=True) def __str__(self): return self.name class Size(models.Model): - name = models.CharField(max_length=5, choices=SizeChoices.choices, unique=True) + name = models.CharField(max_length=20, choices=SizeChoices.choices, unique=True) def __str__(self): return self.name @@ -35,6 +41,11 @@ class Product(models.Model): # Use string references to prevent circular imports colors = models.ManyToManyField("shop.Color", blank=True, related_name="products") sizes = models.ManyToManyField("shop.Size", blank=True, related_name="products") + order = models.IntegerField(default=0, blank=False) + cut = models.IntegerField(choices=CutChoices.choices, default=CutChoices.MEN) + + class Meta: + ordering = ['order', 'cut'] # Add this line to sort by title def __str__(self): return self.title @@ -43,6 +54,8 @@ class CartItem(models.Model): user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True, blank=True) product = models.ForeignKey(Product, on_delete=models.CASCADE) quantity = models.PositiveIntegerField(default=1) + color = models.ForeignKey(Color, on_delete=models.SET_NULL, null=True, blank=True) + size = models.ForeignKey(Size, on_delete=models.SET_NULL, null=True, blank=True) session_id = models.CharField(max_length=255, null=True, blank=True) date_added = models.DateTimeField(auto_now_add=True) diff --git a/shop/static/shop/css/shop.css b/shop/static/shop/css/shop.css index ee4cde8..95e02d8 100644 --- a/shop/static/shop/css/shop.css +++ b/shop/static/shop/css/shop.css @@ -1,37 +1,124 @@ +.options-container { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + column-gap: 8px; + align-content: center; +} + +.no-image, .product-image { + height: 240px; width: 100%; - height: 180px; - object-fit: contain; - display: block; - margin: 0 auto; + object-fit: contain; /* This will maintain the aspect ratio of the image */ + background-color: black; } -.bubble { - width: 100%; - height: 365px; - display: flex; - flex-direction: column; +.no-image { + background-color: white; } -.bubble h3 { - margin-top: 10px; - font-size: 1.2em; - flex-grow: 1; +.product-title { + font-size: 16px; /* Increase the font size for a bigger title */ + font-weight: bold; /* Make the title bold */ } .product-price { - font-weight: bold; - color: #f39200; - margin: 10px 0; + font-size: 16px; /* Increase the font size for a bigger title */ + font-weight: bold; /* Make the title bold */ +} + +.option-element { + align-content: center; +} + +.option-element:nth-child(1) { + grid-column: 1 / span 2; + grid-row: 1; + height: 64px; +} + +.option-element:nth-child(2) { + grid-column: 3; + grid-row: 1; + text-align: right; +} + +.option-element:nth-child(3) { + grid-column: 1; + grid-row: 2; +} +.option-element:nth-child(4) { + grid-column: 2; + grid-row: 2; +} +.option-element:nth-child(5) { + grid-column: 3; + grid-row: 2; +} + +.option-element:nth-child(6) { + grid-column: 1 / span 2; + grid-row: 3; +} +.option-element:nth-child(7) { + grid-column: 3; + grid-row: 3; + text-align: right; +} + +.add-to-cart-button { + margin-top: 10px; + width: 100%; + background-color: #90ee90; /* Green background */ + text-align: center; + display: inline-block; + height: 40px; /* Set the height to 40 pixels */ + transition: background-color 0.3s ease; /* Smooth transition on hover */ + color: #707070; + border-radius: 12px; + text-decoration: none; + font-size: 12px; + font-weight: 600; +} + +.add-to-cart-button:hover { + background-color: #f39200; + color: white; +} + +.confirm-nav-button { + background-color: #90ee90; +} + +.cancel-nav-button { + background-color: #e84039; + color: white; +} + +.confirm-nav-button:hover, +.cancel-nav-button:hover { + background-color: orange; + color: white; +} + +.cart-table tbody tr.odd { + background-color: #f0f0f0; +} + +.cart-table tbody tr.even { + background-color: #e8e8e8; } -.add-to-cart-form { - display: flex; - gap: 10px; - margin-top: auto; +.cart-table th.price-column, +.cart-table td.price-column { + text-align: right; } -.quantity-input { - width: 50px; - padding: 5px; +.cart-table tfoot .total-label { + font-weight: bold; +} + +.cart-table tfoot .total-price { + font-weight: bold; + font-size: 1.2em; } diff --git a/shop/templates/shop/cart.html b/shop/templates/shop/cart.html index 307285a..2c63185 100644 --- a/shop/templates/shop/cart.html +++ b/shop/templates/shop/cart.html @@ -19,26 +19,43 @@
| Produit | +Couleur | +Taille | +Quantité | +Prix | +
|---|---|---|---|---|
| {{ item.product.title }} | +{{ item.color.name }} | +{{ item.size.name }} | +{{ item.quantity }} | +{{ item.get_total_price }} € | +
| Total: | +{{ cart_items.total_quantity }} | +{{ total }} € | +||
Votre panier est vide.
diff --git a/shop/templates/shop/product_item.html b/shop/templates/shop/product_item.html index 04f41c5..7660871 100644 --- a/shop/templates/shop/product_item.html +++ b/shop/templates/shop/product_item.html @@ -1,17 +1,56 @@ -