From 540000277240f720e62a990c1e45b5caabdf6085 Mon Sep 17 00:00:00 2001 From: Nathan Chapman Date: Sun, 3 Apr 2022 09:56:12 -0600 Subject: [PATCH 1/4] Updates and fixes --- src/accounts/forms.py | 30 ++++++++- src/core/models.py | 12 ++++ .../dashboard/coupon_confirm_delete.html | 2 +- .../templates/dashboard/coupon_detail.html | 4 +- .../templates/dashboard/customer_form.html | 1 + src/dashboard/views.py | 2 +- src/static/images/site_logo.svg | 27 ++++++++ src/static/styles/main.css | 35 +++++++--- src/storefront/cart.py | 7 +- src/storefront/forms.py | 35 ++++++++-- .../templates/storefront/about.html | 16 +++-- .../templates/storefront/address_form.html | 16 +++++ .../templates/storefront/cart_detail.html | 54 ++++++++------- .../storefront/checkout_address.html | 8 ++- .../templates/storefront/customer_detail.html | 11 ++- .../templates/storefront/customer_form.html | 3 +- .../templates/storefront/order_detail.html | 50 ++++++++++++++ .../templates/storefront/order_form.html | 17 +++-- .../templates/storefront/product_detail.html | 6 ++ .../templates/storefront/product_list.html | 5 +- src/storefront/urls.py | 5 ++ src/storefront/views.py | 67 +++++++++++++++---- src/templates/account/email.html | 1 + src/templates/base.html | 19 ++---- 24 files changed, 332 insertions(+), 101 deletions(-) create mode 100644 src/static/images/site_logo.svg create mode 100644 src/storefront/templates/storefront/address_form.html create mode 100644 src/storefront/templates/storefront/order_detail.html diff --git a/src/accounts/forms.py b/src/accounts/forms.py index aa7e2c5..aa0d7b8 100644 --- a/src/accounts/forms.py +++ b/src/accounts/forms.py @@ -5,7 +5,15 @@ from .models import Address, User class AddressForm(forms.ModelForm): class Meta: model = Address - fields = '__all__' + fields = ( + 'first_name', + 'last_name', + 'street_address_1', + 'street_address_2', + 'city', + 'state', + 'postal_code', + ) class AccountCreateForm(UserCreationForm): @@ -16,8 +24,24 @@ class AccountCreateForm(UserCreationForm): class AccountUpdateForm(UserChangeForm): class Meta: model = User - fields = [ + fields = ( 'first_name', 'last_name', 'email', - ] + 'default_shipping_address', + 'addresses', + ) + +class CustomerUpdateForm(forms.ModelForm): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields['default_shipping_address'].queryset = kwargs['instance'].addresses + + class Meta: + model = User + fields = ( + 'first_name', + 'last_name', + 'email', + 'default_shipping_address', + ) diff --git a/src/core/models.py b/src/core/models.py index 9e9082c..a64e201 100644 --- a/src/core/models.py +++ b/src/core/models.py @@ -73,6 +73,12 @@ class ProductPhoto(models.Model): def __str__(self): return self.product.name + def delete(self, *args, **kwargs): + storage, path = self.image.storage, self.image.path + + super(ProductPhoto, self).delete(*args, **kwargs) + storage.delete(path) + # def save(self, *args, **kwargs): # super().save(*args, **kwargs) @@ -109,6 +115,9 @@ class Coupon(models.Model): class Meta: ordering = ("code",) + def __str__(self): + return self.name + @property def is_valid(self): today = timezone.localtime(timezone.now()) @@ -224,6 +233,9 @@ class Order(models.Model): def get_absolute_url(self): return reverse('dashboard:order-detail', kwargs={'pk': self.pk}) + class Meta: + ordering = ('-created_at',) + class Transaction(models.Model): diff --git a/src/dashboard/templates/dashboard/coupon_confirm_delete.html b/src/dashboard/templates/dashboard/coupon_confirm_delete.html index a5e20c6..ed1a632 100644 --- a/src/dashboard/templates/dashboard/coupon_confirm_delete.html +++ b/src/dashboard/templates/dashboard/coupon_confirm_delete.html @@ -7,7 +7,7 @@

Coupon

-
{% csrf_token %} + {% csrf_token %}

Are you sure you want to delete "{{ object }}"?

{{ form.as_p }}

diff --git a/src/dashboard/templates/dashboard/coupon_detail.html b/src/dashboard/templates/dashboard/coupon_detail.html index 857efec..aaa3354 100644 --- a/src/dashboard/templates/dashboard/coupon_detail.html +++ b/src/dashboard/templates/dashboard/coupon_detail.html @@ -6,8 +6,8 @@

{{ coupon.name }}

diff --git a/src/dashboard/templates/dashboard/customer_form.html b/src/dashboard/templates/dashboard/customer_form.html index 0c73630..4d157a5 100644 --- a/src/dashboard/templates/dashboard/customer_form.html +++ b/src/dashboard/templates/dashboard/customer_form.html @@ -2,6 +2,7 @@ {% block content %}
+

← Back

Update Customer

diff --git a/src/dashboard/views.py b/src/dashboard/views.py index 29d798a..5525621 100644 --- a/src/dashboard/views.py +++ b/src/dashboard/views.py @@ -279,7 +279,7 @@ class CustomerUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView): model = User template_name = 'dashboard/customer_form.html' context_object_name = 'customer' - success_message = '%(name)s saved.' + success_message = 'Customer saved.' fields = ( 'first_name', 'last_name', diff --git a/src/static/images/site_logo.svg b/src/static/images/site_logo.svg new file mode 100644 index 0000000..fe1303e --- /dev/null +++ b/src/static/images/site_logo.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + Port Townsend Roasting Company + + + + + diff --git a/src/static/styles/main.css b/src/static/styles/main.css index 17e4494..4d4d669 100644 --- a/src/static/styles/main.css +++ b/src/static/styles/main.css @@ -1,5 +1,5 @@ :root { - --fg-color: #333; + --fg-color: #34201A; --bg-color: #f5f5f5; --gray-color: #9d9d9d; --yellow-color: #f8a911; @@ -33,7 +33,6 @@ a { h1, h2, h3, h4, h5 { margin: 0; - font-family: 'Eczar', serif; font-weight: 700; line-height: 1.3; } @@ -63,6 +62,10 @@ small, .text_small { font-size: 0.833rem; } +.text-center { + text-align: center; +} + @@ -196,6 +199,7 @@ figure { } img { box-sizing: border-box; + max-width: 100%; } .product__item { @@ -228,7 +232,8 @@ img { } .site__logo { - text-decoration: none; + height: 3rem; + vertical-align: middle; } .site__header div, @@ -238,6 +243,13 @@ img { align-items: baseline; } +@media (max-width: 911px) { + .site__header div { + flex-direction: column; + justify-content: center; + } +} + nav a { text-transform: lowercase; font-variant: small-caps; @@ -288,12 +300,17 @@ nav { .cart__item { display: grid; - grid-template-columns: 1fr 5fr; + grid-template-columns: 1fr 1.5fr; gap: 1rem; padding: 2rem 0; border-bottom: 0.05rem solid var(--gray-color); } +.cart__item:last-child { + margin-bottom: 2rem; + border-bottom: none; +} + .cart__total_price { text-align: right; font-size: 1.5rem; @@ -337,10 +354,6 @@ nav { } -.order__shipping { -} - - .shipping__details { margin-bottom: 3rem; max-width: 32rem; @@ -353,7 +366,7 @@ nav { .order__total { - margin: 3rem 0; + /*margin: 3rem 0;*/ text-align: right; } @@ -437,8 +450,8 @@ footer { ._form_1 { margin: 0; } -._form_1 div form { - margin: 1rem 0 !important; +#_form_62486B0492FDE_ { + margin: 1.7rem 0 !important; padding: 0 !important; } diff --git a/src/storefront/cart.py b/src/storefront/cart.py index 2a6ba01..08ce2dd 100644 --- a/src/storefront/cart.py +++ b/src/storefront/cart.py @@ -31,10 +31,7 @@ class Cart: 'roast': roast, 'price': str(product.price) } - elif product_id in self.cart: - self.cart[product_id].update({ - 'roast': roast, - }) + if update_quantity: self.cart[product_id]['quantity'] = quantity else: @@ -71,7 +68,7 @@ class Cart: def clear(self): del self.session[settings.CART_SESSION_ID] - del self.coupon_code + del self.session[self.coupon_code] self.session.modified = True def build_order_params(self): diff --git a/src/storefront/forms.py b/src/storefront/forms.py index 524c351..0582874 100644 --- a/src/storefront/forms.py +++ b/src/storefront/forms.py @@ -31,11 +31,34 @@ class AddToCartForm(forms.Form): (OTHER, 'Other (enter below)') ] - ONE_TIME = 'One-time purchase' - SUBSCRIBE = 'Subscribe' - PURCHASE_TYPE_CHOICES = [ - (ONE_TIME, 'One-time purchase'), - (SUBSCRIBE, 'Subscribe and save 10%'), + quantity = forms.IntegerField(min_value=1, initial=1) + roast = forms.ChoiceField(choices=ROAST_CHOICES) + +class UpdateCartItemForm(forms.Form): + quantity = forms.IntegerField(min_value=1, initial=1) + update = forms.BooleanField(required=False, initial=True, widget=forms.HiddenInput) + + +class AddToSubscriptionForm(forms.Form): + WHOLE = 'Whole Beans' + ESPRESSO = 'Espresso' + CONE_DRIP = 'Cone Drip' + BASKET_DRIP = 'Basket Drip' + FRENCH_PRESS = 'French Press' + STOVETOP_ESPRESSO = 'Stovetop Espresso (Moka Pot)' + AEROPRESS = 'AeroPress' + PERCOLATOR = 'Percolator' + OTHER = 'Other' + ROAST_CHOICES = [ + (WHOLE, 'Whole Beans'), + (ESPRESSO, 'Espresso'), + (CONE_DRIP, 'Cone Drip'), + (BASKET_DRIP, 'Basket Drip'), + (FRENCH_PRESS, 'French Press'), + (STOVETOP_ESPRESSO, 'Stovetop Espresso (Moka Pot)'), + (AEROPRESS, 'AeroPress'), + (PERCOLATOR, 'Percolator'), + (OTHER, 'Other (enter below)') ] SEVEN_DAYS = 7 @@ -49,9 +72,7 @@ class AddToCartForm(forms.Form): quantity = forms.IntegerField(min_value=1, initial=1) roast = forms.ChoiceField(choices=ROAST_CHOICES) - purchase_type = forms.ChoiceField(choices=PURCHASE_TYPE_CHOICES, initial=ONE_TIME) schedule = forms.ChoiceField(choices=SCHEDULE_CHOICES) - update = forms.BooleanField(required=False, initial=False, widget=forms.HiddenInput) class AddressForm(forms.Form): diff --git a/src/storefront/templates/storefront/about.html b/src/storefront/templates/storefront/about.html index 6a01753..77c238b 100644 --- a/src/storefront/templates/storefront/about.html +++ b/src/storefront/templates/storefront/about.html @@ -3,12 +3,18 @@ {% block content %}
-

About PT Coffee

-
- -
+
+

About PT Coffee

+
-

We love coffee!

+
+ +
+
+
+
+

We love coffee!

+

If you’ve found Port Townsend Coffee Roasting Co., you probably love coffee so much that you seek out the best tasting, Certified Fair Trade Organic coffees available.

You’ve probably been around coffee for years, perhaps starting with Specialty Coffees in the 1980’s, and know your way around fairly well. How and where coffee is grown and harvested, how it’s roasted, how to brew it. You value fair, guaranteed wages for growers and sustainable stewardship of the land where it’s grown.

No matter how much you drink, if you’re like us, great coffee is an important perk in your life. You are not alone in this… coffee is the one of the world’s most heavily traded commodities. In addition to the impact it has as a crop on the economies of producing countries, the cafe and coffee house industry touches millions of lives everyday, worldwide, as well.

diff --git a/src/storefront/templates/storefront/address_form.html b/src/storefront/templates/storefront/address_form.html new file mode 100644 index 0000000..ac38b54 --- /dev/null +++ b/src/storefront/templates/storefront/address_form.html @@ -0,0 +1,16 @@ +{% extends 'base.html' %} + +{% block content %} +
+
+

← Back

+

Update Address

+ + {% csrf_token %} + {{ form.as_p }} + + + +
+
+{% endblock %} diff --git a/src/storefront/templates/storefront/cart_detail.html b/src/storefront/templates/storefront/cart_detail.html index 8c349a9..1aae45d 100644 --- a/src/storefront/templates/storefront/cart_detail.html +++ b/src/storefront/templates/storefront/cart_detail.html @@ -2,20 +2,23 @@ {% block content %}
-

Shopping Cart

-
+
+
+

Shopping Cart

+
{% for item in cart %} -
+
{% with product=item.product %}
{{product.productphoto_set.first.image}}

{{product.name}}
${{item.price}}

+

{{item.roast}}

Remove from cart

-
+ {% csrf_token %} {{ item.update_quantity_form }} @@ -27,26 +30,31 @@

No items in cart yet.

{% endfor %}
-
-
- - {% csrf_token %} - {{ coupon_apply_form.as_p }} -

- -

- +
+
+

Cart Totals

+
+
+
+
+ {% csrf_token %} + {{ coupon_apply_form.as_p }} +

+ +

+
+
+

+ Subtotal: ${{cart.get_total_price|floatformat:"2"}}
+ {% if cart.coupon %} + Coupon: {{cart.coupon.discount_value}} {{cart.coupon.get_discount_value_type_display}}
+ {% endif %} + Cart total: ${{cart.get_total_price_after_discount|floatformat:"2"}} +

+

+ Continue Shopping or Proceed to Checkout +

-

- Subtotal: ${{cart.get_total_price|floatformat:"2"}}
- {% if cart.coupon %} - Coupon: {{cart.coupon.discount_value}} {{cart.coupon.get_discount_value_type_display}}
- {% endif %} - Cart total: ${{cart.get_total_price_after_discount|floatformat:"2"}} -

-

- Continue Shopping or Proceed to Checkout -

{% endblock %} diff --git a/src/storefront/templates/storefront/checkout_address.html b/src/storefront/templates/storefront/checkout_address.html index d5d1f4e..ef7ca16 100644 --- a/src/storefront/templates/storefront/checkout_address.html +++ b/src/storefront/templates/storefront/checkout_address.html @@ -3,9 +3,11 @@ {% block content %}
-

Checkout

-
-
+
+

Checkout

+
+
+

Shipping Address

{% csrf_token %} diff --git a/src/storefront/templates/storefront/customer_detail.html b/src/storefront/templates/storefront/customer_detail.html index 62f6d1f..6069a1e 100644 --- a/src/storefront/templates/storefront/customer_detail.html +++ b/src/storefront/templates/storefront/customer_detail.html @@ -28,11 +28,10 @@ {% endif %} {{shipping_address.city}}, {{shipping_address.state}}, {{shipping_address.postal_code}} - Edit {% endwith %}
- Other addresses
+

All addresses

{% for address in customer.addresses.all %}

@@ -44,7 +43,7 @@ {% endif %} {{address.city}}, {{address.state}}, {{address.postal_code}}
- Edit + Edit

{% empty %}

No other addresses.

@@ -53,15 +52,15 @@
{% with order_list=customer.orders.all %}
-
+
Order # Date Total
{% for order in order_list %} - + #{{order.pk}} - {{order.created_at|date:"D, M j Y"}} + {{order.created_at|date:"M j, Y"}} ${{order.total_net_amount}} {% empty %} diff --git a/src/storefront/templates/storefront/customer_form.html b/src/storefront/templates/storefront/customer_form.html index 4ef2901..37680d0 100644 --- a/src/storefront/templates/storefront/customer_form.html +++ b/src/storefront/templates/storefront/customer_form.html @@ -2,13 +2,14 @@ {% block content %}
+

← Back

Update your profile

{% csrf_token %} {{form.as_p}}

- or cancel +

diff --git a/src/storefront/templates/storefront/order_detail.html b/src/storefront/templates/storefront/order_detail.html new file mode 100644 index 0000000..a2bbe6c --- /dev/null +++ b/src/storefront/templates/storefront/order_detail.html @@ -0,0 +1,50 @@ +{% extends "base.html" %} +{% load static %} + +{% block content %} +
+

← Back

+
+

Order #{{order.pk}}

+
+
+
+ Product + + Quantity + Price + Total +
+ {% for item in order.lines.all %} +
+ {% with product=item.product %} +
+ {{product.productphoto_set.first.image}} +
+ {{product.name}} + {{item.quantity}} + ${{product.price}} + ${{item.get_total}} + {% endwith %} +
+ {% empty %} +

No items in order yet.

+ {% endfor %} +
+ +
+
+

Payment

+
+
+

+ Subtotal: {{order.total_net_amount}}
+ {% if order.coupon %} + Discount: {{order.coupon.discount_value}} {{order.coupon.get_discount_value_type_display}}
+ {% endif %} + Total: {{order.get_total_price_after_discount}} +

+
+
+
+{% endblock content %} diff --git a/src/storefront/templates/storefront/order_form.html b/src/storefront/templates/storefront/order_form.html index a29d6ec..0fc9f7a 100644 --- a/src/storefront/templates/storefront/order_form.html +++ b/src/storefront/templates/storefront/order_form.html @@ -8,9 +8,11 @@ {% block content %}
-

Checkout

-
-
+
+

Checkout

+
+
+

Shipping Address

{{shipping_address.first_name}} @@ -23,24 +25,25 @@
edit
-
+

Cart Summary

{% for item in cart %}
{% with product=item.product %}
- {{item.quantity}} x {{product.productphoto_set.first.image}}

{{product.name}}
${{item.price}}

-

Grind options: {{item.customer_note}}

+

Quantity: {{item.quantity}}

+

Grind options: {{item.roast}}

{% endwith %}
{% endfor %}
-
+
+

Order Totals

{% csrf_token %} {{form.as_p}} diff --git a/src/storefront/templates/storefront/product_detail.html b/src/storefront/templates/storefront/product_detail.html index f2287fb..724e8e3 100644 --- a/src/storefront/templates/storefront/product_detail.html +++ b/src/storefront/templates/storefront/product_detail.html @@ -17,11 +17,17 @@

{{product.weight.oz}} oz

{% csrf_token %} +

One-time purchase

{{ form.as_p }}

+


+
+

Subscribe and save 10%

+
+ Subscriptions
{% endblock %} diff --git a/src/storefront/templates/storefront/product_list.html b/src/storefront/templates/storefront/product_list.html index 5229c94..1d6b6b0 100644 --- a/src/storefront/templates/storefront/product_list.html +++ b/src/storefront/templates/storefront/product_list.html @@ -9,9 +9,10 @@ {{product.productphoto_set.first.image}}
-

{{ product.name }}


-

${{product.price}}

+

{{ product.name }}

{{product.description}}

+

${{product.price}}

+

{{product.weight.oz}} oz

diff --git a/src/storefront/urls.py b/src/storefront/urls.py index 1cfc1a1..4c505f8 100644 --- a/src/storefront/urls.py +++ b/src/storefront/urls.py @@ -12,6 +12,7 @@ urlpatterns = [ path('cart/', views.CartView.as_view(), name='cart-detail'), path('cart//add/', views.CartAddProductView.as_view(), name='cart-add'), + path('cart//update/', views.CartUpdateProductView.as_view(), name='cart-update'), path('cart//remove/', views.cart_remove_product_view, name='cart-remove'), path('coupon/apply/', views.CouponApplyView.as_view(), name='coupon-apply'), @@ -28,5 +29,9 @@ urlpatterns = [ path('', views.CustomerDetailView.as_view(), name='customer-detail'), path('update/', views.CustomerUpdateView.as_view(), name='customer-update'), # path('delete/', views.CustomerDeleteView.as_view(), name='customer-delete'), + + path('orders//', views.OrderDetailView.as_view(), name='order-detail'), + path('addresses//update/', views.AddressUpdateView.as_view(), name='address-update'), ])), + ] diff --git a/src/storefront/views.py b/src/storefront/views.py index 0eed505..bff7fb3 100644 --- a/src/storefront/views.py +++ b/src/storefront/views.py @@ -23,10 +23,11 @@ from paypalcheckoutsdk.core import PayPalHttpClient, SandboxEnvironment from accounts.models import User, Address from accounts.utils import get_or_create_customer +from accounts.forms import AddressForm as AccountAddressForm, CustomerUpdateForm from core.models import Product, Order, Transaction, OrderLine, Coupon from core.forms import ShippingMethodForm -from .forms import AddToCartForm, OrderCreateForm, AddressForm, CouponApplyForm, ContactForm +from .forms import AddToCartForm, UpdateCartItemForm, OrderCreateForm, AddressForm, CouponApplyForm, ContactForm from .cart import Cart from .payments import CaptureOrder @@ -39,11 +40,9 @@ class CartView(TemplateView): context = super().get_context_data(**kwargs) cart = Cart(self.request) for item in cart: - item['update_quantity_form'] = AddToCartForm( + item['update_quantity_form'] = UpdateCartItemForm( initial={ 'quantity': item['quantity'], - 'roast': item['roast'], - 'update': True } ) context['cart'] = cart @@ -64,6 +63,29 @@ class CartAddProductView(SingleObjectMixin, FormView): cart.add( product=self.get_object(), roast=form.cleaned_data['roast'], + quantity=form.cleaned_data['quantity'] + ) + return self.form_valid(form) + else: + return self.form_invalid(form) + + def form_valid(self, form): + return super().form_valid(form) + + +class CartUpdateProductView(SingleObjectMixin, FormView): + model = Product + form_class = UpdateCartItemForm + + def get_success_url(self): + return reverse('storefront:cart-detail') + + def post(self, request, *args, **kwargs): + cart = Cart(request) + form = self.get_form() + if form.is_valid(): + cart.add( + product=self.get_object(), quantity=form.cleaned_data['quantity'], update_quantity=form.cleaned_data['update'] ) @@ -227,25 +249,46 @@ class PaymentCanceledView(TemplateView): template_name = 'storefront/payment_canceled.html' -class CustomerDetailView(DetailView): +class CustomerDetailView(LoginRequiredMixin, DetailView): model = User template_name = 'storefront/customer_detail.html' context_object_name = 'customer' -class CustomerUpdateView(UpdateView): +class CustomerUpdateView(LoginRequiredMixin, UpdateView): model = User template_name = 'storefront/customer_form.html' context_object_name = 'customer' - fields = ( - 'first_name', - 'last_name', - 'email', - 'default_shipping_address' - ) + form_class = CustomerUpdateForm def get_success_url(self): return reverse('storefront:customer-detail', kwargs={'pk': self.object.pk}) +class OrderDetailView(LoginRequiredMixin, DetailView): + model = Order + template_name = 'storefront/order_detail.html' + pk_url_kwarg = 'order_pk' + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['customer'] = User.objects.get(pk=self.kwargs['pk']) + return context + +class AddressUpdateView(LoginRequiredMixin, UpdateView): + model = Address + pk_url_kwarg = 'address_pk' + template_name = 'storefront/address_form.html' + form_class = AccountAddressForm + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['customer'] = User.objects.get(pk=self.kwargs['pk']) + return context + + def get_success_url(self): + return reverse('storefront:customer-detail',kwargs={'pk': self.kwargs['pk']}) + + + class AboutView(TemplateView): template_name = 'storefront/about.html' diff --git a/src/templates/account/email.html b/src/templates/account/email.html index a2bc362..9884d05 100644 --- a/src/templates/account/email.html +++ b/src/templates/account/email.html @@ -6,6 +6,7 @@ {% block content %}
+

← Back

{% trans "E-mail Addresses" %}

diff --git a/src/templates/base.html b/src/templates/base.html index 818312a..7abba39 100644 --- a/src/templates/base.html +++ b/src/templates/base.html @@ -25,19 +25,19 @@ - -
{% block content %} {% endblock content %} From f55a87dca459032313eb1249a5dfdcaf712d7ac1 Mon Sep 17 00:00:00 2001 From: Nathan Chapman Date: Tue, 5 Apr 2022 10:04:24 -0600 Subject: [PATCH 2/4] UI cleanup and fixes --- .../dashboard/product_create_form.html | 8 +- src/dashboard/views.py | 5 +- src/static/images/site_logo.svg | 28 +----- src/static/styles/main.css | 89 +++++++++++++++++-- src/storefront/cart.py | 8 +- src/storefront/forms.py | 12 +-- .../templates/storefront/cart_detail.html | 17 ++-- .../templates/storefront/customer_detail.html | 3 + .../templates/storefront/order_form.html | 5 +- .../templates/storefront/product_detail.html | 7 +- src/storefront/views.py | 2 +- src/templates/base.html | 55 ++++++------ 12 files changed, 150 insertions(+), 89 deletions(-) diff --git a/src/dashboard/templates/dashboard/product_create_form.html b/src/dashboard/templates/dashboard/product_create_form.html index 93af236..4716353 100644 --- a/src/dashboard/templates/dashboard/product_create_form.html +++ b/src/dashboard/templates/dashboard/product_create_form.html @@ -2,9 +2,11 @@ {% block content %}
-

Create product

-
-
+
+

Create product

+
+
+ {% csrf_token %} {{form.as_p}}

diff --git a/src/dashboard/views.py b/src/dashboard/views.py index 5525621..7a5a50b 100644 --- a/src/dashboard/views.py +++ b/src/dashboard/views.py @@ -116,9 +116,10 @@ class OrderListView(LoginRequiredMixin, ListView): def get_queryset(self): query = self.request.GET.get('status') - if query: + if query == 'unfulfilled': object_list = Order.objects.filter( - status=query + Q(status=OrderStatus.UNFULFILLED) | + Q(status=OrderStatus.PARTIALLY_FULFILLED) ).order_by( '-created_at' ).select_related( diff --git a/src/static/images/site_logo.svg b/src/static/images/site_logo.svg index fe1303e..dc5c8d2 100644 --- a/src/static/images/site_logo.svg +++ b/src/static/images/site_logo.svg @@ -1,27 +1 @@ - - - - - - - - - - - - - - - - - - - - - - Port Townsend Roasting Company - - - - - + \ No newline at end of file diff --git a/src/static/styles/main.css b/src/static/styles/main.css index 4d4d669..3dffd95 100644 --- a/src/static/styles/main.css +++ b/src/static/styles/main.css @@ -202,12 +202,23 @@ img { max-width: 100%; } +.fair_trade--small { + max-width: 4rem; + vertical-align: middle; +} + .product__item { display: grid; grid-template-columns: 2fr 1fr; gap: 0 2rem; } +@media (max-width: 876px) { + .product__item { + grid-template-columns: 1fr; + } +} + .product__list-item button { grid-column: 1/3; align-self: end; @@ -222,17 +233,17 @@ img { .product__form { display: grid; - grid-template-columns: 1fr 3fr; + grid-template-columns: 1fr 1fr 1fr; gap: 1rem; } .product__form input[type=submit] { - grid-column: 2; + /*grid-column: 2;*/ justify-self: end; } -.site__logo { - height: 3rem; +.site-logo { + height: 4rem; vertical-align: middle; } @@ -257,10 +268,55 @@ nav a { text-decoration: none; } +nav a:not(:last-child) { + margin-right: 2rem; +} + nav { margin-bottom: 4rem; } +.has-menu { + position: relative; +} + +.has-menu a { + text-transform: lowercase; + font-variant: small-caps; + font-weight: bold; + text-decoration: none; +} + +.has-menu:hover .dropdown-menu { + display: unset; +} + +[role="menu"] { + list-style: none; + margin: 0; + padding: 0; +} + +[role="menuitem"] { + cursor: pointer; + position: relative; +} +[role="menuitem"]:not(:last-child) { + margin-bottom: 0.5rem; + +} + +.dropdown-menu { + background-color: var(--bg-color); + border: var(--default-border); + padding: 0.5rem; + position: absolute; + top: 100%; + right: 0; + z-index: 1000; + display: none; +} + .site__copyright { text-align: center; } @@ -270,20 +326,31 @@ nav { grid-template-columns: 1fr 2fr; gap: 2rem; } + .keep_calm__img { max-width: 250px; } +@media (max-width: 564px) { + .keep_calm { + grid-template-columns: 1fr; + } + .keep_calm figure { + text-align: center; + } +} + .site__cart { display: flex; align-items: center; background-color: var(--yellow-color); - padding: 0.25rem 1rem; + padding: 0 1rem; text-decoration: none; border-radius: 0.2rem; color: var(--fg-color); cursor: pointer; + margin-left: 2rem; } @@ -337,6 +404,13 @@ nav { gap: 8rem; } +@media (max-width: 911px) { + .product__list { + grid-template-columns: 1fr; + gap: 4rem; + } +} + .product__list-item { text-decoration: none; display: grid; @@ -384,6 +458,7 @@ footer { + .object__header { display: flex; align-items: baseline; @@ -437,6 +512,10 @@ footer { gap: 2rem; } +.fair-trade-stamp { + text-align: center; +} + .user__emails { margin-bottom: 4rem; diff --git a/src/storefront/cart.py b/src/storefront/cart.py index 08ce2dd..906e10e 100644 --- a/src/storefront/cart.py +++ b/src/storefront/cart.py @@ -23,12 +23,12 @@ class Cart: cart = self.session[settings.CART_SESSION_ID] = {} self.cart = cart - def add(self, product, quantity=1, roast='', update_quantity=False): + def add(self, product, quantity=1, grind='', update_quantity=False): product_id = str(product.id) if product_id not in self.cart: self.cart[product_id] = { 'quantity': 0, - 'roast': roast, + 'grind': grind, 'price': str(product.price) } @@ -68,7 +68,7 @@ class Cart: def clear(self): del self.session[settings.CART_SESSION_ID] - del self.session[self.coupon_code] + del self.session['coupon_code'] self.session.modified = True def build_order_params(self): @@ -94,7 +94,7 @@ class Cart: bulk_list = [OrderLine( order=order, product=item['product'], - customer_note=item['roast'], + customer_note=item['grind'], unit_price=item['price'], quantity=item['quantity'], tax_rate=2, diff --git a/src/storefront/forms.py b/src/storefront/forms.py index 0582874..15fbc92 100644 --- a/src/storefront/forms.py +++ b/src/storefront/forms.py @@ -19,7 +19,7 @@ class AddToCartForm(forms.Form): AEROPRESS = 'AeroPress' PERCOLATOR = 'Percolator' OTHER = 'Other' - ROAST_CHOICES = [ + GRIND_CHOICES = [ (WHOLE, 'Whole Beans'), (ESPRESSO, 'Espresso'), (CONE_DRIP, 'Cone Drip'), @@ -31,11 +31,11 @@ class AddToCartForm(forms.Form): (OTHER, 'Other (enter below)') ] - quantity = forms.IntegerField(min_value=1, initial=1) - roast = forms.ChoiceField(choices=ROAST_CHOICES) + quantity = forms.IntegerField(min_value=1, max_value=20, initial=1) + grind = forms.ChoiceField(choices=GRIND_CHOICES) class UpdateCartItemForm(forms.Form): - quantity = forms.IntegerField(min_value=1, initial=1) + quantity = forms.IntegerField(min_value=1, max_value=20, initial=1) update = forms.BooleanField(required=False, initial=True, widget=forms.HiddenInput) @@ -49,7 +49,7 @@ class AddToSubscriptionForm(forms.Form): AEROPRESS = 'AeroPress' PERCOLATOR = 'Percolator' OTHER = 'Other' - ROAST_CHOICES = [ + GRIND_CHOICES = [ (WHOLE, 'Whole Beans'), (ESPRESSO, 'Espresso'), (CONE_DRIP, 'Cone Drip'), @@ -71,7 +71,7 @@ class AddToSubscriptionForm(forms.Form): ] quantity = forms.IntegerField(min_value=1, initial=1) - roast = forms.ChoiceField(choices=ROAST_CHOICES) + grind = forms.ChoiceField(choices=GRIND_CHOICES) schedule = forms.ChoiceField(choices=SCHEDULE_CHOICES) diff --git a/src/storefront/templates/storefront/cart_detail.html b/src/storefront/templates/storefront/cart_detail.html index 1aae45d..4d98dde 100644 --- a/src/storefront/templates/storefront/cart_detail.html +++ b/src/storefront/templates/storefront/cart_detail.html @@ -13,21 +13,24 @@ {{product.productphoto_set.first.image}}

-

{{product.name}}
${{item.price}}

-

{{item.roast}}

-

- Remove from cart -

+

{{product.name}}

+

${{item.price}}

+

Grind: {{item.grind}}

{% csrf_token %} {{ item.update_quantity_form }} +

+ Remove from cart +

{% endwith %}
{% empty %} -

No items in cart yet.

+
+

No items in cart yet.

+
{% endfor %}
@@ -52,7 +55,7 @@ Cart total: ${{cart.get_total_price_after_discount|floatformat:"2"}}

- Continue Shopping or Proceed to Checkout + Continue Shopping{% if cart|length > 0 %} or Proceed to Checkout{% endif %}

diff --git a/src/storefront/templates/storefront/customer_detail.html b/src/storefront/templates/storefront/customer_detail.html index 6069a1e..c79c217 100644 --- a/src/storefront/templates/storefront/customer_detail.html +++ b/src/storefront/templates/storefront/customer_detail.html @@ -51,6 +51,9 @@
{% with order_list=customer.orders.all %} +
+

Your orders

+
Order # diff --git a/src/storefront/templates/storefront/order_form.html b/src/storefront/templates/storefront/order_form.html index 0fc9f7a..72b37a9 100644 --- a/src/storefront/templates/storefront/order_form.html +++ b/src/storefront/templates/storefront/order_form.html @@ -34,9 +34,10 @@ {{product.productphoto_set.first.image}}
-

{{product.name}}
${{item.price}}

+

{{product.name}}

+

${{item.price}}

Quantity: {{item.quantity}}

-

Grind options: {{item.roast}}

+

Grind options: {{item.grind}}

{% endwith %}
diff --git a/src/storefront/templates/storefront/product_detail.html b/src/storefront/templates/storefront/product_detail.html index 724e8e3..7a9e22f 100644 --- a/src/storefront/templates/storefront/product_detail.html +++ b/src/storefront/templates/storefront/product_detail.html @@ -13,21 +13,16 @@

{{product.name}}

{{product.description}}

+

${{product.price}}

{{product.weight.oz}} oz

{% csrf_token %} -

One-time purchase

{{ form.as_p }}

-


-
-

Subscribe and save 10%

-
- Subscriptions
{% endblock %} diff --git a/src/storefront/views.py b/src/storefront/views.py index bff7fb3..6e93ba0 100644 --- a/src/storefront/views.py +++ b/src/storefront/views.py @@ -62,7 +62,7 @@ class CartAddProductView(SingleObjectMixin, FormView): if form.is_valid(): cart.add( product=self.get_object(), - roast=form.cleaned_data['roast'], + grind=form.cleaned_data['grind'], quantity=form.cleaned_data['quantity'] ) return self.form_valid(form) diff --git a/src/templates/base.html b/src/templates/base.html index 7abba39..70d3d32 100644 --- a/src/templates/base.html +++ b/src/templates/base.html @@ -25,34 +25,37 @@
{% block content %} From f803491fa304d57cdcc4769ab6b0dbb6e2ced342 Mon Sep 17 00:00:00 2001 From: Nathan Chapman Date: Tue, 5 Apr 2022 11:23:35 -0600 Subject: [PATCH 3/4] Add modal menu for newsletter --- src/static/scripts/cookie.js | 4 +-- src/static/scripts/index.js | 37 ++++++++++++++++++++++++ src/static/styles/main.css | 54 ++++++++++++++++++++++++++++++++++++ src/templates/base.html | 15 +++++++++- 4 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 src/static/scripts/index.js diff --git a/src/static/scripts/cookie.js b/src/static/scripts/cookie.js index fcc94bc..8e2378d 100644 --- a/src/static/scripts/cookie.js +++ b/src/static/scripts/cookie.js @@ -16,9 +16,9 @@ export function getCookie(name) { const twentyYears = 20 * 365 * 24 * 60 * 60 * 1000 -export function setCookie(name, value) { +export function setCookie(name, value, expiration=twentyYears) { const body = [ name, value ].map(encodeURIComponent).join("=") - const expires = new Date(Date.now() + twentyYears).toUTCString() + const expires = new Date(Date.now() + expiration).toUTCString() const cookie = `${body}; domain=; path=/; SameSite=Lax; expires=${expires}` document.cookie = cookie } diff --git a/src/static/scripts/index.js b/src/static/scripts/index.js new file mode 100644 index 0000000..e7820e6 --- /dev/null +++ b/src/static/scripts/index.js @@ -0,0 +1,37 @@ +import { getCookie, setCookie } from "./cookie.js" + +// Get the modal +const modal = document.querySelector(".modal-menu"); + +// Get the element that closes the modal +const closeBtn = document.querySelector(".close-modal"); + +const oneDay = 1 * 24 * 60 * 60 * 1000 + +// When the user clicks on (x), close the modal +closeBtn.addEventListener("click", event => { + modal.style.display = "none"; + setCookie('newsletter-modal', 'true', oneDay) +}) + +const scrollFunction = () => { + let modalDismissed = getCookie('newsletter-modal') + console.log(modalDismissed) + if (modalDismissed != 'true') { + if (document.body.scrollTop > 600 || document.documentElement.scrollTop > 600) { + modal.style.display = "block"; + } + } +} + +window.onscroll = () => { + scrollFunction(); +}; + +// When the user clicks anywhere outside of the modal, close it +window.addEventListener("click", event => { + if (event.target == modal) { + modal.style.display = "none"; + } + setCookie('newsletter-modal', 'true', oneDay) +}); diff --git a/src/static/styles/main.css b/src/static/styles/main.css index 3dffd95..ab1aea1 100644 --- a/src/static/styles/main.css +++ b/src/static/styles/main.css @@ -202,6 +202,60 @@ img { max-width: 100%; } + + + + +/* MODAL MENU */ +.modal-menu { + display: none; + position: fixed; /* Stay in place */ + z-index: 1; /* Sit on top */ + left: 0; + top: 0; + width: 100%; /* Full width */ + height: 100%; /* Full height */ + overflow: auto; /* Enable scroll if needed */ + background-color: rgb(0,0,0); /* Fallback color */ + background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ +} + +/* Modal Content/Box */ +.modal-menu__content { + background-color: #fefefe; + margin: 25vh auto; + padding: 20px; + border: 1px solid #888; + max-width: 40rem; +} + +.modal-menu__form { + +} + +.modal-menu__header { + display: flex; + justify-content: space-between; + align-items: baseline; +} + +/* The Close Button */ +.close-modal { + color: #aaa; + font-size: 2rem; + line-height: 0; + font-weight: bold; +} + +.close-modal:hover, +.close-modal:focus { + color: black; + text-decoration: none; + cursor: pointer; +} + + + .fair_trade--small { max-width: 4rem; vertical-align: middle; diff --git a/src/templates/base.html b/src/templates/base.html index 70d3d32..74d7dab 100644 --- a/src/templates/base.html +++ b/src/templates/base.html @@ -18,11 +18,24 @@ {% endcompress %} + {% block head %} {% endblock %} + +