diff options
author | Mark Powers <markppowers0@gmail.com> | 2020-10-07 08:45:32 -0500 |
---|---|---|
committer | Mark Powers <markppowers0@gmail.com> | 2020-10-07 08:45:32 -0500 |
commit | 98da11b940c194f5e4bd423cb57d252df6185715 (patch) | |
tree | a6b55f19fe08be5cc68033fee2b72c53ac269170 /src | |
parent | 0712bdcc1e9c67bdde0a89c94ca5d72822ead854 (diff) |
Add budget goals
Diffstat (limited to 'src')
-rw-r--r-- | src/index.html | 35 | ||||
-rw-r--r-- | src/index.js | 18 | ||||
-rw-r--r-- | src/login.html | 15 | ||||
-rw-r--r-- | src/main.js | 22 | ||||
-rw-r--r-- | src/server.js | 41 |
5 files changed, 124 insertions, 7 deletions
diff --git a/src/index.html b/src/index.html index ef86835..08c5007 100644 --- a/src/index.html +++ b/src/index.html @@ -18,6 +18,7 @@ <div> <button v-bind:class="{ bold: activeTab == 0 }" v-on:click="setTab(0)">Ledger</button> <button v-bind:class="{ bold: activeTab == 1 }" v-on:click="setTab(1)">Summary</button> + <button v-bind:class="{ bold: activeTab == 2 }" v-on:click="setTab(2)">Goals</button> </div> <!-- Ledger --> @@ -64,7 +65,6 @@ <th>Amount</th> <th>Category</th> <th>Subcategory</th> - </tr> <tr> <td></td> @@ -148,6 +148,39 @@ </table> </div> </div> + + <!-- Goals --> + <div v-if="activeTab == 2"> + <div> + <div class="newItem"> + <span>New Goal</span> + <input v-model="ng.name" placeholder="Name"> + <input v-model="ng.total" placeholder="Total" type="number" step="0.01"> + <button v-on:click="post(ng, '/goals')">Add</button> + </div> + <div class="newAllocation"> + <span>Allocate funds</span> + <select v-model="na.name"> + <option v-for="option in goals" v-bind:value="option.name"> + {{ option.name }} + </option> + <input v-model="na.amount" type="number"> + <span>out of {{total_to_allocate}}</span> + </select> + <button v-on:click="post(na, '/allocate')">Add</button> + </div> + <table> + <tr><th></th><th>Name</th><th>Amount</th><th>Total</th><th>Remaining</th></tr> + <tr v-for="(goal, i) in goals"> + <td class="table-index">{{i+1}}</td> + <td>{{goal.name}}</td> + <td>{{goal.amount}}</td> + <td>{{goal.total}}</td> + <td>{{goal.total - goal.amount}}</td> + </tr> + </table> + </div> + </div> </div> </body> diff --git a/src/index.js b/src/index.js index f783076..bf64586 100644 --- a/src/index.js +++ b/src/index.js @@ -72,6 +72,24 @@ function setUpModels() { allowNull: false, }, }), + "goals": database.define('goal', { + username: { + type: Sequelize.STRING, + allowNull: false, + }, + name: { + type: Sequelize.STRING, + allowNull: false, + }, + total: { + type: Sequelize.DECIMAL, + allowNull: false, + }, + amount: { + type: Sequelize.DECIMAL, + allowNull: false, + } + }), "users": database.define('user', { username: { type: Sequelize.STRING, diff --git a/src/login.html b/src/login.html index d1dbe1d..ec41762 100644 --- a/src/login.html +++ b/src/login.html @@ -7,9 +7,11 @@ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <link rel="stylesheet" type="text/css" href="/css/styles.css"> <script> + let usernameEl = document.getElementById('username'); + let passwordEl = document.getElementById('password'); function sendPost(){ - let username = document.getElementById('username').value; - let password = document.getElementById('password').value; + let username = usernameEl.value; + let password = passwordEl.value; fetch(new Request("/login", { method: 'POST', headers: { @@ -23,6 +25,13 @@ window.location = "/"; }); } + let onEnterEvent = function(event) { + if (event.keyCode === 13) { + sendPost() + } + } + usernameEl.addEventListener("keyup", onEnterEvent); + passwordEl.addEventListener("keyup", onEnterEvent); </script> </head> @@ -30,7 +39,7 @@ <div> <h1>Login</h1> <div class="form"> - <input type="text" placeholder="Enter Username" name="username" id="username" required> + <input on type="text" placeholder="Enter Username" name="username" id="username" required> <input type="password" placeholder="Enter Password" name="password" id="password" required> <button onclick="sendPost()">Log in</button> </div> diff --git a/src/main.js b/src/main.js index b5e6b86..78b918e 100644 --- a/src/main.js +++ b/src/main.js @@ -6,6 +6,8 @@ window.onload = function () { transactions: [], summary: {username : ""}, selTodoType: "all", + total_to_allocate: 0, + goals: [] }, methods: { setTab: function (value) { @@ -26,6 +28,15 @@ window.onload = function () { category: "", subcategory: "", } + this.ng = { + name: "", + total: "", + amount: 0 + } + this.na = { + selected: "", + amount: "" + } }, requestThenUpdate: function (request) { fetch(request) @@ -81,6 +92,8 @@ window.onload = function () { }, created() { this.clearData(); + fetch(new Request(`/goals`)).then(response => response.json()) + .then(response => this.goals = response); fetch(new Request(`/transaction`)).then(response => response.json()) .then(response => this.transactions = response); fetch(new Request(`/summary`)).then(response => response.json()) @@ -160,6 +173,12 @@ window.onload = function () { // Note we flip these since income is negative item.negative = el.s > 0 item.positive = el.s < 0 + + // -= since its flipped + this.total_to_allocate -= item.net + }) + this.goals.forEach(el => { + this.total_to_allocate -= el.amount }) this.summary.week.sort(function(a, b){ @@ -173,6 +192,9 @@ window.onload = function () { this.summary.year.sort(function(a, b){ return a.y-b.y; }) + + seriesX = this.summary.month.map(el => el.y) + this.summary.username = response.username }); diff --git a/src/server.js b/src/server.js index 53db084..69d3968 100644 --- a/src/server.js +++ b/src/server.js @@ -14,7 +14,7 @@ server.use(bodyParser.json()); //server.use(bodyParser.urlencoded({ extended: true })); function listen(port) { - server.listen(port, () => console.info(`Listening on port ${port}!`)); + server.listen(port, () => console.info(`Listening: http://localhost:${port} `)); } function hashWithSalt(password, salt){ @@ -36,7 +36,6 @@ function setUpRoutes(models, jwtFunctions, database) { try { const decryptedUserId = jwtFunctions.verify(cookie); var user = await models.users.findOne({ where: { username: decryptedUserId } }); - // .then((user, error) => { if (user) { res.locals.user = user.get({ plain: true }); } else { @@ -44,7 +43,6 @@ function setUpRoutes(models, jwtFunctions, database) { res.redirect('/login'); return; } - // }); } catch (e) { res.status(400).send(e.message); } @@ -128,6 +126,43 @@ function setUpRoutes(models, jwtFunctions, database) { res.status(400).send(e.message); } }) + server.get(`/goals`, async (req, res, next) => { + try { + var result = await database.query("SELECT * FROM goals WHERE username = '" + res.locals.user.username + "' ORDER BY `name` DESC", { type: database.QueryTypes.SELECT }) + res.status(200).send(result); + next(); + } catch (e) { + console.log(e) + res.status(400).send(e.message); + } + }) + server.post(`/goals`, async (req, res, next) => { + try { + let item = req.body; + console.log(item); + item.username = res.locals.user.username + await models.goals.create(item); + var result = await database.query("SELECT * FROM goals WHERE username = '" + res.locals.user.username + "' ORDER BY `name` DESC", { type: database.QueryTypes.SELECT }) + res.status(200).send(result); + } catch (e) { + console.log(e); + res.status(400).send(e.message); + } + }) + server.post(`/allocate`, async (req, res, next) => { + try { + let name = req.body.name; + let amount = req.body.amount; + var toUpdate = await models.goals.findOne({ where: { name: name, username:res.locals.user.username } }); + var update = {amount: toUpdate.amount + amount} + await toUpdate.update(update); + var result = await await database.query("SELECT * FROM goals WHERE username = '" + res.locals.user.username + "' ORDER BY `name` DESC", { type: database.QueryTypes.SELECT }) + res.status(200).send(result); + } catch (e) { + console.log(e); + res.status(400).send(e.message); + } + }) server.get(`/summary`, async (req, res, next) => { try { res.status(200).send({ |