Merge branch 'release/0.6.1'
This commit is contained in:
commit
cd251d0e5c
@ -3,7 +3,7 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<article class="product">
|
<article class="product">
|
||||||
<header class="object__header">
|
<header class="object__header">
|
||||||
<h1>Add photo</h1>
|
<h1>Add photo to {{product.name}}</h1>
|
||||||
</header>
|
</header>
|
||||||
<section class="object__panel">
|
<section class="object__panel">
|
||||||
<form class="panel__item" enctype="multipart/form-data" method="POST" action="{% url 'dashboard:prodphoto-create' product.pk %}">
|
<form class="panel__item" enctype="multipart/form-data" method="POST" action="{% url 'dashboard:prodphoto-create' product.pk %}">
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 123 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 350 KiB |
BIN
src/static/images/coffee_banner.jpg
Normal file
BIN
src/static/images/coffee_banner.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 197 KiB |
BIN
src/static/images/fairtrade_banner.jpg
Normal file
BIN
src/static/images/fairtrade_banner.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 333 KiB |
BIN
src/static/images/reviews_banner.jpg
Normal file
BIN
src/static/images/reviews_banner.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 277 KiB |
@ -3,6 +3,8 @@ import { getCookie, setCookie } from "./cookie.js"
|
|||||||
// Get the modal
|
// Get the modal
|
||||||
const modal = document.querySelector(".modal-menu");
|
const modal = document.querySelector(".modal-menu");
|
||||||
|
|
||||||
|
const showBtn = document.querySelector(".show-modal");
|
||||||
|
|
||||||
// Get the <span> element that closes the modal
|
// Get the <span> element that closes the modal
|
||||||
const closeBtn = document.querySelector(".close-modal");
|
const closeBtn = document.querySelector(".close-modal");
|
||||||
|
|
||||||
@ -14,9 +16,13 @@ closeBtn.addEventListener("click", event => {
|
|||||||
setCookie('newsletter-modal', 'true', oneDay)
|
setCookie('newsletter-modal', 'true', oneDay)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
showBtn.addEventListener("click", event => {
|
||||||
|
modal.style.display = "block";
|
||||||
|
setCookie('newsletter-modal', 'true', oneDay)
|
||||||
|
})
|
||||||
|
|
||||||
const scrollFunction = () => {
|
const scrollFunction = () => {
|
||||||
let modalDismissed = getCookie('newsletter-modal')
|
let modalDismissed = getCookie('newsletter-modal')
|
||||||
console.log(modalDismissed)
|
|
||||||
if (modalDismissed != 'true') {
|
if (modalDismissed != 'true') {
|
||||||
if (document.body.scrollTop > 600 || document.documentElement.scrollTop > 600) {
|
if (document.body.scrollTop > 600 || document.documentElement.scrollTop > 600) {
|
||||||
modal.style.display = "block";
|
modal.style.display = "block";
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { getCookie } from "./cookie.js"
|
import { getCookie } from "./cookie.js"
|
||||||
|
|
||||||
let form = document.querySelector('form')
|
let form = document.querySelector('.order-create-form')
|
||||||
|
|
||||||
// Render the PayPal button into #paypal-button-container
|
// Render the PayPal button into #paypal-button-container
|
||||||
paypal.Buttons({
|
paypal.Buttons({
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
const gallery = document.querySelectorAll('.gallery__thumbnail')
|
const gallery = document.querySelectorAll('.gallery__thumbnail')
|
||||||
const productImage = document.querySelector('.product__image')
|
const productImage = document.querySelector('.gallery__image')
|
||||||
let currentImg = document.querySelector('.gallery__thumbnail--focus')
|
let currentImg = document.querySelector('.gallery__thumbnail--focus')
|
||||||
|
|
||||||
gallery.forEach(image => {
|
gallery.forEach(image => {
|
||||||
|
|||||||
@ -366,6 +366,10 @@ main article {
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.product__figure img {
|
||||||
|
max-height: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.product__detail {
|
.product__detail {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|||||||
@ -196,13 +196,24 @@ input[type=submit],
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
button,
|
button:hover,
|
||||||
input[type=submit]:hover,
|
input[type=submit]:hover,
|
||||||
.action-button:hover {
|
.action-button:hover {
|
||||||
background-color: var(--yellow-alt-color);
|
background-color: var(--yellow-alt-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Contact form
|
||||||
|
========================================================================== */
|
||||||
|
.contact-form label {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
:is(.contact-form) input, select, textarea {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -252,7 +263,7 @@ footer > section {
|
|||||||
background-color: var(--bg-color);
|
background-color: var(--bg-color);
|
||||||
margin: 25vh auto;
|
margin: 25vh auto;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
border: var(--default-border);
|
border: 2rem solid var(--bg-alt-color);
|
||||||
max-width: 40rem;
|
max-width: 40rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -545,10 +556,14 @@ article + article {
|
|||||||
aspect-ratio: 1/1;
|
aspect-ratio: 1/1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.gallery__image {
|
.gallery__image-wrapper {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gallery__image {
|
||||||
|
max-height: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
.gallery__thumbnail--focus {
|
.gallery__thumbnail--focus {
|
||||||
border-color: var(--yellow-color);
|
border-color: var(--yellow-color);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -68,7 +68,10 @@ class Cart:
|
|||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
del self.session[settings.CART_SESSION_ID]
|
del self.session[settings.CART_SESSION_ID]
|
||||||
del self.session['coupon_code']
|
try:
|
||||||
|
del self.session['coupon_code']
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
self.session.modified = True
|
self.session.modified = True
|
||||||
|
|
||||||
def build_order_params(self):
|
def build_order_params(self):
|
||||||
|
|||||||
@ -95,11 +95,9 @@ class OrderCreateForm(forms.ModelForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Order
|
model = Order
|
||||||
fields = (
|
fields = (
|
||||||
'coupon',
|
|
||||||
'total_net_amount',
|
'total_net_amount',
|
||||||
)
|
)
|
||||||
widgets = {
|
widgets = {
|
||||||
'coupon': forms.HiddenInput(),
|
|
||||||
'total_net_amount': forms.HiddenInput()
|
'total_net_amount': forms.HiddenInput()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@ COTACT_FORM_TEMPLATE = 'storefront/contact_form'
|
|||||||
def contact_form_email(formdata):
|
def contact_form_email(formdata):
|
||||||
send_templated_mail(
|
send_templated_mail(
|
||||||
template_name=COTACT_FORM_TEMPLATE,
|
template_name=COTACT_FORM_TEMPLATE,
|
||||||
from_email=settings.DEFAULT_FROM_EMAIL,
|
from_email=formdata['email_address'],
|
||||||
recipient_list=[settings.DEFAULT_CONTACT_EMAIL],
|
recipient_list=[settings.DEFAULT_CONTACT_EMAIL],
|
||||||
context=formdata
|
context=formdata
|
||||||
)
|
)
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
</header>
|
</header>
|
||||||
<section>
|
<section>
|
||||||
<figure>
|
<figure>
|
||||||
<img src="{% static 'images/coffee_banner.jpeg' %}" alt="">
|
<img src="{% static 'images/coffee_banner.jpg' %}" alt="Banner">
|
||||||
</figure>
|
</figure>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
<h1>Contact us</h1>
|
<h1>Contact us</h1>
|
||||||
</header>
|
</header>
|
||||||
<section>
|
<section>
|
||||||
<form action="{% url 'storefront:contact' %}" method="post">
|
<form action="{% url 'storefront:contact' %}" method="post" class="contact-form">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{form.as_p}}
|
{{form.as_p}}
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
34
src/storefront/templates/storefront/fairtrade.html
Normal file
34
src/storefront/templates/storefront/fairtrade.html
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<article>
|
||||||
|
<header>
|
||||||
|
<h1>Fair Trade and Organic</h1>
|
||||||
|
</header>
|
||||||
|
<section>
|
||||||
|
<figure>
|
||||||
|
<img src="{% static 'images/fairtrade_banner.jpg' %}" alt="Banner">
|
||||||
|
</figure>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<p>We pay a steep premium for these beans, which are typically from smaller farms that are organized into co-ops. These farms take pride in their coffees, as the farmers make a living wage and their families are able to live in a healthier, more secure environment than farmers who grow a conventional coffee crop. The quality of our coffee is consistent, in part due to the quality of organic and fair trade beans.</p>
|
||||||
|
<figure style="text-align: center;">
|
||||||
|
<img class="site__ft-stamp" src="{% static 'images/fair_trade_stamp.png' %}" alt="Fair trade">
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
<p>Farmers, growers, fishers and workers are the heart of the fair trade movement. Purchasing Fair Trade Certified™ products is a choice to support responsible companies, protect the environment, and empower farmers, workers and fishers.</p>
|
||||||
|
|
||||||
|
<h4>Better for you</h4>
|
||||||
|
<p>Buying fair trade lets you feel good about the products you bring into your home.</p>
|
||||||
|
|
||||||
|
<h4>Better for others</h4>
|
||||||
|
<p>Buying fair trade ensures a more equitable world by protecting and empowering the people behind our products</p>
|
||||||
|
|
||||||
|
<h4>Better for the planet</h4>
|
||||||
|
<p>Buying fair trade creates a more sustainable environment by improving systems and equipment in producer groups around the world.</p>
|
||||||
|
|
||||||
|
<p>When you choose our Coffee with the Fair Trade Certified™ seal, you can be sure that the people behind it worked in safe, healthy conditions and earned additional money to uplift their communities. It’s an easy way to have a direct, positive impact global communities. When you choose our Fair Trade Certified™ coffee, you’re voting with your dollar to support responsible businesses, empower farmers, and protect the environment. Fair trade is a way of supporting safe, healthy working conditions and extra income for the people behind our products through your everyday purchases</p>
|
||||||
|
</section>
|
||||||
|
</article>
|
||||||
|
{% endblock %}
|
||||||
@ -46,7 +46,7 @@
|
|||||||
</section>
|
</section>
|
||||||
<section class="cart__summary">
|
<section class="cart__summary">
|
||||||
<h3>Order summary</h3>
|
<h3>Order summary</h3>
|
||||||
<form action="" method="POST">
|
<form action="" method="POST" class="order-create-form">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{form.as_p}}
|
{{form.as_p}}
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
450
src/storefront/templates/storefront/partials/_newsletter.html
Normal file
450
src/storefront/templates/storefront/partials/_newsletter.html
Normal file
@ -0,0 +1,450 @@
|
|||||||
|
<form method="POST" action="https://ptcoffee.activehosted.com/proc.php" id="_form_3_" class="_form _form_3 _inline-form _dark" novalidate>
|
||||||
|
<input type="hidden" name="u" value="3" />
|
||||||
|
<input type="hidden" name="f" value="3" />
|
||||||
|
<input type="hidden" name="s" />
|
||||||
|
<input type="hidden" name="c" value="0" />
|
||||||
|
<input type="hidden" name="m" value="0" />
|
||||||
|
<input type="hidden" name="act" value="sub" />
|
||||||
|
<input type="hidden" name="v" value="2" />
|
||||||
|
<input type="hidden" name="or" value="4ef7da616ee5aadd87ec694f0969cb87" />
|
||||||
|
<div class="_form-content">
|
||||||
|
<div class="_form_element _x15986148 _full_width _clear" >
|
||||||
|
<div class="_form-title">
|
||||||
|
<h5>Get 10% OFF</h5>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="_form_element _x92496915 _full_width _clear" >
|
||||||
|
<div class="_html-code">
|
||||||
|
<p>
|
||||||
|
Subscribe to get 10% off your first order!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="_form_element _x55366865 _full_width " >
|
||||||
|
<label for="fullname" class="_form-label">
|
||||||
|
Full Name
|
||||||
|
</label>
|
||||||
|
<div class="_field-wrapper">
|
||||||
|
<input type="text" id="fullname" name="fullname" placeholder="Type your name" />
|
||||||
|
</div>
|
||||||
|
<!-- This STARTS the Custom Objects section -->
|
||||||
|
</div><br>
|
||||||
|
<div class="_form_element _x53687886 _full_width " >
|
||||||
|
<label for="email" class="_form-label">
|
||||||
|
Email*
|
||||||
|
</label>
|
||||||
|
<div class="_field-wrapper">
|
||||||
|
<input type="text" id="email" name="email" placeholder="Type your email" required/>
|
||||||
|
</div>
|
||||||
|
<!-- This STARTS the Custom Objects section -->
|
||||||
|
</div><br>
|
||||||
|
<div class="_button-wrapper _full_width">
|
||||||
|
<p>
|
||||||
|
<button id="_form_3_submit" class="_submit" type="submit">
|
||||||
|
Subscribe
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="_clear-element">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="_form-thank-you" style="display:none;">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.cfields = [];
|
||||||
|
window._show_thank_you = function(id, message, trackcmp_url, email) {
|
||||||
|
var form = document.getElementById('_form_' + id + '_'),
|
||||||
|
thank_you = form.querySelector('._form-thank-you');
|
||||||
|
form.querySelector('._form-content').style.display = 'none';
|
||||||
|
thank_you.innerHTML = message;
|
||||||
|
thank_you.style.display = 'block';
|
||||||
|
const vgoAlias = typeof visitorGlobalObjectAlias === 'undefined' ? 'vgo' : visitorGlobalObjectAlias;
|
||||||
|
var visitorObject = window[vgoAlias];
|
||||||
|
if (email && typeof visitorObject !== 'undefined') {
|
||||||
|
visitorObject('setEmail', email);
|
||||||
|
visitorObject('update');
|
||||||
|
} else if (typeof(trackcmp_url) != 'undefined' && trackcmp_url) {
|
||||||
|
// Site tracking URL to use after inline form submission.
|
||||||
|
_load_script(trackcmp_url);
|
||||||
|
}
|
||||||
|
if (typeof window._form_callback !== 'undefined') window._form_callback(id);
|
||||||
|
};
|
||||||
|
window._show_error = function(id, message, html) {
|
||||||
|
var form = document.getElementById('_form_' + id + '_'),
|
||||||
|
err = document.createElement('div'),
|
||||||
|
button = form.querySelector('button'),
|
||||||
|
old_error = form.querySelector('._form_error');
|
||||||
|
if (old_error) old_error.parentNode.removeChild(old_error);
|
||||||
|
err.innerHTML = message;
|
||||||
|
err.className = '_error-inner _form_error _no_arrow';
|
||||||
|
var wrapper = document.createElement('div');
|
||||||
|
wrapper.className = '_form-inner';
|
||||||
|
wrapper.appendChild(err);
|
||||||
|
button.parentNode.insertBefore(wrapper, button);
|
||||||
|
document.querySelector('[id^="_form"][id$="_submit"]').disabled = false;
|
||||||
|
if (html) {
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.className = '_error-html';
|
||||||
|
div.innerHTML = html;
|
||||||
|
err.appendChild(div);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
window._load_script = function(url, callback) {
|
||||||
|
var head = document.querySelector('head'),
|
||||||
|
script = document.createElement('script'),
|
||||||
|
r = false;
|
||||||
|
script.type = 'text/javascript';
|
||||||
|
script.charset = 'utf-8';
|
||||||
|
script.src = url;
|
||||||
|
if (callback) {
|
||||||
|
script.onload = script.onreadystatechange = function() {
|
||||||
|
if (!r && (!this.readyState || this.readyState == 'complete')) {
|
||||||
|
r = true;
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
head.appendChild(script);
|
||||||
|
};
|
||||||
|
(function() {
|
||||||
|
if (window.location.search.search("excludeform") !== -1) return false;
|
||||||
|
var getCookie = function(name) {
|
||||||
|
var match = document.cookie.match(new RegExp('(^|; )' + name + '=([^;]+)'));
|
||||||
|
return match ? match[2] : null;
|
||||||
|
}
|
||||||
|
var setCookie = function(name, value) {
|
||||||
|
var now = new Date();
|
||||||
|
var time = now.getTime();
|
||||||
|
var expireTime = time + 1000 * 60 * 60 * 24 * 365;
|
||||||
|
now.setTime(expireTime);
|
||||||
|
document.cookie = name + '=' + value + '; expires=' + now + ';path=/';
|
||||||
|
}
|
||||||
|
var addEvent = function(element, event, func) {
|
||||||
|
if (element.addEventListener) {
|
||||||
|
element.addEventListener(event, func);
|
||||||
|
} else {
|
||||||
|
var oldFunc = element['on' + event];
|
||||||
|
element['on' + event] = function() {
|
||||||
|
oldFunc.apply(this, arguments);
|
||||||
|
func.apply(this, arguments);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var _removed = false;
|
||||||
|
var form_to_submit = document.getElementById('_form_3_');
|
||||||
|
var allInputs = form_to_submit.querySelectorAll('input, select, textarea'),
|
||||||
|
tooltips = [],
|
||||||
|
submitted = false;
|
||||||
|
|
||||||
|
var getUrlParam = function(name) {
|
||||||
|
var params = new URLSearchParams(window.location.search);
|
||||||
|
return params.get(name) || false;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (var i = 0; i < allInputs.length; i++) {
|
||||||
|
var regexStr = "field\\[(\\d+)\\]";
|
||||||
|
var results = new RegExp(regexStr).exec(allInputs[i].name);
|
||||||
|
if (results != undefined) {
|
||||||
|
allInputs[i].dataset.name = window.cfields[results[1]];
|
||||||
|
} else {
|
||||||
|
allInputs[i].dataset.name = allInputs[i].name;
|
||||||
|
}
|
||||||
|
var fieldVal = getUrlParam(allInputs[i].dataset.name);
|
||||||
|
|
||||||
|
if (fieldVal) {
|
||||||
|
if (allInputs[i].dataset.autofill === "false") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (allInputs[i].type == "radio" || allInputs[i].type == "checkbox") {
|
||||||
|
if (allInputs[i].value == fieldVal) {
|
||||||
|
allInputs[i].checked = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
allInputs[i].value = fieldVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var remove_tooltips = function() {
|
||||||
|
for (var i = 0; i < tooltips.length; i++) {
|
||||||
|
tooltips[i].tip.parentNode.removeChild(tooltips[i].tip);
|
||||||
|
}
|
||||||
|
tooltips = [];
|
||||||
|
};
|
||||||
|
var remove_tooltip = function(elem) {
|
||||||
|
for (var i = 0; i < tooltips.length; i++) {
|
||||||
|
if (tooltips[i].elem === elem) {
|
||||||
|
tooltips[i].tip.parentNode.removeChild(tooltips[i].tip);
|
||||||
|
tooltips.splice(i, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var create_tooltip = function(elem, text) {
|
||||||
|
var tooltip = document.createElement('div'),
|
||||||
|
arrow = document.createElement('div'),
|
||||||
|
inner = document.createElement('div'),
|
||||||
|
new_tooltip = {};
|
||||||
|
if (elem.type != 'radio' && elem.type != 'checkbox') {
|
||||||
|
tooltip.className = '_error';
|
||||||
|
arrow.className = '_error-arrow';
|
||||||
|
inner.className = '_error-inner';
|
||||||
|
inner.innerHTML = text;
|
||||||
|
tooltip.appendChild(arrow);
|
||||||
|
tooltip.appendChild(inner);
|
||||||
|
elem.parentNode.appendChild(tooltip);
|
||||||
|
} else {
|
||||||
|
tooltip.className = '_error-inner _no_arrow';
|
||||||
|
tooltip.innerHTML = text;
|
||||||
|
elem.parentNode.insertBefore(tooltip, elem);
|
||||||
|
new_tooltip.no_arrow = true;
|
||||||
|
}
|
||||||
|
new_tooltip.tip = tooltip;
|
||||||
|
new_tooltip.elem = elem;
|
||||||
|
tooltips.push(new_tooltip);
|
||||||
|
return new_tooltip;
|
||||||
|
};
|
||||||
|
var resize_tooltip = function(tooltip) {
|
||||||
|
var rect = tooltip.elem.getBoundingClientRect();
|
||||||
|
var doc = document.documentElement,
|
||||||
|
scrollPosition = rect.top - ((window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0));
|
||||||
|
if (scrollPosition < 40) {
|
||||||
|
tooltip.tip.className = tooltip.tip.className.replace(/ ?(_above|_below) ?/g, '') + ' _below';
|
||||||
|
} else {
|
||||||
|
tooltip.tip.className = tooltip.tip.className.replace(/ ?(_above|_below) ?/g, '') + ' _above';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var resize_tooltips = function() {
|
||||||
|
if (_removed) return;
|
||||||
|
for (var i = 0; i < tooltips.length; i++) {
|
||||||
|
if (!tooltips[i].no_arrow) resize_tooltip(tooltips[i]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var validate_field = function(elem, remove) {
|
||||||
|
var tooltip = null,
|
||||||
|
value = elem.value,
|
||||||
|
no_error = true;
|
||||||
|
remove ? remove_tooltip(elem) : false;
|
||||||
|
if (elem.type != 'checkbox') elem.className = elem.className.replace(/ ?_has_error ?/g, '');
|
||||||
|
if (elem.getAttribute('required') !== null) {
|
||||||
|
if (elem.type == 'radio' || (elem.type == 'checkbox' && /any/.test(elem.className))) {
|
||||||
|
var elems = form_to_submit.elements[elem.name];
|
||||||
|
if (!(elems instanceof NodeList || elems instanceof HTMLCollection) || elems.length <= 1) {
|
||||||
|
no_error = elem.checked;
|
||||||
|
} else {
|
||||||
|
no_error = false;
|
||||||
|
for (var i = 0; i < elems.length; i++) {
|
||||||
|
if (elems[i].checked) no_error = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!no_error) {
|
||||||
|
tooltip = create_tooltip(elem, "Please select an option.");
|
||||||
|
}
|
||||||
|
} else if (elem.type == 'checkbox') {
|
||||||
|
var elems = form_to_submit.elements[elem.name],
|
||||||
|
found = false,
|
||||||
|
err = [];
|
||||||
|
no_error = true;
|
||||||
|
for (var i = 0; i < elems.length; i++) {
|
||||||
|
if (elems[i].getAttribute('required') === null) continue;
|
||||||
|
if (!found && elems[i] !== elem) return true;
|
||||||
|
found = true;
|
||||||
|
elems[i].className = elems[i].className.replace(/ ?_has_error ?/g, '');
|
||||||
|
if (!elems[i].checked) {
|
||||||
|
no_error = false;
|
||||||
|
elems[i].className = elems[i].className + ' _has_error';
|
||||||
|
err.push("Checking %s is required".replace("%s", elems[i].value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!no_error) {
|
||||||
|
tooltip = create_tooltip(elem, err.join('<br/>'));
|
||||||
|
}
|
||||||
|
} else if (elem.tagName == 'SELECT') {
|
||||||
|
var selected = true;
|
||||||
|
if (elem.multiple) {
|
||||||
|
selected = false;
|
||||||
|
for (var i = 0; i < elem.options.length; i++) {
|
||||||
|
if (elem.options[i].selected) {
|
||||||
|
selected = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (var i = 0; i < elem.options.length; i++) {
|
||||||
|
if (elem.options[i].selected && (!elem.options[i].value || (elem.options[i].value.match(/\n/g)))) {
|
||||||
|
selected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!selected) {
|
||||||
|
elem.className = elem.className + ' _has_error';
|
||||||
|
no_error = false;
|
||||||
|
tooltip = create_tooltip(elem, "Please select an option.");
|
||||||
|
}
|
||||||
|
} else if (value === undefined || value === null || value === '') {
|
||||||
|
elem.className = elem.className + ' _has_error';
|
||||||
|
no_error = false;
|
||||||
|
tooltip = create_tooltip(elem, "This field is required.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (no_error && elem.name == 'email') {
|
||||||
|
if (!value.match(/^[\+_a-z0-9-'&=]+(\.[\+_a-z0-9-']+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,})$/i)) {
|
||||||
|
elem.className = elem.className + ' _has_error';
|
||||||
|
no_error = false;
|
||||||
|
tooltip = create_tooltip(elem, "Enter a valid email address.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (no_error && /date_field/.test(elem.className)) {
|
||||||
|
if (!value.match(/^\d\d\d\d-\d\d-\d\d$/)) {
|
||||||
|
elem.className = elem.className + ' _has_error';
|
||||||
|
no_error = false;
|
||||||
|
tooltip = create_tooltip(elem, "Enter a valid date.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tooltip ? resize_tooltip(tooltip) : false;
|
||||||
|
return no_error;
|
||||||
|
};
|
||||||
|
var needs_validate = function(el) {
|
||||||
|
if (el.getAttribute('required') !== null) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (el.name === 'email' && el.value !== "") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
};
|
||||||
|
var validate_form = function(e) {
|
||||||
|
var err = form_to_submit.querySelector('._form_error'),
|
||||||
|
no_error = true;
|
||||||
|
if (!submitted) {
|
||||||
|
submitted = true;
|
||||||
|
for (var i = 0, len = allInputs.length; i < len; i++) {
|
||||||
|
var input = allInputs[i];
|
||||||
|
if (needs_validate(input)) {
|
||||||
|
if (input.type == 'text' || input.type == 'number' || input.type == 'time') {
|
||||||
|
addEvent(input, 'blur', function() {
|
||||||
|
this.value = this.value.trim();
|
||||||
|
validate_field(this, true);
|
||||||
|
});
|
||||||
|
addEvent(input, 'input', function() {
|
||||||
|
validate_field(this, true);
|
||||||
|
});
|
||||||
|
} else if (input.type == 'radio' || input.type == 'checkbox') {
|
||||||
|
(function(el) {
|
||||||
|
var radios = form_to_submit.elements[el.name];
|
||||||
|
for (var i = 0; i < radios.length; i++) {
|
||||||
|
addEvent(radios[i], 'click', function() {
|
||||||
|
validate_field(el, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})(input);
|
||||||
|
} else if (input.tagName == 'SELECT') {
|
||||||
|
addEvent(input, 'change', function() {
|
||||||
|
validate_field(this, true);
|
||||||
|
});
|
||||||
|
} else if (input.type == 'textarea') {
|
||||||
|
addEvent(input, 'input', function() {
|
||||||
|
validate_field(this, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
remove_tooltips();
|
||||||
|
for (var i = 0, len = allInputs.length; i < len; i++) {
|
||||||
|
var elem = allInputs[i];
|
||||||
|
if (needs_validate(elem)) {
|
||||||
|
if (elem.tagName.toLowerCase() !== "select") {
|
||||||
|
elem.value = elem.value.trim();
|
||||||
|
}
|
||||||
|
validate_field(elem) ? true : no_error = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!no_error && e) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
resize_tooltips();
|
||||||
|
return no_error;
|
||||||
|
};
|
||||||
|
addEvent(window, 'resize', resize_tooltips);
|
||||||
|
addEvent(window, 'scroll', resize_tooltips);
|
||||||
|
var _form_serialize = function(form) {
|
||||||
|
if (!form || form.nodeName !== "FORM") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var i, j, q = [];
|
||||||
|
for (i = 0; i < form.elements.length; i++) {
|
||||||
|
if (form.elements[i].name === "") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch (form.elements[i].nodeName) {
|
||||||
|
case "INPUT":
|
||||||
|
switch (form.elements[i].type) {
|
||||||
|
case "text":
|
||||||
|
case "number":
|
||||||
|
case "date":
|
||||||
|
case "time":
|
||||||
|
case "hidden":
|
||||||
|
case "password":
|
||||||
|
case "button":
|
||||||
|
case "reset":
|
||||||
|
case "submit":
|
||||||
|
q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
|
||||||
|
break;
|
||||||
|
case "checkbox":
|
||||||
|
case "radio":
|
||||||
|
if (form.elements[i].checked) {
|
||||||
|
q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value))
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "file":
|
||||||
|
break
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "TEXTAREA":
|
||||||
|
q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
|
||||||
|
break;
|
||||||
|
case "SELECT":
|
||||||
|
switch (form.elements[i].type) {
|
||||||
|
case "select-one":
|
||||||
|
q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
|
||||||
|
break;
|
||||||
|
case "select-multiple":
|
||||||
|
for (j = 0; j < form.elements[i].options.length; j++) {
|
||||||
|
if (form.elements[i].options[j].selected) {
|
||||||
|
q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].options[j].value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "BUTTON":
|
||||||
|
switch (form.elements[i].type) {
|
||||||
|
case "reset":
|
||||||
|
case "submit":
|
||||||
|
case "button":
|
||||||
|
q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
|
||||||
|
break
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return q.join("&")
|
||||||
|
};
|
||||||
|
var form_submit = function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (validate_form()) {
|
||||||
|
// use this trick to get the submit button & disable it using plain javascript
|
||||||
|
document.querySelector('#_form_3_submit').disabled = true;
|
||||||
|
var serialized = _form_serialize(document.getElementById('_form_3_')).replace(/%0A/g, '\\n');
|
||||||
|
var err = form_to_submit.querySelector('._form_error');
|
||||||
|
err ? err.parentNode.removeChild(err) : false;
|
||||||
|
_load_script('https://ptcoffee.activehosted.com/proc.php?' + serialized + '&jsonp=true');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
addEvent(form_to_submit, 'submit', form_submit);
|
||||||
|
})();
|
||||||
|
|
||||||
|
</script>
|
||||||
@ -12,13 +12,13 @@
|
|||||||
<img class="gallery__thumbnail {% if forloop.first %}gallery__thumbnail--focus{% endif %}" src="{{ photo.image.url }}" alt="{{ photo }}">
|
<img class="gallery__thumbnail {% if forloop.first %}gallery__thumbnail--focus{% endif %}" src="{{ photo.image.url }}" alt="{{ photo }}">
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</section>
|
</section>
|
||||||
<figure class="gallery__image">
|
<figure class="gallery__image-wrapper">
|
||||||
<img class="product__image" src="{{ product.productphoto_set.first.image.url }}" alt="{{ product.name }}">
|
<img class="gallery__image" src="{{ product.productphoto_set.first.image.url }}" alt="{{ product.name }}">
|
||||||
</figure>
|
</figure>
|
||||||
<section class="product__info">
|
<section class="product__info">
|
||||||
<h1>{{product.name}}</h1>
|
<h1>{{product.name}}</h1>
|
||||||
<p>{{product.description}}</p>
|
<p>{{product.description}}</p>
|
||||||
<p class="site__ft-stamp"><img class="fair_trade--small" src="{% static 'images/fair_trade_stamp.png' %}" alt=""></p>
|
<p class="site__ft-stamp"><img class="fair_trade--small" src="{% static 'images/fair_trade_stamp.png' %}" alt="Fair trade"></p>
|
||||||
<p>$<strong>{{product.price}}</strong></p>
|
<p>$<strong>{{product.price}}</strong></p>
|
||||||
<p>{{product.weight.oz}} oz</p>
|
<p>{{product.weight.oz}} oz</p>
|
||||||
<form class="product__form" method="post" action="{% url 'storefront:cart-add' product.pk %}">
|
<form class="product__form" method="post" action="{% url 'storefront:cart-add' product.pk %}">
|
||||||
|
|||||||
@ -1,10 +1,16 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<article>
|
<article>
|
||||||
<header>
|
<header>
|
||||||
<h2>Reviews</h2>
|
<h2>Reviews</h2>
|
||||||
</header>
|
</header>
|
||||||
|
<section>
|
||||||
|
<figure>
|
||||||
|
<img src="{% static 'images/reviews_banner.jpg' %}" alt="Banner">
|
||||||
|
</figure>
|
||||||
|
</section>
|
||||||
<section class="review__list">
|
<section class="review__list">
|
||||||
<blockquote class="review__item">
|
<blockquote class="review__item">
|
||||||
<q>Really good coffee. That's all there is to say. Supposedly the pour over coffee is the best way to go. It is definitely nothing like a Starbucks, and in this case, that's a very good thing!</q>
|
<q>Really good coffee. That's all there is to say. Supposedly the pour over coffee is the best way to go. It is definitely nothing like a Starbucks, and in this case, that's a very good thing!</q>
|
||||||
|
|||||||
@ -3,6 +3,7 @@ from . import views
|
|||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('about/', views.AboutView.as_view(), name='about'),
|
path('about/', views.AboutView.as_view(), name='about'),
|
||||||
|
path('fair-trade/', views.FairTradeView.as_view(), name='fair-trade'),
|
||||||
path('reviews/', views.ReviewListView.as_view(), name='reviews'),
|
path('reviews/', views.ReviewListView.as_view(), name='reviews'),
|
||||||
path('contact/', views.ContactFormView.as_view(), name='contact'),
|
path('contact/', views.ContactFormView.as_view(), name='contact'),
|
||||||
|
|
||||||
|
|||||||
@ -178,7 +178,6 @@ class OrderCreateView(CreateView):
|
|||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
cart = Cart(self.request)
|
cart = Cart(self.request)
|
||||||
initial = {
|
initial = {
|
||||||
'coupon': cart.coupon,
|
|
||||||
'total_net_amount': cart.get_total_price()
|
'total_net_amount': cart.get_total_price()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,6 +293,9 @@ class AddressUpdateView(LoginRequiredMixin, UpdateView):
|
|||||||
class AboutView(TemplateView):
|
class AboutView(TemplateView):
|
||||||
template_name = 'storefront/about.html'
|
template_name = 'storefront/about.html'
|
||||||
|
|
||||||
|
class FairTradeView(TemplateView):
|
||||||
|
template_name = 'storefront/fairtrade.html'
|
||||||
|
|
||||||
class ReviewListView(TemplateView):
|
class ReviewListView(TemplateView):
|
||||||
template_name = 'storefront/reviews.html'
|
template_name = 'storefront/reviews.html'
|
||||||
|
|
||||||
|
|||||||
@ -32,7 +32,7 @@
|
|||||||
<span class="close-modal">×</span>
|
<span class="close-modal">×</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-menu__form">
|
<div class="modal-menu__form">
|
||||||
<div class="_form_1"></div>
|
{% include "storefront/partials/_newsletter.html" %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -42,8 +42,8 @@
|
|||||||
<a class="site__logo" href="{% url 'storefront:product-list' %}"><img src="{% static 'images/site_logo.svg' %}" alt="Port Townsend Roasting Co."></a>
|
<a class="site__logo" href="{% url 'storefront:product-list' %}"><img src="{% static 'images/site_logo.svg' %}" alt="Port Townsend Roasting Co."></a>
|
||||||
<ul class="nav__list nav__main">
|
<ul class="nav__list nav__main">
|
||||||
<li><a class="nav__link" href="{% url 'storefront:product-list' %}">Shop</a></li>
|
<li><a class="nav__link" href="{% url 'storefront:product-list' %}">Shop</a></li>
|
||||||
<li><a class="nav__link" href="">Cafe</a></li>
|
<li><a class="nav__link" href="https://bltcoffee.com/">Cafe</a></li>
|
||||||
<li><a class="nav__link" href="">Fair trade</a></li>
|
<li><a class="nav__link" href="{% url 'storefront:fair-trade' %}">Fair trade</a></li>
|
||||||
<li><a class="nav__link" href="{% url 'storefront:about' %}">About</a></li>
|
<li><a class="nav__link" href="{% url 'storefront:about' %}">About</a></li>
|
||||||
<li><a class="nav__link" href="{% url 'storefront:contact' %}">Contact</a></li>
|
<li><a class="nav__link" href="{% url 'storefront:contact' %}">Contact</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -77,14 +77,13 @@
|
|||||||
</main>
|
</main>
|
||||||
<footer>
|
<footer>
|
||||||
<section>
|
<section>
|
||||||
|
<p><button class="show-modal">Subscribe to our newsletter</button></p>
|
||||||
<p>
|
<p>
|
||||||
<small>Copyright © 2016-{% now "Y" %} Better Living Food Company Inc.</small><br>
|
<small>Copyright © 2016-{% now "Y" %} Better Living Food Company Inc.</small><br>
|
||||||
<small>Fair Trade | Organic | Port Townsend, WA 98368</small><br><br>
|
<small>Fair Trade | Organic | Port Townsend, WA 98368</small><br><br>
|
||||||
<img class="site__ft-stamp" src="{% static 'images/fair_trade_stamp.png' %}" alt="">
|
<img class="site__ft-stamp" src="{% static 'images/fair_trade_stamp.png' %}" alt="Fair trade">
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script src="https://ptcoffee.activehosted.com/f/embed.php?id=1" type="text/javascript" charset="utf-8"></script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -2,17 +2,21 @@
|
|||||||
{% block plain %}
|
{% block plain %}
|
||||||
Thank you for your order!
|
Thank you for your order!
|
||||||
|
|
||||||
Hi {{full_name}}, we roast our coffee as orders come in. We'll send you a seperate email when your order ships. To view or change your order...
|
Hi {{full_name}}, we're getting your order ready to be shipped. We will notify you when it has been sent.
|
||||||
|
|
||||||
|
If you have any questions, reply to this email or contact us at support@ptcoffee.com
|
||||||
|
|
||||||
Thanks,
|
Thanks,
|
||||||
Port Townsend Coffee
|
Port Townsend Roasting Co.
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block html %}
|
{% block html %}
|
||||||
<h3>Thank you for your order!</h3>
|
<h3>Thank you for your order!</h3>
|
||||||
|
|
||||||
<p>Hi {{full_name}}, we roast our coffee as orders come in. We'll send you a seperate email when your order ships. To view or change your order...</p>
|
<p>Hi {{full_name}}, we're getting your order ready to be shipped. We will notify you when it has been sent.</p>
|
||||||
|
|
||||||
|
<p>If you have any questions, reply to this email or contact us at <a href="mailto:support@ptcoffee.com">support@ptcoffee.com</a></p>
|
||||||
|
|
||||||
<p>Thanks,<br>
|
<p>Thanks,<br>
|
||||||
Port Townsend Coffee</p>
|
Port Townsend Roasting Co.</p>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user