Functionality of Widgets

main
Chris 3 years ago
parent 377ac40bd6
commit 5448ba665a

70
package-lock.json generated

@ -21,6 +21,7 @@
"axios": "^1.3.5",
"bootstrap": "^5.2.3",
"chart.js": "^4.2.1",
"ng2-charts": "^4.1.1",
"react": "^18.0.0",
"react-bootstrap": "^2.7.4",
"react-bootstrap-validation": "^0.1.11",
@ -4436,41 +4437,6 @@
"tslib": "^2.4.0"
}
},
"node_modules/@testing-library/dom": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.2.0.tgz",
"integrity": "sha512-xTEnpUKiV/bMyEsE5bT4oYA0x0Z/colMtxzUY8bKyPXBNLn/e0V4ZjBZkEhms0xE4pv9QsPfSRu9AWS4y5wGvA==",
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.10.4",
"@babel/runtime": "^7.12.5",
"@types/aria-query": "^5.0.1",
"aria-query": "^5.0.0",
"chalk": "^4.1.0",
"dom-accessibility-api": "^0.5.9",
"lz-string": "^1.5.0",
"pretty-format": "^27.0.2"
},
"engines": {
"node": ">=14"
}
},
"node_modules/@testing-library/dom/node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"peer": true,
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/@testing-library/jest-dom": {
"version": "5.16.5",
"resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz",
@ -12915,6 +12881,11 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/lodash-es": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
},
"node_modules/lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
@ -13260,6 +13231,22 @@
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
},
"node_modules/ng2-charts": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/ng2-charts/-/ng2-charts-4.1.1.tgz",
"integrity": "sha512-iHwXDbmX86lfeH8VRcsaW2tJATsuAZo4kvvC/Yk2l35zOHjevja1qBvO6BAibiDazi9r9aS6ZRJOqWPsz1pP2w==",
"dependencies": {
"lodash-es": "^4.17.15",
"tslib": "^2.3.0"
},
"peerDependencies": {
"@angular/cdk": ">=14.0.0",
"@angular/common": ">=14.0.0",
"@angular/core": ">=14.0.0",
"chart.js": "^3.4.0 || ^4.0.0",
"rxjs": "^6.5.3 || ^7.4.0"
}
},
"node_modules/no-case": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
@ -17328,19 +17315,6 @@
"is-typedarray": "^1.0.0"
}
},
"node_modules/typescript": {
"version": "4.9.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=4.2.0"
}
},
"node_modules/unbox-primitive": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",

@ -16,6 +16,7 @@
"axios": "^1.3.5",
"bootstrap": "^5.2.3",
"chart.js": "^4.2.1",
"ng2-charts": "^4.1.1",
"react": "^18.0.0",
"react-bootstrap": "^2.7.4",
"react-bootstrap-validation": "^0.1.11",

@ -1,6 +1,7 @@
import { Doughnut } from "react-chartjs-2";
import { Chart as ChartJS, ArcElement, Tooltip, Legend, defaults } from 'chart.js';
import { AppProvider } from "../context/AppContext";
import { useState, useEffect } from 'react'
import { calculateValue, getSessionKey } from '../utils/utils.js'

@ -2,21 +2,103 @@ import React, { useContext, useState, useEffect } from 'react';
import ExpenseItem from './ExpenseItem';
import { AppContext } from '../context/AppContext';
const ExpenseList = () => {
const { expenses } = useContext(AppContext);
const [whole, setWhole] = useState('');
const [decimal, setDecimal] = useState('');
const [transaction, setTransactions] = useState('');
const [category, setCategories] = useState('');
function getSessionKey() {
var cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim(); // Remove any leading or trailing whitespace
if (cookie.startsWith('session=')) {
return cookie.substring('session='.length, cookie.length); // Extract the value of the cookie
}
}
return null;
}
async function getTransactionsBalance() {
try {
const response = await fetch('https://api.bb.gabefarrell.com/w/transactions/recent', {
method: 'GET',
headers: {
'x-session-key': getSessionKey(),
},
});
const data = await response.json();
let whole = data.transactions.map((item)=>item.amount.whole);
let decimal = data.transactions.map((item)=>item.amount.decimal);
let balance = [];
for (let i = 0; i < whole.length; i++) {
let expense_balance = whole[i] + '.' + decimal[i];
balance.push(expense_balance);
}
//console.log(whole + decimal + "<- total recent transacations");
//console.log(whole, decimal, balance);
//const transactions_balance = whole + '.' + decimal;
//console.log(whole, decimal, category);
return balance;
} catch (error) {
console.error(error);
}
}
async function getTransactionsCategory() {
try {
const response = await fetch('https://api.bb.gabefarrell.com/w/transactions/recent', {
method: 'GET',
headers: {
'x-session-key': getSessionKey(),
},
});
const data = await response.json();
const category = data.transactions.map((item)=>item.category);
//console.log(category);
return category;
} catch (error) {
console.error(error);
}
}
async function buildTable(data1, data2){
var table = document.getElementById('myTable')
for (var i = 0; i < data1.length; i++){
var row = `<tr>
<td>${data1[i]}</td>
<td>${data2[i]}</td>
</tr>`
table.innerHTML += row
}
}
buildTable(category, transaction);
async function fetchTransactions() {
const categories = await getTransactionsCategory();
const transaction_balance = await getTransactionsBalance();
const [filteredExpenses, setfilteredExpenses] = useState(expenses || []);
setCategories(categories);
setTransactions(transaction_balance);
}
useEffect(() => {
setfilteredExpenses(expenses);
}, [expenses]);
fetchTransactions(); //b36efa01-7824-4f61-a274-63131b58d8fe
}, [])
const handleChange = (event) => {
const searchResults = expenses.filter((filteredExpense) =>
filteredExpense.name.toLowerCase().includes(event.target.value)
);
setfilteredExpenses(searchResults);
};
return (
<div className='widget'>
@ -26,16 +108,14 @@ const ExpenseList = () => {
placeholder='Type to search...'
onChange={handleChange}
/> */}
<h4>Expenses</h4>
<ul className='list-group mt-3 mb-3'>
{filteredExpenses.map((expense) => (
<ExpenseItem
id={expense.id}
name={expense.name}
cost={expense.cost}
/>
))}
</ul>
<h4>Recent Transactions</h4>
{/* <h4>{category}</h4>
<h4>{transaction}</h4> */}
<table><tbody id="myTable">
</tbody></table>
</div>
);
};

@ -1,23 +1,124 @@
import React, { useContext } from 'react';
import { AppContext } from '../context/AppContext';
import logo from './widget_logos/budget_logo.png';
import './css/Remaining.css'
import React, {useState, useEffect} from 'react';
import './css/ViewBudget.css'
import logo from './widget_logos/current_balance_logo.png';
const RemainingBudget = () => {
const { expenses, budget } = useContext(AppContext);
export default function Remaining() {
const [budget, setBudget] = useState('');
const [whole, setWhole] = useState('');
const [decimal, setDecimal] = useState('');
const totalExpenses = expenses.reduce((total, item) => {
return (total += item.cost);
}, 0);
function getSessionKey() {
var cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim(); // Remove any leading or trailing whitespace
if (cookie.startsWith('session=')) {
return cookie.substring('session='.length, cookie.length); // Extract the value of the cookie
}
}
return null;
}
const alertType = totalExpenses > budget ? 'alert-danger' : 'alert-success';
async function getBudget() {
try {
const response = await fetch('https://api.bb.gabefarrell.com/w/budget', {
method: 'GET',
headers: {
'x-session-key': getSessionKey(),
},
});
const data = await response.json();
const whole = data.budget.whole;
const decimal = data.budget.decimal;
const budget_balance = whole + '.' + decimal;
console.log(budget_balance);
return budget_balance;
} catch (error) {
console.error(error);
}
}
async function getMonthlyExpenses() {
try {
const response = await fetch('https://api.bb.gabefarrell.com/w/expenses/month', {
method: 'GET',
headers: {
'x-session-key': getSessionKey(),
},
});
const data = await response.json();
const whole = data.whole;
const decimal = data.decimal;
const total_expenses = whole + '.' + decimal;
console.log(total_expenses + "<- Total Expenses");
return total_expenses;
} catch (error) {
console.error(error);
}
}
async function fetchBudget() {
const name = await getBudget();
const expenses = await getMonthlyExpenses();
const budget_remaining = (name - expenses).toFixed(2);
setBudget(budget_remaining);
}
useEffect(() => {
fetchBudget();
}, [])
function handleSubmit(event) {
event.preventDefault();
const budget = whole.split('.')
if (budget.length < 2)
budget.push(0);
else if (budget[1].length < 1)
budget.push(0);
var details = {
// 'currency' : currency,
'whole' : budget[0],
'decimal' : budget[1]
};
var formBody = []
for (var property in details) {
var encodedKey = encodeURIComponent(property);
var encodedValue = encodeURIComponent(details[property]);
formBody.push(encodedKey + "=" + encodedValue);
}
formBody = formBody.join("&");
fetch('https://api.bb.gabefarrell.com/w/budget', {
method: 'POST',
body: formBody,
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
'x-session-key': getSessionKey()
}
})
.then((response) => response.json())
.then((data) => {
console.log(data)
if (data.status == 200)
fetchBudget();
});
}
return (
<div className={`alert p-4 ${alertType} widget`}>
<img src={logo}></img>
<span>Budget Remaining: ${budget - totalExpenses}</span>
</div>
<>
{/* <img src={logo}></img>
<span>Current Balance: ${data}</span> */}
{/* <button onClick={apiGet()}> TEST</button> */}
<h1>{budget}</h1>
<form id="form" onSubmit={handleSubmit}>
<input
type = "text"
className="form-control"
placeholder="Enter Budget"
value={whole}
onChange={(event) => setWhole(event.target.value)}
required />
<button type="submit">Submit</button>
</form>
</>
);
};
export default RemainingBudget;
};

@ -1,11 +1,12 @@
import React, {useState, useEffect} from 'react';
import React, {useState, useEffect, useRef} from 'react';
import './css/ViewBudget.css'
import logo from './widget_logos/current_balance_logo.png';
export default function FetchAPI() {
const [whole, setWhole] = useState('');
const [decimal, setDecimal] = useState('')
const [decimal, setDecimal] = useState('');
const [balance, setBalance] = useState('');
const [error, setError] = useState(false);
function getSessionKey() {
var cookies = document.cookie.split(';');
@ -41,19 +42,36 @@ export default function FetchAPI() {
setBalance(name);
}
useEffect(() => {
fetchBalance();
}, [])
const handleBlur = (event) => {
const handleBlur = (event) => {
if (event.target.validity.patternMismatch) {
setError(true);
}
};
};
function handleSubmit(event) {
// const form = document.getElementById('form');
event.preventDefault();
// const payload = new FormData(form);
const balance = whole.split('.')
if (balance.length < 2)
balance.push(0);
else if (balance[1].length < 1)
balance.push(0);
console.log(whole);
const balance = whole.split('.')
console.log(balance)
if (balance.length < 2) {
balance.push('0');
}
else if (balance[1].length > 2) {
console.log("TEST SUCCESS")
}
else if (balance[1].length < 1) {
balance.push('0');
}
// console.log([...payload])
// const formData = new FormData();
// formData.append('whole', whole);
@ -86,6 +104,7 @@ export default function FetchAPI() {
fetchBalance();
});
}
return (
<>
{/* <img src={logo}></img>
@ -98,8 +117,13 @@ export default function FetchAPI() {
className="form-control"
placeholder="Enter Balance"
value={whole}
maxLength="10"
pattern="^[+]?[0-9]{1,3}(?:,?[0-9]{3})*(?:\.[0-9]{2})?"
title="Please enter the balance with two decimal places for cents. Please enter a balance 999999999.99"
onChange={(event) => setWhole(event.target.value)}
required />
<button type="submit">Submit</button>
</form>
</>

@ -49,4 +49,4 @@ export const AppProvider = (props) => {
{props.children}
</AppContext.Provider>
);
};
};

@ -9,13 +9,13 @@ import Main from './Main.js'
function App() {
return (
<React.StrictMode>
// <React.StrictMode> COMMENTED OUT BY CHRIS TO FIX MULTIPLE TABLE DISPLAYED IN RECENT TRANSACTION
<div className="app">
<ThemeProvider theme={theme}>
<Main/>
</ThemeProvider>
</div>
</React.StrictMode>
// </React.StrictMode> praying I didn't break the project tbh
);
}

@ -3,7 +3,7 @@ import { useState } from 'react'
import 'bootstrap/dist/css/bootstrap.min.css';
import { AppProvider } from '../context/AppContext';
import FetchAPI from '../components/Budget';
import FetchAPI from '../components/budget';
import ExpenseTotal from '../components/ExpenseTotal';
import ExpenseList from '../components/ExpenseList';
import AddExpenseForm from '../components/AddExpenseForm';
@ -24,11 +24,11 @@ export default function Dashboard() {
<div className='col-sm'>
<FetchAPI />
</div>
<div className='col-sm'>
<div className='col-sm widget d-flex align-items-center justify-content-between'>
<RemainingBudget />
</div>
<div className='col-sm'>
<ExpenseTotal />
{/* <ExpenseTotal /> */}
</div>
</div>

Loading…
Cancel
Save