From 87a61d8da7534b910dffa004888aef221382a240 Mon Sep 17 00:00:00 2001 From: Farmin Farzin Date: Tue, 23 Jan 2018 10:01:30 +0100 Subject: [PATCH 1/4] random color generator for pie chart --- src/components/CategoryForm.js | 1 - src/components/FilterDashboard.js | 31 +++++++++++++--------- src/components/MyPieChart.js | 44 ++++++++++++++++++++++++------- src/containers/Dashboard.js | 24 ++++++++--------- 4 files changed, 65 insertions(+), 35 deletions(-) diff --git a/src/components/CategoryForm.js b/src/components/CategoryForm.js index a75dbe9..731f911 100644 --- a/src/components/CategoryForm.js +++ b/src/components/CategoryForm.js @@ -82,7 +82,6 @@ class CategoryForm extends React.Component { className={classes.textField} type="text" placeholder="category" - autoFocus value={this.state.name} onChange={this.onNameChange}/> diff --git a/src/components/FilterDashboard.js b/src/components/FilterDashboard.js index c5fd582..4509c5d 100644 --- a/src/components/FilterDashboard.js +++ b/src/components/FilterDashboard.js @@ -2,8 +2,9 @@ import React from 'react'; import {withStyles} from 'material-ui/styles'; import Paper from 'material-ui/Paper'; import Select from 'material-ui/Select'; -import Input, {InputLabel} from 'material-ui/Input'; -import {FormControl} from 'material-ui/Form'; +// import Input, {InputLabel} from 'material-ui/Input'; +import {FormControl , FormHelperText} from 'material-ui/Form'; +import moment from 'moment'; const styles = theme => ({ root: { @@ -32,7 +33,10 @@ const styles = theme => ({ marginTop: 10, minWidth: 200, padding: 10 - } + }, + selectEmpty: { + marginTop: theme.spacing.unit * 2, + }, }); class FilterDashboard extends React.Component { @@ -41,10 +45,10 @@ class FilterDashboard extends React.Component { this.state = { dashboardMonthFilter: props.dashboardMonthFilter ? props.dashboardMonthFilter - : '', + : moment().month() +1, dashboardYearFilter: props.dashboardYearFilter ? props.dashboardYearFilter - : '' + : moment().year() }; } @@ -75,13 +79,12 @@ class FilterDashboard extends React.Component { return ( - Month + Month - Year + Year + ) diff --git a/src/components/MyPieChart.js b/src/components/MyPieChart.js index 0b2c273..9e68f2b 100644 --- a/src/components/MyPieChart.js +++ b/src/components/MyPieChart.js @@ -32,11 +32,36 @@ const styles = theme => ({ }) }); +class MyPieChart extends React.Component { + constructor(props) { + super(props); + this.state = { + colors: [] + } + } + - -class MyPieChart extends React.Component { + getRandomColor = (categoriesNumber) => { + var letters = '0123456789ABCDEF'; + var color = '#'; + let colors = [] + while (colors.length < categoriesNumber) { + for (var i = 0; i < 6; i++) { + color += letters[Math.floor(Math.random() * 16)]; + } + colors.push(color); + color = '#'; + } + this.setState ({ + colors + }) + } + + componentWillReceiveProps(nextProps){ + this.getRandomColor(nextProps.data.length); + } renderCustomizedLabel = ({ cx, @@ -51,7 +76,7 @@ class MyPieChart extends React.Component { const radius = innerRadius + (outerRadius - innerRadius) * 0.5; const x = cx + radius * Math.cos(-midAngle * RADIAN); const y = cy + radius * Math.sin(-midAngle * RADIAN); - + return ( {`${ (percent * 100).toFixed(0)}%`} - ); + ) }; render() { - const COLORS = ['#0088FE', '#00C49F', '#FFBB28', '#FF8042']; + //const COLORS = ['#0088FE', '#00C49F', '#FFBB28', '#FF8042']; const {classes} = this.props; return ( @@ -83,15 +108,14 @@ class MyPieChart extends React.Component { cy="50%" outerRadius={100} fill="#8884d8" - label={this.renderCustomizedLabel} - labelLine={false} - > + label={this.renderCustomizedLabel} + labelLine={false}> {this .props .data - .map((entry, index) => )} + .map((entry, index) => )} - + diff --git a/src/containers/Dashboard.js b/src/containers/Dashboard.js index 2f8bcd1..86dc773 100644 --- a/src/containers/Dashboard.js +++ b/src/containers/Dashboard.js @@ -27,10 +27,10 @@ class Dashboard extends React.Component { } } - updateStatisticData = () => { - let totalExpenseDay = _.filter(this.props.transactions, {'type': 'Expense'}); - let totalIncomeDay = _.filter(this.props.transactions, {'type': 'Income'}); - let expensesByCategory = _.filter(this.props.transactions, {'type': 'Expense'}); + updateStatisticData = (nextProps = this.props) => { + let totalExpenseDay = _.filter(nextProps.transactions, {'type': 'Expense'}); + let totalIncomeDay = _.filter(nextProps.transactions, {'type': 'Income'}); + let expensesByCategory = _.filter(nextProps.transactions, {'type': 'Expense'}); totalExpenseDay = _(totalExpenseDay) .groupBy('date') @@ -65,14 +65,14 @@ class Dashboard extends React.Component { this.setState({totalExpenseDay, totalIncomeDay, expensesByCategory}); } - componentWillReceiveProps() { - this.updateStatisticData(); + componentWillReceiveProps(nextProps) { + this.updateStatisticData(nextProps); } componentDidMount() { - this - .props - .startSetTransactions(); + // this + // .props + // .startSetTransactions(); this.updateStatisticData(); } @@ -119,10 +119,10 @@ class Dashboard extends React.Component { @@ -161,7 +161,7 @@ const mapStateToProps = (state) => { }; const mapDispatchToProps = (dispatch) => ({ - startSetTransactions: () => dispatch(startSetTransactions()), + startSetTransactions: (startDate , endDate) => dispatch(startSetTransactions(startDate,endDate)), startSetAccounts: () => dispatch(startSetAccounts()), startSetCategories: () => dispatch(startSetCategories()) }); From 1264890fa6ae7782d93347934ab61b7f1290fb1d Mon Sep 17 00:00:00 2001 From: Farmin Farzin Date: Tue, 23 Jan 2018 12:30:40 +0100 Subject: [PATCH 2/4] adding month and year filter as redux state to synchronize between dashboard and transaction page --- src/actions/filters.js | 7 ++++ src/components/FilterDashboard.js | 8 ++--- src/components/MyAreaChart.js | 7 ++-- src/components/MyLineChart.js | 2 +- src/containers/Dashboard.js | 45 +++++++++++++++---------- src/containers/Transactions.js | 56 ++++++++++++++++++++++++------- src/reducers/filters.js | 10 ++++++ 7 files changed, 98 insertions(+), 37 deletions(-) diff --git a/src/actions/filters.js b/src/actions/filters.js index 7235f2a..ede834d 100644 --- a/src/actions/filters.js +++ b/src/actions/filters.js @@ -19,5 +19,12 @@ export const setTypeFilter = (typeFilter) => ({type: 'SET_TRANSACTION_TYPE_FILTE // SET_TRANSACTION_TYPE_DESCRIPTION export const setDescriptionFilter = (descriptionFilter) => ({type: 'SET_TRANSACTION_DESCRIPTION_FILTER', descriptionFilter}); +// SET_DASHBOARD_MONTH +export const setDashboardMonthFilter = (dashboardMonthFilter) => ({type: 'SET_DASHBOARD_MONTH', dashboardMonthFilter}); + +//SET_DASHBOARD_YEAR +export const setDashboardYearFilter = (dashboardYearFilter) => ({type: 'SET_DASHBOARD_YEAR', dashboardYearFilter}); + + diff --git a/src/components/FilterDashboard.js b/src/components/FilterDashboard.js index 4509c5d..76680d5 100644 --- a/src/components/FilterDashboard.js +++ b/src/components/FilterDashboard.js @@ -43,11 +43,11 @@ class FilterDashboard extends React.Component { constructor(props) { super(props); this.state = { - dashboardMonthFilter: props.dashboardMonthFilter - ? props.dashboardMonthFilter + dashboardMonthFilter: props.filters.dashboardMonthFilter + ? props.filters.dashboardMonthFilter : moment().month() +1, - dashboardYearFilter: props.dashboardYearFilter - ? props.dashboardYearFilter + dashboardYearFilter: props.filters.dashboardYearFilter + ? props.filters.dashboardYearFilter : moment().year() }; } diff --git a/src/components/MyAreaChart.js b/src/components/MyAreaChart.js index 4f9236e..86e1b35 100644 --- a/src/components/MyAreaChart.js +++ b/src/components/MyAreaChart.js @@ -49,12 +49,15 @@ class MyAreaChart extends React.Component { - + + fill={this.props.fillColor} + unit="€" + + /> diff --git a/src/components/MyLineChart.js b/src/components/MyLineChart.js index 0b6b8ef..3de576f 100644 --- a/src/components/MyLineChart.js +++ b/src/components/MyLineChart.js @@ -45,7 +45,7 @@ class MyLineChart extends React.Component { - + diff --git a/src/containers/Dashboard.js b/src/containers/Dashboard.js index 86dc773..f601f21 100644 --- a/src/containers/Dashboard.js +++ b/src/containers/Dashboard.js @@ -8,12 +8,12 @@ import {connect} from 'react-redux'; import {startSetTransactions} from '../actions/transactions'; import {startSetAccounts} from '../actions/accounts'; import {startSetCategories} from '../actions/categories'; +import {setDashboardMonthFilter , setDashboardYearFilter} from '../actions/filters' //import MyLineChart from '../components/MyLineChart'; import MyAreaChart from '../components/MyAreaChart'; import MyBarChart from '../components/MyBarChart.js'; import MyPieChart from '../components/MyPieChart'; import FilterDashboard from '../components/FilterDashboard'; - import _ from 'lodash'; import moment from 'moment'; @@ -70,36 +70,45 @@ class Dashboard extends React.Component { } componentDidMount() { - // this - // .props - // .startSetTransactions(); + // this .props .startSetTransactions(); this.updateStatisticData(); } // handleClickFloatingButton = event => {}; - onFilterDashboard = ({dashboardYearFilter , dashboardMonthFilter}) =>{ - var startDate = moment([dashboardYearFilter, dashboardMonthFilter - 1]); + onFilterDashboard = ({dashboardYearFilter, dashboardMonthFilter}) => { + this.props.setDashboardMonthFilter(dashboardMonthFilter); + this.props.setDashboardYearFilter(dashboardYearFilter); + + var startDate = moment([ + dashboardYearFilter, dashboardMonthFilter - 1 + ]); var endDate = moment(startDate).endOf('month'); this .props - .startSetTransactions(startDate.valueOf() , endDate.valueOf()); + .startSetTransactions(startDate.valueOf(), endDate.valueOf()); } - render() { return (
{/*

{Constants.DASHBOARD_PAGE_TITLE}

*/} - + m.set(o.date, Object.assign(m.get(o.date) || {}, o)), new Map()) + .values() + ]), ['date'], ['asc'])} title="Expense/Income/Time" yAxis1="expense" yAxis2="income" @@ -117,16 +126,16 @@ class Dashboard extends React.Component { fillColor="#8884d8"/> - + - + {/* - + */} @@ -157,13 +166,15 @@ class Dashboard extends React.Component { } const mapStateToProps = (state) => { - return {transactions: state.transactions}; + return {transactions: state.transactions, filters: state.filters}; }; const mapDispatchToProps = (dispatch) => ({ - startSetTransactions: (startDate , endDate) => dispatch(startSetTransactions(startDate,endDate)), + startSetTransactions: (startDate, endDate) => dispatch(startSetTransactions(startDate, endDate)), startSetAccounts: () => dispatch(startSetAccounts()), - startSetCategories: () => dispatch(startSetCategories()) + startSetCategories: () => dispatch(startSetCategories()), + setDashboardMonthFilter: (dashboardMonthFilter) => dispatch(setDashboardMonthFilter(dashboardMonthFilter)), + setDashboardYearFilter: (dashboardYearFilter) => dispatch(setDashboardYearFilter(dashboardYearFilter)) }); export default connect(mapStateToProps, mapDispatchToProps)(Dashboard); diff --git a/src/containers/Transactions.js b/src/containers/Transactions.js index f7f453c..50b6a75 100644 --- a/src/containers/Transactions.js +++ b/src/containers/Transactions.js @@ -4,11 +4,13 @@ import Grid from 'material-ui/Grid'; import Constants from '../utils/constants'; import TransactionForm from '../components/TransactionForm'; import {connect} from 'react-redux'; -import {startAddTransaction} from '../actions/transactions'; +import {startSetTransactions , startAddTransaction} from '../actions/transactions'; +import {setDashboardMonthFilter , setDashboardYearFilter} from '../actions/filters' import TransactionList from '../components/TransactionList'; import {updateAccountBalance} from '../actions/accounts'; import AddFloatingButton from '../components/AddFloatingButton'; - +import FilterDashboard from '../components/FilterDashboard'; +import moment from 'moment'; const styles = theme => ({ @@ -23,9 +25,9 @@ const styles = theme => ({ marginTop: theme.spacing.unit, marginRight: theme.spacing.unit, marginLeft: theme.spacing.unit, - textAlign: 'center', + textAlign: 'center' } - + }); class AddTransactionContainer extends React.Component { @@ -40,6 +42,20 @@ class AddTransactionContainer extends React.Component { .push('/transactions'); }; + onFilterDashboard = ({dashboardYearFilter, dashboardMonthFilter}) => { + this.props.setDashboardMonthFilter(dashboardMonthFilter); + this.props.setDashboardYearFilter(dashboardYearFilter); + + var startDate = moment([ + dashboardYearFilter, dashboardMonthFilter - 1 + ]); + var endDate = moment(startDate).endOf('month'); + + this + .props + .startSetTransactions(startDate.valueOf(), endDate.valueOf()); + } + render() { const {classes} = this.props; return ( @@ -49,12 +65,16 @@ class AddTransactionContainer extends React.Component {

{Constants.ADD_TRANSACTION_PAGE_TITLE}

+ + + + - + - - + +
@@ -64,15 +84,25 @@ class AddTransactionContainer extends React.Component { } } +const mapStateToProps = (state, props) => { + return { + filters: state.filters + }; + +}; + + const mapDispatchToProps = (dispatch) => ({ - startAddTransaction: (transaction) => dispatch(startAddTransaction(transaction)) - .then(() => { + startAddTransaction: (transaction) => dispatch(startAddTransaction(transaction)).then(() => { let delta = transaction.amount - if(transaction.type === 'Expense'){ - delta = -delta + if (transaction.type === 'Expense') { + delta = -delta } dispatch(updateAccountBalance(transaction.account, delta)) - }) + }), + startSetTransactions: (startDate, endDate) => dispatch(startSetTransactions(startDate, endDate)), + setDashboardMonthFilter : (dashboardMonthFilter)=>dispatch(setDashboardMonthFilter(dashboardMonthFilter)), + setDashboardYearFilter : (dashboardYearFilter)=>dispatch(setDashboardYearFilter(dashboardYearFilter)) }); -export default connect(undefined, mapDispatchToProps)(withStyles(styles)(AddTransactionContainer)); +export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(AddTransactionContainer)); diff --git a/src/reducers/filters.js b/src/reducers/filters.js index 83bbfac..aec0ccd 100644 --- a/src/reducers/filters.js +++ b/src/reducers/filters.js @@ -47,6 +47,16 @@ export default(state = filtersReducerDefaultState, action) => { ...state, endDate: action.endDate }; + case 'SET_DASHBOARD_MONTH': + return { + ...state, + dashboardMonthFilter: action.dashboardMonthFilter + }; + case 'SET_DASHBOARD_YEAR': + return { + ...state, + dashboardYearFilter: action.dashboardYearFilter + }; default: return state; } From 60604e0281163c8ca37438a98283b9b19e723229 Mon Sep 17 00:00:00 2001 From: Farmin Farzin Date: Tue, 23 Jan 2018 12:37:33 +0100 Subject: [PATCH 3/4] signInWithRedirect --- src/actions/auth.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/actions/auth.js b/src/actions/auth.js index c1e4162..83e2595 100644 --- a/src/actions/auth.js +++ b/src/actions/auth.js @@ -10,7 +10,7 @@ export const startLoginGoogle = () => { //return firebase.auth().signInWithRedirect(googleAuthProvider); return firebase .auth() - .signInWithPopup(googleAuthProvider); + .signInWithRedirect(googleAuthProvider); }; }; From 1471bad40e808e7c24a236b40165c77b038f5645 Mon Sep 17 00:00:00 2001 From: Farmin Farzin Date: Tue, 23 Jan 2018 20:38:49 +0100 Subject: [PATCH 4/4] error handling for the unauthorized users and fix for floating button --- src/App.js | 9 +- src/actions/accounts.js | 18 ++- src/actions/categories.js | 20 ++-- src/actions/errors.js | 6 + src/actions/transactions.js | 17 ++- src/components/AccountForm.js | 29 ++++- src/components/AddFloatingButton.js | 9 +- src/components/CategoryForm.js | 21 +++- src/components/CategoryList.js | 4 +- src/components/MyPieChart.js | 7 +- src/components/TransactionForm.js | 163 ++++++++++++++-------------- src/components/TransactionList.js | 4 +- src/components/UserErrors.js | 17 +++ src/containers/Accounts.js | 2 +- src/containers/Categories.js | 2 +- src/containers/Dashboard.js | 7 ++ src/reducers/MyBarChart.js | 68 ++++++++++++ src/reducers/errors.js | 14 +++ src/store/configureStore.js | 4 +- 19 files changed, 302 insertions(+), 119 deletions(-) create mode 100644 src/actions/errors.js create mode 100644 src/components/UserErrors.js create mode 100644 src/reducers/MyBarChart.js create mode 100644 src/reducers/errors.js 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)) );