Compare commits
No commits in common. "378751ecedd9a1382aef05cbb15c3aa4636235a7" and "6133aca0ef3967c56c88d7f3e181724a28f28dd1" have entirely different histories.
378751eced
...
6133aca0ef
1
package-lock.json
generated
1
package-lock.json
generated
@ -14,7 +14,6 @@
|
|||||||
"bootstrap": "^5.1.3",
|
"bootstrap": "^5.1.3",
|
||||||
"gridjs": "^5.0.2",
|
"gridjs": "^5.0.2",
|
||||||
"gridjs-react": "^5.0.2",
|
"gridjs-react": "^5.0.2",
|
||||||
"lodash": "^4.17.21",
|
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-bootstrap": "^2.1.2",
|
"react-bootstrap": "^2.1.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
|
|||||||
@ -9,7 +9,6 @@
|
|||||||
"bootstrap": "^5.1.3",
|
"bootstrap": "^5.1.3",
|
||||||
"gridjs": "^5.0.2",
|
"gridjs": "^5.0.2",
|
||||||
"gridjs-react": "^5.0.2",
|
"gridjs-react": "^5.0.2",
|
||||||
"lodash": "^4.17.21",
|
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-bootstrap": "^2.1.2",
|
"react-bootstrap": "^2.1.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
|
|||||||
@ -1,26 +1,10 @@
|
|||||||
import { useEffect, useContext } from 'react';
|
|
||||||
import mockedData from '../mocked/MockedData';
|
import mockedData from '../mocked/MockedData';
|
||||||
import BudgetCardView from '../views/BudgetCardView';
|
import BudgetCardView from '../views/BudgetCardView';
|
||||||
import { BudgetContext, BudgetState } from '../data/context/BudgetContext';
|
|
||||||
import './App.css';
|
import './App.css';
|
||||||
|
|
||||||
const AppImpl = () => {
|
function App() {
|
||||||
const context = useContext(BudgetContext);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
context.api.loadData(mockedData.budgetPeriods);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BudgetCardView />
|
<BudgetCardView budgetPeriods={mockedData.ranges} />
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const App = (props) => {
|
|
||||||
return (
|
|
||||||
<BudgetState>
|
|
||||||
<AppImpl {...props}/>
|
|
||||||
</BudgetState>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,27 +0,0 @@
|
|||||||
import { useReducer, createContext } from 'react';
|
|
||||||
import BudgetReducer from './BudgetReducer';
|
|
||||||
|
|
||||||
const BudgetContext = createContext();
|
|
||||||
|
|
||||||
const BudgetState = (props) => {
|
|
||||||
const initialState = {
|
|
||||||
budgetPeriods: []
|
|
||||||
},
|
|
||||||
[state, dispatch] = useReducer(BudgetReducer, initialState),
|
|
||||||
api = {
|
|
||||||
loadData: (data) => {
|
|
||||||
dispatch({ type: 'budget/populate', data });
|
|
||||||
},
|
|
||||||
updateBillPaid: (periodId, billId) => {
|
|
||||||
dispatch({ type: 'budget/period/bills/update', data: { periodId, billId }});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<BudgetContext.Provider value={{...state, api}}>
|
|
||||||
{props.children}
|
|
||||||
</BudgetContext.Provider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export { BudgetState, BudgetContext };
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
const BudgetReducer = (state, action) => {
|
|
||||||
if (action.type === 'budget/populate') {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
budgetPeriods: action.data
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (action.type === 'budget/period/bills/update') {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
budgetPeriods: state.budgetPeriods.map(bp => ({...bp,
|
|
||||||
bills: bp.bills.map(b => ({...b,
|
|
||||||
paid: (bp.id === action.data.periodId && b.id === action.data.billId) ? !b.paid : b.paid
|
|
||||||
}))
|
|
||||||
}))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {...state };
|
|
||||||
};
|
|
||||||
|
|
||||||
export default BudgetReducer;
|
|
||||||
@ -8,4 +8,4 @@ ReactDOM.render(
|
|||||||
<App />
|
<App />
|
||||||
</React.StrictMode>,
|
</React.StrictMode>,
|
||||||
document.getElementById('root')
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,30 +1,26 @@
|
|||||||
const mockedData = {
|
const mockedData = {
|
||||||
budgetPeriods: [{
|
ranges: [{
|
||||||
id: 1,
|
id: 1,
|
||||||
locked: true,
|
locked: true,
|
||||||
startDate: new Date('1-7-2022 0:0:0'),
|
startDate: new Date('1-7-2022 0:0:0'),
|
||||||
endDate: new Date('1-20-2022 23:59:59'),
|
endDate: new Date('1-20-2022 23:59:59'),
|
||||||
startingAmount: 0.00,
|
startingAmount: 0.00,
|
||||||
bills: [{
|
bills: [{
|
||||||
id: 1,
|
|
||||||
description: 'Amazon purchase',
|
description: 'Amazon purchase',
|
||||||
amount: 46.00,
|
amount: 46.00,
|
||||||
paid: false
|
paid: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
|
||||||
description: 'Bill 1',
|
description: 'Bill 1',
|
||||||
amount: 40.00,
|
amount: 40.00,
|
||||||
paid: true
|
paid: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 3,
|
|
||||||
description: 'Bill 2',
|
description: 'Bill 2',
|
||||||
amount: 50.00,
|
amount: 50.00,
|
||||||
paid: true
|
paid: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 4,
|
|
||||||
description: 'Bill 3',
|
description: 'Bill 3',
|
||||||
amount: 30.00,
|
amount: 30.00,
|
||||||
paid: true
|
paid: true
|
||||||
@ -43,25 +39,21 @@ const mockedData = {
|
|||||||
endDate: new Date('2-3-2022 23:59:59'),
|
endDate: new Date('2-3-2022 23:59:59'),
|
||||||
startingAmount: 0.00,
|
startingAmount: 0.00,
|
||||||
bills: [{
|
bills: [{
|
||||||
id: 5,
|
|
||||||
description: 'Amazon purchase',
|
description: 'Amazon purchase',
|
||||||
amount: 46.00,
|
amount: 46.00,
|
||||||
paid: false
|
paid: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 6,
|
|
||||||
description: 'Bill 1',
|
description: 'Bill 1',
|
||||||
amount: 40.00,
|
amount: 40.00,
|
||||||
paid: true
|
paid: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 7,
|
|
||||||
description: 'Bill 2',
|
description: 'Bill 2',
|
||||||
amount: 50.00,
|
amount: 50.00,
|
||||||
paid: true
|
paid: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 8,
|
|
||||||
description: 'Bill 3',
|
description: 'Bill 3',
|
||||||
amount: 30.00,
|
amount: 30.00,
|
||||||
paid: true
|
paid: true
|
||||||
@ -80,25 +72,21 @@ const mockedData = {
|
|||||||
endDate: new Date('2-17-2022 23:59:59'),
|
endDate: new Date('2-17-2022 23:59:59'),
|
||||||
startingAmount: 0.00,
|
startingAmount: 0.00,
|
||||||
bills: [{
|
bills: [{
|
||||||
id: 9,
|
|
||||||
description: 'Amazon purchase',
|
description: 'Amazon purchase',
|
||||||
amount: 46.00,
|
amount: 46.00,
|
||||||
paid: false
|
paid: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 10,
|
|
||||||
description: 'Bill 1',
|
description: 'Bill 1',
|
||||||
amount: 40.00,
|
amount: 40.00,
|
||||||
paid: true
|
paid: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 11,
|
|
||||||
description: 'Bill 2',
|
description: 'Bill 2',
|
||||||
amount: 50.00,
|
amount: 50.00,
|
||||||
paid: true
|
paid: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 12,
|
|
||||||
description: 'Bill 3',
|
description: 'Bill 3',
|
||||||
amount: 30.00,
|
amount: 30.00,
|
||||||
paid: true
|
paid: true
|
||||||
@ -117,25 +105,21 @@ const mockedData = {
|
|||||||
endDate: new Date('3-3-2022 23:59:59'),
|
endDate: new Date('3-3-2022 23:59:59'),
|
||||||
startingAmount: 0.00,
|
startingAmount: 0.00,
|
||||||
bills: [{
|
bills: [{
|
||||||
id: 13,
|
|
||||||
description: 'Amazon purchase',
|
description: 'Amazon purchase',
|
||||||
amount: 46.00,
|
amount: 46.00,
|
||||||
paid: false
|
paid: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 14,
|
|
||||||
description: 'Bill 1',
|
description: 'Bill 1',
|
||||||
amount: 40.00,
|
amount: 40.00,
|
||||||
paid: true
|
paid: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 15,
|
|
||||||
description: 'Bill 2',
|
description: 'Bill 2',
|
||||||
amount: 50.00,
|
amount: 50.00,
|
||||||
paid: true
|
paid: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 16,
|
|
||||||
description: 'Bill 3',
|
description: 'Bill 3',
|
||||||
amount: 30.00,
|
amount: 30.00,
|
||||||
paid: true
|
paid: true
|
||||||
@ -154,25 +138,21 @@ const mockedData = {
|
|||||||
endDate: new Date('3-17-2022 23:59:59'),
|
endDate: new Date('3-17-2022 23:59:59'),
|
||||||
startingAmount: 0.00,
|
startingAmount: 0.00,
|
||||||
bills: [{
|
bills: [{
|
||||||
id: 17,
|
|
||||||
description: 'Amazon purchase',
|
description: 'Amazon purchase',
|
||||||
amount: 46.00,
|
amount: 46.00,
|
||||||
paid: false
|
paid: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 18,
|
|
||||||
description: 'Bill 1',
|
description: 'Bill 1',
|
||||||
amount: 40.00,
|
amount: 40.00,
|
||||||
paid: true
|
paid: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 19,
|
|
||||||
description: 'Bill 2',
|
description: 'Bill 2',
|
||||||
amount: 50.00,
|
amount: 50.00,
|
||||||
paid: true
|
paid: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 20,
|
|
||||||
description: 'Bill 3',
|
description: 'Bill 3',
|
||||||
amount: 30.00,
|
amount: 30.00,
|
||||||
paid: true
|
paid: true
|
||||||
|
|||||||
@ -1,16 +1,13 @@
|
|||||||
import _ from 'lodash';
|
import BudgetPeriodCard from "./BudgetPeriodCard";
|
||||||
import BudgetPeriodCard from './BudgetPeriodCard';
|
|
||||||
import { BudgetContext } from '../data/context/BudgetContext'
|
|
||||||
import { useContext } from 'react';
|
|
||||||
import './BudgetCardView.scss';
|
import './BudgetCardView.scss';
|
||||||
|
|
||||||
const BudgetCardView = () => {
|
const BudgetCardView = ({budgetPeriods}) => {
|
||||||
const context = useContext(BudgetContext),
|
const activePeriod = budgetPeriods.find(p => !p.locked);
|
||||||
activePeriod = context?.budgetPeriods?.find?.(p => !p.locked);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="budget-card-view-tray">
|
<div className="budget-card-view-tray">
|
||||||
{context?.budgetPeriods?.map?.(p => {
|
{budgetPeriods.map(p => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BudgetPeriodCard key={p.id} periodData={p} isActive={p === activePeriod} />
|
<BudgetPeriodCard key={p.id} periodData={p} isActive={p === activePeriod} />
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,24 +1,19 @@
|
|||||||
import { useState, useEffect, useRef, useContext } from 'react';
|
import { useState, useEffect, useRef } from 'react';
|
||||||
import BudgetPeriodTransTable from './BudgetPeriodTransTable';
|
import BudgetPeriodTransTable from './BudgetPeriodTransTable';
|
||||||
import Lock from '../resources/Lock.svg';
|
import Lock from '../resources/Lock.svg';
|
||||||
import OpenLock from '../resources/OpenLock.svg';
|
import OpenLock from '../resources/OpenLock.svg';
|
||||||
import './BudgetPeriodCard.scss';
|
import './BudgetPeriodCard.scss';
|
||||||
import { BudgetContext } from '../data/context/BudgetContext';
|
|
||||||
|
|
||||||
const BudgetPeriodCard = ({periodData, isActive}) => {
|
const BudgetPeriodCard = ({periodData, isActive}) => {
|
||||||
const cardRef = useRef(),
|
const cardRef = useRef(),
|
||||||
context = useContext(BudgetContext),
|
|
||||||
[bankBalance, setBankBalance] = useState(0),
|
[bankBalance, setBankBalance] = useState(0),
|
||||||
[projectedLeftover, setProjectedLeftover] = useState(0),
|
[projectedLeftover, setProjectedLeftover] = useState(0),
|
||||||
paidBills = periodData.bills.filter((bill) => bill.paid),
|
[bills, setBills] = useState(periodData.bills),
|
||||||
unpaidBills = periodData.bills.filter((bill) => !bill.paid),
|
[paidBills, setPaidBills] = useState([]),
|
||||||
|
[unpaidBills, setUnpaidBills] = useState([]),
|
||||||
[incomes, setIncomes] = useState(periodData.income),
|
[incomes, setIncomes] = useState(periodData.income),
|
||||||
[paidIncomes, setPaidIncomes] = useState([]),
|
[paidIncomes, setPaidIncomes] = useState([]),
|
||||||
[unpaidIncomes, setUnpaidIncomes] = useState([]),
|
[unpaidIncomes, setUnpaidIncomes] = useState([]);
|
||||||
moveTransItemAction = (row) => {
|
|
||||||
const data = row.cells[2].data
|
|
||||||
context.api.updateBillPaid(periodData.id, data.id);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(isActive) {
|
if(isActive) {
|
||||||
@ -26,6 +21,8 @@ const BudgetPeriodCard = ({periodData, isActive}) => {
|
|||||||
cardRef.current.parentElement.scrollBy(-40, 0);
|
cardRef.current.parentElement.scrollBy(-40, 0);
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
useEffect(() => { setPaidBills(bills.filter((bill) => bill.paid)); }, [bills]);
|
||||||
|
useEffect(() => { setUnpaidBills(bills.filter((bill) => !bill.paid)); }, [bills]);
|
||||||
useEffect(() => { setPaidIncomes(incomes.filter((income) => income.paid)); }, [incomes]);
|
useEffect(() => { setPaidIncomes(incomes.filter((income) => income.paid)); }, [incomes]);
|
||||||
useEffect(() => { setUnpaidIncomes(incomes.filter((income) => !income.paid)); }, [incomes]);
|
useEffect(() => { setUnpaidIncomes(incomes.filter((income) => !income.paid)); }, [incomes]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -64,9 +61,9 @@ const BudgetPeriodCard = ({periodData, isActive}) => {
|
|||||||
<span className='bank-projected-label'>Projected Leftover</span>
|
<span className='bank-projected-label'>Projected Leftover</span>
|
||||||
<span className='bank-projected-value'>{ '$' + parseFloat(projectedLeftover).toFixed(2) }</span>
|
<span className='bank-projected-value'>{ '$' + parseFloat(projectedLeftover).toFixed(2) }</span>
|
||||||
</div>
|
</div>
|
||||||
<BudgetPeriodTransTable title={'Unpaid'} transList={ unpaidBills } actionHandler={moveTransItemAction} isBill />
|
<BudgetPeriodTransTable title={'Unpaid'} transList={ unpaidBills } isBill />
|
||||||
<BudgetPeriodTransTable title={'Paid'} transList={ paidBills } actionHandler={moveTransItemAction} isBill />
|
<BudgetPeriodTransTable title={'Paid'} transList={ paidBills } isBill />
|
||||||
<BudgetPeriodTransTable title={'Income'} transList={ incomes } isPaid />
|
<BudgetPeriodTransTable title={'Income'} transList={ incomes } />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
margin: 1em;
|
margin: 1em;
|
||||||
width: 400px;
|
width: 300px;
|
||||||
.card-header {
|
.card-header {
|
||||||
height: 3em;
|
height: 3em;
|
||||||
background-color: #ccc;
|
background-color: #ccc;
|
||||||
|
|||||||
@ -1,24 +1,11 @@
|
|||||||
import { Grid } from 'gridjs-react';
|
import { Grid } from 'gridjs-react';
|
||||||
import { h } from 'gridjs';
|
|
||||||
import './BudgetPeriodTransTable.scss';
|
import './BudgetPeriodTransTable.scss';
|
||||||
import '../../node_modules/gridjs/dist/theme/mermaid.css'
|
import '../../node_modules/gridjs/dist/theme/mermaid.css'
|
||||||
|
|
||||||
const BudgetPeriodTransTable = ({title, transList, isBill, actionHandler}) => {
|
const BudgetPeriodTransTable = ({title, transList, isBill}) => {
|
||||||
const columns = [
|
const columns = ['Description', 'Amount'],
|
||||||
'Description',
|
|
||||||
'Amount',
|
|
||||||
{
|
|
||||||
name: 'Actions',
|
|
||||||
formatter: (cell, row) => {
|
|
||||||
return h('button', {
|
|
||||||
className: 'py-2 mb-4 px-4 border rounded-md text-white bg-blue-600',
|
|
||||||
onClick: () => actionHandler(row)
|
|
||||||
}, row.cells[2].data.paid ? 'Unpay' : 'Pay');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
toCurrency = (amount) => { return '$' + (isBill === true ? '-' : '') + amount; },
|
toCurrency = (amount) => { return '$' + (isBill === true ? '-' : '') + amount; },
|
||||||
tableData = transList.map(t => { return [t.description, toCurrency(t.amount), t]});
|
tableData = transList.map(t => { return [t.description, toCurrency(t.amount)]});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='budget-period-trans-table'>
|
<div className='budget-period-trans-table'>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user