Add dynamic subscription calculation
This commit is contained in:
parent
41ddfd8952
commit
27a0f94c4e
128
src/static/scripts/subscriptions.js
Normal file
128
src/static/scripts/subscriptions.js
Normal 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)
|
||||||
@ -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 {
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user