Quick Transaction

main
jveebs 3 years ago
parent ab1db7dbae
commit e90e8d413e

@ -13,24 +13,7 @@ const AddExpenseForm = (props) => {
const [transactionType, setTransactionType] = useState('expenses'); const [transactionType, setTransactionType] = useState('expenses');
useEffect(() => { useEffect(() => {
try { getCategoryList();
fetch('https://api.bb.gabefarrell.com/w/budget', {
method: 'GET',
headers: {
'x-session-key' : getSessionKey(),
}
})
.then(response => response.json())
.then(data => {
if (data.status != 200) {
console.log(data.error);
} else {
getCategoryList();
}
})
} catch(error) {
console.error(error);
}
}, [transactionType]) }, [transactionType])
const toggleTransactionType = () => { const toggleTransactionType = () => {
@ -42,32 +25,43 @@ const AddExpenseForm = (props) => {
} }
const getCategoryList = () => { const getCategoryList = () => {
fetch('https://api.bb.gabefarrell.com/w/budget', { if (transactionType == "expenses") {
method: 'GET', fetch('https://api.bb.gabefarrell.com/w/budget', {
headers: { method: 'GET',
'x-session-key' : getSessionKey(), headers: {
} 'x-session-key' : getSessionKey(),
}) }
.then(response => response.json()) })
.then(data => { .then(response => response.json())
if (data.status != 200) { .then(data => {
console.log(data.error); if (data.status != 200) {
} else { console.log(data.error);
let categories = []; } else {
let categories = Object.keys(data.expenses_by_category).length > 0 ? Object.keys(data.expenses_by_category) : ["Uncategorized"];
Object.values(data.expenses).map((transactions) => {
transactions.forEach(transaction => { setCategoryList(categories);
if (transaction.type == transactionType && !categories.includes(transaction.category)) { setCategory(categories[0])
categories.push(transaction.category) }
} })
}); } else {
}); fetch('https://api.bb.gabefarrell.com/w/income', {
method: 'GET',
if (categories.length == 0) categories = ["Uncategorized"]; headers: {
setCategoryList(categories); 'x-session-key' : getSessionKey(),
setCategory(categories[0]) }
} })
}) .then(response => response.json())
.then(data => {
if (data.status != 200) {
console.log(data.error);
} else {
let categories = Object.keys(data.income_by_category).length > 0 ? Object.keys(data.income_by_category) : ["Uncategorized"];
setCategoryList(categories);
setCategory(categories[0])
}
})
}
}; };
const onSubmit = (event) => { const onSubmit = (event) => {
@ -92,8 +86,6 @@ const AddExpenseForm = (props) => {
formData.append('decimal', decimal); formData.append('decimal', decimal);
formData.append('type', transactionType) formData.append('type', transactionType)
console.log(transactionType);
try { try {
fetch(`https://api.bb.gabefarrell.com/w/transactions?whole=${whole}&decimal=${decimal}&currency=${currency}&category=${category}&type=${transactionType}`, { fetch(`https://api.bb.gabefarrell.com/w/transactions?whole=${whole}&decimal=${decimal}&currency=${currency}&category=${category}&type=${transactionType}`, {
method: 'POST', method: 'POST',
@ -113,7 +105,6 @@ const AddExpenseForm = (props) => {
} catch(error) { } catch(error) {
console.error(error); console.error(error);
} }
setCost(''); setCost('');
}; };
@ -128,6 +119,10 @@ const AddExpenseForm = (props) => {
} }
} }
const quickSet = (event) => {
setCost(event.target.value)
}
return ( return (
<div className='widget'> <div className='widget'>
<h4>Add Transaction</h4> <h4>Add Transaction</h4>
@ -159,19 +154,44 @@ const AddExpenseForm = (props) => {
</select> </select>
</div> </div>
</div> </div>
<div className='row mt-3'>
<div className='row mt-2'>
<div className='col'>
<button className='btn btn-outline-success m-right' value={1} onClick={quickSet}>
$1
</button>
<button className='btn btn-outline-success m-right' value={5} onClick={quickSet}>
$5
</button>
<button className='btn btn-outline-success m-right' value={10} onClick={quickSet}>
$10
</button>
<button className='btn btn-outline-success m-right' value={15} onClick={quickSet}>
$15
</button>
<button className='btn btn-outline-success m-right' value={20} onClick={quickSet}>
$20
</button>
<button className='btn btn-outline-success m-right' value={50} onClick={quickSet}>
$50
</button>
</div>
</div>
<div className='row mt-2'>
<div className='col-sm'> <div className='col-sm'>
<button type='submit' onClick={onSubmit} className='btn btn-primary' style={{marginRight:"12px"}}> <button className='btn btn-dark m-right' onClick={toggleTransactionType}>
{transactionType.toUpperCase()}
</button>
<button type='submit' onClick={onSubmit} id="add-transaction-button" className='btn btn-primary m-right'>
Add {transactionType.substring(0, 1).toUpperCase() + transactionType.substring(1)} Add {transactionType.substring(0, 1).toUpperCase() + transactionType.substring(1)}
</button> </button>
<button className='btn btn-primary' onClick={handleAddCategory} style={{marginRight:"12px"}}> <button className='btn btn-primary' onClick={handleAddCategory}>
Add New Category Add New Category
</button> </button>
<button onClick={toggleTransactionType}>
{transactionType.toUpperCase()}
</button>
</div> </div>
</div> </div>
</div> </div>
); );
}; };

@ -8,9 +8,11 @@ import { Minimize } from "@material-ui/icons";
ChartJS.register(ArcElement, Tooltip, Legend); ChartJS.register(ArcElement, Tooltip, Legend);
export default function CategorizedExpenses() { export default function CategorizedExpenses(props) {
const [chartData, setChartData] = useState(null); const [chartData, setChartData] = useState(null);
useEffect(() => { useEffect(() => {
async function getChartData() { async function getChartData() {
try { try {
@ -25,30 +27,24 @@ export default function CategorizedExpenses() {
if (data.status != 200) { if (data.status != 200) {
console.log(data.error); console.log(data.error);
} else { } else {
let categories = [];
let values = [];
Object.values(data.expenses).map((transactions) => {
let cost = 0;
categories.push(transactions[0].category)
transactions.forEach(transaction => {
cost += calculateValue(transaction.amount);
});
values.push(cost);
});
if (categories.length == 0) categories = [`No expenses`];
const chartData = { const chartData = {
labels: categories, labels: Object.keys(data.expenses_by_category).length > 0 ? Object.keys(data.expenses_by_category) : ["No income."],
datasets: [{ datasets: [{
data: values, data: Object.values(data.expenses_by_category).map((category) => {
return calculateValue(category);
}),
label: "Category", label: "Category",
backgroundColor: [ backgroundColor: [
'#FFC857', '#FFC857',
'#ED8146', '#5C919B',
'#DB3A34', '#DB3A34',
'#F6A54F',
'#61B06E',
'#8166CC',
'#ED8146',
'#B0BC63',
'#5672C7', '#5672C7',
'#E45E3D'
], ],
borderColor: [ borderColor: [
"white" "white"
@ -68,7 +64,7 @@ export default function CategorizedExpenses() {
} }
} }
getChartData(); getChartData();
}); }, []);
if (!chartData) { if (!chartData) {
return <p>Loading...</p> return <p>Loading...</p>

@ -8,13 +8,13 @@ import { Minimize } from "@material-ui/icons";
ChartJS.register(ArcElement, Tooltip, Legend); ChartJS.register(ArcElement, Tooltip, Legend);
export default function CategorizedIncome() { export default function CategorizedExpenses(props) {
const [chartData, setChartData] = useState(null); const [chartData, setChartData] = useState(null);
useEffect(() => { useEffect(() => {
async function getChartData() { async function getChartData() {
try { try {
fetch('https://api.bb.gabefarrell.com/w/budget', { fetch('https://api.bb.gabefarrell.com/w/income', {
method: 'GET', method: 'GET',
headers: { headers: {
'x-session-key' : getSessionKey(), 'x-session-key' : getSessionKey(),
@ -25,27 +25,32 @@ export default function CategorizedIncome() {
if (data.status != 200) { if (data.status != 200) {
console.log(data.error); console.log(data.error);
} else { } else {
const chartData = { const chartData = {
labels: Object.keys(data.income).length > 0 ? Object.keys(data.income) : [ "no income"], labels: Object.keys(data.income_by_category).length > 0 ? Object.keys(data.income_by_category) : ["No income."],
datasets: [ datasets: [{
{ data: Object.values(data.income_by_category).map((category) => {
data: Object.values(data.income_by_category).map(category => { return calculateValue(category);
return calculateValue(category); }),
}), label: "Total cost",
backgroundColor: [ backgroundColor: [
'#FFC857', '#61B06E',
'#ED8146', '#8166CC',
'#DB3A34', '#ED8146',
'#5672C7', '#B0BC63',
], '#5672C7',
borderColor: [ '#E45E3D',
"white" '#FFC857',
], '#5C919B',
borderWidth: 2, '#DB3A34',
}, '#F6A54F'
], ],
borderColor: [
"white"
],
borderWidth: 2,
}],
} }
setChartData(chartData); setChartData(chartData);
} }
}) })

@ -0,0 +1,168 @@
import React, { useContext, useEffect, useState } from 'react';
import { AppContext } from '../context/AppContext';
import { v4 as uuidv4 } from 'uuid';
import './AddExpenseForm.css'
import { getSessionKey } from '../utils/utils.js'
export default function QuickTransaction(props) {
const { dispatch } = useContext(AppContext);
const [cost, setCost] = useState('');
const [category, setCategory] = useState('');
const [categoryList, setCategoryList] = useState([]);
const [transactionType, setTransactionType] = useState('expenses');
useEffect(() => {
getCategoryList();
}, [transactionType])
const toggleTransactionType = () => {
if (transactionType == "expenses") {
setTransactionType("income");
} else {
setTransactionType("expenses");
}
}
const getCategoryList = () => {
if (transactionType == "expenses") {
fetch('https://api.bb.gabefarrell.com/w/budget', {
method: 'GET',
headers: {
'x-session-key' : getSessionKey(),
}
})
.then(response => response.json())
.then(data => {
if (data.status != 200) {
console.log(data.error);
} else {
let categories = Object.keys(data.expenses_by_category).length > 0 ? Object.keys(data.expenses_by_category) : ["Uncategorized"];
setCategoryList(categories);
setCategory(categories[0])
}
})
} else {
fetch('https://api.bb.gabefarrell.com/w/income', {
method: 'GET',
headers: {
'x-session-key' : getSessionKey(),
}
})
.then(response => response.json())
.then(data => {
if (data.status != 200) {
console.log(data.error);
} else {
let categories = Object.keys(data.income_by_category).length > 0 ? Object.keys(data.income_by_category) : ["Uncategorized"];
setCategoryList(categories);
setCategory(categories[0])
}
})
}
};
const onSubmit = (event) => {
event.preventDefault();
const formData = new FormData();
let currency = "USD"
let whole = 0;
let decimal = 0;
if (cost.includes(".")) {
whole = parseInt(cost.split(".")[0]);
decimal = parseInt(cost.split(".")[1]);
} else {
whole = parseInt(cost);
}
formData.append('category', category)
formData.append('currency', currency);
formData.append('whole', whole);
formData.append('decimal', decimal);
formData.append('type', transactionType)
try {
fetch(`https://api.bb.gabefarrell.com/w/transactions?whole=${whole}&decimal=${decimal}&currency=${currency}&category=${category}&type=${transactionType}`, {
method: 'POST',
body: formData,
headers: {
'x-session-key' : getSessionKey(),
}
})
.then(response => response.json())
.then(data => {
if (data.status != 200) {
console.log(data.error);
} else {
}
})
} catch(error) {
console.error(error);
}
setCost('');
};
const handleAddCategory = () => {
const newCategory = prompt('Enter the new category name:');
if (newCategory) {
if (categoryList.indexOf(newCategory) == -1) {
const newCategories = [...categoryList, newCategory];
setCategoryList(newCategories);
}
setCategory(newCategory);
}
}
return (
<div className='widget'>
<h4>Add Transaction</h4>
<div className='row'>
<div className='col-md col-lg-4'>
<label htmlFor='cost'>Cost</label>
<input
required='required'
type='number'
className='form-control'
id='cost'
min="0.00"
step=".01"
value={cost}
onChange={(event) => setCost(event.target.value)}
/>
</div>
<div className='col-md col-lg-4'>
<label htmlFor='category-select'>Category</label>
<select className="form-select" id='category-select'
value={category}
onChange={(event) => setCategory(event.target.value)}>
{categoryList.map((category) => (
<option key={category} value={category}>
{category}
</option>
))}
</select>
</div>
</div>
<div className='row mt-3'>
<div className='col-sm'>
<button type='submit' onClick={onSubmit} id="add-transaction-button" className='btn btn-primary' style={{marginRight:"12px"}}>
Add {transactionType.substring(0, 1).toUpperCase() + transactionType.substring(1)}
</button>
<button className='btn btn-primary' onClick={handleAddCategory} style={{marginRight:"12px"}}>
Add New Category
</button>
<button onClick={toggleTransactionType}>
{transactionType.toUpperCase()}
</button>
</div>
</div>
</div>
);
};

@ -1,4 +1,5 @@
import React from 'react'; import React from 'react';
import { useState } from 'react'
import 'bootstrap/dist/css/bootstrap.min.css'; import 'bootstrap/dist/css/bootstrap.min.css';
import { AppProvider } from '../context/AppContext'; import { AppProvider } from '../context/AppContext';
@ -8,12 +9,14 @@ import ExpenseList from '../components/ExpenseList';
import AddExpenseForm from '../components/AddExpenseForm'; import AddExpenseForm from '../components/AddExpenseForm';
import RemainingBudget from '../components/Remaining'; import RemainingBudget from '../components/Remaining';
import AddIncome from '../components/AddIncome' import AddIncome from '../components/AddIncome'
import QuickTransaction from '../components/QuickTransaction'
import CategorizedExpenses from '../components/CategorizedExpenses'; import CategorizedExpenses from '../components/CategorizedExpenses';
import CategorizedIncome from '../components/CategorizedIncome'; import CategorizedIncome from '../components/CategorizedIncome';
import { Typography } from '@mui/material'; import { Typography } from '@mui/material';
export default function Dashboard() { export default function Dashboard() {
return (
return (
<AppProvider> <AppProvider>
<div className='container-fluid'> <div className='container-fluid'>
<div className='row align-items-stretch'> <div className='row align-items-stretch'>
@ -30,21 +33,19 @@ export default function Dashboard() {
<div className='row mt-3'> <div className='row mt-3'>
<div className='col'> <div className='col'>
<ExpenseList /> <AddExpenseForm/>
</div> </div>
</div>
<div className='row mt-3'>
<div className='col'> <div className='col'>
<AddExpenseForm /> <ExpenseList />
</div> </div>
</div> </div>
<div className='row mt-3'> <div className='row mt-3'>
<div className='col-12 col-lg-6'> <div className='col-12 col-lg-6'>
<CategorizedExpenses type={"expenses"}/> <CategorizedExpenses/>
</div> </div>
<div className='col-12 col-lg-6'> <div className='col-12 col-lg-6'>
<CategorizedExpenses type={"income"}/> <CategorizedIncome/>
</div> </div>
</div> </div>
</div> </div>

@ -49,3 +49,7 @@ code {
background-color: #5672C7 !important; background-color: #5672C7 !important;
border-color: #4766C2 !important; border-color: #4766C2 !important;
} }
.m-right {
margin-right: 10px;
}

@ -40,6 +40,6 @@ export function handleLogout() {
window.location.href='/welcome'; window.location.href='/welcome';
} }
export function calculateValue(amount) { export function calculateValue(category) {
return amount.whole + amount.decimal * 0.01; return category.whole + category.decimal * 0.01;
} }
Loading…
Cancel
Save