Improving checkout experience Fixes #103

master
Mark Moffat 2019-12-21 13:16:48 +10:30
parent 588fdddb75
commit b48b2237ee
21 changed files with 602 additions and 292 deletions

View File

@ -67,15 +67,6 @@ const convertBool = (value) => {
return false; return false;
}; };
const showCartCloseBtn = (page) => {
let showCartCloseButton = true;
if(page === 'checkout' || page === 'pay'){
showCartCloseButton = false;
}
return showCartCloseButton;
};
// adds products to sitemap.xml // adds products to sitemap.xml
const addSitemapProducts = (req, res, cb) => { const addSitemapProducts = (req, res, cb) => {
const db = req.app.db; const db = req.app.db;
@ -587,7 +578,6 @@ module.exports = {
safeParseInt, safeParseInt,
checkboxBool, checkboxBool,
convertBool, convertBool,
showCartCloseBtn,
addSitemapProducts, addSitemapProducts,
clearSessionValue, clearSessionValue,
updateTotalCartAmount, updateTotalCartAmount,

View File

@ -0,0 +1,51 @@
{
"$id": "saveCustomer",
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "emailAddress"
},
"firstName": {
"type": "string",
"isNotEmpty": true
},
"lastName": {
"type": "string",
"isNotEmpty": true
},
"address1": {
"type": "string",
"isNotEmpty": true
},
"address2": {
"type": "string"
},
"country": {
"type": "string",
"isNotEmpty": true
},
"state": {
"type": "string",
"isNotEmpty": true
},
"postcode": {
"type": "string",
"isNotEmpty": true
},
"phone": {
"type": "string",
"isNotEmpty": true
}
},
"required": [
"email",
"firstName",
"lastName",
"address1",
"country",
"state",
"postcode",
"phone"
]
}

View File

@ -166,5 +166,9 @@
"Payment ID": "Payment ID", "Payment ID": "Payment ID",
"Payment Message": "Payment Message", "Payment Message": "Payment Message",
"Password": "Password", "Password": "Password",
"Cart Email": "Cart Email" "Cart Email": "Cart Email",
"Information": "Information",
"Shipping options": "Shipping options",
"Proceed to payment": "Proceed to payment",
"Return to information": "Return to information"
} }

View File

@ -58,8 +58,9 @@ $(document).ready(function (){
} }
}); });
$('.menu-btn').on('click', function(e){ $(document).on('click', '.menu-btn', function(e){
e.preventDefault(); e.preventDefault();
$('body').addClass('pushy-open-right');
}); });
// add the table class to all tables // add the table class to all tables
@ -75,9 +76,11 @@ $(document).ready(function (){
$(this).toggleClass('hover'); $(this).toggleClass('hover');
}); });
if($('.product-title').length){
$('.product-title').dotdotdot({ $('.product-title').dotdotdot({
ellipsis: '...' ellipsis: '...'
}); });
}
$(document).on('click', '.btn-qty-minus', function(e){ $(document).on('click', '.btn-qty-minus', function(e){
var qtyElement = $(e.target).parent().parent().find('.cart-product-quantity'); var qtyElement = $(e.target).parent().parent().find('.cart-product-quantity');
@ -161,12 +164,21 @@ $(document).ready(function (){
} }
}); });
$('#createCustomerAccount').validator().on('click', function(e){ $(document).on('click', '#createAccountCheckbox', function(e){
$('#newCustomerPassword').prop('required', $('#createAccountCheckbox').prop('checked'));
});
$('#checkoutInformation').validator().on('click', function(e){
e.preventDefault(); e.preventDefault();
if($('#shipping-form').validator('validate').has('.has-error').length === 0){ if($('#shipping-form').validator('validate').has('.has-error').length === 0){
// Change route if customer to be saved for later
var route = '/customer/save';
if($('#createAccountCheckbox').prop('checked')){
route = '/customer/create';
}
$.ajax({ $.ajax({
method: 'POST', method: 'POST',
url: '/customer/create', url: route,
data: { data: {
email: $('#shipEmail').val(), email: $('#shipEmail').val(),
firstName: $('#shipFirstname').val(), firstName: $('#shipFirstname').val(),
@ -177,11 +189,12 @@ $(document).ready(function (){
state: $('#shipState').val(), state: $('#shipState').val(),
postcode: $('#shipPostcode').val(), postcode: $('#shipPostcode').val(),
phone: $('#shipPhoneNumber').val(), phone: $('#shipPhoneNumber').val(),
password: $('#newCustomerPassword').val() password: $('#newCustomerPassword').val(),
orderComment: $('#orderComment').val()
} }
}) })
.done(function(){ .done(function(){
showNotification('Customer created successfully', 'success', true); window.location = '/checkout/shipping';
}) })
.fail(function(msg){ .fail(function(msg){
showNotification(msg.responseJSON.message, 'danger'); showNotification(msg.responseJSON.message, 'danger');

File diff suppressed because one or more lines are too long

View File

@ -51,10 +51,24 @@ router.post('/customer/create', async (req, res) => {
const newCustomer = await db.customers.insertOne(customerObj); const newCustomer = await db.customers.insertOne(customerObj);
indexCustomers(req.app) indexCustomers(req.app)
.then(() => { .then(() => {
// Customer creation successful // Return the new customer
const customerReturn = newCustomer.ops[0]; const customerReturn = newCustomer.ops[0];
delete customerReturn.password; delete customerReturn.password;
req.session.customer = customerReturn;
// Set the customer into the session
req.session.customerPresent = true;
req.session.customerEmail = customerReturn.email;
req.session.customerFirstname = customerReturn.firstName;
req.session.customerLastname = customerReturn.lastName;
req.session.customerAddress1 = customerReturn.address1;
req.session.customerAddress2 = customerReturn.address2;
req.session.customerCountry = customerReturn.country;
req.session.customerState = customerReturn.state;
req.session.customerPostcode = customerReturn.postcode;
req.session.customerPhone = customerReturn.phone;
req.session.orderComment = req.body.orderComment;
// Return customer oject
res.status(200).json(customerReturn); res.status(200).json(customerReturn);
}); });
}catch(ex){ }catch(ex){
@ -65,6 +79,41 @@ router.post('/customer/create', async (req, res) => {
} }
}); });
router.post('/customer/save', async (req, res) => {
const customerObj = {
email: req.body.email,
firstName: req.body.firstName,
lastName: req.body.lastName,
address1: req.body.address1,
address2: req.body.address2,
country: req.body.country,
state: req.body.state,
postcode: req.body.postcode,
phone: req.body.phone
};
const schemaResult = validateJson('saveCustomer', customerObj);
if(!schemaResult.result){
res.status(400).json(schemaResult.errors);
return;
}
// Set the customer into the session
req.session.customerPresent = true;
req.session.customerEmail = customerObj.email;
req.session.customerFirstname = customerObj.firstName;
req.session.customerLastname = customerObj.lastName;
req.session.customerAddress1 = customerObj.address1;
req.session.customerAddress2 = customerObj.address2;
req.session.customerCountry = customerObj.country;
req.session.customerState = customerObj.state;
req.session.customerPostcode = customerObj.postcode;
req.session.customerPhone = customerObj.phone;
req.session.orderComment = req.body.orderComment;
res.status(200).json(customerObj);
});
// Update a customer // Update a customer
router.post('/admin/customer/update', restrict, async (req, res) => { router.post('/admin/customer/update', restrict, async (req, res) => {
const db = req.app.db; const db = req.app.db;
@ -259,7 +308,17 @@ router.post('/customer/login_action', async (req, res) => {
} }
// Customer login successful // Customer login successful
req.session.customer = customer; req.session.customerPresent = true;
req.session.customerEmail = customer.email;
req.session.customerFirstname = customer.firstName;
req.session.customerLastname = customer.lastName;
req.session.customerAddress1 = customer.address1;
req.session.customerAddress2 = customer.address2;
req.session.customerCountry = customer.country;
req.session.customerState = customer.state;
req.session.customerPostcode = customer.postcode;
req.session.customerPhone = customer.phone;
res.status(200).json({ res.status(200).json({
message: 'Successfully logged in', message: 'Successfully logged in',
customer: customer customer: customer
@ -379,7 +438,7 @@ router.post('/customer/reset/:token', async (req, res) => {
common.sendEmail(mailOpts.to, mailOpts.subject, mailOpts.body); common.sendEmail(mailOpts.to, mailOpts.subject, mailOpts.body);
req.session.message = 'Password successfully updated'; req.session.message = 'Password successfully updated';
req.session.message_type = 'success'; req.session.message_type = 'success';
return res.redirect('/pay'); return res.redirect('/checkout/payment');
}catch(ex){ }catch(ex){
console.log('Unable to reset password', ex); console.log('Unable to reset password', ex);
req.session.message = 'Unable to reset password'; req.session.message = 'Unable to reset password';
@ -390,7 +449,19 @@ router.post('/customer/reset/:token', async (req, res) => {
// logout the customer // logout the customer
router.post('/customer/logout', (req, res) => { router.post('/customer/logout', (req, res) => {
req.session.customer = null; // Clear our session
req.session.customerPresent = null;
req.session.customerEmail = null;
req.session.customerFirstname = null;
req.session.customerLastname = null;
req.session.customerAddress1 = null;
req.session.customerAddress2 = null;
req.session.customerCountry = null;
req.session.customerState = null;
req.session.customerPostcode = null;
req.session.customerPhone = null;
req.session.orderComment = null;
res.status(200).json({}); res.status(200).json({});
}); });

View File

@ -6,7 +6,6 @@ const _ = require('lodash');
const { const {
getId, getId,
hooker, hooker,
showCartCloseBtn,
clearSessionValue, clearSessionValue,
sortMenu, sortMenu,
getMenu, getMenu,
@ -61,7 +60,6 @@ router.get('/payment/:orderId', async (req, res, next) => {
title: 'Payment complete', title: 'Payment complete',
config: req.app.config, config: req.app.config,
session: req.session, session: req.session,
pageCloseBtn: showCartCloseBtn('payment'),
result: order, result: order,
message: clearSessionValue(req.session, 'message'), message: clearSessionValue(req.session, 'message'),
messageType: clearSessionValue(req.session, 'messageType'), messageType: clearSessionValue(req.session, 'messageType'),
@ -75,7 +73,32 @@ router.get('/emptycart', async (req, res, next) => {
emptyCart(req, res, ''); emptyCart(req, res, '');
}); });
router.get('/checkout', async (req, res, next) => { // router.get('/checkout', async (req, res, next) => {
// const config = req.app.config;
// // if there is no items in the cart then render a failure
// if(!req.session.cart){
// req.session.message = 'The are no items in your cart. Please add some items before checking out';
// req.session.messageType = 'danger';
// res.redirect('/');
// return;
// }
// // render the checkout
// res.render(`${config.themeViews}checkout`, {
// title: 'Checkout',
// config: req.app.config,
// session: req.session,
// checkout: 'hidden',
// page: 'checkout',
// message: clearSessionValue(req.session, 'message'),
// messageType: clearSessionValue(req.session, 'messageType'),
// helpers: req.handlebars.helpers,
// showFooter: 'showFooter'
// });
// });
router.get('/checkout/information', async (req, res, next) => {
const config = req.app.config; const config = req.app.config;
// if there is no items in the cart then render a failure // if there is no items in the cart then render a failure
@ -86,47 +109,20 @@ router.get('/checkout', async (req, res, next) => {
return; return;
} }
// render the checkout
res.render(`${config.themeViews}checkout`, {
title: 'Checkout',
config: req.app.config,
session: req.session,
pageCloseBtn: showCartCloseBtn('checkout'),
checkout: 'hidden',
page: 'checkout',
message: clearSessionValue(req.session, 'message'),
messageType: clearSessionValue(req.session, 'messageType'),
helpers: req.handlebars.helpers,
showFooter: 'showFooter'
});
});
router.get('/pay', async (req, res, next) => {
const config = req.app.config;
// if there is no items in the cart then render a failure
if(!req.session.cart){
req.session.message = 'The are no items in your cart. Please add some items before checking out';
req.session.messageType = 'danger';
res.redirect('/checkout');
return;
}
let paymentType = ''; let paymentType = '';
if(req.session.cartSubscription){ if(req.session.cartSubscription){
paymentType = '_subscription'; paymentType = '_subscription';
} }
// render the payment page // render the payment page
res.render(`${config.themeViews}pay`, { res.render(`${config.themeViews}checkout-information`, {
title: 'Pay', title: 'Checkout',
config: req.app.config, config: req.app.config,
paymentConfig: getPaymentConfig(),
pageCloseBtn: showCartCloseBtn('pay'),
session: req.session, session: req.session,
paymentPage: true,
paymentType, paymentType,
page: 'pay', cartSize: 'part',
cartClose: false,
page: 'checkout-information',
countryList, countryList,
message: clearSessionValue(req.session, 'message'), message: clearSessionValue(req.session, 'message'),
messageType: clearSessionValue(req.session, 'messageType'), messageType: clearSessionValue(req.session, 'messageType'),
@ -135,16 +131,86 @@ router.get('/pay', async (req, res, next) => {
}); });
}); });
router.get('/cartPartial', (req, res) => { router.get('/checkout/shipping', async (req, res, next) => {
const config = req.app.config; const config = req.app.config;
res.render(`${config.themeViews}cart`, { // if there is no items in the cart then render a failure
pageCloseBtn: showCartCloseBtn(req.query.path), if(!req.session.cart){
page: req.query.path, req.session.message = 'The are no items in your cart. Please add some items before checking out';
layout: false, req.session.messageType = 'danger';
helpers: req.handlebars.helpers, res.redirect('/');
return;
}
if(!req.session.customerEmail){
req.session.message = 'Cannot proceed to shipping without customer information';
req.session.messageType = 'danger';
res.redirect('/checkout/information');
return;
}
// render the payment page
res.render(`${config.themeViews}checkout-shipping`, {
title: 'Checkout',
config: req.app.config, config: req.app.config,
session: req.session session: req.session,
cartSize: 'part',
cartClose: false,
page: 'checkout-shipping',
countryList,
message: clearSessionValue(req.session, 'message'),
messageType: clearSessionValue(req.session, 'messageType'),
helpers: req.handlebars.helpers,
showFooter: 'showFooter'
});
});
router.get('/checkout/cart', (req, res) => {
const config = req.app.config;
res.render(`${config.themeViews}checkout-cart`, {
page: req.query.path,
cartSize: 'full',
config: req.app.config,
session: req.session,
message: clearSessionValue(req.session, 'message'),
messageType: clearSessionValue(req.session, 'messageType'),
helpers: req.handlebars.helpers,
showFooter: 'showFooter'
});
});
router.get('/checkout/payment', (req, res) => {
const config = req.app.config;
// if there is no items in the cart then render a failure
if(!req.session.cart){
req.session.message = 'The are no items in your cart. Please add some items before checking out';
req.session.messageType = 'danger';
res.redirect('/');
return;
}
let paymentType = '';
if(req.session.cartSubscription){
paymentType = '_subscription';
}
res.render(`${config.themeViews}checkout-payment`, {
title: 'Checkout',
config: req.app.config,
paymentConfig: getPaymentConfig(),
session: req.session,
paymentPage: true,
paymentType,
cartSize: 'part',
cartClose: true,
page: 'checkout-information',
countryList,
message: clearSessionValue(req.session, 'message'),
messageType: clearSessionValue(req.session, 'messageType'),
helpers: req.handlebars.helpers,
showFooter: 'showFooter'
}); });
}); });
@ -180,7 +246,6 @@ router.get('/product/:id', async (req, res) => {
images: images, images: images,
productDescription: product.productDescription, productDescription: product.productDescription,
metaDescription: config.cartTitle + ' - ' + product.productTitle, metaDescription: config.cartTitle + ' - ' + product.productTitle,
pageCloseBtn: showCartCloseBtn('product'),
config: config, config: config,
session: req.session, session: req.session,
pageUrl: config.baseUrl + req.originalUrl, pageUrl: config.baseUrl + req.originalUrl,
@ -210,6 +275,12 @@ router.post('/product/updatecart', (req, res, next) => {
let hasError = false; let hasError = false;
let stockError = false; let stockError = false;
// Check cart exists
if(!req.session.cart){
emptyCart(req, res, 'json', 'There are no items if your cart or your cart is expired');
return;
}
async.eachSeries(cartItems, async (cartItem, callback) => { async.eachSeries(cartItems, async (cartItem, callback) => {
// Find index in cart // Find index in cart
const cartIndex = _.findIndex(req.session.cart, { productId: cartItem.productId }); const cartIndex = _.findIndex(req.session.cart, { productId: cartItem.productId });
@ -308,11 +379,12 @@ router.post('/product/emptycart', async (req, res, next) => {
emptyCart(req, res, 'json'); emptyCart(req, res, 'json');
}); });
const emptyCart = async (req, res, type) => { const emptyCart = async (req, res, type, customMessage) => {
const db = req.app.db; const db = req.app.db;
// Remove from session // Remove from session
delete req.session.cart; delete req.session.cart;
delete req.session.shippingAmount;
delete req.session.orderId; delete req.session.orderId;
// Remove cart from DB // Remove cart from DB
@ -324,13 +396,19 @@ const emptyCart = async (req, res, type) => {
// Update checking cart for subscription // Update checking cart for subscription
updateSubscriptionCheck(req, res); updateSubscriptionCheck(req, res);
// Set returned message
let message = 'Cart successfully emptied';
if(customMessage){
message = customMessage;
}
// If POST, return JSON else redirect nome // If POST, return JSON else redirect nome
if(type === 'json'){ if(type === 'json'){
res.status(200).json({ message: 'Cart successfully emptied', totalCartItems: 0 }); res.status(200).json({ message: message, totalCartItems: 0 });
return; return;
} }
req.session.message = 'Cart successfully emptied.'; req.session.message = message;
req.session.messageType = 'success'; req.session.messageType = 'success';
res.redirect('/'); res.redirect('/');
}; };
@ -513,7 +591,6 @@ router.get('/search/:searchTerm/:pageNum?', (req, res) => {
session: req.session, session: req.session,
metaDescription: req.app.config.cartTitle + ' - Search term: ' + searchTerm, metaDescription: req.app.config.cartTitle + ' - Search term: ' + searchTerm,
searchTerm: searchTerm, searchTerm: searchTerm,
pageCloseBtn: showCartCloseBtn('search'),
message: clearSessionValue(req.session, 'message'), message: clearSessionValue(req.session, 'message'),
messageType: clearSessionValue(req.session, 'messageType'), messageType: clearSessionValue(req.session, 'messageType'),
productsPerPage: numberProducts, productsPerPage: numberProducts,
@ -569,7 +646,6 @@ router.get('/category/:cat/:pageNum?', (req, res) => {
session: req.session, session: req.session,
searchTerm: searchTerm, searchTerm: searchTerm,
metaDescription: `${req.app.config.cartTitle} - Category: ${searchTerm}`, metaDescription: `${req.app.config.cartTitle} - Category: ${searchTerm}`,
pageCloseBtn: showCartCloseBtn('category'),
message: clearSessionValue(req.session, 'message'), message: clearSessionValue(req.session, 'message'),
messageType: clearSessionValue(req.session, 'messageType'), messageType: clearSessionValue(req.session, 'messageType'),
productsPerPage: numberProducts, productsPerPage: numberProducts,
@ -650,7 +726,6 @@ router.get('/page/:pageNum', (req, res, next) => {
message: clearSessionValue(req.session, 'message'), message: clearSessionValue(req.session, 'message'),
messageType: clearSessionValue(req.session, 'messageType'), messageType: clearSessionValue(req.session, 'messageType'),
metaDescription: req.app.config.cartTitle + ' - Products page: ' + req.params.pageNum, metaDescription: req.app.config.cartTitle + ' - Products page: ' + req.params.pageNum,
pageCloseBtn: showCartCloseBtn('page'),
config: req.app.config, config: req.app.config,
productsPerPage: numberProducts, productsPerPage: numberProducts,
totalProductCount: results.totalProducts, totalProductCount: results.totalProducts,
@ -692,7 +767,6 @@ router.get('/:page?', async (req, res, next) => {
session: req.session, session: req.session,
message: clearSessionValue(req.session, 'message'), message: clearSessionValue(req.session, 'message'),
messageType: clearSessionValue(req.session, 'messageType'), messageType: clearSessionValue(req.session, 'messageType'),
pageCloseBtn: showCartCloseBtn('page'),
config, config,
productsPerPage: numberProducts, productsPerPage: numberProducts,
totalProductCount: results.totalProducts, totalProductCount: results.totalProducts,
@ -722,7 +796,6 @@ router.get('/:page?', async (req, res, next) => {
session: req.session, session: req.session,
message: clearSessionValue(req.session, 'message'), message: clearSessionValue(req.session, 'message'),
messageType: clearSessionValue(req.session, 'messageType'), messageType: clearSessionValue(req.session, 'messageType'),
pageCloseBtn: showCartCloseBtn('page'),
config: req.app.config, config: req.app.config,
metaDescription: req.app.config.cartTitle + ' - ' + page, metaDescription: req.app.config.cartTitle + ' - ' + page,
helpers: req.handlebars.helpers, helpers: req.handlebars.helpers,

View File

@ -77,16 +77,16 @@ router.post('/checkout_action', async (req, res, next) => {
orderPaymentGateway: 'Adyen', orderPaymentGateway: 'Adyen',
orderPaymentMessage: response.refusalReason, orderPaymentMessage: response.refusalReason,
orderTotal: req.session.totalCartAmount, orderTotal: req.session.totalCartAmount,
orderEmail: req.body.shipEmail, orderEmail: req.session.customerEmail,
orderFirstname: req.body.shipFirstname, orderFirstname: req.session.customerFirstname,
orderLastname: req.body.shipLastname, orderLastname: req.session.customerLastname,
orderAddr1: req.body.shipAddr1, orderAddr1: req.session.customerAddress1,
orderAddr2: req.body.shipAddr2, orderAddr2: req.session.customerAddress2,
orderCountry: req.body.shipCountry, orderCountry: req.session.customerCountry,
orderState: req.body.shipState, orderState: req.session.customerState,
orderPostcode: req.body.shipPostcode, orderPostcode: req.session.customerPostcode,
orderPhoneNumber: req.body.shipPhoneNumber, orderPhoneNumber: req.session.customerPhone,
orderComment: req.body.orderComment, orderComment: req.session.orderComment,
orderStatus: paymentStatus, orderStatus: paymentStatus,
orderDate: new Date(), orderDate: new Date(),
orderProducts: req.session.cart, orderProducts: req.session.cart,

View File

@ -60,16 +60,16 @@ router.post('/checkout_action', (req, res, next) => {
orderPaymentGateway: 'AuthorizeNet', orderPaymentGateway: 'AuthorizeNet',
orderPaymentMessage: 'Your payment was successfully completed', orderPaymentMessage: 'Your payment was successfully completed',
orderTotal: req.session.totalCartAmount, orderTotal: req.session.totalCartAmount,
orderEmail: req.body.shipEmail, orderEmail: req.session.customerEmail,
orderFirstname: req.body.shipFirstname, orderFirstname: req.session.customerFirstname,
orderLastname: req.body.shipLastname, orderLastname: req.session.customerLastname,
orderAddr1: req.body.shipAddr1, orderAddr1: req.session.customerAddress1,
orderAddr2: req.body.shipAddr2, orderAddr2: req.session.customerAddress2,
orderCountry: req.body.shipCountry, orderCountry: req.session.customerCountry,
orderState: req.body.shipState, orderState: req.session.customerState,
orderPostcode: req.body.shipPostcode, orderPostcode: req.session.customerPostcode,
orderPhoneNumber: req.body.shipPhoneNumber, orderPhoneNumber: req.session.customerPhone,
orderComment: req.body.orderComment, orderComment: req.session.orderComment,
orderStatus: orderStatus, orderStatus: orderStatus,
orderDate: new Date(), orderDate: new Date(),
orderProducts: req.session.cart orderProducts: req.session.cart

View File

@ -138,7 +138,7 @@ router.post('/checkout_action', (req, res, next) => {
if(error){ if(error){
req.session.message = 'There was an error processing your payment. You have not been changed and can try again.'; req.session.message = 'There was an error processing your payment. You have not been changed and can try again.';
req.session.messageType = 'danger'; req.session.messageType = 'danger';
res.redirect('/pay'); res.redirect('/checkout/payment');
return; return;
} }
if(payment.payer.payment_method === 'paypal'){ if(payment.payer.payment_method === 'paypal'){
@ -164,16 +164,16 @@ router.post('/checkout_action', (req, res, next) => {
orderPaymentId: payment.id, orderPaymentId: payment.id,
orderPaymentGateway: 'Paypal', orderPaymentGateway: 'Paypal',
orderTotal: req.session.totalCartAmount, orderTotal: req.session.totalCartAmount,
orderEmail: req.body.shipEmail, orderEmail: req.session.customerEmail,
orderFirstname: req.body.shipFirstname, orderFirstname: req.session.customerFirstname,
orderLastname: req.body.shipLastname, orderLastname: req.session.customerLastname,
orderAddr1: req.body.shipAddr1, orderAddr1: req.session.customerAddress1,
orderAddr2: req.body.shipAddr2, orderAddr2: req.session.customerAddress2,
orderCountry: req.body.shipCountry, orderCountry: req.session.customerCountry,
orderState: req.body.shipState, orderState: req.session.customerState,
orderPostcode: req.body.shipPostcode, orderPostcode: req.session.customerPostcode,
orderPhoneNumber: req.body.shipPhoneNumber, orderPhoneNumber: req.session.customerPhone,
orderComment: req.body.orderComment, orderComment: req.session.orderComment,
orderStatus: payment.state, orderStatus: payment.state,
orderDate: new Date(), orderDate: new Date(),
orderProducts: req.session.cart orderProducts: req.session.cart

View File

@ -18,13 +18,13 @@ router.post('/checkout_action', (req, res, next) => {
source: req.body.stripeToken, source: req.body.stripeToken,
description: stripeConfig.stripeDescription, description: stripeConfig.stripeDescription,
shipping: { shipping: {
name: `${req.body.shipFirstname} ${req.body.shipLastname}`, name: `${req.session.customerFirstname} ${req.session.customerFirstname}`,
address: { address: {
line1: req.body.shipAddr1, line1: req.session.customerAddress1,
line2: req.body.shipAddr2, line2: req.session.customerAddress2,
postal_code: req.body.shipPostcode, postal_code: req.session.customerPostcode,
state: req.body.shipState, state: req.session.customerState,
country: req.body.shipCountry country: req.session.customerCountry
} }
} }
}; };
@ -37,7 +37,7 @@ router.post('/checkout_action', (req, res, next) => {
req.session.message = 'Your payment has declined. Please try again'; req.session.message = 'Your payment has declined. Please try again';
req.session.paymentApproved = false; req.session.paymentApproved = false;
req.session.paymentDetails = ''; req.session.paymentDetails = '';
res.redirect('/pay'); res.redirect('/checkout/payment');
return; return;
} }
@ -53,16 +53,16 @@ router.post('/checkout_action', (req, res, next) => {
orderPaymentGateway: 'Stripe', orderPaymentGateway: 'Stripe',
orderPaymentMessage: charge.outcome.seller_message, orderPaymentMessage: charge.outcome.seller_message,
orderTotal: req.session.totalCartAmount, orderTotal: req.session.totalCartAmount,
orderEmail: req.body.shipEmail, orderEmail: req.session.customerEmail,
orderFirstname: req.body.shipFirstname, orderFirstname: req.session.customerFirstname,
orderLastname: req.body.shipLastname, orderLastname: req.session.customerLastname,
orderAddr1: req.body.shipAddr1, orderAddr1: req.session.customerAddress1,
orderAddr2: req.body.shipAddr2, orderAddr2: req.session.customerAddress2,
orderCountry: req.body.shipCountry, orderCountry: req.session.customerCountry,
orderState: req.body.shipState, orderState: req.session.customerState,
orderPostcode: req.body.shipPostcode, orderPostcode: req.session.customerPostcode,
orderPhoneNumber: req.body.shipPhoneNumber, orderPhoneNumber: req.session.customerPhone,
orderComment: req.body.orderComment, orderComment: req.session.orderComment,
orderStatus: paymentStatus, orderStatus: paymentStatus,
orderDate: new Date(), orderDate: new Date(),
orderProducts: req.session.cart, orderProducts: req.session.cart,
@ -183,13 +183,13 @@ router.post('/checkout_action_subscription', async (req, res, next) => {
if(!plan){ if(!plan){
req.session.messageType = 'danger'; req.session.messageType = 'danger';
req.session.message = 'The plan connected to this product doesn\'t exist'; req.session.message = 'The plan connected to this product doesn\'t exist';
res.redirect('/pay/'); res.redirect('/checkout/payment');
return; return;
} }
}catch(ex){ }catch(ex){
req.session.messageType = 'danger'; req.session.messageType = 'danger';
req.session.message = 'The plan connected to this product doesn\'t exist'; req.session.message = 'The plan connected to this product doesn\'t exist';
res.redirect('/pay/'); res.redirect('/checkout/payment');
return; return;
} }
@ -207,7 +207,7 @@ router.post('/checkout_action_subscription', async (req, res, next) => {
req.session.message = 'Your subscripton has declined. Please try again'; req.session.message = 'Your subscripton has declined. Please try again';
req.session.paymentApproved = false; req.session.paymentApproved = false;
req.session.paymentDetails = ''; req.session.paymentDetails = '';
res.redirect('/pay'); res.redirect('/checkout/payment');
return; return;
} }
@ -217,7 +217,7 @@ router.post('/checkout_action_subscription', async (req, res, next) => {
req.session.message = 'Your subscripton has declined. Please try again'; req.session.message = 'Your subscripton has declined. Please try again';
req.session.paymentApproved = false; req.session.paymentApproved = false;
req.session.paymentDetails = ''; req.session.paymentDetails = '';
res.redirect('/pay'); res.redirect('/checkout/payment');
return; return;
} }
@ -229,16 +229,16 @@ router.post('/checkout_action_subscription', async (req, res, next) => {
orderPaymentGateway: 'Stripe', orderPaymentGateway: 'Stripe',
orderPaymentMessage: subscription.collection_method, orderPaymentMessage: subscription.collection_method,
orderTotal: req.session.totalCartAmount, orderTotal: req.session.totalCartAmount,
orderEmail: req.body.shipEmail, orderEmail: req.session.customerEmail,
orderFirstname: req.body.shipFirstname, orderFirstname: req.session.customerFirstname,
orderLastname: req.body.shipLastname, orderLastname: req.session.customerLastname,
orderAddr1: req.body.shipAddr1, orderAddr1: req.session.customerAddress1,
orderAddr2: req.body.shipAddr2, orderAddr2: req.session.customerAddress2,
orderCountry: req.body.shipCountry, orderCountry: req.session.customerCountry,
orderState: req.body.shipState, orderState: req.session.customerState,
orderPostcode: req.body.shipPostcode, orderPostcode: req.session.customerPostcode,
orderPhoneNumber: req.body.shipPhoneNumber, orderPhoneNumber: req.session.customerPhone,
orderComment: req.body.orderComment, orderComment: req.session.orderComment,
orderStatus: 'Pending', orderStatus: 'Pending',
orderDate: new Date(), orderDate: new Date(),
orderProducts: req.session.cart, orderProducts: req.session.cart,

View File

@ -121,19 +121,17 @@
</li> </li>
{{/ifCond}} {{/ifCond}}
{{#unless admin}} {{#unless admin}}
{{#ifCond page '!=' 'checkout'}}
{{#ifCond page '!=' 'pay'}}
{{#if @root.session.cart}} {{#if @root.session.cart}}
<li><a href="/cart" class="menu-btn"><i class="fa fa-shopping-cart" aria-hidden="true"></i> {{ @root.__ "Cart" }} <span class="badge" id="cart-count">{{@root.session.cartTotalItems}}</span></a></li> <li><a href="/checkout/cart" class="menu-btn"><i class="fa fa-shopping-cart" aria-hidden="true"></i> {{ @root.__ "Cart" }} <span class="badge" id="cart-count">{{@root.session.cartTotalItems}}</span></a></li>
{{else}} {{else}}
<li><a href="/cart" class="menu-btn"><i class="fa fa-shopping-cart" aria-hidden="true"></i> {{ @root.__ "Cart" }} <span class="badge" id="cart-count">0</span></a></li> <li><a href="/checkout/cart" class="menu-btn"><i class="fa fa-shopping-cart" aria-hidden="true"></i> {{ @root.__ "Cart" }} <span class="badge" id="cart-count">0</span></a></li>
{{/if}} {{/if}}
{{/ifCond}}
{{/ifCond}}
{{/unless}} {{/unless}}
{{#if admin}}
{{#if @root.session.user}} {{#if @root.session.user}}
<li><a href="/admin/logout"><i class="fa fa-sign-out" aria-hidden="true"> </i>Logout</a></li> <li><a href="/admin/logout"><i class="fa fa-sign-out" aria-hidden="true"> </i>Logout</a></li>
{{/if}} {{/if}}
{{/if}}
</ul> </ul>
</div> </div>
</div> </div>
@ -142,8 +140,25 @@
{{#unless admin}} {{#unless admin}}
{{#ifCond page '!=' 'checkout'}} {{#ifCond page '!=' 'checkout'}}
{{#ifCond page '!=' 'pay'}} {{#ifCond page '!=' 'pay'}}
<div id="cart" class="col-md-12 pushy pushy-right"> <div id="cart" class="col-md-12 pad-left-12 pushy pushy-right">
<div class="row {{checkout}}">
<div class="col-lg-12 col l12 text-right">
<button class="pushy-link btn btn-primary" type="button">X</button>
</div>
</div>
<div class="row">
<div id="cart" class="col-md-12">
{{> (getTheme 'cart')}} {{> (getTheme 'cart')}}
<div class="row">
{{#if @root.session.cart}}
<div class="col-xs-12 col s12">
<button class="btn btn-danger pull-left" id="empty-cart" type="button">{{ @root.__ "Empty cart" }}</button>
<a href="/checkout/information" class="btn btn-primary pull-right">Checkout</a>
</div>
{{/if}}
</div>
</div>
</div>
</div> </div>
{{/ifCond}} {{/ifCond}}
{{/ifCond}} {{/ifCond}}

View File

@ -52,7 +52,7 @@
data-clientKey="{{@root.paymentConfig.clientKey}}" data-clientKey="{{@root.paymentConfig.clientKey}}"
data-acceptUIFormBtnTxt="Submit" data-acceptUIFormBtnTxt="Submit"
data-acceptUIFormHeaderTxt="Card Information" data-acceptUIFormHeaderTxt="Card Information"
data-responseHandler="responseHandler">Process payment data-responseHandler="responseHandler">Pay Now
</button> </button>
</form> </form>
</div> </div>

View File

@ -11,14 +11,14 @@
data-name="{{@root.config.cartTitle}}" data-name="{{@root.config.cartTitle}}"
data-description="{{@root.config.cartTitle}} Payment" data-description="{{@root.config.cartTitle}} Payment"
data-image="{{@root.paymentConfig.stripeLogoURL}}" data-image="{{@root.paymentConfig.stripeLogoURL}}"
data-email="{{@root.session.customer.email}}" data-email="{{@root.session.customerEmail}}"
{{#if @root.session.cartSubscription}} {{#if @root.session.cartSubscription}}
data-subscription="{{@root.session.cartSubscription}}" data-subscription="{{@root.session.cartSubscription}}"
{{/if}} {{/if}}
data-locale="auto" data-locale="auto"
data-zip-code="false" data-zip-code="false"
data-currency="{{@root.paymentConfig.stripeCurrency}}"> data-currency="{{@root.paymentConfig.stripeCurrency}}">
<i class="fa fa-cc-stripe fa-lg" aria-hidden="true"></i> Process payment <i class="fa fa-cc-stripe fa-lg" aria-hidden="true"></i> <i class="fa fa-cc-stripe fa-lg" aria-hidden="true"></i> Pay Now <i class="fa fa-cc-stripe fa-lg" aria-hidden="true"></i>
</button> </button>
<script src="https://checkout.stripe.com/v2/checkout.js"></script> <script src="https://checkout.stripe.com/v2/checkout.js"></script>
</form> </form>

View File

@ -1,13 +1,5 @@
<div class="row">
<div class="col-xs-12 col s12"> <div class="panel panel-default" style="margin-top: 30px;">
{{#if pageCloseBtn}}
<div class="row {{checkout}}">
<div class="col-lg-12 col l12 text-right">
<button class="pushy-link btn btn-primary" type="button">X</button>
</div>
</div>
{{/if}}
<div class="panel panel-default" style="margin-top: 30px;">
<div class="panel-heading">{{ @root.__ "Cart contents" }}</div> <div class="panel-heading">{{ @root.__ "Cart contents" }}</div>
<div class="panel-body cart-body"> <div class="panel-body cart-body">
<div class="container-fluid"> <div class="container-fluid">
@ -39,7 +31,7 @@
<span class="input-group-btn"> <span class="input-group-btn">
<button class="btn btn-sm btn-primary btn-qty-minus" type="button">-</button> <button class="btn btn-sm btn-primary btn-qty-minus" type="button">-</button>
</span> </span>
<input type="number" class="form-control cart-product-quantity input-sm text-center" data-id="{{this.productId}}" id="{{@key}}" <input type="number" class="form-control cart-product-quantity input-sm text-center" data-id="{{this.productId}}" data-index="{{@key}}"
maxlength="2" value="{{this.quantity}}"> maxlength="2" value="{{this.quantity}}">
<span class="input-group-btn"> <span class="input-group-btn">
<button class="btn btn-sm btn-primary btn-qty-add" type="button">+</button> <button class="btn btn-sm btn-primary btn-qty-add" type="button">+</button>
@ -88,21 +80,4 @@
{{/if}} {{/if}}
</div> </div>
</div> </div>
</div>
<div class="row">
{{#if @root.session.cart}}
<div class="col-xs-6 col s6 text-left align-right">
<button class="btn btn-danger" id="empty-cart" type="button">{{ @root.__ "Empty cart" }}</button>
</div>
{{#ifCond page '!=' 'pay'}}
<div class="text-right align-right col-xs-6 col s6">
{{#ifCond @root.page '==' 'checkout'}}
<a href="/pay" class="btn btn-default">{{ @root.__ "Pay now" }}</a>
{{else}}
<a href="/checkout" class="btn btn-default">Checkout</a>
{{/ifCond}}
</div>
{{/ifCond}} {{/if}}
</div>
</div>
</div> </div>

View File

@ -0,0 +1,15 @@
<div class="col-xl-8 col-xl-offset-2 col-xs-12">
<div class="row">
<div id="cart" class="col-md-12">
{{> (getTheme 'cart')}}
<div class="row">
{{#if @root.session.cart}}
<div class="col-xs-12 col s12">
<button class="btn btn-danger pull-left" id="empty-cart" type="button">{{ @root.__ "Empty cart" }}</button>
<a href="/checkout/information" class="btn btn-danger pull-right">Checkout</a>
</div>
{{/if}}
</div>
</div>
</div>
</div>

View File

@ -2,8 +2,14 @@
<nav aria-label="breadcrumb"> <nav aria-label="breadcrumb">
<ol class="breadcrumb"> <ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/">Home</a></li> <li class="breadcrumb-item"><a href="/">Home</a></li>
<li class="breadcrumb-item active" aria-current="page"><a href="/checkout">Checkout</a></li> <li class="breadcrumb-item active" aria-current="page"><a href="/checkout/information">Information</a></li>
<li class="breadcrumb-item active" aria-current="page">{{ @root.__ "Pay now" }}</li> {{#if @root.session.customerPresent}}
<li class="breadcrumb-item" aria-current="page"><a href="/checkout/shipping">Shipping</a></li>
<li class="breadcrumb-item" aria-current="page"><a href="/checkout/payment">Payment</a></li>
{{else}}
<li class="breadcrumb-item text-muted" aria-current="page">Shipping</li>
<li class="breadcrumb-item text-muted" aria-current="page">Payment</li>
{{/if}}
</ol> </ol>
</nav> </nav>
<div class="row"> <div class="row">
@ -13,7 +19,7 @@
<div class="col-md-5"> <div class="col-md-5">
<div class="panel panel-default" style="margin-top: 30px;"> <div class="panel panel-default" style="margin-top: 30px;">
<div class="panel-heading">{{ @root.__ "Customer details" }}</div> <div class="panel-heading">{{ @root.__ "Customer details" }}</div>
{{#unless session.customer}} {{#unless @root.session.customerPresent}}
<div class="panel-body customer-details-login"> <div class="panel-body customer-details-login">
<p>{{ @root.__ "Existing customer" }}</p> <p>{{ @root.__ "Existing customer" }}</p>
<div class="form-group"> <div class="form-group">
@ -26,49 +32,52 @@
<a href="/customer/forgotten" class="btn btn-default pull-left">{{ @root.__ "Forgotten" }}</a> <a href="/customer/forgotten" class="btn btn-default pull-left">{{ @root.__ "Forgotten" }}</a>
</div> </div>
<div class="form-group"> <div class="form-group">
<button id="customerLogin" class="btn btn-success pull-right" type="submit">Login</button> <button id="customerLogin" class="btn btn-primary pull-right" type="submit">Login</button>
</div> </div>
</div> </div>
{{/unless}} {{/unless}}
<div class="panel-body customer-details"> <div class="panel-body customer-details">
{{#if session.customer}} {{#if @root.session.customerPresent}}
<div class="col-xs-12 col-md-12"> <div class="col-xs-12 col-md-12">
<button id="customerLogout" class="btn btn-sm btn-success pull-right">{{ @root.__ "Change customer" }}</button> <button id="customerLogout" class="btn btn-sm btn-primary pull-right">{{ @root.__ "Change customer" }}</button>
</div> </div>
{{/if}} {{/if}}
<form id="shipping-form" class="shipping-form" action="/{{config.paymentGateway}}/checkout_action{{@root.paymentType}}" method="post" role="form" data-toggle="validator" novalidate="false"> <form id="shipping-form" class="shipping-form" role="form" data-toggle="validator" novalidate="false">
{{> themes/Cloth/shipping-form}} {{> themes/Cloth/shipping-form}}
{{#if session.customer}} {{#unless @root.session.customerPresent}}
{{#ifCond config.paymentGateway '==' 'paypal'}}
{{> partials/payments/paypal}}
{{/ifCond}}
{{/if}}
{{#unless session.customer}}
<div class="col-xs-12 col-md-12"> <div class="col-xs-12 col-md-12">
<p class="text-muted">{{ @root.__ "Enter a password to create an account for next time" }}</p> <p class="text-muted">{{ @root.__ "Enter a password to create an account for next time" }}</p>
<div class="form-group">
<input type="password" class="form-control customerDetails" id="newCustomerPassword" name="newCustomerPassword" placeholder="Password" required>
</div> </div>
<a id="createCustomerAccount" class="btn btn-success pull-right">{{ @root.__ "Create account" }}</a> <div class="col-xs-6 col-md-6">
<div class="form-group">
<input type="password" class="form-control customerDetails" id="newCustomerPassword" name="newCustomerPassword" placeholder="Password">
</div>
</div>
<div class="col-xs-6 col-md-6">
<div class="checkbox">
<label>
<input type="checkbox" id="createAccountCheckbox"> Create an account
</label>
</div>
</div> </div>
{{/unless}} {{/unless}}
<div class="col-xs-12 col-md-12">
<a href="/checkout/cart" class="btn btn-primary pull-left">Return to cart</a>
<a href="/checkout/shipping" id="checkoutInformation" class="btn btn-primary pull-right">Continue to shipping</a>
</div>
</form> </form>
{{#if session.customer}}
{{#ifCond config.paymentGateway '==' 'stripe'}}
{{> partials/payments/stripe}}
{{/ifCond}}
{{#ifCond config.paymentGateway '==' 'authorizenet'}}
{{> partials/payments/authorizenet}}
{{/ifCond}}
{{#ifCond config.paymentGateway '==' 'adyen'}}
{{> partials/payments/adyen}}
{{/ifCond}}
{{/if}}
</div> </div>
</div> </div>
</div> </div>
<div id="cart" class="col-md-7"> <div id="cart" class="col-md-7">
{{> (getTheme 'cart')}} {{> (getTheme 'cart')}}
<div class="row">
{{#if @root.session.cart}}
<div class="col-xs-12 col s12">
<button class="btn btn-danger pull-right" id="empty-cart" type="button">{{ @root.__ "Empty cart" }}</button>
</div>
{{/if}}
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -0,0 +1,65 @@
<div class="col-xl-8 col-xl-offset-2 col-xs-12">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/">Home</a></li>
<li class="breadcrumb-item" aria-current="page"><a href="/checkout/information">Information</a></li>
<li class="breadcrumb-item" aria-current="page"><a href="/checkout/shipping">Shipping</a></li>
<li class="breadcrumb-item active" aria-current="page"><a href="/checkout/payment">Payment</a></li>
</ol>
</nav>
<div class="row">
{{#if paymentMessage}}
<p class="text-danger text-center">{{paymentMessage}}</p>
{{/if}}
<div class="col-md-5">
<div class="panel panel-default" style="margin-top: 30px;">
<div class="panel-heading">{{ @root.__ "Customer details" }}</div>
<div class="panel-body">
<ul class="list-group">
<li class="list-group-item">
{{@root.session.customerFirstname}} {{@root.session.customerLastname}} -
{{@root.session.customerEmail}}
<span class="pull-right"><a href="/checkout/information">Change</a></span>
</li>
</ul>
<ul class="list-group">
{{#if @root.session.shippingCostApplied}}
<li class="list-group-item">
<div class="row">
<div class="col-md-6">
Standard shipping
</div>
<div class="col-md-6">
<span><strong>{{currencySymbol @root.config.currencySymbol}}{{formatAmount @root.config.flatShipping}}</strong></span>
<span class="pull-right"><a href="/checkout/shipping">Change</a></span>
</div>
</div>
</li>
{{else}}
<li class="list-group-item">FREE shipping <span class="pull-right"><a href="/checkout/shipping">Change</a></span></li>
{{/if}}
</ul>
<form id="shipping-form" class="shipping-form" action="/{{config.paymentGateway}}/checkout_action{{@root.paymentType}}" method="post" role="form" data-toggle="validator" novalidate="false">
{{#if session.customerPresent}}
{{#ifCond config.paymentGateway '==' 'paypal'}}
{{> partials/payments/paypal}}
{{/ifCond}}
{{#ifCond config.paymentGateway '==' 'stripe'}}
{{> partials/payments/stripe}}
{{/ifCond}}
{{#ifCond config.paymentGateway '==' 'authorizenet'}}
{{> partials/payments/authorizenet}}
{{/ifCond}}
{{#ifCond config.paymentGateway '==' 'adyen'}}
{{> partials/payments/adyen}}
{{/ifCond}}
{{/if}}
</form>
</div>
</div>
</div>
<div id="cart" class="col-md-7">
{{> (getTheme 'cart')}}
</div>
</div>
</div>

View File

@ -0,0 +1,40 @@
<div class="col-xl-8 col-xl-offset-2 col-xs-12">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/">Home</a></li>
<li class="breadcrumb-item" aria-current="page"><a href="/checkout/information">Information</a></li>
<li class="breadcrumb-item active" aria-current="page"><a href="/checkout/shipping">Shipping</a></li>
<li class="breadcrumb-item" aria-current="page"><a href="/checkout/payment">Payment</a></li>
</ol>
</nav>
<div class="row">
<div class="col-md-5">
<div class="panel panel-default" style="margin-top: 30px;">
<div class="panel-heading">{{ @root.__ "Shipping options" }}</div>
<div class="panel-body cart-body">
{{#unless @root.session.shippingOptions}}
<ul class="list-group">
{{#if @root.session.shippingCostApplied}}
<li class="list-group-item">Standard shipping <span class="pull-right"><strong>{{currencySymbol @root.config.currencySymbol}}{{formatAmount @root.config.flatShipping}}</strong></span></li>
{{else}}
<li class="list-group-item">FREE shipping <span class="pull-right"></li>
{{/if}}
</ul>
{{/unless}}
</div>
</div>
<a href="/checkout/information" class="btn btn-primary pull-left">{{ @root.__ "Return to information" }}</a>
<a href="/checkout/payment" class="btn btn-primary pull-right">{{ @root.__ "Proceed to payment" }}</a>
</div>
<div id="cart" class="col-md-7">
{{> (getTheme 'cart')}}
<div class="row">
{{#if @root.session.cart}}
<div class="col-xs-12 col s12">
<button class="btn btn-danger pull-right" id="empty-cart" type="button">{{ @root.__ "Empty cart" }}</button>
</div>
{{/if}}
</div>
</div>
</div>
</div>

View File

@ -1,11 +0,0 @@
<div class="col-xl-8 col-xl-offset-2 col-xs-12">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/">Home</a></li>
<li class="breadcrumb-item active" aria-current="page">Checkout</li>
</ol>
</nav>
<div id="cart">
{{> (getTheme 'cart')}}
</div>
</div>

View File

@ -1,26 +1,26 @@
<div class="col-xs-12 col-md-12"> <div class="col-xs-12 col-md-12">
<div class="form-group"> <div class="form-group">
<input type="email" class="form-control customerDetails" id="shipEmail" name="shipEmail" minlength="5" placeholder="Email address" value="{{session.customer.email}}" required> <input type="email" class="form-control customerDetails" id="shipEmail" name="shipEmail" minlength="5" placeholder="Email address" value="{{@root.session.customerEmail}}" required>
</div> </div>
</div> </div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
<div class="form-group"> <div class="form-group">
<input type="text" class="form-control customerDetails" id="shipFirstname" name="shipFirstname" placeholder="First name" value="{{session.customer.firstName}}" required> <input type="text" class="form-control customerDetails" id="shipFirstname" name="shipFirstname" placeholder="First name" value="{{@root.session.customerFirstname}}" required>
</div> </div>
</div> </div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
<div class="form-group"> <div class="form-group">
<input type="text" class="form-control customerDetails" id="shipLastname" name="shipLastname" placeholder="Last name" value="{{@root.session.customer.lastName}}" required> <input type="text" class="form-control customerDetails" id="shipLastname" name="shipLastname" placeholder="Last name" value="{{@root.session.customerLastname}}" required>
</div> </div>
</div> </div>
<div class="col-xs-12 col-md-12"> <div class="col-xs-12 col-md-12">
<div class="form-group"> <div class="form-group">
<input type="text" class="form-control customerDetails" id="shipAddr1" name="shipAddr1" placeholder="Address 1" value="{{session.customer.address1}}" required> <input type="text" class="form-control customerDetails" id="shipAddr1" name="shipAddr1" placeholder="Address 1" value="{{@root.session.customerAddress1}}" required>
</div> </div>
</div> </div>
<div class="col-xs-12 col-md-12"> <div class="col-xs-12 col-md-12">
<div class="form-group"> <div class="form-group">
<input type="text" class="form-control customerDetails" id="shipAddr2" name="shipAddr2" placeholder="Address 2 (optional)" value="{{session.customer.address2}}"> <input type="text" class="form-control customerDetails" id="shipAddr2" name="shipAddr2" placeholder="Address 2 (optional)" value="{{@root.session.customerAddress2}}">
</div> </div>
</div> </div>
<div class="col-xs-12"> <div class="col-xs-12">
@ -28,28 +28,28 @@
<select class="form-control" id="shipCountry" name="shipCountry" required> <select class="form-control" id="shipCountry" name="shipCountry" required>
<option value="" disabled selected>Select Country</option> <option value="" disabled selected>Select Country</option>
{{#each countryList}} {{#each countryList}}
<option {{selectState this @root.session.customer.country}} value="{{this}}">{{this}}</option> <option {{selectState this @root.session.customerCountry}} value="{{this}}">{{this}}</option>
{{/each}} {{/each}}
</select> </select>
</div> </div>
</div> </div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
<div class="form-group"> <div class="form-group">
<input type="text" class="form-control customerDetails" id="shipState" name="shipState" placeholder="State" value="{{session.customer.state}}" required> <input type="text" class="form-control customerDetails" id="shipState" name="shipState" placeholder="State" value="{{@root.session.customerState}}" required>
</div> </div>
</div> </div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
<div class="form-group"> <div class="form-group">
<input type="text" class="form-control customerDetails" id="shipPostcode" name="shipPostcode" placeholder="Post code" value="{{session.customer.postcode}}" required> <input type="text" class="form-control customerDetails" id="shipPostcode" name="shipPostcode" placeholder="Post code" value="{{@root.session.customerPostcode}}" required>
</div> </div>
</div> </div>
<div class="col-xs-12 col-md-12"> <div class="col-xs-12 col-md-12">
<div class="form-group"> <div class="form-group">
<input type="number" class="form-control customerDetails" id="shipPhoneNumber" name="shipPhoneNumber" placeholder="Phone number" value="{{session.customer.phone}}" required> <input type="number" class="form-control customerDetails" id="shipPhoneNumber" name="shipPhoneNumber" placeholder="Phone number" value="{{@root.session.customerPhone}}" required>
</div> </div>
</div> </div>
<div class="col-xs-12 col-md-12"> <div class="col-xs-12 col-md-12">
<div class="form-group"> <div class="form-group">
<textarea class="form-control customerDetails" placeholder="Order comment" id="orderComment" name="orderComment"></textarea> <textarea class="form-control customerDetails" placeholder="Order comment" id="orderComment" name="orderComment">{{@root.session.orderComment}}</textarea>
</div> </div>
</div> </div>