Add Drop and Send, replace loyalty system with accounts, TODO: save credit card info

master
Skylar Ittner 3 years ago
parent d819f11228
commit 671ca65661

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

@ -4,32 +4,66 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
class Map {
constructor(mapboxElement) {
class MapControl {
constructor(mapboxElement, interactive) {
this.mapObj = null;
this.mapEl = mapboxElement;
this.interactiveMap = interactive == true;
}
createMap() {
if (mapboxgl.supported()) {
$(this.mapEl).css("display", "");
this.mapObj = maplibreMap(this.mapEl);
this.mapObj = maplibreMap(this.mapEl, this.interactiveMap);
} else {
console.log("maplibre-gl not supported, disabling map");
$(this.mapEl).css("display", "none");
}
}
clearOldMarkersAndCenterMapOnNewMarker(classname) {
var latitude = $(this.mapEl).data("latitude");
var longitude = $(this.mapEl).data("longitude");
var accurate = $(this.mapEl).data("accurate") == true;
/**
* Clear all markers from the map, make a new marker, and fly to it.
* @param {string} classname CSS class for the marker, for adding icon and stuff. Default will be invisible and 0x0px.
* @param {number} latitude
* @param {number} longitude
* @param {boolean} accurate set true to zoom to street level (z13), false to zoom to general area (z10).
* @returns {undefined}
*/
clearMarkersAndCenterMapOnNewMarker(classname, latitude, longitude, accurate) {
this.mapObj.removeMarkers();
this.mapObj.addMarker(latitude, longitude, classname);
this.mapObj.animateMapIn(latitude, longitude, (accurate ? 13 : 10));
}
loadMarkersFromGeoJson(geojson, iconname, name) {
this.mapObj.addSource("markers-" + name, {
'type': 'geojson',
'data': geojson
});
this.mapObj.addLayer({
id: "marker-layer-" + name,
type: "symbol",
source: "markers-" + name,
layout: {
"icon-image": iconname,
"icon-anchor": "bottom",
'icon-allow-overlap': true
}
});
}
loadIcon(url, name, callback) {
var mapObj = this.mapObj;
this.mapObj.loadImage(
url,
function (error, image) {
if (error)
throw error;
mapObj.addImage(name, image);
callback();
});
}
/**
* Destroy and re-create the map.
* @returns {undefined}
@ -57,10 +91,10 @@ class Map {
}
setMapLocation(latitude, longitude) {
if (mapObj == null) {
if (this.mapObj == null) {
return;
}
mapObj.setMapLocation(latitude, longitude);
this.mapObj.setMapLocation(latitude, longitude);
}
animateMapIn(latitude, longitude, zoom, heading) {

@ -0,0 +1,249 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
function checkAccountStatus(callback) {
if (inStorage("phonenumber")) {
apirequest(SETTINGS.apis.authorstartverify, {
phone: getStorage("phonenumber"),
accountkey: (inStorage("accountkey") ? getStorage("accountkey") : "")
}, function (resp) {
if (resp.status == "OK") {
if (resp.authok && resp.accountok) {
callback(true);
} else if (!resp.authok && resp.accountok) {
// verify phone or email
// openAccountVerify(resp.verifymsg);
callback("noauth", resp.verifymsg);
} else if (!resp.authok && !resp.accountok) {
callback(false);
} else {
callback("badstate");
}
} else {
app.dialog.alert(resp.msg, "Error");
}
}, function (err) {
app.dialog.alert("Something went wrong. Try again later.", "Error");
});
} else {
callback(false);
}
}
function openAccountVerify(verifymsg) {
app.dialog.prompt(verifymsg, "Verify Your Account", function (val) {
verifyCode(val);
}, function (cancel) {
// shrug
}, "");
}
/**
* Confirm auth/login code with server and store login key if successful.
* @param {type} code
* @returns {undefined}
*/
function verifyCode(code) {
app.dialog.preloader("Verifying...");
apirequest(SETTINGS.apis.verifyauthcode, {
code: code,
phone: getStorage("phonenumber")
}, function (resp) {
app.dialog.close();
if (resp.status == "OK") {
setStorage("accountkey", resp.authkey);
app.dialog.alert("This device has been successfully linked to your Helena Express account.", "Account verified!");
displayAccountInfo();
} else if (resp.status == "ERROR") {
app.dialog.alert(resp.msg, "Error");
}
}, function (error) {
app.dialog.close();
app.dialog.alert("There's a server or network problem. Check your Internet connection or try again later.", "Error");
});
}
function displayAccountInfo() {
$("#loyaltyBalanceBox").addClass("display-none");
$("#loyaltyErrorMessage").html("");
if (inStorage("accountkey") && inStorage("phonenumber")) {
} else {
$("#loyaltyErrorMessage").text("Error: No account connected.");
return;
}
apirequest(SETTINGS.apis.getaccountinfo, {
phone: getStorage("phonenumber"),
accountkey: getStorage("accountkey")
}, function (success) {
$("#hasaccountbox").css("display", "");
$("#loadingaccountbox").css("display", "none");
if (success.status == "OK") {
$("#loyaltyCreditBalanceHeading").text(success.credits + " points");
$("#loyaltyBalanceBox").removeClass("display-none");
var canvas = document.createElement('canvas');
bwipjs.toCanvas(canvas, {
bcid: 'code128', // Barcode type
text: success.phone, // Text to encode
scaleX: 5,
scaleY: 1,
includetext: false, // Show human-readable text
textxalign: 'center', // Always good to set this
eclevel: 'M'
});
$("#accountnumberspan").text("Account number: " + success.phone);
document.getElementById("loyaltyBarcodeImg").src = canvas.toDataURL('image/png');
if (success.payments_setup === false) {
$("#addPaymentMethodBox").css("display", "");
}
$("#accountupdateform input#name").val(success.name);
$("#accountupdateform input#email").val(success.email);
$("#accountupdateform input#streetaddress").val(success.streetaddress);
$("#accountupdateform input#zipcode").val(success.zipcode);
} else {
$("#loyaltyBalanceBox").addClass("display-none");
$("#loyaltyErrorMessage").text("Error: " + success.msg);
}
}, function (error) {
$("#loyaltyErrorMessage").text("Error: Couldn't get your account info. Try again later.");
}, "GET");
}
$("#app").on("click", "#setupAccountBtn", function () {
if ($("#accountsetupform input#phonenumber").val() == "") {
app.dialog.alert("Add your phone number.", "Error");
return;
}
if ($("#accountsetupform input#name").val() == "") {
app.dialog.alert("Add your name.", "Error");
return;
}
if ($("#accountsetupform input#email").val() == "") {
app.dialog.alert("Add your email address.", "Error");
return;
}
if ($("#accountsetupform input#streetaddress").val() == "") {
app.dialog.alert("Add your street address.", "Error");
return;
}
if ($("#accountsetupform input#zipcode").val() == "") {
app.dialog.alert("Add your ZIP Code.", "Error");
return;
}
app.dialog.preloader("Creating Account...");
apirequest(SETTINGS.apis.accountregister, {
phone: $("#accountsetupform input#phonenumber").val(),
name: $("#accountsetupform input#name").val(),
email: $("#accountsetupform input#email").val(),
address: $("#accountsetupform input#streetaddress").val(),
zipcode: $("#accountsetupform input#zipcode").val()
}, function (resp) {
app.dialog.close();
if (resp.status == "ERROR") {
app.dialog.alert(resp.msg, "Error");
return;
} else {
setStorage("phonenumber", resp.phone);
router.refreshPage();
}
}, function (error) {
app.dialog.close();
app.dialog.alert("There's a server or network problem. Check your Internet connection or try again later.", "Error");
});
});
$("#app").on("click", "#updateAccountBtn", function () {
if ($("#accountupdateform input#name").val() == "") {
app.dialog.alert("Add your name.", "Error");
return;
}
if ($("#accountupdateform input#email").val() == "") {
app.dialog.alert("Add your email address.", "Error");
return;
}
if ($("#accountupdateform input#streetaddress").val() == "") {
app.dialog.alert("Add your street address.", "Error");
return;
}
if ($("#accountupdateform input#zipcode").val() == "") {
app.dialog.alert("Add your ZIP Code.", "Error");
return;
}
app.dialog.preloader("Updating Account...");
apirequest(SETTINGS.apis.accountregister, {
phone: getStorage("phonenumber"),
accountkey: getStorage("accountkey"),
name: $("#accountupdateform input#name").val(),
email: $("#accountupdateform input#email").val(),
address: $("#accountupdateform input#streetaddress").val(),
zipcode: $("#accountupdateform input#zipcode").val()
}, function (resp) {
app.dialog.close();
if (resp.status == "ERROR") {
app.dialog.alert(resp.msg, "Error");
return;
} else {
app.popup.close("#accountUpdatePopup", true);
setStorage("phonenumber", resp.phone);
router.refreshPage();
app.dialog.alert("Account details updated.", "Account Updated");
}
}, function (error) {
app.dialog.close();
app.dialog.alert("There's a server or network problem. Check your Internet connection or try again later.", "Error");
});
});
$("#app").on("click", "#connectExistingAccountBtn", function () {
app.dialog.prompt("Enter your phone number or account number:", "Connect Your Account", function (val) {
var phone = val.replace(/\D/g, '');
if (phone.length < 10) {
app.dialog.alert("Please enter a full 10-digit phone number.", "Oops!");
return;
}
setStorage("phonenumber", phone);
router.refreshPage();
}, function (cancel) {
// shrug
}, "");
});
$("#app").on("popup:open", "#accountUpdatePopup", function () {
app.input.checkEmptyState("#accountupdateform input#name");
app.input.checkEmptyState("#accountupdateform input#email");
app.input.checkEmptyState("#accountupdateform input#streetaddress");
app.input.checkEmptyState("#accountupdateform input#zipcode");
});
function initAccountPage() {
checkAccountStatus(function (result, msg) {
switch (result) {
case true:
displayAccountInfo();
break;
case false:
$("#setupaccountbox").css("display", "");
$("#loadingaccountbox").css("display", "none");
break;
case "noauth":
openAccountVerify(msg);
break;
case "badstate":
app.dialog.alert("Your account is in an unstable state. This shouldn't happen. Please contact us at (406) 389-8988 and we'll fix it.", "Error");
break;
default:
app.dialog.alert("Something went very wrong. Close the app completely (swipe it away from the app switcher) and re-open it. If you continue to get this message, contact us for help: (406) 389-8988", "Error");
break;
}
});
}

@ -0,0 +1,66 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
function captureAndSendPickupCode() {
scanBarcode(function (result) {
var code = "";
var coderegex = /^[0-9a-zA-Z]{5,40}$/;
if (result.startsWith("https://helena.express/dropandsend#")) {
code = result.split("#")[1];
} else if (coderegex.test(result)) {
code = result;
} else {
app.dialog.alert("That's not a valid drop box code.", "Error");
return;
}
sendPickupCode(code);
}, function () {
app.dialog.prompt("Something went wrong while trying to scan the barcode. Type the location number to request a pickup.", "Send Pickup Code", function (code) {
if (code == "") {
app.dialog.alert("You didn't enter a location number.", "Error");
} else {
sendPickupCode(code);
}
}, function (cancel) {
}, "");
});
}
function sendPickupCode(code) {
app.dialog.preloader("Loading...");
apirequest(SETTINGS.apis.dropandsendpickup, {
phone: getStorage("phonenumber"),
accountkey: getStorage("accountkey"),
locationnumber: code
}, function (resp) {
app.dialog.close();
if (resp.status == "OK") {
app.dialog.alert("Thank you for using Helena Express! You'll get an emailed receipt after we pick up and process your package(s).", "Pickup Requested!");
} else if (resp.status == "ERROR") {
app.dialog.alert(resp.msg, "Error");
}
}, function (error) {
app.dialog.close();
app.dialog.alert("There's a server or network problem. Check your Internet connection or try again later.", "Error");
});
}
$("#app").on("click", "#pickupCodeQRScanBtn", function () {
captureAndSendPickupCode();
});
$("#app").on("click", "#pickupCodeManualEntryBtn", function () {
app.dialog.prompt("Enter the location number to request a pickup.", "Send Pickup Code", function (code) {
if (code == "") {
app.dialog.alert("You didn't enter a location number.", "Error");
} else {
sendPickupCode(code);
}
}, function (cancel) {
}, "");
});

@ -1,52 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
function displayLoyaltyPoints() {
$("#loyalty-balance-box").addClass("display-none");
$("#loyalty-error").html("");
if (inStorage("phonenumber")) {
var phone = getStorage("phonenumber");
} else {
$("#loyalty-error").text("Error: No phone number saved.");
}
app.dialog.preloader("Checking points balance...");
apirequest(SETTINGS.apis.loyalty, {phone: phone}, function (success) {
app.dialog.close();
if (success.status == "OK") {
$("#loyalty-credit-balance").text(success.credits + " points");
$("#loyalty-balance-box").removeClass("display-none");
var canvas = document.createElement('canvas');
bwipjs.toCanvas(canvas, {
bcid: 'code128', // Barcode type
text: success.phone, // Text to encode
scaleX: 5,
scaleY: 1,
includetext: false, // Show human-readable text
textxalign: 'center', // Always good to set this
eclevel: 'M'
});
document.getElementById("loyalty-barcode").src = canvas.toDataURL('image/png');
} else {
$("#loyalty-balance-box").addClass("display-none");
$("#loyalty-error").text("Error: " + success.message);
}
}, function (error) {
$("#loyalty-error").text("Error: Couldn't check your points balance. Try again later.");
}, "GET");
}
function savePhoneNumber() {
var phone = $("#phonenumber").val().replace(/\D/g, '');
if (phone.length < 10) {
app.dialog.alert("Please enter a full 10-digit phone number.", "Oops!");
return;
}
setStorage("phonenumber", phone);
router.refreshPage();
}

@ -5,4 +5,4 @@
*/
///var trackingMap = new Map(document.getElementById("mapbox-track"));
var dropboxMap = null;

@ -4,7 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
function maplibreMap(containerEl) {
function maplibreMap(containerEl, interactive) {
var theme = "liberty";
if ($("#app").hasClass("theme-dark")) {
@ -17,13 +17,39 @@ function maplibreMap(containerEl) {
container: containerEl.id,
style: SETTINGS.maptileurls[theme].json,
//attributionControl: false,
interactive: false,
interactive: interactive,
pitch: 0,
zoom: 1,
maxZoom: 14,
maxZoom: 18,
center: [-97, 38]
});
if (interactive) {
map.addControl(new mapboxgl.NavigationControl({
visualizePitch: false,
showCompass: false
}), 'top-left');
map.addControl(
new mapboxgl.GeolocateControl({
positionOptions: {
enableHighAccuracy: true,
timeout: 10 * 1000
},
fitBoundsOptions: {
maxZoom: 16
},
trackUserLocation: false
}), 'top-left'
);
map.addControl(
new mapboxgl.ScaleControl({
unit: "imperial"
})
);
}
map.mapEasing = function (t) {
return t * (2 - t);
};

@ -179,7 +179,13 @@ function initCordova() {
// Handle geo: urls
$("#app").on("click", "a[href^='geo:']", function (evt) {
window.open($(this).attr("href"), "_system");
if (cordova.platformId == "ios") {
window.open($(this).attr("href").replace("geo:", "http://maps.apple.com/?q="), "_system");
} else if (cordova.platformId == "android") {
window.open($(this).attr("href").replace("geo:", "geo:0,0?q="), "_system");
} else {
window.open($(this).attr("href"), "_system");
}
evt.preventDefault();
});
}
@ -223,7 +229,7 @@ function initNW() {
setupHTML5BarcodeScanner();
// Handle geo: urls
$("#app").on("click", ".geolink", function (evt) {
$("#app").on("click", "a[href^='geo:']", function (evt) {
require('nw.gui').Shell.openExternal($(this).attr("href"));
evt.preventDefault();
});

@ -47,14 +47,15 @@
<script src="assets/js/platform.js"></script>
<script src="assets/js/map_maplibre.js"></script>
<script src="assets/js/Map.class.js"></script>
<script src="assets/js/MapControl.class.js"></script>
<script src="assets/js/map.js"></script>
<script src="assets/js/util.js"></script>
<script src="assets/js/track.js"></script>
<script src="assets/js/dropandsend.js"></script>
<script src="assets/js/addresscode.js"></script>
<script src="assets/js/rates.js"></script>
<script src="assets/js/noticeslip.js"></script>
<script src="assets/js/loyalty.js"></script>
<script src="assets/js/account.js"></script>
<script src="routes.js"></script>
<script src="assets/js/main.js"></script>

@ -0,0 +1,178 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<div class="page" data-name="account">
<div class="navbar">
<div class="navbar-bg"></div>
<div class="navbar-inner">
<div class="left">
<a class="link back hapticbtn" href="#">
<i class="icon icon-back"></i>
<span class="if-not-md">Back</span>
</a>
</div>
<div class="title">My Account</div>
</div>
</div>
<div class="page-content">
<div class="row justify-content-center">
<div class="col-100 medium-90 xlarge-75 margin-horizontal">
<div class="card margin">
<div class="card-content text-align-center padding-vertical">
<div id="loadingaccountbox" style="text-align: center;">
<div class="preloader"></div>
<br /><br />
Loading...
</div>
<div id="hasaccountbox" style="display: none;">
<div id="addPaymentMethodBox" style="display: none;">
Add a credit or debit card to use Drop and Send. It'll be securely saved for future use.
<a class="button hapticbtn button-fill margin" href="/account/managepayment" onclick="alert('TODO')"><i class="fas fa-credit-card"></i> Add Card</a>
<hr />
</div>
<div id="loyaltyBalanceBox" class="card-content-padding">
<div>You have earned a total of</div>
<h1 id="loyaltyCreditBalanceHeading">...</h1>
<img id="loyaltyBarcodeImg" style="width: 90%; max-width: 300px; padding: 1.2em; background: white;" />
<br />
<span id="accountnumberspan"></span>
</div>
<div class="block">
<div class="button hapticbtn popup-open" data-popup="#accountUpdatePopup"><i class="fas fa-edit"></i> Update account details</div>
</div>
<div id="loyaltyErrorMessage"></div>
<div class="block">
Loyalty points have no cash value. All points and associated discounts
are offered as a courtesy by and at the discretion of Helena Express
and may be revoked, canceled, or modified at any time for any reason.
</div>
</div>
<div id="setupaccountbox" style="display: none;">
<div class="block">
Set up an account to use our Drop and Send service, earn rewards points, and more!
</div>
<div class="block">
Already have an account?
<div class="button hapticbtn" id="connectExistingAccountBtn">
<span class="taptext">Tap</span>
<span class="clicktext">Click</span> here</div>
to connect it.
</div>
<div class="list">
<ul id="accountsetupform">
<li class="item-content item-input item-input-outline">
<div class="item-inner">
<div class="item-title item-floating-label">Name</div>
<div class="item-input-wrap">
<input type="text" id="name" />
<span class="input-clear-button"></span>
</div>
</div>
</li>
<li class="item-content item-input item-input-outline">
<div class="item-inner">
<div class="item-title item-floating-label">Email</div>
<div class="item-input-wrap">
<input type="email" id="email" autocorrect="off" />
<span class="input-clear-button"></span>
</div>
</div>
</li>
<li class="item-content item-input item-input-outline">
<div class="item-inner">
<div class="item-title item-floating-label">Phone Number</div>
<div class="item-input-wrap">
<input type="tel" id="phonenumber" />
<span class="input-clear-button"></span>
</div>
</div>
</li>
<li class="item-content item-input item-input-outline">
<div class="item-inner">
<div class="item-title item-floating-label">House number and street</div>
<div class="item-input-wrap">
<input type="text" id="streetaddress" placeholder="1234 Notareal Road" autocomplete="off" autocorrect="off"/>
<span class="input-clear-button"></span>
</div>
</div>
</li>
<li class="item-content item-input item-input-outline">
<div class="item-inner">
<div class="item-title item-floating-label">ZIP Code</div>
<div class="item-input-wrap">
<input type="text" id="zipcode" placeholder="59601" autocomplete="off" autocorrect="off" inputmode="numeric"/>
<span class="input-clear-button"></span>
</div>
</div>
</li>
</ul>
</div>
<div class="card-content-padding">
<div class="button hapticbtn" id="setupAccountBtn"><i class="far fa-plus"></i> Setup Account</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="popup text-color-black" id="accountUpdatePopup">
<div class="list">
<ul id="accountupdateform">
<li class="item-content item-input item-input-outline">
<div class="item-inner">
<div class="item-title item-floating-label">Name</div>
<div class="item-input-wrap">
<input type="text" id="name" />
<span class="input-clear-button"></span>
</div>
</div>
</li>
<li class="item-content item-input item-input-outline">
<div class="item-inner">
<div class="item-title item-floating-label">Email</div>
<div class="item-input-wrap">
<input type="email" id="email" autocorrect="off" />
<span class="input-clear-button"></span>
</div>
</div>
</li>
<li class="item-content item-input item-input-outline">
<div class="item-inner">
<div class="item-title item-floating-label">House number and street</div>
<div class="item-input-wrap">
<input type="text" id="streetaddress" placeholder="1234 Notareal Road" autocomplete="off" autocorrect="off"/>
<span class="input-clear-button"></span>
</div>
</div>
</li>
<li class="item-content item-input item-input-outline">
<div class="item-inner">
<div class="item-title item-floating-label">ZIP Code</div>
<div class="item-input-wrap">
<input type="text" id="zipcode" placeholder="59601" autocomplete="off" autocorrect="off" inputmode="numeric"/>
<span class="input-clear-button"></span>
</div>
</div>
</li>
</ul>
</div>
<div class="card-content-padding">
<div class="button button-fill hapticbtn" id="updateAccountBtn"><i class="far fa-edit"></i> Update Account</div>
</div>
<div class="block text-align-center">
<p><a class="button popup-close" href="#">Cancel</a></p>
</div>
</div>
</div>

@ -0,0 +1,62 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<div class="page" data-name="dropandsend">
<div class="navbar">
<div class="navbar-bg"></div>
<div class="navbar-inner">
<div class="left">
<a class="link back" href="#">
<i class="icon icon-back"></i>
<span class="if-not-md">Back</span>
</a>
</div>
<div class="title">Drop and Send</div>
</div>
</div>
<div class="page-content">
<div class="row justify-content-center">
<div class="col-100 medium-60 large-50 xlarge-40">
<div class="list transparent no-hairlines no-margin-top-sm tablet-inset elevation-tablet media-list">
<ul>
<li class="padding">
Use one of our Drop and Send package drop locations to send mail,
packages, and more. No lines, no appointment, no postage, no label
printing, no problem!
</li>
<li class="item-divider">Step 1: Find a Location</li>
<li>
<div class="mapbox" style="width: 100%; min-height: 300px; max-height: 800px; height: 50vh;" id="mapbox-dropboxes"></div>
</li>
<li class="item-divider">Step 2: Request Pickup</li>
<li>
<div class="item-content item-link hapticbtn" id="pickupCodeQRScanBtn">
<div class="item-inner">
<div class="item-title-row">
<div class="item-title"><i class="fas fa-qrcode"></i> Scan Pickup Code</div>
</div>
<div class="item-text">Scan the pickup code and we'll come get your package.</div>
</div>
</div>
</li>
<li>
<div class="item-content item-link hapticbtn" id="pickupCodeManualEntryBtn">
<div class="item-inner">
<div class="item-title-row">
<div class="item-title"><i class="fas fa-keyboard"></i> Type Location Number</div>
</div>
<div class="item-text">Type the location number and we'll come get your package.</div>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>

@ -1,135 +0,0 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<div class="page" data-name="loyalty">
<div class="navbar">
<div class="navbar-bg"></div>
<div class="navbar-inner">
<div class="left">
<a class="link back hapticbtn" href="#">
<i class="icon icon-back"></i>
<span class="if-not-md">Back</span>
</a>
</div>
<div class="title">Loyalty Points</div>
</div>
</div>
<div class="page-content">
<div class="row justify-content-center">
<div class="col-100 medium-90 xlarge-75 margin-horizontal">
<div class="card margin">
<div class="card-content text-align-center padding-vertical">
{{#if hasphone}}
<div id="loyalty-balance-box" class="card-content-padding">
<div>You have earned a total of</div>
<h1 id="loyalty-credit-balance">...</h1>
<img id="loyalty-barcode" style="max-width: 90%; padding: 1.2em; background: white;" />
<!-- Timeline -->
<div class="timeline">
<!-- Timeline item -->
<div class="timeline-item">
<div class="timeline-item-date">36 Points</div>
<div class="timeline-item-divider"></div>
<div class="timeline-item-content">
<div class="timeline-item-inner">
Postcard stamp
</div>
</div>
</div>
<!-- Timeline item with inner -->
<div class="timeline-item">
<div class="timeline-item-date">50 Points</div>
<div class="timeline-item-divider"></div>
<div class="timeline-item-content">
<div class="timeline-item-inner">
Forever stamp
</div>
</div>
</div>
<div class="timeline-item">
<div class="timeline-item-date">100 Points</div>
<div class="timeline-item-divider"></div>
<div class="timeline-item-content">
<div class="timeline-item-inner">
$1 pickup discount
</div>
</div>
</div>
<div class="timeline-item">
<div class="timeline-item-date">500 Points</div>
<div class="timeline-item-divider"></div>
<div class="timeline-item-content">
<div class="timeline-item-inner">
<div class="timeline-item-text">$5 pickup discount</div>
</div>
<div class="timeline-item-inner">
<div class="timeline-item-text">Sheet of Forever stamps</div>
</div>
</div>
</div>
<div class="timeline-item">
<div class="timeline-item-date">800 Points</div>
<div class="timeline-item-divider"></div>
<div class="timeline-item-content">
<div class="timeline-item-inner">
Postage for a Priority Mail envelope or small flat rate box
</div>
</div>
</div>
<div class="timeline-item">
<div class="timeline-item-date">2500 Points</div>
<div class="timeline-item-divider"></div>
<div class="timeline-item-content">
<div class="timeline-item-inner">
Postage for a Priority Mail Express envelope
</div>
</div>
</div>
</div>
</div>
<div id="loyalty-error"></div>
{{else}}
<div class="block">
Save your phone number to start earning points!
</div>
<div class="list">
<ul id="savephoneform">
<li class="item-content item-input item-input-outline">
<div class="item-inner">
<div class="item-title item-floating-label">Phone Number</div>
<div class="item-input-wrap">
<input type="tel" id="phonenumber" />
<span class="input-clear-button"></span>
</div>
</div>
</li>
</ul>
</div>
<div class="card-content-padding">
<div class="button hapticbtn" onclick="savePhoneNumber()"><i class="far fa-phone-plus"></i> Save Number</div>
</div>
{{/if}}
</div>
</div>
<div class="block">
Loyalty points have no cash value. All points and associated discounts
are offered as a courtesy by and at the discretion of Helena Express
and may be revoked, canceled, or modified at any time for any reason.
</div>
</div>
</div>
</div>
<div class="popup text-color-black" id="addresscode-popup">
<div class="block text-align-center">
<img id="addresscode-barcode" style="max-width: 90%;" />
<p>Present this code to the Helena Express agent.</p>
<p><a class="button popup-close" href="#">Close</a></p>
</div>
</div>
</div>

@ -20,36 +20,42 @@ var routes = [
icon: "fad fa-calendar-alt",
text: "Get mailing, shipping, and notary services on your schedule anywhere in the Helena area."
},
{
title: "Drop and Send",
href: "/dropandsend",
icon: "fad fa-box-alt",
text: "Bring your package to a secure drop location and we'll ship it for you. No postage or appointment needed."
},
{
title: "Track Package",
href: "/track",
icon: "fad fa-search",
text: "Find the latest location and updates about any shipment."
},
{
title: "Pick Up and Redeliver",
href: "/noticeslip",
icon: "fad fa-sticky-note",
text: "Take a picture of your pink postal notice slip and we'll go get your missed delivery."
},
{
title: "Loyalty Points",
href: "/loyalty",
icon: "fad fa-badge-dollar",
text: "Earn free stamps and discounts."
},
{
title: "Express Pickup",
href: "/addresscode",
icon: "fal fa-qrcode",
text: "Get a faster pickup and a discount by pre-typing the destination address here."
},
{
title: "Get Rates",
href: "/rates",
icon: "fad fa-calculator",
text: "Calculate postage and prices for your item."
},
{
title: "My Account",
href: "/account",
icon: "fad fa-user-circle",
text: "Earn rewards and use Drop and Send with a Helena Express account."
},
// {
// title: "Express Pickup",
// href: "/addresscode",
// icon: "fal fa-qrcode",
// text: "Get a faster pickup and a discount by pre-typing the destination address here."
// },
{
title: "Pick Up and Redeliver",
href: "/noticeslip",
icon: "fad fa-sticky-note",
text: "Take a picture of your pink postal notice slip and we'll go get your missed delivery."
}
]
}
});
@ -99,6 +105,76 @@ var routes = [
}
]
},
{
path: '/dropandsend',
name: 'dropandsend',
templateUrl: './pages/dropandsend.html',
on: {
pageAfterIn: function () {
var mapboxel = document.getElementById("mapbox-dropboxes");
dropboxMap = new MapControl(mapboxel, true);
dropboxMap.reloadMap();
dropboxMap.mapObj.on('load', function () {
dropboxMap.mapObj.jumpTo({center: [-112.005, 46.589], zoom: 8});
dropboxMap.loadIcon("./assets/images/dropbox-icon.png", "dropbox", function () {
apirequest(SETTINGS.apis.dropandsendlocations, {}, function (data) {
dropboxMap.loadMarkersFromGeoJson(data, "dropbox", "dropbox");
dropboxMap.mapObj.on('click', 'marker-layer-dropbox', function (e) {
var coordinates = e.features[0].geometry.coordinates.slice();
var name = e.features[0].properties.name;
var type = e.features[0].properties.type;
var info = e.features[0].properties.info;
var hours = e.features[0].properties.hours;
var geolink = "geo:" + (Math.round(coordinates[1] * 1000000) / 1000000) + "," + (Math.round(coordinates[0] * 1000000) / 1000000);
var typedesc = "<i class='fas fa-question-circle'></i> Unknown package size limits";
switch (type) {
case "micro":
typedesc = "<i class='fas fa-envelope'></i> Fits envelopes";
break;
case "mini":
typedesc = "<i class='fas fa-mail-bulk'></i> Fits large envelopes and small packages";
break;
case "standard":
typedesc = "<i class='fas fa-box-alt'></i> Fits up to medium-size packages";
break;
case "large":
typedesc = "<i class='fas fa-boxes-alt'></i> Fits most packages";
break;
case "business":
typedesc = "<i class='fas fa-store-alt'></i> Shipping location, accepts any size package";
break;
}
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}
new mapboxgl.Popup()
.setLngLat(coordinates)
.setHTML("<b>" + name + "</b><br>" + typedesc
+ "<br><b>Hours:</b><br>" + hours
+ "<br><b>More Info:</b><br>" + info
+ "<br><a class=\"button button-fill button-small\" href=\"" + geolink + "\"><i class=\"fas fa-location-circle\"></i> Directions</a>")
.addTo(dropboxMap.mapObj);
});
dropboxMap.mapObj.on('mouseenter', 'marker-layer-dropbox', function () {
dropboxMap.mapObj.getCanvas().style.cursor = 'pointer';
});
dropboxMap.mapObj.on('mouseleave', 'marker-layer-dropbox', function () {
dropboxMap.mapObj.getCanvas().style.cursor = '';
});
dropboxMap.animateMapIn(46.589, -112.005, 9, 0);
}, function (error) {
}, "GET");
});
});
}
}
},
{
path: '/track',
url: './pages/track.html',
@ -164,23 +240,21 @@ var routes = [
}
},
{
path: '/loyalty',
name: 'loyalty',
async: function (routeTo, routeFrom, resolve, reject) {
var hasPhone = inStorage("phonenumber");
var phone = getStorage("phonenumber");
resolve({
templateUrl: './pages/loyalty.html'
}, {
context: {
hasphone: hasPhone,
phone: phone
},
on: {
pageAfterIn: displayLoyaltyPoints
}
});
}
path: '/account',
name: 'account',
templateUrl: './pages/account.html',
on: {
pageAfterIn: function () {
initAccountPage();
}
},
routes: [
{
path: '/managepayment',
name: 'managepayment',
templateUrl: './pages/managepayment.html'
}
]
},
{
path: '/track/:code',
@ -188,9 +262,13 @@ var routes = [
async: trackOpenAsync,
on: {
pageAfterIn: function () {
var trackingMap = new Map(document.getElementById("mapbox-track"));
var mapboxel = document.getElementById("mapbox-track");
var trackingMap = new MapControl(mapboxel, false);
trackingMap.reloadMap();
trackingMap.clearOldMarkersAndCenterMapOnNewMarker("package-marker");
var latitude = $(mapboxel).data("latitude");
var longitude = $(mapboxel).data("longitude");
var accurate = $(mapboxel).data("accurate") == true;
trackingMap.clearMarkersAndCenterMapOnNewMarker("package-marker", latitude, longitude, accurate);
}
}
},

@ -6,10 +6,16 @@
var SETTINGS = {
apis: {
track: "https://helena.express/tracker/api.php",
rates: "https://helena.express/rateapi.php",
track: "https://helena.express/apis/track/",
rates: "https://helena.express/apis/rates/",
pickuprequest: "https://helena.express/pspickup.php",
loyalty: "https://helena.express/loyalty.php"
dropandsendlocations: "https://helena.express/apis/dropandsend/locations/",
dropandsendpickup: "https://helena.express/apis/dropandsend/requestpickup/",
getaccountinfo: "https://helena.express/apis/account/getinfo/",
authorstartverify: "https://helena.express/apis/account/authorstartverify/",
verifyauthcode: "https://helena.express/apis/account/verifyauthcode/",
accountregister: "https://helena.express/apis/account/register/",
updatepaymentmethod: "https://helena.express/apis/account/updatepaymentmethod/",
},
stripe_pubkey: "pk_live_RgpadCo1LIIkfyUsY47VhUq6",
appointmenturl: "https://appointments.netsyms.com/index.php?hlnexp=1&embed=1&only=1&theme=darkly",

Loading…
Cancel
Save