analytics.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. let analytics = {
  2. isPopulated: false,
  3. ingredient: {},
  4. recipe: {},
  5. transactionsByDate: [],
  6. display: function(Transaction){
  7. if(!this.isPopulated){
  8. document.getElementById("analRecipeContent").style.display = "none";
  9. let to = new Date()
  10. let from = new Date(to.getFullYear(), to.getMonth() - 1, to.getDate());
  11. document.getElementById("analStartDate").valueAsDate = from;
  12. document.getElementById("analEndDate").valueAsDate = to;
  13. let analSlider = document.getElementById("analSlider");
  14. analSlider.onclick = ()=>{this.switchDisplay()};
  15. analSlider.checked = false;
  16. document.getElementById("analDateBtn").onclick = ()=>{this.newDates(Transaction)};
  17. this.populateButtons();
  18. this.ingredient = merchant.ingredients[0].ingredient;
  19. this.recipe = merchant.recipes[0];
  20. this.newDates(Transaction);
  21. this.isPopulated = true;
  22. }
  23. },
  24. populateButtons: function(){
  25. let ingredientButtons = document.getElementById("analIngredientList");
  26. let recipeButtons = document.getElementById("analRecipeList");
  27. for(let i = 0; i < merchant.ingredients.length; i++){
  28. let button = document.createElement("button");
  29. button.innerText = merchant.ingredients[i].ingredient.name;
  30. button.classList.add("choosable");
  31. button.onclick = ()=>{
  32. this.ingredient = merchant.ingredients[i].ingredient;
  33. this.displayIngredient()
  34. };
  35. ingredientButtons.appendChild(button);
  36. }
  37. for(let i = 0; i < merchant.recipes.length; i++){
  38. let button = document.createElement("button");
  39. button.innerText = merchant.recipes[i].name;
  40. button.classList.add("choosable");
  41. button.onclick = ()=>{
  42. this.recipe = merchant.recipes[i];
  43. this.displayRecipe()
  44. };
  45. recipeButtons.appendChild(button);
  46. }
  47. },
  48. getData: function(from, to, Transaction){
  49. let loader = document.getElementById("loaderContainer");
  50. loader.style.display = "flex";
  51. return fetch(`/transactions/${from.toISOString()}/${to.toISOString()}`)
  52. .then(response => response.json())
  53. .then((response)=>{
  54. if(typeof(response) === "string"){
  55. banner.createError(response);
  56. }else{
  57. this.transactionsByDate = [];
  58. for(let i = 0; i < response.length; i++){
  59. const date = new Date(response[i].date);
  60. let newDate = {
  61. date: date,
  62. transactions: []
  63. };
  64. for(let j = 0; j < response[i].transactions.length; j++){
  65. newDate.transactions.push(new Transaction(
  66. response[i].transactions[j]._id,
  67. date,
  68. response[i].transactions[j].recipes,
  69. merchant
  70. ));
  71. }
  72. this.transactionsByDate.push(newDate);
  73. }
  74. }
  75. })
  76. .catch((err)=>{
  77. banner.createError("UNABLE TO UPDATE THE PAGE");
  78. })
  79. .finally(()=>{
  80. loader.style.display = "none";
  81. });
  82. },
  83. displayIngredient: function(ingredient){
  84. //break down data into dates and quantities
  85. let dates = [];
  86. let quantities = [];
  87. for(let i = 0; i < this.transactionsByDate.length; i++){
  88. dates.push(this.transactionsByDate[i].date);
  89. let sum = 0;
  90. for(let j = 0; j < this.transactionsByDate[i].transactions.length; j++){
  91. let transactions = this.transactionsByDate[i].transactions[j];
  92. sum += transactions.getIngredientQuantity(this.ingredient);
  93. }
  94. quantities.push(sum);
  95. }
  96. //create and display the graph
  97. let trace = {
  98. x: dates,
  99. y: quantities,
  100. mode: "lines+markers",
  101. line: {
  102. color: "rgb(255, 99, 107)"
  103. }
  104. }
  105. const layout = {
  106. title: this.ingredient.name.toUpperCase(),
  107. xaxis: {title: "DATE"},
  108. yaxis: {title: `QUANTITY (${this.ingredient.unit.toUpperCase()})`}
  109. }
  110. Plotly.newPlot("itemUseGraph", [trace], layout);
  111. //Create min/max/avg
  112. //Current ingredient is stored on the "analMinUse" element
  113. let min = quantities[0];
  114. let max = quantities[0];
  115. let sum = 0;
  116. for(let i = 0; i < quantities.length; i++){
  117. if(quantities[i] < min){
  118. min = quantities[i];
  119. }
  120. if(quantities[i] > max){
  121. max = quantities[i];
  122. }
  123. sum += quantities[i];
  124. }
  125. document.getElementById("analMinUse").innerText = `${min.toFixed(2)} ${this.ingredient.unit.toUpperCase()}`;
  126. document.getElementById("analAvgUse").innerText = `${(sum / quantities.length).toFixed(2)} ${this.ingredient.unit.toUpperCase()}`;
  127. document.getElementById("analMaxUse").innerText = `${max.toFixed(2)} ${this.ingredient.unit.toUpperCase()}`;
  128. //Create weekday averages
  129. let dayUse = [0, 0, 0, 0, 0, 0, 0];
  130. let dayCount = [0, 0, 0, 0, 0, 0, 0];
  131. for(let i = 0; i < quantities.length; i++){
  132. dayUse[dates[i].getDay()] += quantities[i];
  133. dayCount[dates[i].getDay()]++;
  134. }
  135. document.getElementById("analDayOne").innerText = `${(dayUse[0] / dayCount[0]).toFixed(2)} ${this.ingredient.unit.toUpperCase()}`;
  136. document.getElementById("analDayTwo").innerText = `${(dayUse[1] / dayCount[1]).toFixed(2)} ${this.ingredient.unit.toUpperCase()}`;
  137. document.getElementById("analDayThree").innerText = `${(dayUse[2] / dayCount[2]).toFixed(2)} ${this.ingredient.unit.toUpperCase()}`;
  138. document.getElementById("analDayFour").innerText = `${(dayUse[3] / dayCount[3]).toFixed(2)} ${this.ingredient.unit.toUpperCase()}`;
  139. document.getElementById("analDayFive").innerText = `${(dayUse[4] / dayCount[4]).toFixed(2)} ${this.ingredient.unit.toUpperCase()}`;
  140. document.getElementById("analDaySix").innerText = `${(dayUse[5] / dayCount[5]).toFixed(2)} ${this.ingredient.unit.toUpperCase()}`;
  141. document.getElementById("analDaySeven").innerText = `${(dayUse[6] / dayCount[6]).toFixed(2)} ${this.ingredient.unit.toUpperCase()}`;
  142. },
  143. displayRecipe: function(){
  144. //break down data into dates and quantities
  145. let dates = [];
  146. let quantities = [];
  147. for(let i = 0; i < this.transactionsByDate.length; i++){
  148. dates.push(this.transactionsByDate[i].date);
  149. let sum = 0;
  150. for(let j = 0; j < this.transactionsByDate[i].transactions.length; j++){
  151. const transaction = this.transactionsByDate[i].transactions[j];
  152. for(let k = 0; k < transaction.recipes.length; k++){
  153. if(transaction.recipes[k].recipe === this.recipe){
  154. sum += transaction.recipes[k].quantity;
  155. }
  156. }
  157. }
  158. quantities.push(sum);
  159. }
  160. //create and display the graph
  161. const trace = {
  162. x: dates,
  163. y: quantities,
  164. mode: "lines+markers",
  165. line: {
  166. color: "rgb(255, 99, 107)"
  167. }
  168. }
  169. const layout = {
  170. title: this.recipe.name.toUpperCase(),
  171. xaxis: {title: "DATE"},
  172. yaxis: {title: "QUANTITY"}
  173. }
  174. Plotly.newPlot("recipeSalesGraph", [trace], layout);
  175. //Display the boxes at the bottom
  176. //Current recipe is stored on the "recipeAvgUse" element
  177. let avg = 0;
  178. for(let i = 0; i < quantities.length; i++){
  179. avg += quantities[i];
  180. }
  181. avg = avg / quantities.length;
  182. document.getElementById("recipeAvgUse").innerText = avg.toFixed(2);
  183. document.getElementById("recipeAvgRevenue").innerText = `$${(avg * this.recipe.price).toFixed(2)}`
  184. },
  185. switchDisplay: function(){
  186. const checkbox = document.getElementById("analSlider");
  187. let ingredient = document.getElementById("analIngredientContent");
  188. let recipe = document.getElementById("analRecipeContent");
  189. if(checkbox.checked === true){
  190. ingredient.style.display = "none";
  191. recipe.style.display = "flex";
  192. this.displayRecipe();
  193. }else{
  194. ingredient.style.display = "flex";
  195. recipe.style.display = "none";
  196. this.displayIngredient();
  197. }
  198. },
  199. newDates: async function(Transaction){
  200. const from = document.getElementById("analStartDate").valueAsDate;
  201. const to = document.getElementById("analEndDate").valueAsDate;
  202. await this.getData(from, to, Transaction);
  203. if(document.getElementById("analSlider").checked === true){
  204. this.displayRecipe();
  205. }else{
  206. this.displayIngredient();
  207. }
  208. }
  209. }
  210. module.exports = analytics;