Skip to content

Instantly share code, notes, and snippets.

@shofetim
Created February 28, 2017 22:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shofetim/0a237d635b4cca6eb843399a7352241e to your computer and use it in GitHub Desktop.
Save shofetim/0a237d635b4cca6eb843399a7352241e to your computer and use it in GitHub Desktop.
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