Add dynamic subscription calculation

This commit is contained in:
Nathan Chapman 2022-08-01 18:53:44 -06:00
parent 41ddfd8952
commit 27a0f94c4e
4 changed files with 156 additions and 14 deletions

View File

@ -0,0 +1,128 @@
class Subscription {
static TWELVE_OZ
static SIXTEEN_OZ
static FIVE_LBS
static TWELVE_SHIPPING
static SIXTEEN_SHIPPING
static FIVE_SHIPPING
constructor(element, output) {
this.TWELVE_OZ = '12'
this.SIXTEEN_OZ = '16'
this.FIVE_LBS = '75'
this.TWELVE_SHIPPING = 7
this.SIXTEEN_SHIPPING = 5
this.FIVE_SHIPPING = 1
this.element = element
this.output = this.element.querySelector('.output')
this.shippingDiscount = 10
this.price = this.element.querySelector('select[name=size]')
this.products = this.element.querySelectorAll('input[name^=product]')
this.element.addEventListener('change', this.render.bind(this))
this.render()
}
get total_qty() {
return Array.from(this.products).reduce((total, current) => {
return total + Number(current.value)
}, 0)
}
get hasFreeShipping() {
switch(this.price.value) {
case this.TWELVE_OZ:
if (parseInt(this.total_qty) >= this.TWELVE_SHIPPING) {
return true
} else {
return false
}
break
case this.SIXTEEN_OZ:
if (parseInt(this.total_qty) >= this.SIXTEEN_SHIPPING) {
return true
} else {
return false
}
break
case this.FIVE_LBS:
if (parseInt(this.total_qty) >= this.FIVE_SHIPPING) {
return true
} else {
return false
}
break
default:
throw 'Something is wrong with the price'
}
}
get countToFreeShipping() {
switch(this.price.value) {
case this.TWELVE_OZ:
return this.TWELVE_SHIPPING - this.total_qty
break
case this.SIXTEEN_OZ:
return this.SIXTEEN_SHIPPING - this.total_qty
break
case this.FIVE_LBS:
return this.FIVE_SHIPPING
break
default:
throw 'Something is wrong with the price'
break
}
}
get shippingStatus() {
let items = 0
if (this.hasFreeShipping) {
return 'You have free shipping!'
} else {
return `Add ${this.countToFreeShipping} more item(s) for free shipping!`
}
}
get totalRetailPrice() {
let totalPrice = Array.from(this.products).reduce((total, current) => {
return total + (Number(this.price.value) * current.value);
}, 0);
return new Intl.NumberFormat('en-US', {
currency: 'USD',
style: 'currency',
}).format(totalPrice)
}
get totalPrice() {
let totalPrice = Array.from(this.products).reduce((total, current) => {
return total + (Number(this.price.value) * current.value);
}, 0);
let percentage = (this.shippingDiscount / 100) * totalPrice
return new Intl.NumberFormat('en-US', {
currency: 'USD',
style: 'currency',
}).format(totalPrice - percentage)
}
render() {
this.output.querySelector('.retail-price').innerText = this.totalRetailPrice
this.output.querySelector('.price').innerText = this.totalPrice
this.output.querySelector('.shipping').innerText = this.shippingStatus
}
add_item(item) {
this.items.push(item)
return this.items
}
}
const subCreateFromEl = document.querySelector('.subscription-create-form')
const sub = new Subscription(subCreateFromEl)

View File

@ -639,7 +639,7 @@ article + article {
} }
.create-subscription-form { .subscription-create-form {
display: grid; display: grid;
grid-template-columns: 2fr 1fr; grid-template-columns: 2fr 1fr;
gap: 2rem; gap: 2rem;
@ -649,11 +649,11 @@ article + article {
display: grid; display: grid;
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);
justify-items: center; justify-items: center;
gap: 8rem; gap: 6rem;
overflow-y: scroll; overflow-y: scroll;
max-height: 50rem; max-height: 50rem;
border-bottom: var(--default-border); border-bottom: var(--default-border);
padding: 0 4rem 4rem; padding: 0 2rem 2rem;
} }
.product__subscription-list div { .product__subscription-list div {

View File

@ -178,13 +178,13 @@ class SubscriptionCreateForm(forms.Form):
TWELVE_OZ = 12 TWELVE_OZ = 12
SIXTEEN_OZ = 16 SIXTEEN_OZ = 16
FIVE_LBS = 5 FIVE_LBS = 75
SIZE_CHOICES = [ SIZE_CHOICES = [
(TWELVE_OZ, '12oz'), (TWELVE_OZ, '12 oz ($10.80)'),
(SIXTEEN_OZ, '16oz'), (SIXTEEN_OZ, '16 oz ($14.40)'),
(FIVE_LBS, '5lbs'), (FIVE_LBS, '5 lbs ($67.50)'),
] ]
size = forms.ChoiceField(choices=SIZE_CHOICES)
grind = forms.ChoiceField(choices=CoffeeGrind.GRIND_CHOICES) grind = forms.ChoiceField(choices=CoffeeGrind.GRIND_CHOICES)
schedule = forms.ChoiceField(choices=SCHEDULE_CHOICES) schedule = forms.ChoiceField(choices=SCHEDULE_CHOICES)
size = forms.ChoiceField(choices=SIZE_CHOICES)

View File

@ -2,10 +2,7 @@
{% load static %} {% load static %}
{% block head %} {% block head %}
<script defer src="{% static 'scripts/product_list.js' %}"></script> <script src="{% static 'scripts/subscriptions.js' %}" defer></script>
<link rel="stylesheet" href="{% static 'styles/checkout.css' %}" />
<script src="https://js.stripe.com/v3/"></script>
<script src="{% static 'scripts/checkout.js' %}" defer></script>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
@ -15,7 +12,7 @@
</div> </div>
<article> <article>
<section class=""> <section class="">
<form action="" class="create-subscription-form"> <form action="" class="subscription-create-form">
{% csrf_token %} {% csrf_token %}
<div> <div>
<h4>Pick your coffee</h4> <h4>Pick your coffee</h4>
@ -33,9 +30,26 @@
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
<div> <div class="output">
<h4>Pick your options</h4> <h4>Pick your options</h4>
{{ form.as_p }} {{ form.as_p }}
<div class="cart__table-wrapper">
<table class="cart__totals">
<tr>
<td>Retail total</td>
<td><del class="retail-price"></del></td>
</tr>
<tr>
<td>Save</td>
<td>10%</td>
</tr>
<tr>
<th>Subscription total</th>
<td><strong class="price"></strong></td>
</tr>
</table>
</div>
<p class="shipping"></p>
<p> <p>
<input type="submit" value="Continue to payment"> <input type="submit" value="Continue to payment">
</p> </p>