mirror of
https://github.com/gabehf/BudgetBuddy.git
synced 2026-03-08 23:18:15 -07:00
Functionality of Widgets
This commit is contained in:
parent
377ac40bd6
commit
5448ba665a
9 changed files with 281 additions and 100 deletions
|
|
@ -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('');
|
||||
|
||||
const [filteredExpenses, setfilteredExpenses] = useState(expenses || []);
|
||||
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();
|
||||
|
||||
|
||||
|
||||
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…
Add table
Add a link
Reference in a new issue