diff --git a/src/App.js b/src/App.js index d6981bf..6bcc968 100644 --- a/src/App.js +++ b/src/App.js @@ -1,16 +1,19 @@ import React from 'react'; import './App.css'; import AppRouter from './routers/AppRouter'; +import {connect} from 'react-redux'; +import UserErrors from './components/UserErrors' // console.log(store.getState()) -const App = () => { +const App = ({errors}) => { console.log('You are running this application in ' + process.env.NODE_ENV + ' with parameters of ' + process.env.REACT_APP_ENV); return (
- + {errors && } +
); } -export default App; +export default connect(state => ({errors: state.errors}))(App); diff --git a/src/actions/accounts.js b/src/actions/accounts.js index 4070efb..8560c7d 100644 --- a/src/actions/accounts.js +++ b/src/actions/accounts.js @@ -1,4 +1,6 @@ -import database from '../firebase/firebase' +import database from '../firebase/firebase'; +import {addError} from './errors'; + export const addAccount = (account) => ({type: 'ADD_ACCOUNTS', account}); @@ -22,8 +24,10 @@ export const startAddAccount = (accountData = {}) => { dispatch(addAccount({ ...account })); - }).catch((err)=>{ - console.log(err) + }, (error) => { + console.error("error: " + error); + dispatch(addError({code: error.code,message:error.message})) + }); } @@ -46,6 +50,10 @@ export const startSetAccounts = () => { }) }); dispatch(setAccounts(accounts)); + }, (error) => { + console.error(error); + dispatch(addError({code: error.code,message:error.message})) + }); }; }; @@ -92,7 +100,9 @@ export const updateAccountBalance = (name, delta) => { } else if (!committed) { console.log('aborted the transaction'); } else { - dispatch(editAccount(name, {balance: snapshot.val()})); + dispatch(editAccount(name, { + balance: snapshot.val() + })); } }); } diff --git a/src/actions/categories.js b/src/actions/categories.js index 3919f08..b93b36f 100644 --- a/src/actions/categories.js +++ b/src/actions/categories.js @@ -1,4 +1,6 @@ -import database from '../firebase/firebase' +import database from '../firebase/firebase'; +import {addError} from './errors'; + export const addCategory = (category) => ({type: 'ADD_CATEGORIES', category}); @@ -26,9 +28,11 @@ export const startAddCategory = (categoryData = {}) => { id: ref.key, ...category })); - }) - .catch((err) => { - console.log(err) + }, + (error) => { + console.error(error); + dispatch(addError({code: error.code,message:error.message})) + }); } @@ -52,9 +56,11 @@ export const startSetCategories = () => { }) }); dispatch(setCategories(categories)); - }) - .catch((err) => { - console.log(err) + }, + (error) => { + console.error(error); + dispatch(addError({code: error.code,message:error.message})) + }); }; }; diff --git a/src/actions/errors.js b/src/actions/errors.js new file mode 100644 index 0000000..20a234b --- /dev/null +++ b/src/actions/errors.js @@ -0,0 +1,6 @@ + +export const addError = (error = {}) => ({type: 'ADD_ERROR', error}); + + + +export const resetError = () => ({type: 'RESET_ERROR'}); diff --git a/src/actions/transactions.js b/src/actions/transactions.js index 686b5d4..74fad08 100644 --- a/src/actions/transactions.js +++ b/src/actions/transactions.js @@ -1,9 +1,9 @@ -import database from '../firebase/firebase' +import database from '../firebase/firebase' import moment from 'moment'; import _ from 'lodash'; +import {addError} from './errors'; //{storage} - export const addTransaction = (transaction) => ({type: 'ADD_TRANSACTION', transaction}); export const startAddTransaction = (transactionData = {}) => { @@ -40,6 +40,9 @@ export const startAddTransaction = (transactionData = {}) => { id: ref.key, ...transaction })); + }, (error) => { + console.error("error: " + error); + dispatch(addError({code: error.code,message:error.message})) }); } @@ -47,7 +50,7 @@ export const startAddTransaction = (transactionData = {}) => { export const setTransactions = (transactions) => ({type: 'SET_TRANSACTIONS', transactions}); -export const startSetTransactions = ( fromMoment = moment().startOf('month').valueOf() , toMoment = moment().valueOf() ) => { +export const startSetTransactions = (fromMoment = moment().startOf('month').valueOf(), toMoment = moment().valueOf()) => { return (dispatch, getState) => { const user_uid = getState().auth.uid; @@ -65,7 +68,11 @@ export const startSetTransactions = ( fromMoment = moment().startOf('month').val ...childSnapshot.val() }) }); - dispatch(setTransactions( _.orderBy(transactions , ['date'] , ['desc']))); + dispatch(setTransactions(_.orderBy(transactions, ['date'], ['desc']))); + }, (error) => { + console.error(error); + dispatch(addError({code: error.code,message:error.message})) + }); }; }; @@ -80,6 +87,8 @@ export const startDeleteTransaction = ({id} = {}) => { .remove() .then(() => { dispatch(deleteTransaction({id})); + }, (error) => { + console.error(error); }); } }; diff --git a/src/components/AccountForm.js b/src/components/AccountForm.js index 38ebf6e..beab33b 100644 --- a/src/components/AccountForm.js +++ b/src/components/AccountForm.js @@ -5,7 +5,6 @@ import Button from 'material-ui/Button'; import {connect} from 'react-redux'; import Paper from 'material-ui/Paper'; - const styles = theme => ({ textField: { marginLeft: theme.spacing.unit, @@ -26,7 +25,6 @@ const styles = theme => ({ .mixins .gutters({ - paddingLeft: 0, paddingRight: 0, marginTop: theme.spacing.unit * 3, @@ -63,7 +61,30 @@ class AccountForm extends React.Component { if (!this.state.name || !this.state.balance) { this.setState(() => ({error: 'Please provide name and balance.'})); } else { - if (this.props.accounts.find((account) => account.name === this.state.name) === undefined) { + if (typeof this.props.accounts !== 'undefined' && this.props.accounts.length > 0) { + + if (this.props.accounts.find((account) => account.name === this.state.name) === undefined) { + this.setState(() => ({error: ''})); + this + .props + .onSubmit({ + name: this.state.name, + balance: parseFloat(this.state.balance, 10) * 100 + }); + } else { + if (this.state.submit_button_title === "Update") { + this + .props + .onSubmit({ + name: this.state.name, + balance: parseFloat(this.state.balance, 10) * 100 + }); + } else { + this.setState(() => ({name: '', balance: '', error: 'Account already exists'})); + } + } + + } else { this.setState(() => ({error: ''})); this .props @@ -71,8 +92,6 @@ class AccountForm extends React.Component { name: this.state.name, balance: parseFloat(this.state.balance, 10) * 100 }); - } else { - this.setState(() => ({name: '', balance: '' , error: 'Account already exists'})); } } }; diff --git a/src/components/AddFloatingButton.js b/src/components/AddFloatingButton.js index 6b3d97f..7ae4ce3 100644 --- a/src/components/AddFloatingButton.js +++ b/src/components/AddFloatingButton.js @@ -6,6 +6,7 @@ import Dialog, {DialogContent, DialogTitle} from 'material-ui/Dialog'; import TransactionFrom from './TransactionForm'; import {connect} from 'react-redux'; import {startAddTransaction} from '../actions/transactions'; +import {updateAccountBalance} from '../actions/accounts'; const styles = theme => ({ floatingButton: { @@ -73,7 +74,13 @@ class AddFloatingButton extends React.Component { } } const mapDispatchToProps = (dispatch) => ({ - startAddTransaction: (transaction) => dispatch(startAddTransaction(transaction)) + startAddTransaction: (transaction) => dispatch(startAddTransaction(transaction)).then(() => { + let delta = transaction.amount + if (transaction.type === 'Expense') { + delta = -delta + } + dispatch(updateAccountBalance(transaction.account, delta)) + }), }); export default connect(undefined, mapDispatchToProps) (withStyles(styles)(AddFloatingButton)); diff --git a/src/components/CategoryForm.js b/src/components/CategoryForm.js index 731f911..92138a2 100644 --- a/src/components/CategoryForm.js +++ b/src/components/CategoryForm.js @@ -5,7 +5,6 @@ import Button from 'material-ui/Button'; import {connect} from 'react-redux'; import Paper from 'material-ui/Paper'; - const styles = theme => ({ textField: { marginLeft: theme.spacing.unit, @@ -26,7 +25,6 @@ const styles = theme => ({ .mixins .gutters({ - paddingLeft: 0, paddingRight: 0, marginTop: theme.spacing.unit * 3, @@ -55,13 +53,24 @@ class CategoryForm extends React.Component { if (!this.state.name) { this.setState(() => ({error: 'Please provide name and balance.'})); } else { - if (this.props.categories.find((category) => category.name === this.state.name) === undefined) { + if (typeof this.props.categories !== 'undefined' && this.props.categories.length > 0) { + + if (this.props.categories.find((category) => category.name === this.state.name) === undefined) { + this.setState(() => ({error: ''})); + this + .props + .onSubmit({name: this.state.name}); + } else { + this.setState(() => ({name: '', balance: '', error: 'Category already exists'})); + } + } else { this.setState(() => ({error: ''})); this .props - .onSubmit({name: this.state.name}); - }else { - this.setState(() => ({name: '', balance: '' , error: 'Category already exists'})); + .onSubmit({ + name: this.state.name, + balance: parseFloat(this.state.balance, 10) * 100 + }); } } }; diff --git a/src/components/CategoryList.js b/src/components/CategoryList.js index 375f39f..4284222 100644 --- a/src/components/CategoryList.js +++ b/src/components/CategoryList.js @@ -43,7 +43,7 @@ export class CategoryList extends React.Component { this.state = { page: 0, - rowsPerPage: 5 + rowsPerPage: 10 } } @@ -116,7 +116,7 @@ export class CategoryList extends React.Component { count={this.props.categories.length} rowsPerPage={this.state.rowsPerPage} page={this.state.page} - rowsPerPageOptions={[5]} + rowsPerPageOptions={[5 , 10]} onChangePage={this.handleChangePage} onChangeRowsPerPage={this.handleChangeRowsPerPage}/> diff --git a/src/components/MyPieChart.js b/src/components/MyPieChart.js index 9e68f2b..a001518 100644 --- a/src/components/MyPieChart.js +++ b/src/components/MyPieChart.js @@ -106,14 +106,15 @@ class MyPieChart extends React.Component { nameKey={this.props.nameKey} cx="50%" cy="50%" - outerRadius={100} + outerRadius={120} fill="#8884d8" label={this.renderCustomizedLabel} - labelLine={false}> + labelLine={false} + unit="€"> {this .props .data - .map((entry, index) => )} + .map((entry, index) => )} diff --git a/src/components/TransactionForm.js b/src/components/TransactionForm.js index 3a82d63..789a1ed 100644 --- a/src/components/TransactionForm.js +++ b/src/components/TransactionForm.js @@ -10,7 +10,7 @@ import moment from 'moment'; import {SingleDatePicker} from 'react-dates'; import '../react_dates_overrides.css' import Paper from 'material-ui/Paper'; - +import _ from 'lodash'; const styles = theme => ({ @@ -28,8 +28,7 @@ const styles = theme => ({ marginRight: theme.spacing.unit, width: 250, marginTop: theme.spacing.unit, - marginBottom: 40, - + marginBottom: 40 }, formControl: { margin: theme.spacing.unit, @@ -76,7 +75,9 @@ class TransactionForm extends React.Component { : '', date: props.transaction ? moment(props.transaction.date) - : moment().set({'hour': 12 , 'minute' : 0 , 'second' : 0 , 'millisecond' : 0}).get('today'), + : moment() + .set({'hour': 12, 'minute': 0, 'second': 0, 'millisecond': 0}) + .get('today'), error: '', calendarFocused: false, submit_button_title: props.transaction @@ -147,79 +148,82 @@ class TransactionForm extends React.Component { const {classes} = this.props; return ( - {this.state.error &&

{this.state.error}

} -
- - false}/> - - - Type - - - + + + false}/> + + + Type + + + + + - - Account - }> + + })} - - - - Category - + + + Category + - + + - {/**/} - - + + + )}
) } diff --git a/src/components/TransactionList.js b/src/components/TransactionList.js index 6c67331..b50bb43 100644 --- a/src/components/TransactionList.js +++ b/src/components/TransactionList.js @@ -52,7 +52,7 @@ class TransactionList extends React.Component { onDelete = (idObject, id) => { - console.log(id); + //console.log(id); this .props .transactions @@ -68,7 +68,7 @@ class TransactionList extends React.Component { }; onCopy = (id) => { - console.log(id); + //console.log(id); this .props .transactions diff --git a/src/components/UserErrors.js b/src/components/UserErrors.js new file mode 100644 index 0000000..cc67408 --- /dev/null +++ b/src/components/UserErrors.js @@ -0,0 +1,17 @@ +import React from 'react' + +const UserErrors = (props) => { + return ( +
+ + {props.errors.length > 0 && ( props.errors.map((error)=>{ + return (

+ {error.code} : {error.message} +

) + })) + } +
+ ); +} + +export default UserErrors; \ No newline at end of file diff --git a/src/containers/Accounts.js b/src/containers/Accounts.js index 5fdd330..9a37f29 100644 --- a/src/containers/Accounts.js +++ b/src/containers/Accounts.js @@ -56,7 +56,7 @@ class AddAccountContainer extends React.Component { - + ); diff --git a/src/containers/Categories.js b/src/containers/Categories.js index 14f8a56..6709b25 100644 --- a/src/containers/Categories.js +++ b/src/containers/Categories.js @@ -57,7 +57,7 @@ class CategoriesContainer extends React.Component { - + ); diff --git a/src/containers/Dashboard.js b/src/containers/Dashboard.js index f601f21..6259226 100644 --- a/src/containers/Dashboard.js +++ b/src/containers/Dashboard.js @@ -90,6 +90,13 @@ class Dashboard extends React.Component { .startSetTransactions(startDate.valueOf(), endDate.valueOf()); } + onSubmit = (transaction) => { + this + .props + .startAddTransaction(transaction); + + }; + render() { return (
diff --git a/src/reducers/MyBarChart.js b/src/reducers/MyBarChart.js new file mode 100644 index 0000000..fd0d2fc --- /dev/null +++ b/src/reducers/MyBarChart.js @@ -0,0 +1,68 @@ +import React from 'react'; +import {withStyles} from 'material-ui/styles'; +import { + BarChart, + Bar, + XAxis, + YAxis, + Legend, + CartesianGrid, + Tooltip, + ResponsiveContainer +} from 'recharts'; +import Paper from 'material-ui/Paper'; + +const styles = theme => ({ + root: { + WebkitBoxSizing: "border-box", + MozBoxSizing: "border-box", + padding: 10, + height: 300, + backgroundColor: "#fff" + }, + paper: theme + .mixins + .gutters({ + + boxSizing: "border - box", + paddingLeft: 16, + paddingRight: 16, + marginTop: theme.spacing.unit * 3, + marginLeft: 10, + marginRight: 10, + overflowX: 'auto' + }) +}); + +class MyBarChart extends React.Component { + + render() { + + const {classes} = this.props; + return ( + +

{this.props.title}

+
+ + + + {/**/} + + + {/* + + + + + + + + +
+
+ ) + } +} + +export default withStyles(styles)(MyBarChart); \ No newline at end of file diff --git a/src/reducers/errors.js b/src/reducers/errors.js new file mode 100644 index 0000000..9823f41 --- /dev/null +++ b/src/reducers/errors.js @@ -0,0 +1,14 @@ +export default(state = {}, action) => { + switch (action.type) { + case 'ADD_ERROR': + return[ + ...state, + action.error + ] + case 'RESET_ERROR': + return {}; + default: + return state; + } + }; + \ No newline at end of file diff --git a/src/store/configureStore.js b/src/store/configureStore.js index a1a1d2d..69c8301 100644 --- a/src/store/configureStore.js +++ b/src/store/configureStore.js @@ -7,6 +7,7 @@ import accountsReducer from '../reducers/accounts'; import transactionsReducer from '../reducers/transactions'; import categoriesReducer from '../reducers/categories'; import filtersReducer from '../reducers/filters'; +import errorsReducer from '../reducers/errors'; const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; export default () => { @@ -17,7 +18,8 @@ export default () => { accounts: accountsReducer, transactions: transactionsReducer, categories: categoriesReducer, - filters: filtersReducer + filters: filtersReducer, + errors : errorsReducer }), composeEnhancers(applyMiddleware(thunk)) );