Homework: Online/Offline Budget Trackers Add functionality to our existing Budget Tracker application to allow for offline access and functionality. The user will be able to add expenses and deposits...

1 answer below »

Homework: Online/Offline Budget Trackers


Add functionality to our existing Budget Tracker application to allow for offline access and functionality.


The user will be able to add expenses and deposits to their budget with or without a connection. When entering transactions offline, they should populate the total when brought back online.


Offline Functionality:




  • Enter deposits offline




  • Enter expenses offline




When brought back online:



  • Offline entries should be added to tracker.



User Story


AS AN avid traveller I WANT to be able to track my withdrawals and deposits with or without a data/internet connection SO THAT my account balance is accurate when I am traveling



Business Context


Giving users a fast and easy way to track their money is important, but allowing them to access that information anytime is even more important. Having offline functionality is paramount to our applications success.



Acceptance Criteria


GIVEN a user is on Budget App without an internet connection WHEN the user inputs a withdrawal or deposit THEN that will be shown on the page, and added to their transaction history when their connection is back online.




Develop/models/transaction.js const mongoose = require("mongoose"); const Schema = mongoose.Schema; const transactionSchema = new Schema( { name: { type: String, trim: true, required: "Enter a name for transaction" }, value: { type: Number, required: "Enter an amount" }, date: { type: Date, default: Date.now } } ); const Transaction = mongoose.model("Transaction", transactionSchema); module.exports = Transaction; Develop/package.json { "name": "budget-app", "version": "1.0.0", "description": "", "main": "server.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "node server.js", "lite-server": "lite-server" }, "repository": { "type": "git", "url": "git+https://github.com/coding-boot-camp/unit18hw.git" }, "author": "", "license": "ISC", "bugs": { "url": "https://github.com/coding-boot-camp/unit18hw/issues" }, "homepage": "https://github.com/coding-boot-camp/unit18hw#readme", "dependencies": { "compression": "^1.7.4", "express": "^4.17.1", "lite-server": "^2.5.3", "mongoose": "^5.5.15", "morgan": "^1.9.1" } } Develop/public/icons/icon-192x192.png Develop/public/icons/icon-512x512.png Develop/public/index.html Your total is: $0 Add Funds Subtract Funds TransactionAmount Develop/public/index.js let transactions = []; let myChart; fetch("/api/transaction") .then(response => { return response.json(); }) .then(data => { // save db data on global variable transactions = data; populateTotal(); populateTable(); populateChart(); }); function populateTotal() { // reduce transaction amounts to a single total value let total = transactions.reduce((total, t) => { return total + parseInt(t.value); }, 0); let totalEl = document.querySelector("#total"); totalEl.textContent = total; } function populateTable() { let tbody = document.querySelector("#tbody"); tbody.innerHTML = ""; transactions.forEach(transaction => { // create and populate a table row let tr = document.createElement("tr"); tr.innerHTML = ` ${transaction.name} ${transaction.value} `; tbody.appendChild(tr); }); } function populateChart() { // copy array and reverse it let reversed = transactions.slice().reverse(); let sum = 0; // create date labels for chart let labels = reversed.map(t => { let date = new Date(t.date); return `${date.getMonth() + 1}/${date.getDate()}/${date.getFullYear()}`; }); // create incremental values for chart let data = reversed.map(t => { sum += parseInt(t.value); return sum; }); // remove old chart if it exists if (myChart) { myChart.destroy(); } let ctx = document.getElementById("myChart").getContext("2d"); myChart = new Chart(ctx, { type: 'line', data: { labels, datasets: [{ label: "Total Over Time", fill: true, backgroundColor: "#6666ff", data }] } }); } function sendTransaction(isAdding) { let nameEl = document.querySelector("#t-name"); let amountEl = document.querySelector("#t-amount"); let errorEl = document.querySelector(".form .error"); // validate form if (nameEl.value === "" || amountEl.value === "") { errorEl.textContent = "Missing Information"; return; } else { errorEl.textContent = ""; } // create record let transaction = { name: nameEl.value, value: amountEl.value, date: new Date().toISOString() }; // if subtracting funds, convert amount to negative number if (!isAdding) { transaction.value *= -1; } // add to beginning of current array of data transactions.unshift(transaction); // re-run logic to populate ui with new record populateChart(); populateTable(); populateTotal(); // also send to server fetch("/api/transaction", { method: "POST", body: JSON.stringify(transaction), headers: { Accept: "application/json, text/plain, */*", "Content-Type": "application/json" } }) .then(response => { return response.json(); }) .then(data => { if (data.errors) { errorEl.textContent = "Missing Information"; } else { // clear form nameEl.value = ""; amountEl.value = ""; } }) .catch(err => { // fetch failed, so save in indexed db saveRecord(transaction); // clear form nameEl.value = ""; amountEl.value = ""; }); } document.querySelector("#add-btn").onclick = function() { sendTransaction(true); }; document.querySelector("#sub-btn").onclick = function() { sendTransaction(false); }; Develop/public/styles.css body { font-size: 120%; font-family: Arial; } button, input { font-size: 100%; font-family: Arial; } table { width: 100%; } td, th { border: 1px solid #dddddd; text-align: left; padding: 8px; } tr:nth-child(even) { background-color: #dddddd; } .error { color: red; } .wrapper { margin: 0 auto; max-width: 825px; text-align: center; } .total { font-size: 150%; text-decoration: underline; } .form { margin-top: 25px; width: 100%; } .transactions { text-align: left; max-height: 300px; overflow: auto; width: 90%; margin: 0 auto; } Develop/routes/api.js const router = require("express").Router(); const Transaction = require("../models/transaction.js"); router.post("/api/transaction", ({body}, res) => { Transaction.create(body) .then(dbTransaction => { res.json(dbTransaction); }) .catch(err => { res.status(404).json(err); }); }); router.post("/api/transaction/bulk", ({body}, res) => { Transaction.insertMany(body) .then(dbTransaction => { res.json(dbTransaction); }) .catch(err => { res.status(404).json(err); }); }); router.get("/api/transaction", (req, res) => { Transaction.find({}).sort({date: -1}) .then(dbTransaction => { res.json(dbTransaction); }) .catch(err => { res.status(404).json(err); }); }); module.exports = router; Develop/server.js const express = require("express"); const logger = require("morgan"); const mongoose = require("mongoose"); const compression = require("compression"); const PORT = 3000; const app = express(); app.use(logger("dev")); app.use(compression()); app.use(express.urlencoded({ extended: true })); app.use(express.json()); app.use(express.static("public")); mongoose.connect("mongodb://localhost/budget", { useNewUrlParser: true, useFindAndModify: false }); // routes app.use(require("./routes/api.js")); app.listen(PORT, () => { console.log(`App running on port ${PORT}!`); });
Answered Same DayApr 25, 2021

Answer To: Homework: Online/Offline Budget Trackers Add functionality to our existing Budget Tracker...

Sanghamitra answered on Apr 28 2021
143 Votes
PWA-Budget-Tracker/models/transaction.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const transactionSchema = new Schema({
name: {
type: String,
trim: true,
required: "Enter a name for transaction"
},
value: {
type: Number,
required: "Enter an amount"
},
date: {
type: Date,
default: Date.now
}
});
const Transaction = mongoose.model("Transaction", transactionSchema);
module.exports = Transaction;
PWA-Budget-Tracker/public/db.js
let db;
const request = indexedDB.open("budget", 1);
request.onupgradeneeded = function (event) {
const db = event.target.result;
db.createObjectStore("pending", { autoIncrement: true });
};
request.onsuccess = function (event) {
db = event.target.result;
// check if app is online before reading from db
if (navigator.onLine) {
checkDatabase();
}
};
request.onerror = function (event) {
console.log("Woops! " + event.target.errorCode);
};
function saveRecord(record) {
const transaction = db.transaction(["pending"], "readwrite");
const store = transaction.objectStore("pending");
store.add(record);
}
function checkDatabase() {
const transaction = db.transaction(["pending"], "readwrite");
const store = transaction.objectStore("pending");
const getAll = store.getAll();
getAll.onsuccess = function () {
if (getAll.result.length > 0) {
fetch("/api/transaction/bulk", {
method: "POST",
body: JSON.stringify(getAll.result),
headers: {
Accept: "application/json, text/plain, */*",
"Content-Type": "application/json"
}
})
.then(response => response.json())
.then(() => {
// delete records if successful
const transaction = db.transaction(["pending"], "readwrite");
const store = transaction.objectStore("pending");
store.clear();
});
}
};
}
function deletePending() {
const transaction = db.transaction(["pending"], "readwrite");
const store = transaction.objectStore("pending");
store.clear();
}
// listen for app coming back online
window.addEventListener("online", checkDatabase);
PWA-Budget-Tracker/public/index.html


Your total is: $0


Transaction Name:

Transaction Amount:


Add Deposits

Subtract Expense



        Transaction        Amount









PWA-Budget-Tracker/public/index.js
let transactions = [];
let myChart;
fetch("/api/transaction")
.then(response => response.json())
.then(data => {
// save db data on global variable
transactions = data;
populateTotal();
populateTable();
populateChart();
});
function populateTotal() {
// reduce transaction amounts to a single total value
const total = transactions.reduce((total, t) => {
return total + parseInt(t.value);
}, 0);
const totalEl = document.querySelector("#total");
totalEl.textContent = total;
}
function populateTable() {
const tbody = document.querySelector("#tbody");
tbody.innerHTML = "";
transactions.forEach(transaction => {
// create and populate a table row
const tr = document.createElement("tr");
tr.innerHTML = `
${transaction.name}
${transaction.value}
`;
tbody.appendChild(tr);
});
}
function...
SOLUTION.PDF

Answer To This Question Is Available To Download

Related Questions & Answers

More Questions »

Submit New Assignment

Copy and Paste Your Assignment Here