diff --git a/functions/index.js b/functions/index.js index be146432f..1b76686c1 100644 --- a/functions/index.js +++ b/functions/index.js @@ -1765,7 +1765,7 @@ exports.saveConfig = functions.https.onCall((request, response) => { if (request.uid === undefined || request.obj === undefined) { console.error(`error saving config for ${request.uid} - missing input`); return { - returnCode: -1, + resultCode: -1, message: "Missing input", }; } @@ -1807,7 +1807,7 @@ exports.saveConfig = functions.https.onCall((request, response) => { )}` ); return { - returnCode: -1, + resultCode: -1, message: "Bad input. " + errorMessage, }; } @@ -1823,7 +1823,7 @@ exports.saveConfig = functions.https.onCall((request, response) => { ) .then((e) => { return { - returnCode: 1, + resultCode: 1, message: "Saved", }; }) @@ -1832,7 +1832,7 @@ exports.saveConfig = functions.https.onCall((request, response) => { `error saving config to DB for ${request.uid} - ${e.message}` ); return { - returnCode: -1, + resultCode: -1, message: e.message, }; }); @@ -1845,6 +1845,141 @@ exports.saveConfig = functions.https.onCall((request, response) => { } }); +exports.addPreset = functions.https.onCall((request, response) => { + try { + if (request.uid === undefined || request.obj === undefined) { + console.error(`error saving config for ${request.uid} - missing input`); + return { + resultCode: -1, + message: "Missing input", + }; + } + + let config = request.obj.config; + let errorMessage = ""; + let err = false; + Object.keys(config).forEach((key) => { + if (err) return; + if (!isConfigKeyValid(key)) { + err = true; + console.error(`${key} failed regex check`); + errorMessage = `${key} failed regex check`; + } + if (err) return; + if (key === "resultFilters") return; + if (key === "customBackground") return; + let val = config[key]; + if (Array.isArray(val)) { + val.forEach((valarr) => { + if (!isConfigKeyValid(valarr)) { + err = true; + console.error(`${key}: ${valarr} failed regex check`); + errorMessage = `${key}: ${valarr} failed regex check`; + } + }); + } else { + if (!isConfigKeyValid(val)) { + err = true; + console.error(`${key}: ${val} failed regex check`); + errorMessage = `${key}: ${val} failed regex check`; + } + } + }); + if (err) { + console.error( + `error adding preset for ${request.uid} - bad input - ${JSON.stringify( + request.obj + )}` + ); + return { + resultCode: -1, + message: "Bad input. " + errorMessage, + }; + } + + return db + .collection(`users/${request.uid}/presets`) + .add(request.obj) + .then((e) => { + return { + resultCode: 1, + message: "Saved", + id: e.id, + }; + }) + .catch((e) => { + console.error( + `error adding preset to DB for ${request.uid} - ${e.message}` + ); + return { + resultCode: -1, + message: e.message, + }; + }); + } catch (e) { + console.error(`error adding preset for ${request.uid} - ${e}`); + return { + resultCode: -999, + message: e, + }; + } +}); + +exports.editPreset = functions.https.onCall((request, response) => { + try { + if (!isTagValid(request.name)) { + return { resultCode: -1 }; + } else { + return db + .collection(`users/${request.uid}/presets`) + .doc(request.presetid) + .set({ + config: request.config, + name: request.name, + }) + .then((e) => { + console.log(`user ${request.uid} updated a preset: ${request.name}`); + return { + resultCode: 1, + }; + }) + .catch((e) => { + console.error( + `error while updating preset for user ${request.uid}: ${e.message}` + ); + return { resultCode: -999, message: e.message }; + }); + } + } catch (e) { + console.error(`error updating preset for ${request.uid} - ${e}`); + return { resultCode: -999, message: e.message }; + } +}); + +exports.removePreset = functions.https.onCall((request, response) => { + try { + return db + .collection(`users/${request.uid}/preset`) + .doc(request.presetid) + .delete() + .then((e) => { + console.log(`user ${request.uid} deleted a tag`); + return { + resultCode: 1, + }; + }) + .catch((e) => { + console.error( + `error deleting tag for user ${request.uid}: ${e.message}` + ); + return { resultCode: -999 }; + }); + } catch (e) { + console.error(`error deleting tag for ${request.uid} - ${e}`); + return { resultCode: -999 }; + } +}); + // exports.saveLbMemory = functions.https.onCall((request, response) => { // try { // if (request.uid === undefined || request.obj === undefined) { diff --git a/gulpfile.js b/gulpfile.js index fa16981bb..df9945c07 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -96,6 +96,7 @@ const refactoredSrc = [ "./src/js/theme-controller.js", "./src/js/config.js", "./src/js/tag-controller.js", + "./src/js/preset-controller.js", "./src/js/ui.js", "./src/js/commandline.js", "./src/js/commandline-lists.js", @@ -131,6 +132,7 @@ const refactoredSrc = [ "./src/js/popups/word-filter-popup.js", "./src/js/popups/result-tags-popup.js", "./src/js/popups/edit-tags-popup.js", + "./src/js/popups/edit-preset-popup.js", "./src/js/popups/custom-theme-popup.js", "./src/js/popups/import-settings-popup.js", "./src/js/popups/custom-background-filter.js", diff --git a/src/js/cloud-functions.js b/src/js/cloud-functions.js index 6bf8a2108..9dde1d1f8 100644 --- a/src/js/cloud-functions.js +++ b/src/js/cloud-functions.js @@ -8,6 +8,9 @@ export const updateResultTags = firebase .functions() .httpsCallable("updateResultTags"); export const saveConfig = firebase.functions().httpsCallable("saveConfig"); +export const addPreset = firebase.functions().httpsCallable("addPreset"); +export const editPreset = firebase.functions().httpsCallable("editPreset"); +export const removePreset = firebase.functions().httpsCallable("removePreset"); export const generatePairingCode = firebase .functions() .httpsCallable("generatePairingCode"); diff --git a/src/js/config.js b/src/js/config.js index 47038d191..bcc82ebab 100644 --- a/src/js/config.js +++ b/src/js/config.js @@ -1709,6 +1709,18 @@ export function loadFromLocalStorage() { loadDone(); } +export function getConfigChanges() { + let configChanges = {}; + Object.keys(config) + .filter((key) => { + return config[key] != defaultConfig[key]; + }) + .forEach((key) => { + configChanges[key] = config[key]; + }); + return configChanges; +} + export function setConfig(newConfig) { config = newConfig; } diff --git a/src/js/db.js b/src/js/db.js index 4ba0e7ba0..da1cb2705 100644 --- a/src/js/db.js +++ b/src/js/db.js @@ -33,6 +33,7 @@ export async function initSnapshot() { results: undefined, personalBests: {}, name: undefined, + presets: [], tags: [], favouriteThemes: [], refactored: false, @@ -81,6 +82,29 @@ export async function initSnapshot() { .catch((e) => { throw e; }); + await db + .collection(`users/${user.uid}/presets/`) + .get() + .then((data) => { + data.docs.forEach((doc) => { + console.log(doc); + let preset = doc.data(); + preset.id = doc.id; + snap.presets.push(preset); + }); + snap.presets = snap.presets.sort((a, b) => { + if (a.name > b.name) { + return 1; + } else if (a.name < b.name) { + return -1; + } else { + return 0; + } + }); + }) + .catch((e) => { + throw e; + }); await db .collection("users") .doc(user.uid) @@ -119,6 +143,7 @@ export async function initSnapshot() { .catch((e) => { throw e; }); + console.log(snap.presets); dbSnapshot = snap; } catch (e) { console.error(e); @@ -486,7 +511,7 @@ export async function saveConfig(config) { obj: config, }).then((d) => { AccountButton.loading(false); - if (d.data.returnCode !== 1) { + if (d.data.resultCode !== 1) { Notifications.add(`Error saving config to DB! ${d.data.message}`, 4000); } return; diff --git a/src/js/popups/custom-text-popup.js b/src/js/popups/custom-text-popup.js index a50d8a17d..bac873f4d 100644 --- a/src/js/popups/custom-text-popup.js +++ b/src/js/popups/custom-text-popup.js @@ -10,7 +10,7 @@ let popup = "#customTextPopup"; export function show() { if ($(wrapper).hasClass("hidden")) { - if ($(`${popup} .check input`).prop("checked")) { + if ($(`${popup} .checkbox input`).prop("checked")) { $(`${popup} .inputs .randomInputFields`).removeClass("hidden"); } else { $(`${popup} .inputs .randomInputFields`).addClass("hidden"); @@ -60,8 +60,8 @@ $(wrapper).mousedown((e) => { } }); -$(`${popup} .inputs .check input`).change(() => { - if ($(`${popup} .check input`).prop("checked")) { +$(`${popup} .inputs .checkbox input`).change(() => { + if ($(`${popup} .checkbox input`).prop("checked")) { $(`${popup} .inputs .randomInputFields`).removeClass("hidden"); } else { $(`${popup} .inputs .randomInputFields`).addClass("hidden"); @@ -106,11 +106,11 @@ $("#customTextPopup .apply").click(() => { CustomText.setTime(parseInt($("#customTextPopup .time input").val())); CustomText.setIsWordRandom( - $("#customTextPopup .check input").prop("checked") && + $("#customTextPopup .checkbox input").prop("checked") && !isNaN(CustomText.word) ); CustomText.setIsTimeRandom( - $("#customTextPopup .check input").prop("checked") && + $("#customTextPopup .checkbox input").prop("checked") && !isNaN(CustomText.time) ); diff --git a/src/js/popups/edit-preset-popup.js b/src/js/popups/edit-preset-popup.js new file mode 100644 index 000000000..797ba281d --- /dev/null +++ b/src/js/popups/edit-preset-popup.js @@ -0,0 +1,161 @@ +import * as ResultTagsPopup from "./result-tags-popup"; +import * as ResultFilters from "./result-filters"; +import * as Loader from "./loader"; +import * as DB from "./db"; +import * as CloudFunctions from "./cloud-functions"; +import * as Notifications from "./notifications"; +import * as Settings from "./settings"; +import * as Config from "./config"; + +export function show(action, id, name) { + if (action === "add") { + $("#presetWrapper #presetEdit").attr("action", "add"); + $("#presetWrapper #presetEdit .title").html("Create new preset"); + $("#presetWrapper #presetEdit .button").html(``); + $("#presetWrapper #presetEdit input.text").val(""); + $("#presetWrapper #presetEdit input.text").removeClass("hidden"); + $("#presetWrapper #presetEdit label").addClass("hidden"); + } else if (action === "edit") { + $("#presetWrapper #presetEdit").attr("action", "edit"); + $("#presetWrapper #presetEdit").attr("presetid", id); + $("#presetWrapper #presetEdit .title").html("Edit preset"); + $("#presetWrapper #presetEdit .button").html(``); + $("#presetWrapper #presetEdit input.text").val(name); + $("#presetWrapper #presetEdit input.text").removeClass("hidden"); + $("#presetWrapper #presetEdit label input").prop("checked", false); + $("#presetWrapper #presetEdit label").removeClass("hidden"); + } else if (action === "remove") { + $("#presetWrapper #presetEdit").attr("action", "remove"); + $("#presetWrapper #presetEdit").attr("presetid", id); + $("#presetWrapper #presetEdit .title").html("Remove preset " + name); + $("#presetWrapper #presetEdit .button").html( + `` + ); + $("#presetWrapper #presetEdit input.text").addClass("hidden"); + $("#presetWrapper #presetEdit label").addClass("hidden"); + } + + if ($("#presetWrapper").hasClass("hidden")) { + $("#presetWrapper") + .stop(true, true) + .css("opacity", 0) + .removeClass("hidden") + .animate({ opacity: 1 }, 100, () => { + $("#presetWrapper #presetEdit input").focus(); + }); + } +} + +function hide() { + if (!$("#presetWrapper").hasClass("hidden")) { + $("#presetWrapper #presetEdit").attr("action", ""); + $("#presetWrapper #presetEdit").attr("tagid", ""); + $("#presetWrapper") + .stop(true, true) + .css("opacity", 1) + .animate( + { + opacity: 0, + }, + 100, + () => { + $("#presetWrapper").addClass("hidden"); + } + ); + } +} + +function apply() { + let action = $("#presetWrapper #presetEdit").attr("action"); + let inputVal = $("#presetWrapper #presetEdit input").val(); + let presetid = $("#presetWrapper #presetEdit").attr("presetid"); + let configChanges = Config.getConfigChanges(); + hide(); + if (action === "add") { + Loader.show(); + CloudFunctions.addPreset({ + uid: firebase.auth().currentUser.uid, + obj: { + name: inputVal, + config: configChanges, + }, + }).then((e) => { + Loader.hide(); + let status = e.data.resultCode; + if (status === 1) { + Notifications.add("Preset Added", 1, 2); + DB.getSnapshot().presets.push({ + name: inputVal, + config: configChanges, + id: e.data.id, + }); + Settings.update(); + } else if (status === -1) { + Notifications.add("Invalid preset name", 0); + } else if (status < -1) { + Notifications.add("Unknown error: " + e.data.message, -1); + } + }); + } else if (action === "edit") { + let preset = DB.getSnapshot().presets.filter( + (preset) => preset.id == presetid + )[0]; + Loader.show(); + CloudFunctions.editPreset({ + uid: firebase.auth().currentUser.uid, + name: inputVal, + presetid, + config: preset.config, + }).then((e) => { + Loader.hide(); + let status = e.data.resultCode; + if (status === 1) { + Notifications.add("Tag updated", 1); + DB.getSnapshot().presets.filter( + (preset) => preset.id == presetid + )[0].name = inputVal; + Settings.update(); + } else if (status === -1) { + Notifications.add("Invalid tag name", 0); + } else if (status < -1) { + Notifications.add("Unknown error: " + e.data.message, -1); + } + }); + } else if (action === "remove") { + Loader.show(); + CloudFunctions.removePreset({ + uid: firebase.auth().currentUser.uid, + presetid, + }).then((e) => { + Loader.hide(); + let status = e.data.resultCode; + if (status === 1) { + Notifications.add("Preset removed", 1); + DB.getSnapshot().preset.forEach((preset, index) => { + if (preset.id === presetid) { + DB.getSnapshot().preset.splice(index, 1); + } + }); + Settings.update(); + } else if (status < -1) { + Notifications.add("Unknown error: " + e.data.message, -1); + } + }); + } +} + +$("#presetWrapper").click((e) => { + if ($(e.target).attr("id") === "presetWrapper") { + hide(); + } +}); + +$("#presetWrapper #presetEdit .button").click(() => { + apply(); +}); + +$("#presetWrapper #presetEdit input").keypress((e) => { + if (e.keyCode == 13) { + apply(); + } +}); diff --git a/src/js/popups/edit-tags-popup.js b/src/js/popups/edit-tags-popup.js index 2b33c2c2b..7301063b2 100644 --- a/src/js/popups/edit-tags-popup.js +++ b/src/js/popups/edit-tags-popup.js @@ -59,6 +59,7 @@ function hide() { } function apply() { + console.log(DB.getSnapshot()); let action = $("#tagsWrapper #tagsEdit").attr("action"); let inputVal = $("#tagsWrapper #tagsEdit input").val(); let tagid = $("#tagsWrapper #tagsEdit").attr("tagid"); diff --git a/src/js/preset-controller.js b/src/js/preset-controller.js new file mode 100644 index 000000000..52a77365e --- /dev/null +++ b/src/js/preset-controller.js @@ -0,0 +1,14 @@ +import * as Config from "./config"; +import * as DB from "./db"; +import * as Notifications from "./notifications"; + +export function apply(id) { + console.log(DB.getSnapshot().presets); + DB.getSnapshot().presets.forEach((preset) => { + if (preset.id == id) { + Config.apply(JSON.parse(JSON.stringify(preset.config))); + Notifications.add("Preset Applied", 1, 2); + Config.saveToLocalStorage(); + } + }); +} diff --git a/src/js/settings.js b/src/js/settings.js index 4db31652f..659e4dbe3 100644 --- a/src/js/settings.js +++ b/src/js/settings.js @@ -10,8 +10,10 @@ import * as Loader from "./loader"; import * as CloudFunctions from "./cloud-functions"; import * as Funbox from "./funbox"; import * as TagController from "./tag-controller"; +import * as PresetController from "./preset-controller"; import * as SimplePopups from "./simple-popups"; import * as EditTagsPopup from "./edit-tags-popup"; +import * as EditPresetPopup from "./edit-preset-popup"; import * as ThemePicker from "./theme-picker"; export let groups = {}; @@ -446,35 +448,18 @@ function refreshTagsSettingsSection() { if (tag.pb != undefined && tag.pb > 0) { tagPbString = `PB: ${tag.pb}`; } - if (tag.active === true) { - tagsEl.append(` + tagsEl.append(` +