Created
April 29, 2021 14:37
-
-
Save achisholm/1dcc6389ff6e356f7c887b7ac819c5aa 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 app = { | |
PAGES: ["0", "1", "2", "3", "4-1", "4-2", "4-3", "5", "6", "7"], | |
DOM_ELEMENTS: { | |
buttonBack: document.getElementById('buttonBack'), | |
buttonContinue: document.getElementById('buttonContinue'), | |
buttonDeliveryEdit: document.getElementById('buttonDeliveryEdit'), | |
buttonGetStarted: document.getElementById("buttonGetStarted"), | |
buttonPlaceOrder: document.getElementById('buttonPlaceOrder'), | |
colourSelect: document.getElementById('colour'), | |
componentList: document.getElementById('componentList'), | |
dialogRemoveProduct: document.getElementById('dialogRemoveProduct'), | |
dialogRemoveProductCancel: document.getElementById('dialogRemoveProductCancel'), | |
dialogRemoveProductConfirm: document.getElementById('dialogRemoveProductConfirm'), | |
dialogDelivery: document.getElementById('dialogDelivery'), | |
dialogDeliveryCancel: document.getElementById('dialogDeliveryCancel'), | |
dialogDeliveryConfirm: document.getElementById('dialogDeliveryConfirm'), | |
inputFields: document.querySelectorAll('.field__input'), | |
orderTableTbody: document.getElementById('orderTableTbody'), | |
orderBasketTotal: document.getElementById('orderBasketTotal'), | |
orderCarriageTotal: document.getElementById('orderCarriageTotal'), | |
orderVatTotal: document.getElementById('orderVatTotal'), | |
orderTotal: document.getElementById('orderTotal'), | |
reviewComponentsTbody: document.getElementById('reviewComponents'), | |
reviewProductQtyInputField: document.getElementById('reviewProductQuantity'), | |
templateCable: document.getElementById('templateCable'), | |
templateConnector: document.getElementById('templateConnector'), | |
templateFlexStrip: document.getElementById('templateFlexStrip'), | |
templateLengthInputField: document.getElementById('templateLengthInputField'), | |
templateOptionContent: document.getElementById('optionContent'), | |
templateRadioField: document.getElementById('templateRadioField'), | |
templateReviewTableRow: document.getElementById('templateReviewTableRow'), | |
templateOrderTableRow: document.getElementById('templateOrderTableRow'), | |
templateQtyInputField: document.getElementById('templateQtyInputField'), | |
}, | |
orderData: {}, | |
productData: {}, | |
componentData: {}, | |
abortController: new AbortController(), | |
isLoading: false, | |
initialise: function () { | |
// Register event listeners | |
document.addEventListener("keypress", function (event) { | |
// For some elements, simulate a click when enter key is pressed during focus. | |
var elem = event.target; | |
var clickableElements = [ | |
".js-button-back", | |
".js-button-continue", | |
".js-button-place-order", | |
".js-radio-field", | |
".js-remove-control" | |
]; | |
if (elem.matches(clickableElements) && event.which == 13) { | |
elem.click(); | |
} | |
}); | |
app.DOM_ELEMENTS.buttonGetStarted.addEventListener('click', function (event) { | |
// On clicking 'Get Started', Advance to page 1. | |
app.changePage(1); | |
}); | |
app.DOM_ELEMENTS.buttonContinue.addEventListener('click', function (event) { | |
// 'Continue' button click handler. | |
var currentPage = document.body.dataset.state; | |
var activePage = document.querySelector(".step-body-" + currentPage); | |
var invalidFields = activePage.querySelectorAll(':invalid').length; | |
if (invalidFields > 0) { | |
// Show validation message. | |
validationMessageShow(activePage, "Please check that all form input field values are valid and try again."); | |
} else { | |
switch (currentPage) { | |
case "1": | |
// Proceed from 'Step 1. IP Rating' to 'Step 2. Colours' page. | |
var ipRatingId = document.querySelector("[data-name='ip-rating'][data-checked='true']").dataset.value; | |
if (!app.productData.hasOwnProperty("ip_rating_id") || app.productData.ip_rating_id !== ipRatingId || colourSelect.value == "") { | |
// User's first visit or user has changed IP Rating selection. | |
this.disabled = true; | |
// Reset step 3. | |
app.productData.ip_rating_id = ipRatingId; | |
app.DOM_ELEMENTS.componentList.innerHTML = ""; | |
app.setupData = {}; | |
app.coloursPage.request(app.productData, true); | |
} else { | |
app.changePage(1); | |
}; | |
break; | |
case "2": | |
// Proceed from Step 2. Colour to Step 3. Setup screen. | |
var colourId = colourSelect.value; | |
if (isEmpty(app.setupData) || productData.colour_id !== colourId) { | |
// User's first visit or user has changed their Colour selection. | |
productData.colour_id = colourId; | |
this.disabled = true; | |
// Reset step 3. | |
app.DOM_ELEMENTS.componentList.innerHTML = ""; | |
app.setupData = {}; | |
// Make AJAX request and populate step 3. | |
setupRequest(productData, true); | |
} else { | |
changePage(1); | |
} | |
break; | |
case "3": | |
// Proceed from Step 3. Setup to Step 4. Extras. | |
this.disabled = true; | |
recordSetupProductData(); | |
// Make AJAX request and populate step 4. | |
extrasRequest(productData); | |
break; | |
case "4-1": | |
// Proceed from Step 4.1. to Step 4.2. | |
recordExtrasProductData(); | |
changePage(1); | |
break; | |
case "4-2": | |
// Proceed from Step 4.2. to Step 4.3. | |
recordExtrasProductData(); | |
changePage(1); | |
break; | |
case "4-3": | |
// Proceed from Step 4.3. Profile to Step 5. Review. | |
this.disabled = true; | |
recordExtrasProductData(); | |
// Make AJAX request and populate step 5. | |
reviewRequest(productData, true); | |
break; | |
case "5": | |
// Proceed from 5. Review to Step 6. Order. | |
this.disabled = true; | |
recordReviewProductData(); | |
// Populate step 6. | |
orderRequest(orderData, true); | |
break; | |
default: | |
// Proceed to the next step. | |
changePage(1); | |
} | |
app.saveOrderData(); | |
} | |
this.blur(); | |
}); | |
// '.js-radio-field' click listeners | |
// window onpopstate // When browser history changes, setStateBasedOnURL(); | |
// reviewProductQtyInputField 'change' listener | |
// reviewProductQtyInputField 'keyup' listener | |
// dialogRemoveProductCancel click listener | |
// dialogRemoveProductConfirm click listener | |
// buttonDeliveryEdit click listener | |
// dialogDeliveryCancel click listener | |
// dialogDeliveryConfirm click listener | |
// buttonPlaceOrder click listener | |
function initialiseApp() { | |
// Set up all pages based on the most recently created product. | |
} | |
}, | |
isEmpty: function (obj) { | |
// Checks if an object is empty; | |
return Object.keys(obj).length === 0; | |
}, | |
setStateBasedOnURL: function () { | |
// Inspect URL and switch to page given in the URL parameter. | |
var queryString = new URLSearchParams(window.location.search); | |
var page = queryString.get("page"); | |
if (pages.includes(page)) { | |
document.body.dataset.state = page; | |
} | |
}, | |
changePage: function (increment) { | |
// Jumps the active page backwards or forwards by a given increment. | |
var currentPage = document.body.dataset.state; | |
var index = app.PAGES.indexOf(currentPage); | |
var newPage = app.PAGES[index + increment]; | |
document.body.dataset.state = newPage; | |
history.pushState("", "", "?page=" + newPage); | |
}, | |
fetchOrderData: function () { | |
// Make AJAX GET request to fetch orderData JSON from the server. | |
}, | |
saveOrderData: function () { | |
// Make AJAX POST request to save OrderData to the server. | |
}, | |
isIpRatingComplete: function () { | |
// Checks if the productData product includes an IP Rating id. | |
}, | |
isColourComplete: function () { | |
// Checks if the productData product has includes a Colour id. | |
}, | |
isComponentsComplete: function () { | |
// Checks if the productData product includes valid components. | |
}, | |
isProductComplete: function () { }, | |
// Checks if the productData product is complete. | |
validationMessageShow: function (element) { | |
// Show an invalid message, appended as a child of the given element. | |
}, | |
validationMessageRemove: function (element) { | |
// Remove any invalid messages present in the given element. | |
}, | |
validateApp: function () { | |
// Show validation messages if pages are accessed before it's possible to populate them. | |
}, | |
validationTooltipShow: function () { }, | |
validationTooltipRemove: function () { }, | |
checkValidity: function () { }, | |
handleErrors: function () { }, | |
recordReviewProductData: function () { }, | |
orderDataProductRemove: function () { | |
// Removes a product from orderData | |
}, | |
handleRadioFieldClick: function () { }, | |
handleInputFieldChange: function () { }, | |
handleReviewQtyInputChange: function () { }, | |
handleOrderQtyInputChange: function () { }, | |
handleRemoveButtonClick: function () { | |
}, | |
handleDeliveryMethodRadioChange: function() {}, | |
handleInputFieldChange: function () { }, | |
handleColourSelectChange: function () { }, | |
browserSupportsDialog: function () { }, | |
collapseSection: function (element) { }, | |
expandSection: function (element) { }, | |
ipRatingPage: { | |
initialise: function () { }, | |
}, | |
coloursPage: { | |
initialise: function () { }, | |
request: function () { | |
// Make AJAX Request to fetch Colours JSON based on the selected IP Rating. | |
app.DOM_ELEMENTS.buttonContinue.disabled = true; | |
fetch("/api/bespoke-colours.json?product_data=" + JSON.stringify(app.productData)) | |
.then(handleErrors) | |
.then(function (response) { | |
response.json().then(function (responseData) { | |
// Generate the Colours options. | |
app.coloursPage.construct(responseData); | |
app.DOM_ELEMENTS.buttonContinue.disabled = false; | |
if (advance) { | |
// Proceed to next page. | |
changeState(1); | |
} | |
}) | |
}) | |
.catch(function (error) { | |
console.error('Error:', error); | |
var activePage = document.querySelector(".step-body-1"); | |
app.validationMessageShow(activePage, "Failed to load content for next step. Please try again."); | |
app.DOM_ELEMENTS.buttonContinue.disabled = false; | |
}); | |
}, | |
construct: function() { } | |
}, | |
setupPage: { | |
initialise: function () { }, | |
request: function () { }, | |
construct: function () { }, | |
constructComponentCable: function () { }, | |
constructComponentFlexStrip: function () { }, | |
constructComponentConnector: function () { }, | |
setAddControlsState: function() { }, | |
recordProductData: function () { }, | |
}, | |
extrasPage: { | |
initialise: function () { }, | |
request: function () { }, | |
construct: function () { }, | |
recordProductData: function () { }, | |
getDefaultProfileLength: function () { | |
// Return in mm, the total length of flex strip included in the current order, rounded up to nearest multiple of 1000. | |
}, | |
}, | |
reviewPage: { | |
initialise: function () { }, | |
request: function () { }, | |
construct: function () { } | |
}, | |
orderPage: { | |
initialise: function () { }, | |
request: function () { }, | |
construct: function () { } | |
}, | |
orderConfirmationPage: { | |
request: function () { }, | |
construct: function () { } | |
}, | |
requestPlaceOrder: function () { | |
// AJAX request made on clicking "Place Order" button on Step 6 Order page. | |
}, | |
} | |
app.initialise(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment