const homeStrand = require("./home.js"); const ingredientsStrand = require("./ingredients.js"); const ordersStrand = require("./orders.js"); const recipeBookStrand = require("./recipeBook.js"); const transactionsStrand = require("./transactions.js"); const addIngredientsComp = require("./addIngredients.js"); const ingredientDetailsComp = require("./ingredientDetails.js"); const newIngredientComp = require("./newIngredient.js"); const newOrderComp = require("./newOrder.js"); const newRecipeComp = require("./newRecipe.js"); const newTransactionComp = require("./newTransaction.js"); const orderDetailsComp = require("./orderDetails.js"); const recipeDetailsComp = require("./recipeDetails.js"); const transactionDetailsComp = require("./transactionDetails.js"); const ingredients = require("./ingredients.js"); const recipeBook = require("./recipeBook.js"); const orders = require("./orders.js"); const transactions = require("./transactions.js"); class Ingredient{ constructor(id, name, category, unitType, unit, parent){ this.id = id; this.name = name; this.category = category; this.unitType = unitType; this.unit = unit; this.parent = parent; } convert(quantity){ if(this.unitType === "mass"){ switch(this.unit){ case "g": break; case "kg": quantity /= 1000; break; case "oz": quantity /= 28.3495; break; case "lb": quantity /= 453.5924; break; } }else if(this.unitType === "volume"){ switch(this.unit){ case "ml": quantity *= 1000; break; case "l": break; case "tsp": quantity *= 202.8842; break; case "tbsp": quantity *= 67.6278; break; case "ozfl": quantity *= 33.8141; break; case "cup": quantity *= 4.1667; break; case "pt": quantity *= 2.1134; break; case "qt": quantity *= 1.0567; break; case "gal": quantity /= 3.7854; break; } }else if(this.unitType === "length"){ switch(this.unit){ case "mm": quantity *= 1000; break; case "cm": quantity *= 100; break; case "m": break; case "in": quantity *= 39.3701; break; case "ft": quantity *= 3.2808; break; } } return quantity; } } class Recipe{ constructor(id, name, price, ingredients, parent){ this.id = id; this.name = name; this.price = price; this.parent = parent; this.ingredients = []; for(let i = 0; i < ingredients.length; i++){ for(let j = 0; j < parent.ingredients.length; j++){ if(ingredients[i].ingredient === parent.ingredients[j].ingredient.id){ this.ingredients.push({ ingredient: parent.ingredients[j].ingredient, quantity: ingredients[i].quantity }); break; } } } } } class Transaction{ constructor(id, date, recipes, parent){ this.id = id; this.parent = parent; this.date = new Date(date); this.recipes = []; for(let i = 0; i < recipes.length; i++){ for(let j = 0; j < parent.recipes.length; j++){ if(recipes[i].recipe === parent.recipes[j].id){ this.recipes.push({ recipe: parent.recipes[j], quantity: recipes[i].quantity }); break; } } } } } class Order{ constructor(id, name, date, ingredients, parent){ this.id = id; this.name = name; this.date = new Date(date); this.ingredients = []; this.parent = parent; for(let i = 0; i < ingredients.length; i++){ for(let j = 0; j < parent.ingredients.length; j++){ if(ingredients[i].ingredient === parent.ingredients[j].ingredient.id){ this.ingredients.push({ ingredient: parent.ingredients[j].ingredient, quantity: ingredients[i].quantity, price: ingredients[i].price }); } } } } convertPrice(unitType, unit, price){ if(unitType === "mass"){ switch(unit){ case "g": break; case "kg": price *= 1000; break; case "oz": price *= 28.3495; break; case "lb": price *= 453.5924; break; } }else if(unitType === "volume"){ switch(unit){ case "ml": price /= 1000; break; case "l": break; case "tsp": price /= 202.8842; break; case "tbsp": price /= 67.6278; break; case "ozfl": price /= 33.8141; break; case "cup": price /= 4.1667; break; case "pt": price /= 2.1134; break; case "qt": price /= 1.0567; break; case "gal": price *= 3.7854; break; } }else if(unitType === "length"){ switch(unit){ case "mm": price /= 1000; break; case "cm": price /= 100; break; case "m": break; case "in": price /= 39.3701; break; case "ft": price /= 3.2808; break; } } return price; } } class Merchant{ constructor(oldMerchant, transactions){ this.name = oldMerchant.name; this.pos = oldMerchant.pos; this.ingredients = []; this.recipes = []; this.transactions = []; this.orders = []; this.units = { mass: ["g", "kg", "oz", "lb"], volume: ["ml", "l", "tsp", "tbsp", "ozfl", "cup", "pt", "qt", "gal"], length: ["mm", "cm", "m", "in", "foot"] } for(let i = 0; i < oldMerchant.inventory.length; i++){ this.ingredients.push({ ingredient: new Ingredient( oldMerchant.inventory[i].ingredient._id, oldMerchant.inventory[i].ingredient.name, oldMerchant.inventory[i].ingredient.category, oldMerchant.inventory[i].ingredient.unitType, oldMerchant.inventory[i].defaultUnit, this ), quantity: oldMerchant.inventory[i].quantity }); } for(let i = 0; i < oldMerchant.recipes.length; i++){ this.recipes.push(new Recipe( oldMerchant.recipes[i]._id, oldMerchant.recipes[i].name, oldMerchant.recipes[i].price, oldMerchant.recipes[i].ingredients, this )); } for(let i = 0; i < transactions.length; i++){ this.transactions.push(new Transaction( transactions[i]._id, transactions[i].date, transactions[i].recipes, this )); } } /* Updates all specified item in the merchant's inventory and updates the page If ingredient doesn't exist, add it ingredients = { ingredient: Ingredient object, quantity: new quantity, defaultUnit: the default unit to be displayed } remove = set true if removing isOrder = set true if this is coming from an order */ editIngredients(ingredients, remove = false, isOrder = false){ for(let i = 0; i < ingredients.length; i++){ let isNew = true; for(let j = 0; j < merchant.ingredients.length; j++){ if(merchant.ingredients[j].ingredient === ingredients[i].ingredient){ if(remove){ merchant.ingredients.splice(j, 1); }else if(!remove && isOrder){ merchant.ingredients[j].quantity += ingredients[i].quantity; }else{ merchant.ingredients[j].quantity = ingredients[i].quantity; } isNew = false; break; } } if(isNew){ merchant.ingredients.push({ ingredient: ingredients[i].ingredient, quantity: parseFloat(ingredients[i].quantity), defaultUnit: ingredients[i].defaultUnit }); } } homeStrandObj.drawInventoryCheckCard(); ingredientsStrandObj.populateByProperty("category"); addIngredientsComp.isPopulated = false; closeSidebar(); } /* Updates a recipe in the merchants list of recipes Can create, edit or remove recipe = [Recipe object] remove = will remove recipe when true */ editRecipes(recipes, remove = false){ let isNew = true; for(let i = 0; i < recipes.length; i++){ for(let j = 0; j < this.recipes.length; j++){ if(recipes[i] === this.recipes[j]){ if(remove){ this.recipes.splice(j, 1); }else{ this.recipes[j] = recipes[i]; } isNew = false; break; } } if(isNew){ merchant.recipes.push(recipes[i]); } } transactionsStrandObj.isPopulated = false; recipeBookStrandObj.populateRecipes(); closeSidebar(); } /* Updates a list of orders in the merchants list of orders Create/edit/remove orders = [Order object] remove = will remove order when true */ editOrders(orders, remove = false){ for(let i = 0; i < orders.length; i++){ let isNew = true; for(let j = 0; j < this.orders.length; j++){ if(orders[i] === this.orders[j]){ if(remove){ this.orders.splice(j, 1); }else{ this.orders[j] = orders[i]; } isNew = false; break; } } if(isNew){ this.orders.push(orders[i]); } } ordersStrandObj.populate(); closeSidebar(); } editTransactions(transaction, remove = false){ let isNew = true; for(let i = 0; i < this.transactions.length; i++){ if(this.transactions[i] === transaction){ if(remove){ this.transactions.splice(i, 1); } isNew = false; break; } } if(isNew){ this.transactions.push(transaction); this.transactions.sort((a, b) => a.date > b.date ? 1 : -1); } transactionsStrandObj.isPopulated = false; transactionsStrandObj.display(); closeSidebar(); } /* Gets the indices of two dates from transactions Inputs from: starting date to: ending date (default to now) Output Array containing starting index and ending index Note: Will return false if it cannot find both necessary dates */ transactionIndices(from, to = new Date()){ let indices = []; for(let i = 0; i < this.transactions.length; i++){ if(this.transactions[i].date > from){ indices.push(i); break; } } for(let i = this.transactions.length - 1; i >=0; i--){ if(this.transactions[i].date < to){ indices.push(i); break; } } if(indices.length < 2){ return false; } return indices; } revenue(indices){ let total = 0; for(let i = indices[0]; i <= indices[1]; i++){ for(let j = 0; j < this.transactions[i].recipes.length; j++){ for(let k = 0; k < this.recipes.length; k++){ if(this.transactions[i].recipes[j].recipe === this.recipes[k]){ total += this.transactions[i].recipes[j].quantity * this.recipes[k].price; } } } } return total / 100; } /* Gets the quantity of each ingredient sold between two dates (dateRange) Inputs dateRange: list containing a start date and an end date Return: [{ ingredient: Ingredient object, quantity: quantity of ingredient sold }] */ ingredientsSold(dateRange){ if(!dateRange){ return false; } let recipes = this.recipesSold(dateRange); let ingredientList = []; for(let i = 0; i < recipes.length; i++){ for(let j = 0; j < recipes[i].recipe.ingredients.length; j++){ let exists = false; for(let k = 0; k < ingredientList.length; k++){ if(ingredientList[k].ingredient === recipes[i].recipe.ingredients[j].ingredient){ exists = true; ingredientList[k].quantity += recipes[i].quantity * recipes[i].recipe.ingredients[j].quantity; break; } } if(!exists){ ingredientList.push({ ingredient: recipes[i].recipe.ingredients[j].ingredient, quantity: recipes[i].quantity * recipes[i].recipe.ingredients[j].quantity }); } } } return ingredientList; } singleIngredientSold(dateRange, ingredient){ let total = 0; for(let i = dateRange[0]; i < dateRange[1]; i++){ for(let j = 0; j < this.transactions[i].recipes.length; j++){ for(let k = 0; k < this.transactions[i].recipes[j].recipe.ingredients.length; k++){ if(this.transactions[i].recipes[j].recipe.ingredients[k].ingredient === ingredient.ingredient){ total += this.transactions[i].recipes[j].recipe.ingredients[k].quantity; break; } } } } return total; } /* Gets the number of recipes sold between two dates (dateRange) Inputs: dateRange: array containing a start date and an end date Return: [{ recipe: a recipe object quantity: quantity of the recipe sold }] */ recipesSold(dateRange){ let recipeList = []; for(let i = dateRange[0]; i <= dateRange[1]; i++){ for(let j = 0; j < this.transactions[i].recipes.length; j++){ let exists = false; for(let k = 0; k < recipeList.length; k++){ if(recipeList[k].recipe === this.transactions[i].recipes[j].recipe){ exists = true; recipeList[k].quantity += this.transactions[i].recipes[j].quantity; break; } } if(!exists){ recipeList.push({ recipe: this.transactions[i].recipes[j].recipe, quantity: this.transactions[i].recipes[j].quantity }); } } } return recipeList; } /* Create revenue data for graphing Input: dateRange: [start index, end index] (this.transactionIndices) Return: [total revenue for each day] */ graphDailyRevenue(dateRange){ if(!dateRange){ return false; } let dataList = new Array(30).fill(0); let currentDate = this.transactions[dateRange[0]].date; let arrayIndex = 0; for(let i = dateRange[0]; i <= dateRange[1]; i++){ if(this.transactions[i].date.getDate() !== currentDate.getDate()){ currentDate = this.transactions[i].date; arrayIndex++; } for(let j = 0; j < this.transactions[i].recipes.length; j++){ dataList[arrayIndex] += (this.transactions[i].recipes[j].recipe.price / 100) * this.transactions[i].recipes[j].quantity; } } return dataList; } /* Groups all of the merchant's ingredients by their category Return: [{ name: category name, ingredients: [Ingredient Object] }] */ categorizeIngredients(){ let ingredientsByCategory = []; for(let i = 0; i < this.ingredients.length; i++){ let categoryExists = false; for(let j = 0; j < ingredientsByCategory.length; j++){ if(this.ingredients[i].ingredient.category === ingredientsByCategory[j].name){ ingredientsByCategory[j].ingredients.push(this.ingredients[i]); categoryExists = true; break; } } if(!categoryExists){ ingredientsByCategory.push({ name: this.ingredients[i].ingredient.category, ingredients: [this.ingredients[i]] }); } } return ingredientsByCategory; } unitizeIngredients(){ let ingredientsByUnit = []; for(let i = 0; i < this.ingredients.length; i++){ let unitExists = false; for(let j = 0; j < ingredientsByUnit.length; j++){ if(this.ingredients[i].ingredient.unit === ingredientsByUnit[j].name){ ingredientsByUnit[j].ingredients.push(this.ingredients[i]); unitExists = true; break; } } if(!unitExists){ ingredientsByUnit.push({ name: this.ingredients[i].ingredient.unit, ingredients: [this.ingredients[i]] }); } } return ingredientsByUnit; } getRecipesForIngredient(ingredient){ let recipes = []; for(let i = 0; i < this.recipes.length; i++){ for(let j = 0; j < this.recipes[i].ingredients.length; j++){ if(this.recipes[i].ingredients[j].ingredient === ingredient){ recipes.push(this.recipes[i]); } } } return recipes; } } let convertToMain = (unit, quantity)=>{ let converted = 0; if(merchant.units.mass.includes(unit)){ switch(unit){ case "g": converted = quantity; break; case "kg": converted = quantity * 1000; break; case "oz": converted = quantity * 28.3495; break; case "lb": converted = quantity * 453.5924; break; } }else if(merchant.units.volume.includes(unit)){ switch(unit){ case "ml": converted = quantity / 1000; break; case "l": converted = quantity; break; case "tsp": converted = quantity / 202.8842; break; case "tbsp": converted = quantity / 67.6278; break; case "ozfl": converted = quantity / 33.8141; break; case "cup": converted = quantity / 4.1667; break; case "pt": converted = quantity / 2.1134; break; case "qt": converted = quantity / 1.0567; break; case "gal": converted = quantity * 3.7854; break; } }else if(merchant.units.length.includes(unit)){ switch(unit){ case "mm": converted = quantity / 1000; break; case "cm": converted = quantity / 100; break; case "m": converted = quantity; break; case "in": converted = quantity / 39.3701; break; case "ft": converted = quantity / 3.2808; break; } }else{ converted = quantity; } return converted; } /* Switches to a different strand Input: name: name of the strand. Must end with "Strand" */ window.changeStrand = (name)=>{ closeSidebar(); for(let strand of document.querySelectorAll(".strand")){ strand.style.display = "none"; } let buttons = document.querySelectorAll(".menuButton"); for(let i = 0; i < buttons.length - 1; i++){ buttons[i].classList = "menuButton"; buttons[i].disabled = false; } let activeButton = {}; switch(name){ case 1: activeButton = document.getElementById("homeBtn"); document.getElementById("homeStrand").style.display = "flex"; homeStrand.display(); break; case 2: activeButton = document.getElementById("ingredientsBtn"); document.getElementById("ingredientsStrand").style.display = "flex"; ingredients.display(); break; case 3: activeButton = document.getElementById("recipeBookBtn"); document.getElementById("recipeBookStrand").style.display = "flex"; recipeBook.display(); break; case 4: activeButton = document.getElementById("ordersBtn"); document.getElementById("ordersStrand").style.display = "flex"; orders.display(); break; case 5: activeButton = document.getElementById("transactionsBtn"); document.getElementById("transactionsStrand").style.display = "flex"; transactions.display(); break; } activeButton.classList = "menuButton active"; activeButton.disabled = true; if(window.screen.availWidth <= 1000){ closeMenu(); } } //Close any open sidebar let closeSidebar = ()=>{ let sidebar = document.querySelector("#sidebarDiv"); for(let i = 0; i < sidebar.children.length; i++){ sidebar.children[i].style.display = "none"; } sidebar.classList = "sidebarHide"; if(window.screen.availWidth <= 1000){ document.querySelector(".contentBlock").style.display = "flex"; document.getElementById("mobileMenuSelector").style.display = "block"; document.getElementById("sidebarCloser").style.display = "none"; } } /* Open a specific sidebar Input: sidebar: the outermost element of the sidebar (must contain class sidebar) */ let openSidebar = (sidebar)=>{ document.querySelector("#sidebarDiv").classList = "sidebar"; let sideBars = document.querySelector("#sidebarDiv").children; for(let i = 0; i < sideBars.length; i++){ sideBars[i].style.display = "none"; } sidebar.style.display = "flex"; if(window.screen.availWidth <= 1000){ document.querySelector(".contentBlock").style.display = "none"; document.getElementById("mobileMenuSelector").style.display = "none"; document.getElementById("sidebarCloser").style.display = "block"; } } let changeMenu = ()=>{ let menu = document.querySelector(".menu"); let buttons = document.querySelectorAll(".menuButton"); if(!menu.classList.contains("menuMinimized")){ menu.classList = "menu menuMinimized"; for(let button of buttons){ button.children[1].style.display = "none"; } document.querySelector("#max").style.display = "none"; document.querySelector("#min").style.display = "flex"; }else if(menu.classList.contains("menuMinimized")){ menu.classList = "menu"; for(let button of buttons){ button.children[1].style.display = "block"; } setTimeout(()=>{ document.querySelector("#max").style.display = "flex"; document.querySelector("#min").style.display = "none"; }, 150); } } let openMenu = ()=>{ document.getElementById("menu").style.display = "flex"; document.querySelector(".contentBlock").style.display = "none"; document.getElementById("mobileMenuSelector").onclick = ()=>{closeMenu()}; } let closeMenu = ()=>{ document.getElementById("menu").style.display = "none"; document.querySelector(".contentBlock").style.display = "flex"; document.getElementById("mobileMenuSelector").onclick = ()=>{openMenu()}; } if(window.screen.availWidth > 1000 && window.screen.availWidth <= 1400){ changeMenu(); document.getElementById("menuShifter2").style.display = "none"; } merchant = new Merchant(data.merchant, data.transactions); homeStrand.display(merchant);