Bläddra i källkod

Merge branch 'development'

Lee Morgan 6 år sedan
förälder
incheckning
d1dc55a433

+ 9 - 0
branchNotes.txt

@@ -0,0 +1,9 @@
+I have updated the login and registration so that you can create an account and then login with it.
+
+1.  Create an account and check the rest of the website.
+    A lot of the work style that you changed affects every other page and breaks things.
+    This is why I told you you really should not add style to "shared.css" unless you are absolute certain that you want it to affect every single page.
+    You need to go through and get rid of all of these negative affects.
+    Maybe go through "shared.css" and move all that code to the more local "landing.css"
+
+Other than that, everything seems good to me.  Fix those side effects on the rest of the site and everything should be ready to go.

+ 3 - 2
controllers/renderer.js

@@ -90,8 +90,8 @@ module.exports = {
                                 }
 
                                 transactions.push(newTransaction);
+                                merchant.lastUpdatedTime = Date.now();
                             }
-                            merchant.lastUpdatedTime = Date.now();
 
                             merchant.save()
                                 .then((updatedMerchant)=>{
@@ -153,7 +153,8 @@ module.exports = {
                     let lastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0);
 
                     Transaction.find({merchant: req.session.user, date: {$gte: firstDay, $lt: lastDay}},
-                        {date: 1, recipes: 1, _id: 0})
+                        {date: 1, recipes: 1, _id: 0},
+                        {sort: {date: 1}})
                         .then((transactions)=>{
                             resolve({merchant: merchant, transactions: transactions});
                         })

+ 75 - 3
controllers/transactionData.js

@@ -3,6 +3,12 @@ const Purchase = require("../models/purchase");
 const Merchant = require("../models/merchant");
 
 module.exports = {
+    //POST - returns all transactions for a merchant between given dates
+    //Inputs:
+    //  req.body.from: start date
+    //  req.body.to: end date
+    //Returns:
+    //  List of transactions
     getTransactions: function(req, res){
         if(!req.session.user){
             req.session.error = "You must be logged in to view that page";
@@ -10,10 +16,19 @@ module.exports = {
         }
 
         let date = new Date();
-        let firstDay = new Date(date.getFullYear(), date.getMonth(), 1);
-        let lastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0);
+        let firstDay, lastDay;
+
+        if(req.body.from && req.body.to){
+            firstDay = new Date(req.body.from);
+            lastDay = new Date(req.body.to);
+        }else{
+            firstDay = new Date(date.getFullYear(), date.getMonth(), 1);
+            lastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0);
+        }
 
-        Transaction.find({merchant: req.session.user, date: {$gte: firstDay, $lt: lastDay}})
+        Transaction.find({merchant: req.session.user, date: {$gte: firstDay, $lt: lastDay}},
+            {_id: 0, date: 1, recipes: 1},
+            {sort: {date: 1}})
             .then((transactions)=>{
                 return res.json(transactions);
             })
@@ -91,4 +106,61 @@ module.exports = {
             })
             .catch((err)=>{});
     },
+
+    populate: function(req, res){
+        if(!req.session.user){
+            res.session.error = "Must be logged in to do that";
+            return res.redirect("/");
+        }
+
+        function randomDate() {
+            let now = new Date();
+            let start = new Date();
+            start.setFullYear(now.getFullYear() - 1);
+            return new Date(start.getTime() + Math.random() * (now.getTime() - start.getTime()));
+        }
+
+        Merchant.findOne({_id: req.session.user})
+            .then((merchant)=>{
+                let newTransactions = [];
+
+                for(let i = 0; i < 5000; i++){
+                    let newTransaction = new Transaction({
+                        merchant: merchant._id,
+                        date: randomDate(),
+                        recipes: []
+                    });
+
+                    let numberOfRecipes = Math.floor((Math.random() * 5) + 1);
+
+                    for(let j = 0; j < numberOfRecipes; j++){
+                        let recipeNumber = Math.floor(Math.random() * merchant.recipes.length);
+                        let randQuantity = Math.floor((Math.random() * 3) + 1);
+
+                        newTransaction.recipes.push({
+                            recipe: merchant.recipes[recipeNumber],
+                            quantity: randQuantity
+                        });
+                    }
+
+                    newTransactions.push(newTransaction);
+                }
+
+                Transaction.create(newTransactions)
+                    .then((transactions)=>{
+                        console.log("completed");
+                        return res.redirect("/data");
+                    })
+                    .catch((err)=>{
+                        console.log(err);
+                        return;
+                    });
+            })
+            .catch((err)=>{
+                console.log(err);
+                return;
+            });
+        
+        
+    }
 }

+ 2 - 1
routes.js

@@ -41,7 +41,8 @@ module.exports = function(app){
     app.get("/cloverauth*", otherData.cloverAuth);
 
     //Transactions
-    app.get("/transactions", transactionData.getTransactions);
+    app.post("/transactions", transactionData.getTransactions);
     app.get("/purchases", transactionData.getPurchases);
     app.post("/transactions/create", transactionData.createTransaction);  //Creates transaction for non-pos merchant
+    app.get("/populate", transactionData.populate);
 }

+ 7 - 7
views/dashboardPage/dashboard.ejs

@@ -244,13 +244,13 @@
         <script>let merchant = <%- JSON.stringify(merchant) %>;</script>
         <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
         <script src="../shared/validation.js"></script>
-        <script src="/dashboardPage//inventory.js"></script>
-        <script src="/dashboardPage//recipes.js"></script>
-        <script src="/dashboardPage//account.js"></script>
-        <script src="/dashboardPage//addIngredient.js"></script>
-        <script src="/dashboardPage//enterTransactions.js"></script>
-        <script src="/dashboardPage//enterPurchase.js"></script>
-        <script src="/dashboardPage//singleRecipe.js"></script>
+        <script src="/dashboardPage/inventory.js"></script>
+        <script src="/dashboardPage/recipes.js"></script>
+        <script src="/dashboardPage/account.js"></script>
+        <script src="/dashboardPage/addIngredient.js"></script>
+        <script src="/dashboardPage/enterTransactions.js"></script>
+        <script src="/dashboardPage/enterPurchase.js"></script>
+        <script src="/dashboardPage/singleRecipe.js"></script>
         <script src="/shared/controller.js"></script>
     </body>
 </html>

+ 21 - 0
views/dataPage/data.css

@@ -25,4 +25,25 @@
         display: flex;
         flex-direction: column;
         align-items: center;
+    }
+
+/* Ingredient Strand */
+#ingredientStrand{
+    justify-content: space-between;
+}
+
+    #ingredientStrand > *{
+        margin: 10px;
+    }
+
+    canvas{
+        flex-grow: 10;
+        max-height: 60vh;
+        max-width: 90vw;
+    }
+
+    #ingredientOptions{
+        flex-grow: 1;
+        display: flex;
+        flex-direction: column;
     }

+ 23 - 0
views/dataPage/data.ejs

@@ -19,6 +19,18 @@
         <div id="homeStrand" class="strand">
             <h2 id="month"></h2>
 
+            <div class="buttonBox">
+                <p>From: </p>
+
+                <input id="from" type="date">
+
+                <p>To: </p>
+
+                <input id="to" type="date">
+
+                <button id="dateSort" class="buttonDisabled">Submit</button>
+            </div>
+
             <div class="buttonBox">
                 <a class="button" href="/dashboard">Display Inventory</a>
             </div>
@@ -77,8 +89,19 @@
             </div>
         </div>
 
+        <div id="ingredientStrand" class="strand">
+            <div id="ingredientOptions"></div>
+
+            <canvas></canvas>
+        </div>
+
         <script>let data = <%- JSON.stringify(data); %></script>
+        <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
+        <script src="/shared/validation.js"></script>
         <script src="/dataPage/home.js"></script>
+        <script src="dataPage/ingredient.js"></script>
         <script src="/shared/controller.js"></script>
+        <script src="/shared/graphs.js"></script>
+        <script src="/dataPage/fetchData.js"></script>
     </body>
 </html>

+ 31 - 0
views/dataPage/fetchData.js

@@ -0,0 +1,31 @@
+window.dataLoaded = false;
+
+let date = new Date();
+let yearAgo = new Date(new Date().setFullYear(date.getFullYear() - 1));
+
+let onDataLoad = function(){
+    let dateSort = document.querySelector("#dateSort");
+    dateSort.onclick = ()=>{window.homeObj.newDates()};
+    dateSort.classList = "button";
+
+    let ingredientsBody = document.querySelector("#ingredientsData tbody");
+    for(let row of ingredientsBody.children){
+        row.classList = "clickableRow";
+        row.onclick = ()=>{window.ingredientObj.display("ingredient", row.ingredient)};
+    }
+
+    window.dataLoaded = true;
+}
+
+axios.post("/transactions", {from: yearAgo, to: date})
+    .then((response)=>{
+        if(typeof(response.data) === "string"){
+            banner.createError(response.data);
+        }else{
+            data.transactions = response.data;
+            onDataLoad();
+        }
+    })
+    .catch((err)=>{
+        console.log(err);
+    });

+ 66 - 3
views/dataPage/home.js

@@ -1,6 +1,9 @@
 window.homeObj = {
+    isPopulated: false,
     recipeTotal: 0,
     revenueTotal: 0,
+    dateFrom: "",
+    dateTo: "",
 
     display: function(){
         clearScreen();
@@ -10,10 +13,18 @@ window.homeObj = {
         let months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
         document.querySelector("#month").innerText = `Month of ${months[new Date().getMonth()]}`;
 
-        this.populate();
+        document.querySelector("#to").valueAsDate = new Date();
+
+        if(!this.isPopulated){
+            this.populate(data.transactions);
+            this.isPopulated = true;
+        }
     },
 
-    populate: function(){
+    populate: function(transactions){
+        this.recipeTotal = 0;
+        this.revenueTotal = 0;
+        
         //Create object to store number of recipes sold
         let recipes = [];
         for(let recipe of data.merchant.recipes){
@@ -50,7 +61,7 @@ window.homeObj = {
         }
         
         //Populate number of recipes sold
-        for(let transaction of data.transactions){
+        for(let transaction of transactions){
             for(let recipe of transaction.recipes){
                 for(let newRecipe of recipes){
                     if(recipe.recipe === newRecipe.id){
@@ -89,10 +100,20 @@ window.homeObj = {
 
         //Populate Ingredients table
         let ingredientsBody = document.querySelector("#ingredientsData tbody");
+
+        while(ingredientsBody.children.length > 0){
+            ingredientsBody.removeChild(ingredientsBody.firstChild);
+        }
         
         for(let ingredient of soldIngredients){
             let row = document.createElement("tr");
             ingredientsBody.appendChild(row);
+            if(window.dataLoaded){
+                row.classList = "clickableRow";
+                row.onclick = ()=>{window.ingredientObj.display("ingredient", ingredient)};
+            }else{
+                row.ingredient = ingredient;
+            }
 
             let name = document.createElement("td");
             name.innerText = `${ingredient.name} (${ingredient.unit})`;
@@ -110,6 +131,10 @@ window.homeObj = {
         //Populate recipes table
         let recipesBody = document.querySelector("#recipesData tbody");
 
+        while(recipesBody.children.length > 0){
+            recipesBody.removeChild(recipesBody.firstChild);
+        }
+
         for(let recipe of recipes){
             let row = document.createElement("tr");
             recipesBody.appendChild(row);
@@ -129,6 +154,10 @@ window.homeObj = {
 
         //Populate purchases table
         let purchasesBody = document.querySelector("#purchasesData tbody");
+
+        while(purchasesBody.children.length > 0){
+            purchasesBody.removeChild(purchasesBody.firstChild);
+        }
         
         for(let ingredient of purchaseIngredients){
             let row = document.createElement("tr");
@@ -146,5 +175,39 @@ window.homeObj = {
         //Populate totals
         document.querySelector("#revenueTotal").innerText = `$${this.revenueTotal.toFixed(2)}`;
         document.querySelector("#soldTotal").innerText = this.recipeTotal;
+    },
+
+    newDates: function(){
+        let from = new Date(document.querySelector("#from").value);
+        let to = new Date(document.querySelector("#to").value);
+
+        if(from === "" || to === ""){
+            banner.createError("Invalid date");
+            return;
+        }else{
+            from = new Date(from);
+            to = new Date(to);
+        }
+
+        if(validator.transaction.date(from, to)){
+            let startIndex = 0;
+            let endIndex = data.transactions.length;
+
+            for(let i = 0; i < data.transactions.length; i++){
+                if(from < new Date(data.transactions[i].date)){
+                    startIndex = i;
+                    break;
+                }
+            }
+
+            for(let i = 0; i < data.transactions.length; i++){
+                if(to < new Date(data.transactions[i].date)){
+                    endIndex = i;
+                    break;
+                }
+            }
+
+            this.populate(data.transactions.slice(startIndex, endIndex));
+        }
     }
 }

+ 82 - 0
views/dataPage/ingredient.js

@@ -0,0 +1,82 @@
+window.ingredientObj = {
+    isPopulated: false,
+    graph: {},
+
+    display: function(type, ingredient){
+        clearScreen();
+        document.querySelector("#ingredientStrand").style.display = "flex";
+        document.querySelector("strand-selector").setAttribute("strand", "ingredient");
+
+        if(!this.isPopulated){
+            let ingredientsDiv = document.querySelector("#ingredientOptions");
+
+            for(let item of data.merchant.inventory){
+                let label = document.createElement("label");
+                label.innerText = item.ingredient.name;
+                ingredientsDiv.appendChild(label);
+                
+                let checkbox = document.createElement("input");
+                checkbox.type = "checkbox";
+                checkbox.onchange = ()=>{
+                    if(checkbox.checked){
+                        this.graph.addData(this.formatData("ingredient", item.ingredient._id));
+                    }else{
+                        this.graph.removeData(item.ingredient._id);
+                    }
+                };
+                label.appendChild(checkbox);
+            }
+
+            let startDate = new Date();
+            startDate.setFullYear(new Date().getFullYear() - 1);
+
+            this.graph = new LineGraph(
+                document.querySelector("#ingredientStrand canvas"),
+                "Quantity",
+                "Date",
+                {
+                    type: "date",
+                    start: startDate,
+                    end: new Date()
+                }
+            );
+
+            this.isPopulated = true;
+        }
+
+        if(ingredient){
+            this.graph.addData(this.formatData("ingredient", ingredient.id));
+        }
+    },
+
+    formatData: function(type, id){
+        dataList = new Array(365).fill(0);
+        let today = new Date();
+        
+        if(type === "ingredient"){
+            let dataLastDate = new Date(data.transactions[0].date);
+            let dateRange = Math.floor((Date.UTC(today.getFullYear(), today.getMonth(), today.getDate()) - Date.UTC(dataLastDate.getFullYear(), dataLastDate.getMonth(), dataLastDate.getDate())) / (1000 * 60 * 60 * 24));
+
+            for(let transaction of data.transactions){
+                let transDate = new Date(transaction.date);
+                let diff = Math.floor((Date.UTC(transDate.getFullYear(), transDate.getMonth(), transDate.getDate()) - Date.UTC(today.getFullYear(), today.getMonth(), today.getDate())) / (1000 * 60 * 60 * 24));
+                if(diff <= 0){
+                    for(let recipe of transaction.recipes){
+                        for(let merchRecipe of data.merchant.recipes){
+                            if(merchRecipe._id === recipe.recipe){
+                                for(let ingredient of merchRecipe.ingredients){
+                                    if(ingredient.ingredient === id){
+                                        dataList[dateRange - Math.abs(diff)] += ingredient.quantity;
+                                    }
+                                }
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+
+            return {id: id, set: dataList};
+        }
+    }
+}

+ 0 - 2
views/landingPage/controller.js

@@ -1,7 +1,6 @@
 let controller = {
     publicStrand: document.querySelector("#publicStrand"),
     loginStrand: document.querySelector("#loginStrand"),
-    posChoiceStrand: document.querySelector("#posChoiceStrand"),
     registerStrand: document.querySelector("#registerStrand"),
 
     onStart: function(){
@@ -15,7 +14,6 @@ let controller = {
     clearScreen: function(){
         this.publicStrand.style.display = "none";
         this.loginStrand.style.display = "none";
-        this.posChoiceStrand.style.display = "none";
         this.registerStrand.style.display = "none";
     }
 }

+ 135 - 78
views/landingPage/landing.css

@@ -80,7 +80,8 @@
         }
 
 /* Login Strand */
-#loginStrand{
+
+#loginStrand, #registerStrand{
     display: none;
     flex-direction: column;
     align-items: center;
@@ -91,36 +92,142 @@
     height: 91.5vh;
 }
 
-    #loginStrand form{
-        display: flex;
-        flex-direction: column;
-        justify-content: space-between;
-        align-items: center;
-        border: 2px solid rgb(201, 201, 201);
-        background: rgb(240, 252, 255);
-        color: rgb(255, 99, 107);
-        padding: 25px;
-        border-radius: 10px;
-    }
-
-        #loginStrand form > *{
-            margin: 10px 0;
-        }
-
-/* Register Strand */
-#registerStrand{
+/* ----The Checkbox and Inputs Start---- */
+
+/* The container */
+.container {
+    display: block;
+    position: relative;
+    padding-left: 35px;
+    margin-bottom: 12px;
+    cursor: pointer;
+    font-size: 16px;
+    -webkit-user-select: none;
+    -moz-user-select: none;
+    -ms-user-select: none;
+    user-select: none;
+  }
+  
+  /* Hide the browser's default checkbox */
+  .container input {
+    position: absolute;
+    opacity: 0;
+    cursor: pointer;
+    height: 0;
+    width: 0;
+  }
+  
+  /* Create a custom checkbox */
+  .checkmark {
+    position: absolute;
+    top: 0;
+    left: 0;
+    height: 24px;
+    width: 24px;
+    border: 1px solid#ccc;
+    border-radius: 4px;
+    background-color: rgb(255, 255, 255);
+  }
+  
+  /* On mouse-over, add a grey background color */
+  .checkmark:hover {
+    background-color: #ccc;
+  }
+  
+  /* When the checkbox is checked, add a blue background */
+  .container input:checked ~ .checkmark {
+    background-color: #5A6F7D;
+    border: 1px solid#5A6F7D;
+  }
+  
+  /* Create the checkmark/indicator (hidden when not checked) */
+  .checkmark:after {
+    content: "";
+    position: absolute;
     display: none;
-    flex-direction: column;
-    align-items: center;
+  }
+  
+  /* Show the checkmark when checked */
+  .container input:checked ~ .checkmark:after {
+    display: block;
+  }
+  
+  /* Style the checkmark/indicator */
+  .container .checkmark:after {
+    left: 9px;
+    top: 5px;
+    width: 5px;
+    height: 10px;
+    border: solid white;
+    border-width: 0 3px 3px 0;
+    -webkit-transform: rotate(45deg);
+    -ms-transform: rotate(45deg);
+    transform: rotate(45deg);
+  }
+/* ----The Checkbox and Inputs End---- */
+
+/* Inputs Start */
+
+input[type=text], select {
+    width: 100%;
+    padding: 12px 20px;
+    margin: 8px 0;
+    display: inline-block;
+    border: 1px solid #ccc;
+    border-radius: 4px;
+    box-sizing: border-box;
+    padding-bottom: 16px;
+    font-size: 16px;
+
+  }
+
+  input[type=text], input[type=password], select {
+    width: 100%;
+    padding: 12px 20px;
+    margin: 8px 0;
+    display: inline-block;
+    border: 1px solid #ccc;
+    border-radius: 4px;
+    box-sizing: border-box;
+    font-size: 16px;
+  }
+  
+  input[type=submit] {
+    width: 100%;
+    background-color:rgb(255, 99, 107);
+    color: white;
+    padding: 14px 20px;
+    margin: 8px 0;
+    border: none;
+    border-radius: 4px;
+    cursor: pointer;
+    font-size: 22px;
+    margin-top: 30px;
+  }
+
+  input[type=submit]:hover {
+    background: rgb(243, 77, 86);
+    color: white;
+  }
+
+  input[type=text]:focus, input[type=password]:focus {
+    border: 2px solid #555;
+    outline: none;
+  }
+
+  input[type=button] {
+    background-color: rgb(255, 99, 107);
+  }
+
+  input[type=button]:hover {
+    background-color:rgb(0, 27, 45);
+  }
+
+  .input-error{
+    border-color: red;
 }
 
-    #registerStrand > *{
-        margin: 10px;
-    }
-
-    #agreement{
-        display: flex;
-    }
+/* Inputs End */
 
 @media screen and (max-width: 600px){
     .logo-text img{
@@ -139,53 +246,3 @@
         right: 25vw;
     }
 }
-
-#posChoiceStrand{
-    display: none;
-    flex-direction: column;
-    align-items: center;
-}
-
-    .cards{
-        display: flex;
-        justify-content: space-around;
-    }
-
-        .cards > *{
-            display: flex;
-            flex-direction: column;
-            justify-content: space-around;
-            text-align: center;
-            width: 300px;
-            height: 200px;
-            border-radius: 25px;
-            border: 2px solid black;
-            padding: 50px;
-            cursor: pointer;
-            margin: 25px;
-            box-shadow: 0 0 20px black;
-            text-decoration: none;
-        }
-
-            .cards > * img{
-                max-height: 75%;
-            }
-
-            .cards > *:hover{
-                box-shadow: 0 0 25px #ff636b;
-            }
-
-            .cards > *:active{
-                box-shadow: 0 0 10px #ff636b;
-            }
-
-            .cards p{
-                margin-top: 25px;
-                font-size: 25px;
-                font-weight: bold;
-                color: black;
-            }
-
-        .cards img{
-            margin: auto 10px;
-        }

+ 44 - 58
views/landingPage/landing.ejs

@@ -14,12 +14,6 @@
 
         <div id="publicStrand">
             <div class="main-background">
-                <div class="public-buttons">
-                    <button class="button" onclick="loginObj.display()">Log In</button>
-
-                    <button class="button" onclick="registerObj.display()">Join</button>
-                </div>
-
                 <div class="logo-text">
                     <img src="/shared/images/logoWithText.png" alt="Subline">
 
@@ -49,74 +43,66 @@
             </div>
         </div>
 
-        <div id="loginStrand">
-            <form action="/login" method="post">
-                <h3>Log In</h3>
-                
-                <label>Email:
-                    <input name="email" type="email" required>
-                </label>
-
-                <label>Password:
-                    <input name="password" type="password" required>
-                </label>
-                
-                <div>
-                    <input class="button" type="submit" value="Log In">
-
-                    <button class="button" onclick="loginObj.cancel()">Cancel</button>
-                </div>
-            </form>
+        <div id="registerStrand">
+            <form onsubmit="registerObj.submit()">
+                <h1> Join Subline </h1>
 
-            <a class="button" href="/cloverlogin">Log in with Clover</a>
-        </div>
+                <a class="button buttonWithBorder" href="/cloverlogin"> Sign Up with Clover </a>
 
-        <div id="registerStrand">
-            <form action="/merchant/create/none" method="post" onsubmit="registerObj.submit()">
-                <label>Restaurant Name:
-                    <input id="restName" name="name" type="text" required>
+                <label id="nameLabel">Restaurant Name
+                    <input class="input" id="regName" name="name" type="text" required>
                 </label>
-
-                <label>Email:
-                    <input name="email" type="email" required>
+        
+                <label>Email
+                    <input type="text" id="regEmail" name="email" type="email" required>
                 </label>
-
-                <label>Password:
-                    <input name="password" type="password" required>
+        
+                <label>Password
+                    <input type="password" id="regPass" name="password" type="password" required>
                 </label>
-
-                <label>Confirm Password:
-                    <input name="confirmPassword" type="password" required>
+        
+                <label>Confirm Password
+                    <input type="password" id="regConfirmPass" name="confirmPassword" type="password" required>
                 </label>
-
+        
                 <div id="agreement">
-                    <input id="checkAgree" type="checkbox" onchange="registerObj.agreement()">
+                    <label class="container">
+                        <input id="checkAgree" type="checkbox">
 
-                    <p>I agree to the <a href="/information">Privacy Policy</a> and the <a href="/information">Terms and Conditions</a></p>
+                        <span class="checkmark"></span>
+        
+                        <p style="padding-top: 5px; padding-left: 7px;">I agree to the 
+                            <a class="link" href="/information">Privacy Policy</a> and the 
+                            <a class="link" href="/information">Terms and Conditions</a>
+                        </p>
+                    </label>   
                 </div>
 
-                <input id="regButton" class="buttonDisabled" type="submit" value="Register">
-            </form>
+                <input id="regButton" class="buttonDisabled" type="submit" value="Sign Up with Email">
 
-            <a class="button" href="/cloverlogin">Register with Clover</a>
+                <h3 class="link" style="margin-top: 30px;" onclick="loginObj.display()"> Already have an account? Please Sign In </h3>
 
-            <button class="button" onclick="publicObj.display()">Cancel</button>
+            </form>
         </div>
-        
 
-        <div id="posChoiceStrand">
-            <h1>Choose your POS System</h1>
+        <div id="loginStrand">
+            <form action="/login" method="post">
+                <h1> Welcome Back </h1>
 
-            <div class="cards">
-                <a href="/cloverlogin">
-                    <img src="../shared/images/clover-logo.jpeg" alt="Clover">
-                </a>
+                <a class="button buttonWithBorder" href="/cloverlogin"> Sign In with Clover </a>
+        
+                <label>Email
+                    <input type="text" name="email" type="email" required>
+                </label>
+        
+                <label>Password
+                    <input type="password" name="password" required>
+                </label>
+        
+                <input id="signIn" type="submit" value="Sign In with Email">
 
-                <a href="/merchant/new/none">
-                    <img src="../shared/images/logo.png" alt="None">
-                    <p>None</p>
-                </a>
-            </div>
+                <h3 class="link" style="margin-top: 30px;" onclick="registerObj.display()"> New Here? Please Sign Up </h3>
+            </form>
         </div>
 
         <% include ../shared/footer %>

+ 1 - 1
views/landingPage/login.js

@@ -8,5 +8,5 @@ let loginObj = {
         event.preventDefault();
         
         publicObj.display();
-    }
+    },
 }

+ 0 - 6
views/landingPage/posChoice.js

@@ -1,6 +0,0 @@
-let posChoiceObj = {
-    display: function(){
-        controller.clearScreen();
-        controller.posChoiceStrand.style.display = "flex";
-    }
-}

+ 3 - 1
views/landingPage/register.js

@@ -25,7 +25,9 @@ let registerObj = {
         let checkbox = document.querySelector("#checkAgree");
 
         if(checkbox.checked){
-            if(validator.isSanitary(document.querySelector("#restName").value)){
+            if(validator.isSanitary(document.querySelector("#regName").value)){
+                form.action = "merchant/create/none";
+                form.method = "post";
                 form.submit();
             }
         }else{

+ 8 - 5
views/shared/controller.js

@@ -17,6 +17,14 @@ class StrandSelector extends HTMLElement{
                 this.appendChild(selector);
             }
 
+            for(let button of this.querySelectorAll("button")){
+                button.onclick = ()=>{
+                    this.setAttribute("strand", button.strandName.slice(0, button.strandName.indexOf("Strand")));
+
+                    window[`${button.strandName.slice(0, button.strandName.indexOf("Strand"))}Obj`].display();
+                }
+            }
+
             strands[0].style.display = "flex";
         })
     }
@@ -36,11 +44,6 @@ class StrandSelector extends HTMLElement{
                 }else{
                     button.style.borderBottom = "none";
                     button.style.cursor = "pointer";
-                    button.onclick = ()=>{
-                        this.setAttribute("strand", button.strandName.slice(0, button.strandName.indexOf("Strand")));
-
-                        window[`${button.strandName.slice(0, button.strandName.indexOf("Strand"))}Obj`].display();
-                    }
                 }
             }
         })

+ 146 - 0
views/shared/graphs.js

@@ -0,0 +1,146 @@
+class LineGraph{
+    constructor(canvas, yName, xName, xData){
+        canvas.height = canvas.clientHeight;
+        canvas.width = canvas.clientWidth;
+
+        this.canvas = canvas;
+        this.context = canvas.getContext("2d");
+        this.left = canvas.clientWidth - (canvas.clientWidth * 0.9);
+        this.right = canvas.clientWidth * 0.9;
+        this.top = canvas.clientHeight - (canvas.clientHeight * 0.9);
+        this.bottom = canvas.clientHeight * 0.9;
+        this.data = [];
+        this.max = 0;
+        this.xName = xName;
+        this.yName = yName;
+        this.xData = xData;
+    }
+
+    drawGraph(){
+        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
+        this.drawYAxis();
+        this.drawXAxis();
+
+        for(let dataSet of this.data){
+            this.drawData(dataSet.set);
+        }
+    }
+
+    addData(data){
+        this.data.push(data);
+
+        let isNewMax = false;
+        for(let point of data.set){
+            if(point > this.max){
+                this.max = point;
+                isNewMax = true;
+            }
+        }
+
+        if(isNewMax){
+            this.verticalMultiplier = (this.bottom - this.top) / this.max;
+            this.horizontalMultiplier = (this.right - this.left) / data.set.length;
+            
+            this.xData.dataLength = data.set.length;
+
+            this.drawGraph();
+        }else{
+            this.drawData(data.set);
+        }
+    }
+
+    removeData(id){
+        for(let i = 0; i < this.data.length; i++){
+            if(this.data[i].id === id){
+                this.data.splice(i, 1);
+                break;
+            }
+        }
+
+        this.drawGraph();
+    }
+
+    drawData(dataSet){
+        let redRand = Math.floor(Math.random() * 200);
+        let greenRand = Math.floor(Math.random() * 200);
+        let blueRand = Math.floor(Math.random() * 200);
+
+        for(let i = 0; i < dataSet.length - 1; i++){
+            this.context.beginPath();
+            this.context.moveTo(this.left + (this.horizontalMultiplier * i), this.bottom - (this.verticalMultiplier * dataSet[i]));
+            this.context.lineTo(this.left + (this.horizontalMultiplier * (i + 1)), this.bottom - (this.verticalMultiplier * dataSet[i + 1]));
+            this.context.lineWidth = 1;
+            this.context.strokeStyle = `rgb(${redRand}, ${greenRand}, ${blueRand})`;
+            this.context.stroke();
+        }
+    }
+
+    drawXAxis(){
+        this.context.beginPath();
+        this.context.moveTo(this.left, this.bottom);
+        this.context.lineTo(this.right, this.bottom);
+        this.context.lineWidth = 2;
+        this.context.stroke();
+
+        this.context.font = "25px Arial";
+        this.context.fillText(this.xName, this.right / 2, this.bottom + 50);
+
+        this.context.setLineDash([5, 10]);
+        this.context.font = "10px Arial";
+        this.context.lineWidth = 1;
+
+        if(this.xData.type = "date"){
+            let diff = Math.abs(Math.floor((Date.UTC(this.xData.start.getFullYear(), this.xData.start.getMonth(), this.xData.start.getDate()) - Date.UTC(this.xData.end.getFullYear(), this.xData.end.getMonth(), this.xData.end.getDate())) / (1000 * 60 * 60 * 24)));
+            let showDate = this.xData.start;
+
+            for(let i = 0; i < this.xData.dataLength; i += Math.floor(this.xData.dataLength / 10)){
+                this.context.fillText(showDate.toLocaleDateString("en-US", {month: "short", day: "numeric", year: "2-digit"}), this.left + (this.horizontalMultiplier * i) - 20, this.bottom + 15);
+
+                this.context.beginPath()
+                this.context.moveTo(this.left + (this.horizontalMultiplier * i), this.bottom);
+                this.context.lineTo(this.left + (this.horizontalMultiplier * i), this.top);
+                this.context.strokeStyle = "#a5a5a5";
+                this.context.stroke();
+
+                showDate.setDate(showDate.getDate() + Math.abs(diff / 10));
+            }
+        }
+
+        this.context.strokeStyle = "black";
+        this.context.setLineDash([]);
+    }
+
+    drawYAxis(){
+        this.context.beginPath();
+        this.context.moveTo(this.left, this.top);
+        this.context.lineTo(this.left, this.bottom);
+        this.context.lineWidth = 2;
+        this.context.stroke();
+
+        this.context.font = "25px Arial";
+        this.context.fillText(this.yName, 0, this.bottom / 2);
+
+        this.context.setLineDash([5, 10]);
+        this.context.font = "10px Arial";
+        this.context.lineWidth = 1;
+
+        let axisNum = 0;
+        let verticalIncrement = (this.bottom - this.top) / 10;
+        let verticalOffset = 0;
+        do{
+            this.context.fillText(Math.round(axisNum).toString(), this.left - 20, this.bottom - verticalOffset + 3);
+
+            this.context.beginPath();
+            this.context.moveTo(this.left, this.bottom - verticalOffset);
+            this.context.lineTo(this.right, this.bottom - verticalOffset);
+            this.context.strokeStyle = "#a5a5a5";
+            this.context.stroke();
+
+            verticalOffset += verticalIncrement;
+            axisNum += this.max / 10;
+        }while(verticalOffset <= (this.bottom - this.top));
+
+        this.context.strokeStyle = "black";
+        this.context.setLineDash([]);
+    }
+}

+ 7 - 1
views/shared/header.ejs

@@ -1,10 +1,16 @@
 <div class="header">
     <a class="logo" href="http://www.thesubline.com" >
         <img src="/shared/images/logo.png" alt="Subline">
-        <h1>SUBLINE</h1>
+        <div class='header-logo'> SUBLINE </div>
     </a>
     
     <% if(locals.merchant || locals.data){ %>
         <a class="logout" href="/logout">Log out</a>
+    <% }else{ %>
+        <div class="public-buttons">
+            <button class="button" onclick="loginObj.display()"> Log In </button>
+    
+            <a class="button-join link" onclick="registerObj.display()"> Or Join </a>
+        </div>
     <% } %>
 </div>

+ 94 - 25
views/shared/shared.css

@@ -13,6 +13,30 @@ body{
 }
 
 /* General style that should apply to all pages */
+h1 {
+    text-align: center;
+    padding-bottom: 13px;
+
+}
+
+h3 {
+    text-align: center;
+    font-weight: 500;
+    color: gray;
+}
+
+.link {
+    cursor: pointer;
+    color: gray;
+    text-decoration: none;
+}
+
+.link:hover {
+    color: #ff636b;
+    text-decoration: underline;
+    cursor: pointer;
+}
+
 table{
     border-spacing: 0;
 }
@@ -41,22 +65,34 @@ table{
         background: rgb(240, 252, 255);
     }
 
+    .clickableRow{
+        cursor: pointer;
+        transition: 0.3s;
+    }
+
+        .clickableRow:hover{
+            position: relative;
+            z-index: 2;
+            box-shadow: 0 0 25px black;
+            border-radius: 50px;
+        }
+
 form{
     display: flex;
     flex-direction: column;
     justify-content: center;
     border: 2px solid rgb(0, 27, 45);
-    padding: 25px;
+    padding: 50px;
     border-radius: 10px;
     margin: 10px;
     background: rgb(240, 252, 255);
-    box-shadow: 1px 1px 1px rgb(0, 27, 45);
+    font-size: 16px;
+    margin-top: 40px;
+    width: 550px;
+    justify-content: space-evenly;
+    height: auto;
 }
 
-    form > *{
-        margin: 10px;
-    }
-
 .buttonBox{
     display: flex;
     justify-content: space-between;
@@ -68,26 +104,39 @@ form{
     }
 
 .button{
-    background: none;
-    font-family:'Saira',sans-serif;
-    border: 5px solid rgb(255, 99, 107);
+    display: initial;
+    background: rgb(255, 99, 107);
+    border: none;
     text-decoration: none;
-    border-radius: 10px;
-    padding: 5px;
-    color: rgb(0, 27, 45);
+    border-radius: 4px;
+    padding: 10px 29px;
+    color: white;
     cursor: pointer;
-    font-size: 20px;
-    font-weight: bold;
-    box-shadow: 2px 2px 2px black;
+    font-size: 25px;
     transition: 0.3s;
     text-align: center;
-}
+    font-size: 18px;
+    cursor: pointer;
+    font-weight: 500;
+    margin-right: 33px;
+} 
 
-    .button:hover{
-        background: rgb(0, 27, 45);
-        color: rgb(240, 252, 255);
+    .buttonWithBorder {
+        background: white;
+        border: rgb(255, 99, 107) solid 2px;
+        color: rgb(255, 99, 107);
+        margin: 0;
+        margin-top: 18px;
+        margin-bottom: 12px;
+        padding-top: 14px;
+        padding-bottom: 14px;
     }
 
+.button:hover{
+    background: rgb(243, 77, 86);
+    color: white;
+}
+
 .button-small{
     background: none;
     border: 2px solid rgb(255, 99, 107);
@@ -102,6 +151,12 @@ form{
     transition: 0.3s; 
 }
 
+.public-buttons {
+    position: inherit;
+    align-self: center;
+    margin-right: 39px;
+}
+
 .buttonBox{
     display: flex;
     justify-content: space-around;
@@ -128,9 +183,6 @@ form{
     margin: 30px 0;
 }
 
-.input-error{
-    border-color: red;
-}
 
 .strand, .action{
     display: none;
@@ -174,13 +226,20 @@ strand-selector{
         display: flex;
         align-items: center;
         text-decoration: none;
-        margin-left: 5px;
+        margin-left: 20px;
+    }
+
+    .header-logo{
+        display: inline-block;
+        color: rgb(255, 99, 107);
+        font-size: 25px;
+        font-weight: 600;
     }
 
     .header img{
         display: inline-block;
-        max-height: 65px;
-        margin: 5px;
+        max-height: 40px;
+        margin: 15px;
         text-align: center;
     }
 
@@ -198,6 +257,12 @@ strand-selector{
         text-decoration: none;
     }
 
+    .button-join {
+        font-size: medium;
+        color:white;
+        text-decoration: blink;
+    }
+
 /* Banner partial */
 .banner{
     width: 100%;
@@ -254,4 +319,8 @@ strand-selector{
         overflow: hidden;
         text-overflow: ellipsis;
     }
+}
+
+label {
+    margin-top:20px ;
 }

+ 27 - 0
views/shared/validation.js

@@ -110,6 +110,33 @@ let validator = {
         }
     },
 
+    transaction: {
+        date: function(from, to = new Date(), createBanner = true){
+            let errors = [];
+            let today = new Date();
+
+            if(from > to){
+                errors.push("Starting date must be before ending date");
+            }
+
+            if(from > today || to > today){
+                errors.push("Cannot choose a date in the future");
+            }
+
+            if(errors.length > 0){
+                if(createBanner){
+                    for(let error of errors){
+                        banner.createError(error);
+                    }
+
+                    return false;
+                }
+            }
+
+            return true;
+        }
+    },
+
     isSanitary: function(str){
         let disallowed = ["\\", "<", ">", "$", "{", "}", "(", ")"];