Created
February 28, 2017 22:43
-
-
Save shofetim/0a237d635b4cca6eb843399a7352241e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var bf5 = {}; | |
bf5.util = { | |
getQueryParameter: function (name) { | |
var url = window.location.href; | |
name = name.replace(/[\[\]]/g, "\\$&"); | |
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"), | |
results = regex.exec(url); | |
if (!results) return null; | |
if (!results[2]) return ""; | |
return decodeURIComponent(results[2].replace(/\+/g, " ")); | |
}, | |
uuid: function () { | |
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace( | |
/[xy]/g, function (c) { | |
var r = Math.random() * 16 | 0, v = c == "x" ? r : (r & 0x3 | 0x8); | |
return v.toString(16); | |
}); | |
}, | |
range: function (n) { | |
return Array.apply(null, Array(n)).map(function (_, i) {return i;}); | |
}, | |
validateName: function (v) { | |
return !(/[^a-zA-Z]/.test(v) || v.length < 3); | |
}, | |
validateAddress: function (v) { | |
return v.length > 5; | |
}, | |
validateZip: function (v) { | |
return v.replace(/\D/g, "").length == 5; | |
}, | |
validateCvv: function (v) { | |
return (!/[^0-9-\s]+/.test(v) && v.length == 3); | |
}, | |
validateEmail: function (v) { | |
var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; | |
return re.test(v); | |
}, | |
validateLuhn: function(v) { | |
var nCheck = 0, nDigit = 0, bEven = false; | |
if (/[^0-9-\s]+/.test(v)) return false; | |
v = v.replace(/\D/g, ""); | |
for (var n = v.length - 1; n >= 0; n--) { | |
var cDigit = v.charAt(n), | |
nDigit = parseInt(cDigit, 10); | |
if (bEven) { | |
if ((nDigit *= 2) > 9) nDigit -= 9; | |
} | |
nCheck += nDigit; | |
bEven = !bEven; | |
} | |
return (nCheck % 10) == 0; | |
}, | |
validateNotEmpty: function(v) { | |
return (v != "" && v != undefined); | |
}, | |
stow: function (k, v) { | |
return localStorage.setItem(k, JSON.stringify(v)); | |
}, | |
retrieve: function (k) { | |
return JSON.parse(localStorage.getItem(k)); | |
} | |
}; | |
bf5.Customer = function (data) { | |
var self = this; | |
data = data || {}; | |
this.id = m.prop(data.id || bf5.util.uuid()); | |
this.first_name = m.prop(data.first_name || ""); | |
this.first_name.placeholder = "First Name"; | |
this.first_name.validate = bf5.util.validateName; | |
this.first_name.error = "Please enter your first name."; | |
this.last_name = m.prop(data.last_name || ""); | |
this.last_name.placeholder = "Last Name"; | |
this.last_name.validate = bf5.util.validateName; | |
this.last_name.error = "Please enter your last name."; | |
this.weight = m.prop(data.weight || ""); | |
this.weight.placeholder = "Weight"; | |
this.weight.validate = function (v) { | |
var int = parseInt(v); | |
return !(int < 90 || int > 350); | |
}; | |
this.height = m.prop(data.height || 0); | |
this.height.validate = function (v) { | |
var int = parseInt(v); | |
return !(int < 48 || int > 86); | |
}; | |
this.gender = m.prop(data.gender || ""); | |
this.gender.range = ["male", "female"]; | |
this.gender.validate = function (v) { | |
return (v == "male" || v == "female"); | |
}; | |
this.gender.placeholder = "Gender"; | |
this.email = m.prop(data.email || ""); | |
this.email.placeholder = "Email"; | |
this.email.validate = bf5.util.validateEmail; | |
this.feet = function (ft) { | |
if (ft != undefined) { | |
var feet = parseInt(ft) || 0; | |
self.height(feet * 12 + (self.height() % 12)); | |
return feet; | |
} else { | |
return Math.floor(self.height() / 12); | |
} | |
}; | |
this.feet.placeholder = "Height in feet"; | |
this.feet.range = [4, 5, 6, 7]; | |
this.inches = function (inch) { | |
if (inch != undefined) { | |
var inches = parseInt(inch) || 0; | |
self.height(inches + (self.feet() * 12)); | |
return inches; | |
} else { | |
return self.height() % 12; | |
} | |
}; | |
this.inches.placeholder = "Height in inches"; | |
this.inches.range = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; | |
this.save = function () { | |
bf5.util.stow("customer", this); | |
m.request({ | |
method: "POST", | |
url: "/api/customer", | |
data: this, | |
config: function(xhr) { | |
xhr.setRequestHeader("Prefer", "return=minimal"); | |
} | |
}); | |
}; | |
this.validate = function () { | |
return (self.first_name.validate(self.first_name()) | |
&& self.last_name.validate(self.last_name()) | |
&& self.weight.validate(self.weight()) | |
&& self.height.validate(self.height()) | |
&& self.gender.validate(self.gender()) | |
&& self.email.validate(self.email())); | |
}; | |
}; | |
bf5.Address = function (data) { | |
var self = this; | |
data = data || {}; | |
this.id = m.prop(data.id || bf5.util.uuid()); | |
this.customer_id = m.prop(data.customer_id); | |
this.line_1 = m.prop(data.line_1 || ""); | |
this.line_1.validate = bf5.util.validateAddress; | |
this.line_1.placeholder = "Address"; | |
this.line_1.error = "Please enter your address"; | |
this.city = m.prop(data.city || ""); | |
this.city.validate = bf5.util.validateName; | |
this.city.placeholder = "City"; | |
this.city.error = "Please enter your city"; | |
this.state_id = m.prop(data.state_id || ""); | |
this.state_id.validate = bf5.util.validateNotEmpty; | |
this.state_id.placeholder = "State"; | |
this.state_id.range = []; | |
this.zip = m.prop(data.zip || ""); | |
this.zip.validate = bf5.util.validateZip; | |
this.zip.placeholder = "Zip"; | |
this.zip.error = "Please enter your Zip"; | |
this.save = function () { | |
this.customer_id(bf5.util.retrieve("customer").id); | |
bf5.util.stow("address", this); | |
m.request({ | |
method: "POST", | |
url: "/api/address", | |
data: this, | |
config: function(xhr) { | |
xhr.setRequestHeader("Prefer", "return=minimal"); | |
} | |
}); | |
}; | |
this.validate = function () { | |
return (self.line_1.validate(self.line_1()) | |
&& self.city.validate(self.city()) | |
&& self.state_id.validate(self.state_id()) | |
&& self.zip.validate(self.zip())); | |
}; | |
}; | |
bf5.Card = function (data) { | |
var self = this; | |
data = data || {}; | |
this.number = m.prop(data.number || ""); | |
this.number.validate = bf5.util.validateLuhn; | |
this.number.placeholder = "Card Number"; | |
this.number.error = "Please enter your card number"; | |
this.month = m.prop(data.month || ""); | |
this.month.placeholder = "Expiration Month"; | |
this.month.validate = bf5.util.validateNotEmpty; | |
this.month.range = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; | |
this.year = m.prop(data.year || ""); | |
this.year.placeholder = "Expiration Year"; | |
this.year.validate = bf5.util.validateNotEmpty; | |
this.year.range = bf5.util.range(10).map(function (i) { | |
return i + 1900 + new Date().getYear(); | |
}); | |
this.cvv = m.prop(data.cvv || ""); | |
this.cvv.validate = bf5.util.validateCvv; | |
this.cvv.placeholder = "CVV"; | |
this.cvv.error = "Please enter your cards security code"; | |
this.validate = function () { | |
return (self.number.validate(self.number()) | |
&& self.month.validate(self.month()) | |
&& self.year.validate(self.year()) | |
&& self.cvv.validate(self.cvv())); | |
}; | |
}; | |
bf5.Input = { | |
view: function (ctrl, args) { | |
var error = ""; | |
if (args.field.validate && args.field() != "" | |
&& !args.field.validate(args.field())) { | |
error = args.field.error; | |
} | |
return m("div.col-sm-" + (args.size || 6) + (error ? " error" : ""), [ | |
args.label ? m("label", args.label) : undefined, | |
m("input.form-control[placeholder='" + args.field.placeholder + "']", | |
{onchange: m.withAttr("value", args.field), | |
value: args.field()}), | |
m("span", error) | |
]); | |
} | |
}; | |
bf5.Select = { | |
view: function (ctrl, args) { | |
var error = ""; | |
args.transform = args.transform || function (v) {return v;}; | |
if (args.field.validate && args.field() != "" | |
&& !args.field.validate(args.field())) { | |
error = args.field.error; | |
}; | |
return m("div.col-sm-" + (args.size || 4) + (error ? " error" : ""), [ | |
args.label ? m("label", args.label) : undefined, | |
m("select.form-control", | |
{onchange: m.withAttr("value", args.field), | |
value: args.field()}, [ | |
m("option", { | |
value: args.field(), | |
selected: "selected", | |
disabled: "disabled" | |
}, args.field.placeholder || "Please Select"), | |
args.field.range.map(function (opt) { | |
return m("option", {value: opt}, args.transform(opt)); | |
})])]); | |
} | |
}; | |
bf5.Form = { | |
controller: function () { | |
var self = this; | |
this.customer = new bf5.Customer(); | |
this.product = ( | |
window.location.pathname.indexOf("kratos") > -1) ? "kratos" : "motion"; | |
this.submit = function () { | |
var valid = this.customer.validate(); | |
if (valid) { | |
this.customer.save(); | |
window.location = "/l/step-2/?product=" + self.product + | |
"&first_name=" + self.customer.first_name(); | |
} else { | |
self.showError = true; | |
} | |
}; | |
}, | |
view: function (ctrl) { | |
return m("div", [ | |
m("form.form-horizontal", [ | |
m("div.form-group", [ | |
m(bf5.Input, {field: ctrl.customer.first_name}), | |
m(bf5.Input, {field: ctrl.customer.last_name}) | |
]), | |
m("div.form-group", [ | |
m(bf5.Input, {field: ctrl.customer.email}), | |
m(bf5.Input, {field: ctrl.customer.weight}) | |
]), | |
m("div.form-group", [ | |
m(bf5.Select, {field: ctrl.customer.feet}), | |
m(bf5.Select, {field: ctrl.customer.inches}), | |
m(bf5.Select, | |
{field: ctrl.customer.gender, | |
transform: function (v) { | |
return v.charAt(0).toUpperCase() + v.slice(1); | |
}})])]), | |
ctrl.showError ? | |
m(".error", m("h3", "Please complete all form fields")) : undefined, | |
m("a.btn", { | |
onclick: function () {ctrl.submit();}, | |
class: (ctrl.product == "kratos") ? "red" : "" | |
}, "SEE IF YOU QUALIFY FOR A SAMPLE!") | |
]); | |
} | |
}; | |
bf5.Form2 = { | |
controller: function () { | |
var self = this; | |
this.address = new bf5.Address(); | |
this.product = bf5.util.getQueryParameter("product"); | |
this.processData = function (place) { | |
var componentForm = { | |
street_number: "short_name", | |
route: "long_name", | |
locality: "long_name", | |
administrative_area_level_1: "short_name", | |
country: "long_name", | |
postal_code: "short_name" | |
}, addressParts = { | |
street_number: "", | |
route: "", | |
locality: "", | |
administrative_area_level_1: "", | |
postal_code: "" | |
}; | |
if (typeof place !== "undefined") { | |
for (var i = 0; i < place.address_components.length; i++) { | |
var addressType = place.address_components[i].types[0]; | |
if (componentForm[addressType]) { | |
var val = place.address_components[i][componentForm[addressType]]; | |
addressParts[addressType] = val; | |
} | |
} | |
} | |
return addressParts; | |
}; | |
this.fillAddress = function () { | |
var place = self.autocomplete.getPlace(), | |
data = self.processData(place); | |
self.address.line_1(data.street_number + " " + data.route); | |
self.address.city(data.locality); | |
self.address.zip(data.postal_code); | |
self.address.state_id(self.statesReverse[data.administrative_area_level_1]); | |
m.redraw("diff"); | |
}; | |
this.geolocate = function () { | |
if (navigator.geolocation) { | |
navigator.geolocation.getCurrentPosition(function(position) { | |
var geolocation = { | |
lat: position.coords.latitude, | |
lng: position.coords.longitude | |
}; | |
var circle = new google.maps.Circle({ | |
center: geolocation, | |
radius: position.coords.accuracy | |
}); | |
autocomplete.setBounds(circle.getBounds()); | |
}); | |
} | |
}; | |
this.states = []; | |
this.getStates = function () { | |
return m.request({ | |
method: "GET", | |
url: "/api/state?select=id,abbrev", | |
background: true, | |
initialValue: [] | |
}).then(function (data) { | |
self.states = data.reduce(function(init, i) { | |
init[i.id] = i.abbrev; | |
return init; | |
}, {}); | |
self.statesReverse = data.reduce(function(init, i) { | |
init[i.abbrev] = i.id; | |
return init; | |
}, {}); | |
self.address.state_id.range = data.map(function (i) { | |
return i.id; | |
}); | |
m.redraw("diff"); | |
}); | |
}, | |
this.init = function () { | |
this.getStates(); | |
setTimeout(function () { | |
self.autocomplete = new google.maps.places.Autocomplete( | |
(document.getElementById("autocomplete")), | |
{types: ["geocode"]}); | |
var place = self.autocomplete.getPlace(); | |
self.autocomplete.addListener("place_changed", self.fillAddress); | |
}, 500); | |
}; | |
this.submit = function () { | |
first_name = bf5.util.retrieve("customer").first_name; | |
var valid = self.address.validate(); | |
if (valid) { | |
self.address.save(); | |
window.location = "/l/step-3/?product=" + self.product + | |
"&first_name=" + first_name; | |
} else { | |
self.showError = true; | |
} | |
}; | |
self.init(); | |
}, | |
view: function (ctrl) { | |
return [ | |
m("form.form-horizontal", [ | |
m("div.form-group", [ | |
m("div.form-group", [ | |
m("div.col-sm-12", [ | |
m("input.form-control#autocomplete[placeholder='Address Autocomplete']", | |
{onfocus: ctrl.geolocate()}), | |
m("p.help-block", | |
"Just start typing your address, and we'll take it from there!") | |
]) | |
]), | |
m("div.form-group", [ | |
m(bf5.Input, {size: 12, field: ctrl.address.line_1})]), | |
m("div.form-group", [ | |
m(bf5.Input, {size: 4, field: ctrl.address.city}), | |
m(bf5.Select, {size: 4, field: ctrl.address.state_id, | |
transform: function (i) {return ctrl.states[i];}}), | |
m(bf5.Input, {size: 4, field: ctrl.address.zip})])])]), | |
ctrl.showError ? | |
m(".error", m("h3", "Please complete all form fields")) : undefined, | |
m("a#tmpl-next-page.btn", {onclick: ctrl.submit}, "GET YOUR SAMPLE!")]; | |
} | |
}; | |
bf5.Form3 = { | |
controller: function () { | |
var self = this, product; | |
product = bf5.util.getParameterByName('product'); | |
this.card = new bf5.Card(); | |
this.name = (product == "kratos") ? "KRATOS MAX|5" : "MOTION|5 JOINT SUPPORT"; | |
this.success = false; | |
this.msg = "You must act now to claim your 14-day sample of " + | |
this.name + ". If you qualify for this exclusive online offer, your " + | |
"order will be shipped in 24-48 hours. Sign up now to start seeing the " + | |
"blackfish5 difference in just a few days!"; | |
this.thankYou = "Thank you! You will receive your free sample shortly."; | |
this.stripeResponseHandler = function (status, res) { | |
if (res.error) { | |
alert("There is a problem with your card details, please try again"); | |
} else { | |
var customer_id, product, price; | |
customer_id = bf5.util.retrieve("customer").id; | |
product = getParameterByName("product"); | |
if (product == "motion") { | |
price = 79; | |
} else { | |
price = 69; | |
} | |
m.request({ | |
method: "POST", | |
url: "/api/order", | |
data: {customer_id: customer_id, token: res.id, | |
product: self.name, price: price}, | |
config: function(xhr) { | |
xhr.setRequestHeader("Prefer", "return=minimal"); | |
} | |
}); | |
self.success = true; | |
} | |
}; | |
this.submit = function () { | |
var valid = self.card.validate(); | |
if (valid) { | |
Stripe.card.createToken({ | |
number: self.card.number(), | |
cvc: self.card.cvv(), | |
exp_month: self.card.month(), | |
exp_year: self.card.year() | |
}, self.stripeResponseHandler); | |
self.card = new bf5.Card(); | |
self.showError = false; | |
} else { | |
self.showError = true; | |
} | |
}; | |
}, | |
view: function (ctrl) { | |
return [ | |
m("form", [ | |
m("div.form-group", [ | |
m(bf5.Input, {size: 12, label: "Card Number", field: ctrl.card.number}), | |
m(bf5.Select, {size: 6, label: "Expiration Month", field: ctrl.card.month}), | |
m(bf5.Select, {size: 6, label: "Expiration Year", field: ctrl.card.year}), | |
m(bf5.Input, {size: 12, label: "Security Code", field: ctrl.card.cvv}), | |
])]), | |
m("div.clearfix"), | |
m("p", ctrl.msg), | |
ctrl.showError ? | |
m(".error", m("h3", "Please complete all form fields")) : undefined, | |
ctrl.success ? m("div.thank-you", ctrl.thankYou) : | |
m("a.btn", | |
{class: (ctrl.product == "kratos") ? "red": "", onclick : ctrl.submit}, | |
"RUSH MY SAMPLE!")]; | |
} | |
}; | |
if (document.getElementById("step1form")) { | |
m.mount(document.getElementById("step1form"), bf5.Form); | |
} | |
if (document.getElementById("step2form")) { | |
m.mount(document.getElementById("step2form"), bf5.Form2); | |
} | |
if (document.getElementById("step3form")) { | |
m.mount(document.getElementById("step3form"), bf5.Form3); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment