diff --git a/package-lock.json b/package-lock.json index 9dcbc13..cfe65d4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -317,6 +317,11 @@ "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", "dev": true }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, "bn.js": { "version": "4.11.9", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", @@ -2358,8 +2363,7 @@ "lodash": { "version": "4.17.19", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", - "dev": true + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" }, "logform": { "version": "2.2.0", @@ -3038,8 +3042,7 @@ "psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "optional": true + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" }, "pstree.remy": { "version": "1.1.8", @@ -3221,6 +3224,25 @@ "throttleit": "^1.0.0" } }, + "request-promise": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.6.tgz", + "integrity": "sha512-HCHI3DJJUakkOr8fNoCc73E5nU5bqITjOYFMDrKHYOXWXrgD/SBaC7LjwuPymUprRyuF06UK7hd/lMHkmUXglQ==", + "requires": { + "bluebird": "^3.5.0", + "request-promise-core": "1.1.4", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, + "request-promise-core": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", + "requires": { + "lodash": "^4.17.19" + } + }, "resolve": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", @@ -3515,6 +3537,11 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" + }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -3723,7 +3750,6 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "optional": true, "requires": { "psl": "^1.1.28", "punycode": "^2.1.1" diff --git a/package.json b/package.json index 388c1d9..bad47fa 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ }, "dependencies": { "@xcoobee/payment-sdk": "^0.9.0", + "body-parser": "^1.19.0", "cookie-parser": "^1.4.5", "express": "^4.17.1", "express-async-errors": "^3.1.1", @@ -35,6 +36,7 @@ "html-pdf": "^2.2.0", "http-status-codes": "^1.4.0", "morgan": "^1.10.0", + "request-promise": "^4.2.6", "winston": "^3.3.3", "xcoobee-sdk": "^1.3.0" } diff --git a/public/images/kitchen-logo.png b/public/images/kitchen-logo.png new file mode 100644 index 0000000..925a66d Binary files /dev/null and b/public/images/kitchen-logo.png differ diff --git a/public/javascripts/index.js b/public/javascripts/index.js index f7b1114..0102091 100644 --- a/public/javascripts/index.js +++ b/public/javascripts/index.js @@ -1,6 +1,14 @@ /* eslint-disable */ -const COOKIE_NAME = "settings"; +const SETTINGS_KEY = "xb_efa_settings"; + +const parseJSON = (str) => { + try { + return JSON.parse(str); + } catch (e) { + return null; + } +}; $(() => { // ============== Alerts =============== @@ -19,22 +27,28 @@ $(() => { alertBlock.find($(".close")).click(() => alertBlock.hide()); // ============== Helpers =============== - const setCookie = (key, value, expiry = 24) => { - const expires = new Date(); - expires.setTime(expires.getTime() + (expiry * 24 * 60 * 60 * 1000)); - document.cookie = `${key}=${value};expires=${expires.toISOString()};samesite=strict`; - }; - - const getCookie = (key) => { - if (document.cookie) { - const cookie = document.cookie.split("; ").find(x => x.startsWith(key)); - return cookie && JSON.parse(cookie.split(/=(.+)/)[1]); + const getFromLocalStorage = key => parseJSON(localStorage.getItem(key)); + const setToLocalStorage = (key, value) => localStorage.setItem(key, JSON.stringify(value)); + + const sendMessage = message => { + const settings = getFromLocalStorage(SETTINGS_KEY) || {}; + + if (settings.slack_hook_url) { + $.ajax({ + type: "POST", + url: "/post-to-slack", + data: JSON.stringify({ + text: message, + hookUrl: settings.slack_hook_url, + }), + contentType: "application/json", + dataType: "json", + }); } - return null; }; const getPaymentSDKInstance = (deviceId) => { - const settings = getCookie(COOKIE_NAME) || {}; + const settings = getFromLocalStorage(SETTINGS_KEY) || {}; return new window.XcooBee.XcooBeePaymentSDK({ campaignId: settings.campaign_id, @@ -44,11 +58,12 @@ $(() => { }; const getSDKInstance = () => { - const settings = getCookie(COOKIE_NAME) || {}; + const settings = getFromLocalStorage(SETTINGS_KEY) || {}; + // set this to the instance of the API that you need to access currently we assume production try { const config = new window.XcooBee.sdk.Config({ - apiUrlRoot: "https://api.xcoobee.net", + apiUrlRoot: "https://api.xcoobee.net", apiKey: settings.api_key, apiSecret: settings.api_secret, campaignId: settings.campaign_id, @@ -136,24 +151,25 @@ $(() => { }); // ============= Settings page =========== - const cookieValue = getCookie(COOKIE_NAME); - Object.keys(cookieValue || {}).forEach((name) => { - $(`[name="${name}"]`).val(cookieValue[name]); + const settingsValues = getFromLocalStorage(SETTINGS_KEY) || {}; + + Object.keys(settingsValues).forEach((name) => { + $(`[name="${name}"]`).val(settingsValues[name]); }); $("form.settings-form").submit((e) => { e.preventDefault(); }); $("button.submit-settings-form").click(function () { - let existingCookies = getCookie(COOKIE_NAME) || {}; + let settingsValues = getFromLocalStorage(SETTINGS_KEY) || {}; const formData = $(this.form).serializeArray(); formData.forEach((item) => { - existingCookies = Object.assign(existingCookies, { + settingsValues = Object.assign(settingsValues, { [item.name]: item.value, }); }); - if (Object.keys(existingCookies).length) { - setCookie(COOKIE_NAME, JSON.stringify(existingCookies)); + if (Object.keys(settingsValues).length) { + setToLocalStorage(SETTINGS_KEY, settingsValues); } handleSuccess("Settings saved"); }); @@ -249,7 +265,7 @@ $(() => { .submit(e => e.preventDefault()) .validate({ submitHandler: function () { - const settings = getCookie(COOKIE_NAME) || {}; + const settings = getFromLocalStorage(SETTINGS_KEY) || {}; if (!settings.campaign_id) { alertBlock.show(); @@ -266,4 +282,223 @@ $(() => { window.open(`/generate-invoice?ref=${properties.payment_reference}&amount=${properties.payment_amount}&campaignId=${settings.campaign_id}`, "_blank"); }, }); + + // ============= Kitchen orders page =========== + if ($("#kitchen-orders-table").length) { + const toggledRows = {}; + let kitchenTimer; + + const parseReference = sections => { + let items; + let roomNumber="100"; // default room to 100 if not provided this is only a marker, the real change happens during display + let notes; + let userName; + + + if (Array.isArray(sections)) { + const section = sections.find(item => item.section_id === "2"); + const zeroSection = sections.find(item => item.section_id === "0"); + + if (zeroSection) { + const firstNameField = zeroSection.fields.find(field => field.dataTypeId === 100); + const lastNameField = zeroSection.fields.find(field => field.dataTypeId === 120); + + userName = [firstNameField && firstNameField.value, lastNameField && lastNameField.value].filter(Boolean).join(" "); + } + + if (section) { + const referenceField = section.fields.find(field => field.dataTypeId === 9997); + const notesField = section.fields.find(field => field.dataTypeId === 9998); + + if (notesField.value) { + notes = notesField.value; + } + + if (referenceField.value) { + items = referenceField.value + .split("\n") + .map(itemRef => { + if (/^xb_room_number:/.test(itemRef)) { + roomNumber = itemRef.split(":")[1]; + return; + } + const [name, price] = itemRef.split("-"); + + if (name) { + const [itemName, ...options] = name.split("+"); + const [, itemNameWithoutQty, qty] = /(.+)(?:\((\d+)\))?$/.exec(itemName); + + return { + name: [itemNameWithoutQty, ...options].map(name => name.trim()).join(" + "), + qty: +qty || 1, + price + }; + } + }) + .filter(Boolean); + } + } + } + + + return { items, roomNumber, notes, userName }; + }; + + const renderOrders = () => { + const settings = getFromLocalStorage(SETTINGS_KEY) || {}; + const orders = parseJSON(localStorage.getItem(`${settings.campaign_id}-kitchen-orders`)) || []; + const rows = orders.map(order => ` + + +