From 5448ba665a257c46130c4b7cff5d0ab689ed2dd2 Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 23 Apr 2023 21:30:44 -0400 Subject: [PATCH] Functionality of Widgets --- package-lock.json | 70 +++++-------- package.json | 1 + src/components/CategorizedExpenses.js | 1 + src/components/ExpenseList.js | 120 +++++++++++++++++++---- src/components/Remaining.js | 135 ++++++++++++++++++++++---- src/components/ViewBudget.js | 42 ++++++-- src/context/AppContext.js | 2 +- src/index.js | 4 +- src/pages/Dashboard.jsx | 6 +- 9 files changed, 281 insertions(+), 100 deletions(-) diff --git a/package-lock.json b/package-lock.json index 90d2aac..3be9923 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/package.json b/package.json index 195b87b..ca93a5f 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/components/CategorizedExpenses.js b/src/components/CategorizedExpenses.js index f45bc98..53ff2c1 100644 --- a/src/components/CategorizedExpenses.js +++ b/src/components/CategorizedExpenses.js @@ -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' diff --git a/src/components/ExpenseList.js b/src/components/ExpenseList.js index 520667b..468de76 100644 --- a/src/components/ExpenseList.js +++ b/src/components/ExpenseList.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 = ` + ${data1[i]} + ${data2[i]} + ` + 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 (
@@ -26,16 +108,14 @@ const ExpenseList = () => { placeholder='Type to search...' onChange={handleChange} /> */} -

Expenses

- + +

Recent Transactions

+ {/*

{category}

+

{transaction}

*/} + + +
+
); }; diff --git a/src/components/Remaining.js b/src/components/Remaining.js index 77d5117..370dfcc 100644 --- a/src/components/Remaining.js +++ b/src/components/Remaining.js @@ -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 ( -
- - Budget Remaining: ${budget - totalExpenses} -
+ <> + {/* + Current Balance: ${data} */} + {/* */} +

{budget}

+
+ setWhole(event.target.value)} + required /> + +
+ + ); -}; - -export default RemainingBudget; +}; \ No newline at end of file diff --git a/src/components/ViewBudget.js b/src/components/ViewBudget.js index 31fe56b..c53ee6a 100644 --- a/src/components/ViewBudget.js +++ b/src/components/ViewBudget.js @@ -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 ( <> {/* @@ -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 /> + + diff --git a/src/context/AppContext.js b/src/context/AppContext.js index 10761f0..b409ccc 100644 --- a/src/context/AppContext.js +++ b/src/context/AppContext.js @@ -49,4 +49,4 @@ export const AppProvider = (props) => { {props.children} ); -}; +}; \ No newline at end of file diff --git a/src/index.js b/src/index.js index 94660bc..af99b24 100644 --- a/src/index.js +++ b/src/index.js @@ -9,13 +9,13 @@ import Main from './Main.js' function App() { return ( - + // COMMENTED OUT BY CHRIS TO FIX MULTIPLE TABLE DISPLAYED IN RECENT TRANSACTION
-
+ //
praying I didn't break the project tbh ); } diff --git a/src/pages/Dashboard.jsx b/src/pages/Dashboard.jsx index 3190118..723da7a 100644 --- a/src/pages/Dashboard.jsx +++ b/src/pages/Dashboard.jsx @@ -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() {
-
+
- + {/* */}