/*jshint sub:true, esversion: 6, -W083 */ class Store { constructor(title, storeID, state) { this.items = []; this.state = state || 'planning'; // states: planning/shopping/closed let storeNum = $(".store").length+1; this.title = title || "Store "+storeNum; this.storeID = storeID || null; let html = ""; html += "
"; html += "
"+this.title+"
"; html += "
"; html += " "; html += "
"; html += "
"; html += " edit name"; // html += " sort items"; html += " remove store"; html += "
"; html += "
"; html += "
"; html += " "; html += "
"; html += "
"; // html += " "; // html += " "; html += "
"; html += " "; html += " "; html += "
"; html += "
"; html += " "; html += " "; html += "
"; html += "
"; html += " "; html += "
"; html += "
"; html += "
"; html += "
"; html += " "; html += "
"; this.selector = $(html).appendTo("#stores"); this.selector.find(".addItemForm").on('submit', ev => { ev.preventDefault(); this.addItem($(ev.target).find('.newItemName').val(), $(ev.target).find('.newItemPrice').val()).done(json => { this.selector.find('.newItemPrice').val(0); this.selector.find('.newItemName').val("").focus(); }); }); /** CHANGE STATE **/ this.selector.find('.iconWrapper .page-item').on('click', ev=>{ this.selector.find('.page-item.active').removeClass('active'); $(ev.currentTarget).addClass('active'); if($(ev.currentTarget).hasClass('planningState')){ this.setState('planning'); } else if($(ev.currentTarget).hasClass('shoppingState')){ this.setState('shopping'); } else if($(ev.currentTarget).hasClass('closedState')){ this.setState('closed'); } }); this.selector.find('.editStoreName').one('click', ev => { this.editNameFn(ev); }); this.selector.find('.removeStore').on('click', ev => { if(confirm("Are you sure you want to remove this store?")){ this.removeStore(); } }); $(function () { $('[data-toggle="tooltip"]').tooltip(); }); } setState(state, animTime){ animTime = animTime || 200; let prevState = this.state; if(state === "planning"){ this.state = "planning"; this.selector.find('.itemAmountButtons').slideDown(animTime); this.selector.find('.itemAmountText').slideUp(animTime); this.selector.find('.addItemFormWrapper').slideDown(animTime); } if(state !== "planning"){ this.selector.find('.itemAmountButtons').slideUp(animTime); this.selector.find('.itemAmountText:not(.oneItem)').slideDown(animTime); this.selector.find('.addItemFormWrapper').slideUp(animTime); } if(state === "shopping"){ this.state = "shopping"; } if(state !== "shopping"){ } if(state === "closed"){ this.state = "closed"; this.selector.find('.remItem').hide(); } if(state !== "closed"){ this.selector.find('.remItem').show(); } if(prevState !== state){ ajaxReq({ plan: 'setState', storeID: this.storeID, state: this.state }); } } editNameFn(ev){ if(ev.type === 'click'){ this.selector.find('.iconWrapper').hide(); // $(ev.target).parent().hide(); let headerElem = $(ev.target).parent().parent().find(".card-header"); let orgHtml = headerElem.html(); headerElem.html(""+orgHtml+"
"); headerElem.find(".changeNameForm").on('submit keyup', ev2 => { if(ev2.type === "submit"){ ev2.preventDefault(); let newName = $(ev2.target).find(".newName").val(); let that = this; this.rename(newName).done(json => { // success headerElem.html(newName); that.selector.find('.iconWrapper').show(); that.selector.find('.editStoreName').one('click keyup', ev3 => { this.editNameFn(ev3); }); }); } }); headerElem.find(".newName").on('keyup', ev3 => { this.resetEditNameFn(ev3); }); headerElem.find('input').first().focus(); // $("body").one('click', ev3 => { this.resetEditNameFn(ev3); }); } } resetEditNameFn(ev){ if( (ev.type==="keyup" && ev.keyCode === 27) || ev.type !== "keyup" ){ // cancel let orgHtml = this.selector.find('.card-header span').html(); this.selector.find('.card-header').html(orgHtml); this.selector.find('.iconWrapper').show(); this.selector.find('.editStoreName').one('click keyup', ev3 => { this.editNameFn(ev3); }); } } addItem(text, price){ if(text.length > 0){ if(this.storeID === null){ this.getStoreID().done(json => { this.addItem(text, price); }); return $.ajax(); } let that = this; return ajaxReq({ plan: 'addItem', storeID: this.storeID, name: text, price: price }) .done(json => { return that.addItemHtml(text, price, json['data']); }); } } addItemHtml(text, price, itemID, amount){ amount = amount || 1; try { price = Number(price); this.items.push({ text: text, price: price, itemID: itemID, amount: amount }); let html = "\n"; html += "
  • "; html += " "+text+""; html += "
    "+(price*amount).toFixed(2)+""; html += "Remove item
    "; html += " "; html += "
    "; // "+(this.state !== "planning"?"style='display: none;'":'')+" html += " "; html += " "; if(price !== 0) { html += " x" + price.toFixed(2) + ""; } html += " "; html += "
    "; html += " "; html += "
    "; html += "
  • "; this.selector.find("ul.storeItems").append(html); this.selector.find(".emptyList").hide(); this.verify(); return true; } catch(e){ alert("Something failed. Try again."); console.error(e, e.stack); } return false; } remItem(pos, itemID, price){ let that = this; if(this.state === "planning"){ return ajaxReq({ plan: 'remItem', storeID: this.storeID, itemID: itemID, price: price }) .done(json => { // console.log("remItem return:", json); return that.remItemHtml(itemID); }); } } remItemHtml(itemID){ for(let i = 0; i < this.items.length; i++){ if(this.items[i].itemID === itemID){ this.items.splice(i,1); break; } } this.selector.find('#item_'+itemID).remove(); this.verify(); return true; } setItemAmount(itemID, amount){ // console.log(itemID, amount, this.items); this.items.forEach((item, key) => { if(item.itemID === itemID){ this.items[key].amount = amount; this.selector.find('#item_'+itemID+" .priceWrapper .price").html(Number(amount*this.items[key].price).toFixed(2)); } }); if(typeof this.itemAmountDelay === "undefined"){ this.itemAmountDelay = {}; } if(typeof this.itemAmountDelay[itemID] !== "undefined"){ clearTimeout(this.itemAmountDelay[itemID]); } this.itemAmountDelay[itemID] = setTimeout(() => { return ajaxReq({ plan: 'updateItemAmount', storeID: this.storeID, itemID: itemID, newAmount: amount }) .done(()=>{ this.verify(); }); }, 500); } setItemPosition(itemID, afterID){ afterID = afterID || 0; if(itemID !== afterID){ return ajaxReq({ plan: 'moveItem', storeID: this.storeID, itemID: itemID, afterID: afterID }); } return false; } verify(){ // UPDATE TOTAL PRICE let total = 0; this.items.forEach(item => { total += item.price*item.amount; // console.log("verify - item: "+item.price+"*"+item.amount); }); $(this.selector).find(".subtotal .price").html(total.toFixed(2)); // SHOW if-empty MESSAGE if(this.selector.find("li").length <= 1){ this.selector.find(".emptyList").show(); } // BIND add/remove item amount let that = this; this.selector.find('.itemAmountBtn').off().on('click change', function(e){ let itemid = $(this).parent().parent().parent().attr('data-itemid'); let amountElem = $(this).parent().find('.itemAmount'); let newValue = Number(amountElem.val()); if($(this).html() === "-"){ newValue--; } else if($(this).html() === "+"){ newValue++; } if(newValue > 0 && newValue < 100){ amountElem.val(newValue); that.setItemAmount(itemid, newValue); let textAmountElem = $(this).parent().parent().find('.itemAmountText'); textAmountElem.find('.itemAmount').html(newValue); if(newValue === 1){ textAmountElem.addClass('oneItem'); } else { textAmountElem.removeClass('oneItem'); } } }); // DRAGGABLE let draggingObj = null, dragPos = null; this.selector.find('.draggable').unbind().on('dragstart dragover dragenter dragleave dragend', ev => { // this.selector.find('.draggable').hammer().bind('swipe', ev => { if(ev.type === 'dragover' || ev.type === 'dragenter'){ ev.preventDefault(); // console.log(ev); $(ev.currentTarget).addClass('drag-over'); dragPos = ev.currentTarget; } else if(ev.type === 'dragstart'){ // console.log('drag start'); draggingObj = $(ev.target); draggingObj.css('opacity', 0.2); } else if(ev.type === 'dragleave'){ $('.drag-over').removeClass('drag-over'); } else if(ev.type === 'dragend'){ // console.log(draggingObj); if(draggingObj === null){ console.warn('no object to move'); return; } // console.log("move object", draggingObj, "to", dragPos); draggingObj.css('opacity', 1); if( this.setItemPosition(draggingObj.attr('data-itemid'), $(dragPos).attr('data-itemid')) !== false){ if($(dragPos).attr('data-itemID') == null){ draggingObj.detach().insertAfter('.emptyList'); } else { draggingObj.detach().insertAfter(dragPos); } draggingObj = null; } $('.drag-over').removeClass('drag-over'); } }); // BIND remove-buttons $(this.selector).find(".remItem").each((key, val) => { let that = this; $(val).off().on('click', function(){ // console.log("remItem", $(this).hasClass("confirm"), $(this)); if($(this).hasClass("confirm")){ that.remItem(key+1, $(this).attr('data-itemid'), $(this).attr("data-price")); try { $(this).tooltip('dispose'); } catch(ignore){} } else { // console.log("remItem addClass"); $(".confirm").removeClass("confirm"); setTimeout(() => { $(this).addClass("confirm"); }, 10); let newThat = this; setTimeout(function(){ $(newThat).removeClass("confirm"); }, 5000); } }); }); $(this.selector).find(".ariaButton").off('keydown').on('keydown', function(e){ if(e.code === "Space" || e.code === "Enter"){ e.preventDefault(); $(this).trigger('click'); } }); // Update the total-price updateTotalPrice(); } // STORE MANIPULATION removeStore(){ this.selector.remove(); if(this.storeID != null){ ajaxReq({ plan: 'deleteStore', storeID: this.storeID, storeName: this.title, itemsLength: this.items.length }) .done(json => { console.log("Delete store response:",json); }); } } getStoreID(){ let that = this; return ajaxReq({ plan: 'saveStore', storeName: this.title }) .done(json => { console.log("getStore:", json); that.storeID = json['data']; return that.storeID; }); } rename(newName){ this.title = newName; if(this.storeID !== null){ return ajaxReq({ plan: 'renameStore', storeID: this.storeID, newName: newName }); } // Return blank ajax as a false return $.ajax(); } } var stores = []; $("#stores").html(""); $("#addStore").click(ev => { stores.push(new Store()); }); $("#refreshAll").click(ev => { $(".tooltip").remove(); getStores(spaceID); }); $("body").on('click', function(ev){ if( $(".price").find( ev.target ).length === 0){ $(".confirm").removeClass("confirm"); } }); let totalPrice = 0; function updateTotalPrice(){ totalPrice = 0; for(const storeKey in stores){ const store = stores[storeKey]; for(const itemKey in store.items){ totalPrice += store.items[itemKey].amount*store.items[itemKey].price; } } $("#totalPrice").html(totalPrice); } let spaceID = 0; function getSpaces(){ $("#stores").html("Loading..."); return ajaxReq({plan: 'spaces'}).done(json => { let optionsHtml = ""; // console.log(json); let spaceNum = 1; for(const spaceI in json.data.spaces){ const space = json.data.spaces[spaceI]; if(spaceID === 0){ spaceID = space['space_id']; } let spaceName = space['space_name'] || "Space "+spaceNum; optionsHtml += "\n"; spaceNum++; } let spaceSelectElem = $("#spaceSelect"); spaceSelectElem .html(optionsHtml) .on('change', ev => { spaceID = $(ev.target).val(); getStores(spaceID); }); if(typeof json.data.lastSpace !== "undefined"){ spaceID = Number(json.data.lastSpace); spaceSelectElem.val(spaceID); } }); } getSpaces().done(() => { getStores(spaceID); }); // GET STORES function getStores(spaceID){ spaceID = spaceID || 0; // $("#stores").html(""); stores = []; let options = { plan: '' }; if(spaceID !== 0){ options = { plan: '', space: spaceID } } $.getJSON('do.php', options) .done(json => { if(handleJsonErrors(json)){ return; } $("#stores").html(""); // console.log(json); for(const store in json.data){ let storeKey = stores.length; stores.push(new Store(json.data[store].name, json.data[store].plan_store_id, json.data[store].state)); for(const item in json.data[store].items){ stores[storeKey].addItemHtml( json.data[store].items[item].name, json.data[store].items[item].price, json.data[store].items[item].plan_item_id, json.data[store].items[item].amount); } stores[storeKey].setState(json.data[store].state, 1); } updateTotalPrice(); }) .fail(handleAjaxErrors); } function ajaxReq( data ){ if(typeof spaceID !== "undefined" && spaceID !== 0){ data.space = spaceID; } return $.ajax({ method: "POST", url: "do.php", data: data, dataType: 'JSON' }) .done(json => { if(handleJsonErrors(json)){ return false; } return true; }) .fail(handleAjaxErrors); } function handleJsonErrors(json){ if(typeof json.status != "undefined" && json.status != 0){ if(json.message === "Not logged in"){ location.href = '../login.php'; } else { alert(json.message); } return true; } return false; } function handleAjaxErrors(jqxhr, textStatus, error){ if(textStatus === "parsererror" && jqxhr.responseText != ""){ alert("An error occured:\n"+jqxhr.responseText); } else { alert("An error occured:\n"+error); } }