From 1105f8f46e10cd9a6e9168020ff11908934dbd5f Mon Sep 17 00:00:00 2001 From: Kelly Garry Date: Thu, 21 Mar 2019 22:37:20 -0600 Subject: [PATCH 1/5] app.js breakdown --- src/App.js | 56 ++++++++++++++------------------------ src/components/Expenses.js | 26 ++++++++++++++++++ src/components/Revenue.js | 25 +++++++++++++++++ 3 files changed, 72 insertions(+), 35 deletions(-) create mode 100644 src/components/Expenses.js create mode 100644 src/components/Revenue.js diff --git a/src/App.js b/src/App.js index 39e4f6a..33f8551 100644 --- a/src/App.js +++ b/src/App.js @@ -6,6 +6,8 @@ import { Form } from 'react-bootstrap' import './App.css'; +import Revenue from './components/Revenue.js'; +import Expenses from './components/Expenses.js'; class App extends Component { constructor() { @@ -167,8 +169,8 @@ class App extends Component { }) // Calculations for totals - let totalRevenue = this.state.oneTimeRevenue + (this.state.monthlyRevenue * 12) - let totalExpense = this.state.oneTimeExpense + (this.state.monthlyExpense * 12) + let totalRevenue = this.state.oneTimeRevenue + (this.state.monthlyRevenue * 24) + let totalExpense = this.state.oneTimeExpense + (this.state.monthlyExpense * 24) let monthlyContributionProfit = this.state.monthlyRevenue - this.state.monthlyExpense let totalContributionProfit = totalRevenue - totalExpense // handle case where totalRevenue is 0 (to avoid -Infinity and NaN) @@ -234,44 +236,28 @@ class App extends Component { }
{/* Revenue Table */} - - - - - - - - - - - - - - {revenueTableData} - -
Revenue
One-TimeMonthly
+ {/* Expenses Table */} - - - - - - - - - - - - - - {expensesTableData} - -
Expenses
One-TimeMonthly
+ + {/* Totals Table */} + + + - + diff --git a/src/components/Expenses.js b/src/components/Expenses.js new file mode 100644 index 0000000..42eac61 --- /dev/null +++ b/src/components/Expenses.js @@ -0,0 +1,26 @@ +import React from 'react'; +// import './Expenses.css'; + +const expenses = (props) => { + + return ( +
+
24 Month Term
Total One-Time Monthly Total
+ + + + + + + + + + {props.delete} + +
ExpensesOne-TimeMonthly
+
+ + ) +}; + +export default expenses; \ No newline at end of file diff --git a/src/components/Revenue.js b/src/components/Revenue.js new file mode 100644 index 0000000..c773561 --- /dev/null +++ b/src/components/Revenue.js @@ -0,0 +1,25 @@ +import React from 'react'; + +const revenue = (props) => { + + return ( +
+ + + + + + + + + + + {props.delete} + +
RevenueOne-TimeMonthly
+
+ + ) +}; + +export default revenue; \ No newline at end of file From 2b0e39e1a5d2395e996896bd99efedaae8156a04 Mon Sep 17 00:00:00 2001 From: Kelly Garry Date: Tue, 26 Mar 2019 00:27:57 -0600 Subject: [PATCH 2/5] using data components --- src/App.css | 4 +- src/App.js | 299 +--------------------------------- src/components/Data.css | 40 +++++ src/components/DataDisplay.js | 174 ++++++++++++++++++++ src/components/DataEntry.js | 113 +++++++++++++ src/components/DataTotal.js | 89 ++++++++++ src/components/Expenses.js | 26 --- src/components/Revenue.js | 25 --- src/data/seedData.js | 38 +++++ 9 files changed, 462 insertions(+), 346 deletions(-) create mode 100644 src/components/Data.css create mode 100644 src/components/DataDisplay.js create mode 100644 src/components/DataEntry.js create mode 100644 src/components/DataTotal.js delete mode 100644 src/components/Expenses.js delete mode 100644 src/components/Revenue.js create mode 100644 src/data/seedData.js diff --git a/src/App.css b/src/App.css index bf73fb7..45b32df 100644 --- a/src/App.css +++ b/src/App.css @@ -1,4 +1,4 @@ -.addExpenseOrRevenueForm { +/* .addExpenseOrRevenueForm { padding-top: 3em; } @@ -36,4 +36,4 @@ .roi-tables { padding-left: 1.5em; } -} +} */ diff --git a/src/App.js b/src/App.js index 33f8551..977dfa1 100644 --- a/src/App.js +++ b/src/App.js @@ -1,302 +1,15 @@ import React, { Component } from 'react'; -import { - Row, - Col, - Button, - Form - } from 'react-bootstrap' -import './App.css'; -import Revenue from './components/Revenue.js'; -import Expenses from './components/Expenses.js'; +import DataDisplay from './components/DataDisplay.js'; +import DataEntry from './components/DataEntry.js'; +import DataTotal from './components/DataTotal.js'; class App extends Component { - constructor() { - super() - // "seed" data initially - this.state = { - revenue: [ - { - name: 'Item 1', - oneTime: 100, - monthly: 50 - }, - { - name: 'Item 2', - oneTime: 50, - monthly: 25 - }, - { - name: 'Item 3', - oneTime: 25, - monthly: 85 - }], - expenses:[{ - name: 'Expense 1', - oneTime: 500, - monthly: 20.00 - }, - { - name: 'Expense 2', - oneTime: 200, - monthly: 40 - }], - oneTimeRevenue: 175, - oneTimeExpense: 700, - monthlyRevenue: 160, - monthlyExpense: 60, - newType: '', - newName: '', - newOneTime: '', - newMonthly: '', - error: false - } - - this.handleDelete = this.handleDelete.bind(this) - this.handleAdd = this.handleAdd.bind(this) - - // controlled form elements functions - this.handleTypeChange = this.handleTypeChange.bind(this) - this.handleNameChange = this.handleNameChange.bind(this) - this.handleOneTimeChange = this.handleOneTimeChange.bind(this) - this.handleMonthlyChange = this.handleMonthlyChange.bind(this) - } - - // Delete expense or revenue from list - handleDelete(type, index) { - // listType will be 'expenses' or 'revenue' depending on item to delete - let listType = this.state[type] - // recalculate and set totals in state - if (type === 'expenses') { - this.setState({ - oneTimeExpense: this.state.oneTimeExpense - this.state.expenses[index]['oneTime'], - monthlyExpense: this.state.monthlyExpense - this.state.expenses[index]['monthly'], - }) - } else { - // for revenue - this.setState({ - oneTimeRevenue: this.state.oneTimeRevenue - this.state.revenue[index]['oneTime'], - monthlyRevenue: this.state.monthlyRevenue - this.state.revenue[index]['monthly'], - }) - } - // remove list item from state array - this.setState({ - [listType]: listType.splice(index, 1), - }) - } - - // controlled form elements, watch for changes - handleTypeChange(e) { - this.setState({ - newType: e.target.value - }) - } - handleNameChange(e) { - this.setState({ - newName: e.target.value - }) - } - - handleMonthlyChange(e) { - this.setState({ - newMonthly: Number(e.target.value) - }) - } - handleOneTimeChange(e) { - this.setState({ - newOneTime: Number(e.target.value) - }) - } - - // add new expense or revenue - handleAdd(e) { - e.preventDefault() - // handle form errors, allows one-time and revenue amounts to be 0 - if (!this.state.newType || !this.state.newName || (!this.state.newOneTime && this.state.newOneTime !== 0) || (!this.state.newMonthly && this.state.newMonthly !== 0)) { - this.setState({ - error: true - }) - } - // if there are no form errors, add accordingly - else { - // typeOfAmount will be either 'expenses' or 'revenue' - let typeOfAmount = this.state.newType - let monthly = typeOfAmount === 'expenses' ? 'monthlyExpense' : 'monthlyRevenue' - let oneTime = typeOfAmount === 'expenses' ? 'oneTimeExpense' : 'oneTimeRevenue' - // grab state array of revenues or expenses - let items = this.state[typeOfAmount] - items.push({ - name: this.state.newName, - oneTime:this.state.newOneTime, - monthly: this.state.newMonthly - }) - // set state with new totals and items array, clear errors displaying and form contents - this.setState({ - error: false, - [typeOfAmount]: items, - [monthly]: this.state[monthly] + this.state.newMonthly, - [oneTime]: this.state[oneTime] + this.state.newOneTime, - // Clear values in form - newName: '', - newMonthly: '', - newOneTime: '', - newType: '' - }) - } - } - render() { - // create table rows from revenue state list - let revenueTableData = this.state.revenue.map((item, index) => { - return ( - - {item.name} - ${item.oneTime.toFixed(2)} - ${item.monthly.toFixed(2)} - - - ) - }) - // create table rows from expenses state list - let expensesTableData = this.state.expenses.map((expense, index) => { - return ( - - {expense.name} - ${expense.oneTime.toFixed(2)} - ${expense.monthly.toFixed(2)} - - - ) - }) - - // Calculations for totals - let totalRevenue = this.state.oneTimeRevenue + (this.state.monthlyRevenue * 24) - let totalExpense = this.state.oneTimeExpense + (this.state.monthlyExpense * 24) - let monthlyContributionProfit = this.state.monthlyRevenue - this.state.monthlyExpense - let totalContributionProfit = totalRevenue - totalExpense - // handle case where totalRevenue is 0 (to avoid -Infinity and NaN) - let contributionMargin = totalRevenue !== 0 ? (totalContributionProfit / totalRevenue * 100).toFixed(0) : 0 - // handle case where totalExpense and totalRevenue are 0 (to avoid NaN) - let capitalROI = (totalExpense === 0 && totalRevenue === 0) ? 0 : ((this.state.oneTimeExpense - this.state.oneTimeRevenue) / monthlyContributionProfit).toFixed(1) - return (
-

ROI Calculator

- {/* Add new expense or revenue form */} -
- - - - - - - - - - - - - - - - - - - - - -
- {/* form errors */} - { this.state.error && -

Please fill out all fields

- } -
- {/* Revenue Table */} - - {/* Expenses Table */} - - - {/* Totals Table */} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
24 Month Term
TotalOne-TimeMonthlyTotal
Revenue${(this.state.oneTimeRevenue).toFixed(2)}${(this.state.monthlyRevenue).toFixed(2)}${totalRevenue.toFixed(2)}
Expenses${(this.state.oneTimeExpense).toFixed(2)}${(this.state.monthlyExpense).toFixed(2)}${totalExpense.toFixed(2)}
Contribution Profit${ monthlyContributionProfit.toFixed(2)}${ totalContributionProfit.toFixed(2)}
Contribution Margin{contributionMargin}%
Capital ROI (monthly){capitalROI}
-
+ + +
); } diff --git a/src/components/Data.css b/src/components/Data.css new file mode 100644 index 0000000..831719e --- /dev/null +++ b/src/components/Data.css @@ -0,0 +1,40 @@ +.addExpenseOrRevenueForm { + padding-top: 3em; + } + + .input-field, .add-form-button { + padding-bottom: 1em; + } + + .roi-tables { + padding-top: 2em; + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + } + + .expenses-table, .revenue-table, .totals-table { + margin-bottom: 3em; + } + .expenses-table th, .revenue-table th, .totals-table th { + width: 150px; + } + .expenses-table td, .revenue-table td, .totals-table td { + width: 100px + } + + .error { + color: red; + } + + @media only screen and (max-width:775px) { + .input-field, .add-form-button { + margin-left: .25em; + margin-right: .25em; + } + .roi-tables { + padding-left: 1.5em; + } + } + \ No newline at end of file diff --git a/src/components/DataDisplay.js b/src/components/DataDisplay.js new file mode 100644 index 0000000..e62e522 --- /dev/null +++ b/src/components/DataDisplay.js @@ -0,0 +1,174 @@ +import React, { Component } from 'react'; +import { + Row, + Col, + Button, + Form +} from 'react-bootstrap' +import './Data.css'; + +class DataDisplay extends Component { + constructor() { + super(); + // "seed" data initially + this.state = { + revenue: [ + { + name: 'Item 1', + oneTime: 100, + monthly: 50 + }, + { + name: 'Item 2', + oneTime: 50, + monthly: 25 + }, + { + name: 'Item 3', + oneTime: 25, + monthly: 85 + }], + expenses: [{ + name: 'Expense 1', + oneTime: 500, + monthly: 20.00 + }, + { + name: 'Expense 2', + oneTime: 200, + monthly: 40 + }] + } + + this.handleDelete = this.handleDelete.bind(this) + this.handleAdd = this.handleAdd.bind(this) + } + + // Delete expense or revenue from list + handleDelete(type, index) { + // listType will be 'expenses' or 'revenue' depending on item to delete + let listType = this.state[type] + // recalculate and set totals in state + if (type === 'expenses') { + this.setState({ + oneTimeExpense: this.state.oneTimeExpense - this.state.expenses[index]['oneTime'], + monthlyExpense: this.state.monthlyExpense - this.state.expenses[index]['monthly'], + }) + } else { + // for revenue + this.setState({ + oneTimeRevenue: this.state.oneTimeRevenue - this.state.revenue[index]['oneTime'], + monthlyRevenue: this.state.monthlyRevenue - this.state.revenue[index]['monthly'], + }) + } + // remove list item from state array + this.setState({ + [listType]: listType.splice(index, 1), + }) + } + + // add new expense or revenue + handleAdd(e) { + e.preventDefault() + // handle form errors, allows one-time and revenue amounts to be 0 + if (!this.state.newType || !this.state.newName || (!this.state.newOneTime && this.state.newOneTime !== 0) || (!this.state.newMonthly && this.state.newMonthly !== 0)) { + this.setState({ + error: true + }) + } + // if there are no form errors, add accordingly + else { + // typeOfAmount will be either 'expenses' or 'revenue' + let typeOfAmount = this.state.newType + let monthly = typeOfAmount === 'expenses' ? 'monthlyExpense' : 'monthlyRevenue' + let oneTime = typeOfAmount === 'expenses' ? 'oneTimeExpense' : 'oneTimeRevenue' + // grab state array of revenues or expenses + let items = this.state[typeOfAmount] + items.push({ + name: this.state.newName, + oneTime: this.state.newOneTime, + monthly: this.state.newMonthly + }) + // set state with new totals and items array, clear errors displaying and form contents + this.setState({ + error: false, + [typeOfAmount]: items, + [monthly]: this.state[monthly] + this.state.newMonthly, + [oneTime]: this.state[oneTime] + this.state.newOneTime, + // Clear values in form + newName: '', + newMonthly: '', + newOneTime: '', + newType: '' + }) + } + } + + render() { + // create table rows from revenue state list + let revenueTableData = this.state.revenue.map((item, index) => { + return ( + + {item.name} + ${item.oneTime.toFixed(2)} + ${item.monthly.toFixed(2)} + + + ) + }) + // create table rows from expenses state list + let expensesTableData = this.state.expenses.map((expense, index) => { + return ( + + {expense.name} + ${expense.oneTime.toFixed(2)} + ${expense.monthly.toFixed(2)} + + + ) + }) + + return ( +
+
+ {/* Revenue Table */} + + + + + + + + + + + + + + {revenueTableData} + +
Revenue
One-TimeMonthly
+ {/* Expenses Table */} + + + + + + + + + + + + + + {expensesTableData} + +
Expenses
One-TimeMonthly
+
+
+ ); + } +} + +export default DataDisplay; \ No newline at end of file diff --git a/src/components/DataEntry.js b/src/components/DataEntry.js new file mode 100644 index 0000000..bd73f3c --- /dev/null +++ b/src/components/DataEntry.js @@ -0,0 +1,113 @@ +import React, { Component } from 'react'; +import { + Row, + Col, + Button, + Form + } from 'react-bootstrap'; +import './Data.css'; + +class DataEntry extends Component { + constructor(props) { + super(props); + this.state = { + newType: '', + newName: '', + newOneTime: '', + newMonthly: '', + error: false + } + + // controlled form elements functions + this.handleTypeChange = this.handleTypeChange.bind(this) + this.handleNameChange = this.handleNameChange.bind(this) + this.handleOneTimeChange = this.handleOneTimeChange.bind(this) + this.handleMonthlyChange = this.handleMonthlyChange.bind(this) + } + + // controlled form elements, watch for changes + handleTypeChange(e) { + this.setState({ + newType: e.target.value + }) + } + handleNameChange(e) { + this.setState({ + newName: e.target.value + }) + } + + handleMonthlyChange(e) { + this.setState({ + newMonthly: Number(e.target.value) + }) + } + handleOneTimeChange(e) { + this.setState({ + newOneTime: Number(e.target.value) + }) + } + + render() { + return ( +
+

ROI Calculator

+ {/* Add new expense or revenue form */} +
+ + + + + + + + + + + + + + + + + + + + + +
+ {/* form errors */} + { this.state.error && +

Please fill out all fields

+ } +
+ ); + } +} + +export default DataEntry; \ No newline at end of file diff --git a/src/components/DataTotal.js b/src/components/DataTotal.js new file mode 100644 index 0000000..204eaaf --- /dev/null +++ b/src/components/DataTotal.js @@ -0,0 +1,89 @@ +import React, { Component } from 'react'; +import { + Row, + Col, + Button, + Form +} from 'react-bootstrap' +import './Data.css'; + +class DataTotal extends Component { + constructor(props) { + super(props); + // "seed" data initially + this.state = { + oneTimeRevenue: 175, + oneTimeExpense: 700, + monthlyRevenue: 160, + monthlyExpense: 60 + } + } + + render() { + // MOVE THESE + // Calculations for totals + let totalRevenue = this.state.oneTimeRevenue + (this.state.monthlyRevenue * 24) + let totalExpense = this.state.oneTimeExpense + (this.state.monthlyExpense * 24) + let monthlyContributionProfit = this.state.monthlyRevenue - this.state.monthlyExpense + let totalContributionProfit = totalRevenue - totalExpense + // handle case where totalRevenue is 0 (to avoid -Infinity and NaN) + let contributionMargin = totalRevenue !== 0 ? (totalContributionProfit / totalRevenue * 100).toFixed(0) : 0 + // handle case where totalExpense and totalRevenue are 0 (to avoid NaN) + let capitalROI = (totalExpense === 0 && totalRevenue === 0) ? 0 : ((this.state.oneTimeExpense - this.state.oneTimeRevenue) / monthlyContributionProfit).toFixed(1) + + return ( +
+
+ {/* Totals Table */} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
24 Month Term
TotalOne-TimeMonthlyTotal
Revenue${(this.state.oneTimeRevenue).toFixed(2)}${(this.state.monthlyRevenue).toFixed(2)}${totalRevenue.toFixed(2)}
Expenses${(this.state.oneTimeExpense).toFixed(2)}${(this.state.monthlyExpense).toFixed(2)}${totalExpense.toFixed(2)}
Contribution Profit${monthlyContributionProfit.toFixed(2)}${totalContributionProfit.toFixed(2)}
Contribution Margin{contributionMargin}%
Capital ROI (monthly){capitalROI}
+
+
+ ); + } +} + +export default DataTotal; \ No newline at end of file diff --git a/src/components/Expenses.js b/src/components/Expenses.js deleted file mode 100644 index 42eac61..0000000 --- a/src/components/Expenses.js +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; -// import './Expenses.css'; - -const expenses = (props) => { - - return ( -
- - - - - - - - - - - {props.delete} - -
ExpensesOne-TimeMonthly
-
- - ) -}; - -export default expenses; \ No newline at end of file diff --git a/src/components/Revenue.js b/src/components/Revenue.js deleted file mode 100644 index c773561..0000000 --- a/src/components/Revenue.js +++ /dev/null @@ -1,25 +0,0 @@ -import React from 'react'; - -const revenue = (props) => { - - return ( -
- - - - - - - - - - - {props.delete} - -
RevenueOne-TimeMonthly
-
- - ) -}; - -export default revenue; \ No newline at end of file diff --git a/src/data/seedData.js b/src/data/seedData.js new file mode 100644 index 0000000..be377ee --- /dev/null +++ b/src/data/seedData.js @@ -0,0 +1,38 @@ +export default [{ + revenue: [ + { + name: 'Item 1', + oneTime: 100, + monthly: 50 + }, + { + name: 'Item 2', + oneTime: 50, + monthly: 25 + }, + { + name: 'Item 3', + oneTime: 25, + monthly: 85 + }], + expenses:[{ + name: 'Expense 1', + oneTime: 500, + monthly: 20.00 + }, + { + name: 'Expense 2', + oneTime: 200, + monthly: 40 + }], + oneTimeRevenue: 175, + oneTimeExpense: 700, + monthlyRevenue: 160, + monthlyExpense: 60, + newType: '', + newName: '', + newOneTime: '', + newMonthly: '', + error: false + }]; + \ No newline at end of file From 77d847ec42636720d4d21b63d7b55160b7d215bc Mon Sep 17 00:00:00 2001 From: Kelly Garry Date: Tue, 26 Mar 2019 15:02:23 -0600 Subject: [PATCH 3/5] refactored again --- src/App.js | 38 +++- .../{DataTotal.js => Calculations.js} | 13 +- src/components/DataDisplay.js | 174 ------------------ src/components/DataEntry.js | 58 ++++-- src/components/DataTable.js | 79 ++++++++ src/data/seedData.js | 37 ++-- 6 files changed, 170 insertions(+), 229 deletions(-) rename src/components/{DataTotal.js => Calculations.js} (93%) delete mode 100644 src/components/DataDisplay.js create mode 100644 src/components/DataTable.js diff --git a/src/App.js b/src/App.js index 977dfa1..99ad983 100644 --- a/src/App.js +++ b/src/App.js @@ -1,15 +1,41 @@ import React, { Component } from 'react'; -import DataDisplay from './components/DataDisplay.js'; -import DataEntry from './components/DataEntry.js'; -import DataTotal from './components/DataTotal.js'; +import DataTable from './components/DataTable.js'; +// import DataEntry from './components/DataEntry.js'; +import Calculations from './components/Calculations.js'; +import seedData from './data/seedData'; class App extends Component { + constructor(props) { + super(props); + this.state = { + revenue: seedData.revenue, + expenses: seedData.expenses, + oneTimeRevenue: 175, + oneTimeExpense: 700, + monthlyRevenue: 160, + monthlyExpense: 60 + } + } + render() { + const { revenue, expenses } = this.state; + console.log(revenue); + console.log(expenses); + return (
- - - +

ROI Calculator

+ this.setState({ revenue })} + /> + this.setState({ expenses })} + /> +
); } diff --git a/src/components/DataTotal.js b/src/components/Calculations.js similarity index 93% rename from src/components/DataTotal.js rename to src/components/Calculations.js index 204eaaf..920dea3 100644 --- a/src/components/DataTotal.js +++ b/src/components/Calculations.js @@ -7,20 +7,19 @@ import { } from 'react-bootstrap' import './Data.css'; -class DataTotal extends Component { +class Calculations extends Component { constructor(props) { super(props); // "seed" data initially this.state = { - oneTimeRevenue: 175, - oneTimeExpense: 700, - monthlyRevenue: 160, - monthlyExpense: 60 + // oneTimeRevenue: 175, + // oneTimeExpense: 700, + // monthlyRevenue: 160, + // monthlyExpense: 60 } } render() { - // MOVE THESE // Calculations for totals let totalRevenue = this.state.oneTimeRevenue + (this.state.monthlyRevenue * 24) let totalExpense = this.state.oneTimeExpense + (this.state.monthlyExpense * 24) @@ -86,4 +85,4 @@ class DataTotal extends Component { } } -export default DataTotal; \ No newline at end of file +export default Calculations; \ No newline at end of file diff --git a/src/components/DataDisplay.js b/src/components/DataDisplay.js deleted file mode 100644 index e62e522..0000000 --- a/src/components/DataDisplay.js +++ /dev/null @@ -1,174 +0,0 @@ -import React, { Component } from 'react'; -import { - Row, - Col, - Button, - Form -} from 'react-bootstrap' -import './Data.css'; - -class DataDisplay extends Component { - constructor() { - super(); - // "seed" data initially - this.state = { - revenue: [ - { - name: 'Item 1', - oneTime: 100, - monthly: 50 - }, - { - name: 'Item 2', - oneTime: 50, - monthly: 25 - }, - { - name: 'Item 3', - oneTime: 25, - monthly: 85 - }], - expenses: [{ - name: 'Expense 1', - oneTime: 500, - monthly: 20.00 - }, - { - name: 'Expense 2', - oneTime: 200, - monthly: 40 - }] - } - - this.handleDelete = this.handleDelete.bind(this) - this.handleAdd = this.handleAdd.bind(this) - } - - // Delete expense or revenue from list - handleDelete(type, index) { - // listType will be 'expenses' or 'revenue' depending on item to delete - let listType = this.state[type] - // recalculate and set totals in state - if (type === 'expenses') { - this.setState({ - oneTimeExpense: this.state.oneTimeExpense - this.state.expenses[index]['oneTime'], - monthlyExpense: this.state.monthlyExpense - this.state.expenses[index]['monthly'], - }) - } else { - // for revenue - this.setState({ - oneTimeRevenue: this.state.oneTimeRevenue - this.state.revenue[index]['oneTime'], - monthlyRevenue: this.state.monthlyRevenue - this.state.revenue[index]['monthly'], - }) - } - // remove list item from state array - this.setState({ - [listType]: listType.splice(index, 1), - }) - } - - // add new expense or revenue - handleAdd(e) { - e.preventDefault() - // handle form errors, allows one-time and revenue amounts to be 0 - if (!this.state.newType || !this.state.newName || (!this.state.newOneTime && this.state.newOneTime !== 0) || (!this.state.newMonthly && this.state.newMonthly !== 0)) { - this.setState({ - error: true - }) - } - // if there are no form errors, add accordingly - else { - // typeOfAmount will be either 'expenses' or 'revenue' - let typeOfAmount = this.state.newType - let monthly = typeOfAmount === 'expenses' ? 'monthlyExpense' : 'monthlyRevenue' - let oneTime = typeOfAmount === 'expenses' ? 'oneTimeExpense' : 'oneTimeRevenue' - // grab state array of revenues or expenses - let items = this.state[typeOfAmount] - items.push({ - name: this.state.newName, - oneTime: this.state.newOneTime, - monthly: this.state.newMonthly - }) - // set state with new totals and items array, clear errors displaying and form contents - this.setState({ - error: false, - [typeOfAmount]: items, - [monthly]: this.state[monthly] + this.state.newMonthly, - [oneTime]: this.state[oneTime] + this.state.newOneTime, - // Clear values in form - newName: '', - newMonthly: '', - newOneTime: '', - newType: '' - }) - } - } - - render() { - // create table rows from revenue state list - let revenueTableData = this.state.revenue.map((item, index) => { - return ( - - {item.name} - ${item.oneTime.toFixed(2)} - ${item.monthly.toFixed(2)} - - - ) - }) - // create table rows from expenses state list - let expensesTableData = this.state.expenses.map((expense, index) => { - return ( - - {expense.name} - ${expense.oneTime.toFixed(2)} - ${expense.monthly.toFixed(2)} - - - ) - }) - - return ( -
-
- {/* Revenue Table */} - - - - - - - - - - - - - - {revenueTableData} - -
Revenue
One-TimeMonthly
- {/* Expenses Table */} - - - - - - - - - - - - - - {expensesTableData} - -
Expenses
One-TimeMonthly
-
-
- ); - } -} - -export default DataDisplay; \ No newline at end of file diff --git a/src/components/DataEntry.js b/src/components/DataEntry.js index bd73f3c..19e61da 100644 --- a/src/components/DataEntry.js +++ b/src/components/DataEntry.js @@ -11,7 +11,6 @@ class DataEntry extends Component { constructor(props) { super(props); this.state = { - newType: '', newName: '', newOneTime: '', newMonthly: '', @@ -19,18 +18,12 @@ class DataEntry extends Component { } // controlled form elements functions - this.handleTypeChange = this.handleTypeChange.bind(this) this.handleNameChange = this.handleNameChange.bind(this) this.handleOneTimeChange = this.handleOneTimeChange.bind(this) this.handleMonthlyChange = this.handleMonthlyChange.bind(this) } // controlled form elements, watch for changes - handleTypeChange(e) { - this.setState({ - newType: e.target.value - }) - } handleNameChange(e) { this.setState({ newName: e.target.value @@ -48,24 +41,51 @@ class DataEntry extends Component { }) } + handleAdd(e) { + e.preventDefault() + // handle form errors, allows one-time and revenue amounts to be 0 + if (!this.state.newName || (!this.state.newOneTime && this.state.newOneTime !== 0) || (!this.state.newMonthly && this.state.newMonthly !== 0)) { + this.setState({ + error: true + }) + } + // if there are no form errors, add accordingly + else { + // typeOfAmount will be either 'expenses' or 'revenue' + // let typeOfAmount = this.state.newType + // let monthly = typeOfAmount === 'expenses' ? 'monthlyExpense' : 'monthlyRevenue' + // let oneTime = typeOfAmount === 'expenses' ? 'oneTimeExpense' : 'oneTimeRevenue' + // // grab state array of revenues or expenses + // let items = this.state[typeOfAmount] + items.push({ + name: this.state.newName, + oneTime:this.state.newOneTime, + monthly: this.state.newMonthly + }) + // set state with new totals and items array, clear errors displaying and form contents + this.setState({ + error: false, + // [typeOfAmount]: items, + [monthly]: this.state[monthly] + this.state.newMonthly, + [oneTime]: this.state[oneTime] + this.state.newOneTime, + // Clear values in form + newName: '', + newMonthly: '', + newOneTime: '', + newType: '' + }) + } + } + + render() { + // const { title, data } = this.props; + return (
-

ROI Calculator

{/* Add new expense or revenue form */}
- - - - - - - { + return ( + + {item.name} + ${item.oneTime.toFixed(2)} + ${item.monthly.toFixed(2)} + + + ) + }) + + return ( +
+
+ {/* Revenue Table */} + + + + + + + + + + + + + + {tableData} + +
{title}
One-TimeMonthly
+ this.handleAdd(newName, newOneTime, newMonthly)} + /> +
+
+ ); + } +} + +export default DataTable; \ No newline at end of file diff --git a/src/data/seedData.js b/src/data/seedData.js index be377ee..baed84e 100644 --- a/src/data/seedData.js +++ b/src/data/seedData.js @@ -1,5 +1,5 @@ -export default [{ - revenue: [ +export default { + revenue: [ { name: 'Item 1', oneTime: 100, @@ -15,24 +15,15 @@ export default [{ oneTime: 25, monthly: 85 }], - expenses:[{ - name: 'Expense 1', - oneTime: 500, - monthly: 20.00 - }, - { - name: 'Expense 2', - oneTime: 200, - monthly: 40 - }], - oneTimeRevenue: 175, - oneTimeExpense: 700, - monthlyRevenue: 160, - monthlyExpense: 60, - newType: '', - newName: '', - newOneTime: '', - newMonthly: '', - error: false - }]; - \ No newline at end of file + expenses: [{ + name: 'Expense 1', + oneTime: 500, + monthly: 20.00 + }, + { + name: 'Expense 2', + oneTime: 200, + monthly: 40 + }] + +}; From 7c707f9f9bc6f43762da2cdbf5040f56212d6a8a Mon Sep 17 00:00:00 2001 From: Kelly Garry Date: Tue, 26 Mar 2019 20:59:25 -0600 Subject: [PATCH 4/5] working now clean up --- src/App.js | 9 +++---- src/components/Calculations.js | 46 +++++++++++++++++++++++----------- src/components/DataEntry.js | 42 ++++++++----------------------- src/components/DataTable.js | 2 +- src/data/seedData.js | 9 ++++--- 5 files changed, 53 insertions(+), 55 deletions(-) diff --git a/src/App.js b/src/App.js index 99ad983..17841ef 100644 --- a/src/App.js +++ b/src/App.js @@ -10,10 +10,6 @@ class App extends Component { this.state = { revenue: seedData.revenue, expenses: seedData.expenses, - oneTimeRevenue: 175, - oneTimeExpense: 700, - monthlyRevenue: 160, - monthlyExpense: 60 } } @@ -35,7 +31,10 @@ class App extends Component { data={expenses} onUpdateTableData={(expenses) => this.setState({ expenses })} /> - +
); } diff --git a/src/components/Calculations.js b/src/components/Calculations.js index 920dea3..24efb10 100644 --- a/src/components/Calculations.js +++ b/src/components/Calculations.js @@ -6,30 +6,46 @@ import { Form } from 'react-bootstrap' import './Data.css'; +// import seedData from '../data/seedData'; class Calculations extends Component { constructor(props) { super(props); - // "seed" data initially this.state = { - // oneTimeRevenue: 175, - // oneTimeExpense: 700, - // monthlyRevenue: 160, - // monthlyExpense: 60 + monthTerm: 24 } } render() { + const { monthTerm } = this.state; + const { revenue, expenses } = this.props; // Calculations for totals - let totalRevenue = this.state.oneTimeRevenue + (this.state.monthlyRevenue * 24) - let totalExpense = this.state.oneTimeExpense + (this.state.monthlyExpense * 24) - let monthlyContributionProfit = this.state.monthlyRevenue - this.state.monthlyExpense + let oneTimeRevenue = revenue.reduce(function (prev, cur) { + return prev + cur.oneTime; + }, 0); + + let oneTimeExpense = expenses.reduce(function (prev, cur) { + return prev + cur.oneTime; + }, 0); + + let monthlyRevenue = revenue.reduce(function (prev, cur) { + return prev + cur.monthly; + }, 0); + + let monthlyExpense = expenses.reduce(function (prev, cur) { + return prev + cur.monthly; + }, 0); + + let totalRevenue = oneTimeRevenue + (monthlyRevenue * monthTerm) + let totalExpense = oneTimeExpense + (monthlyExpense * monthTerm) + let monthlyContributionProfit = monthlyRevenue - monthlyExpense let totalContributionProfit = totalRevenue - totalExpense // handle case where totalRevenue is 0 (to avoid -Infinity and NaN) let contributionMargin = totalRevenue !== 0 ? (totalContributionProfit / totalRevenue * 100).toFixed(0) : 0 // handle case where totalExpense and totalRevenue are 0 (to avoid NaN) - let capitalROI = (totalExpense === 0 && totalRevenue === 0) ? 0 : ((this.state.oneTimeExpense - this.state.oneTimeRevenue) / monthlyContributionProfit).toFixed(1) - + let capitalROI = (totalExpense === 0 && totalRevenue === 0) ? 0 : ((oneTimeExpense - oneTimeRevenue) / monthlyContributionProfit).toFixed(1) + + return (
@@ -37,7 +53,7 @@ class Calculations extends Component { - + @@ -49,14 +65,14 @@ class Calculations extends Component { - - + + - - + + diff --git a/src/components/DataEntry.js b/src/components/DataEntry.js index 19e61da..18ec698 100644 --- a/src/components/DataEntry.js +++ b/src/components/DataEntry.js @@ -16,11 +16,6 @@ class DataEntry extends Component { newMonthly: '', error: false } - - // controlled form elements functions - this.handleNameChange = this.handleNameChange.bind(this) - this.handleOneTimeChange = this.handleOneTimeChange.bind(this) - this.handleMonthlyChange = this.handleMonthlyChange.bind(this) } // controlled form elements, watch for changes @@ -43,32 +38,18 @@ class DataEntry extends Component { handleAdd(e) { e.preventDefault() + const { newName, newOneTime, newMonthly } = this.state; // handle form errors, allows one-time and revenue amounts to be 0 - if (!this.state.newName || (!this.state.newOneTime && this.state.newOneTime !== 0) || (!this.state.newMonthly && this.state.newMonthly !== 0)) { + if (!newName || (!newOneTime && newOneTime !== 0) || (!newMonthly && newMonthly !== 0)) { this.setState({ error: true }) } // if there are no form errors, add accordingly else { - // typeOfAmount will be either 'expenses' or 'revenue' - // let typeOfAmount = this.state.newType - // let monthly = typeOfAmount === 'expenses' ? 'monthlyExpense' : 'monthlyRevenue' - // let oneTime = typeOfAmount === 'expenses' ? 'oneTimeExpense' : 'oneTimeRevenue' - // // grab state array of revenues or expenses - // let items = this.state[typeOfAmount] - items.push({ - name: this.state.newName, - oneTime:this.state.newOneTime, - monthly: this.state.newMonthly - }) - // set state with new totals and items array, clear errors displaying and form contents + this.props.onAddData( newName, newOneTime, newMonthly ); this.setState({ error: false, - // [typeOfAmount]: items, - [monthly]: this.state[monthly] + this.state.newMonthly, - [oneTime]: this.state[oneTime] + this.state.newOneTime, - // Clear values in form newName: '', newMonthly: '', newOneTime: '', @@ -77,41 +58,40 @@ class DataEntry extends Component { } } - render() { - // const { title, data } = this.props; + const { newName, newOneTime, newMonthly, error } = this.state; return (
{/* Add new expense or revenue form */} - + this.handleAdd(e)}>
this.handleNameChange(e)} + value={newName ? newName : ''} /> this.handleOneTimeChange(e)} step="0.01" min="0" - value={(this.state.newOneTime || this.state.newOneTime === 0) ? this.state.newOneTime : ''} + value={(newOneTime || newOneTime === 0) ? newOneTime : ''} /> this.handleMonthlyChange(e)} step="0.01" min="0" - value={(this.state.newMonthly || this.state.newMonthly === 0) ? this.state.newMonthly : ''} + value={(newMonthly || newMonthly === 0) ? newMonthly : ''} /> diff --git a/src/components/DataTable.js b/src/components/DataTable.js index 93b6780..e845ef6 100644 --- a/src/components/DataTable.js +++ b/src/components/DataTable.js @@ -13,7 +13,6 @@ class DataTable extends Component { super(props); this.state = {} } - // Delete expense or revenue from list handleDelete(index) { const { data, onUpdateTableData } = this.props; @@ -32,6 +31,7 @@ class DataTable extends Component { onUpdateTableData(data); } + render() { const { title, data } = this.props; diff --git a/src/data/seedData.js b/src/data/seedData.js index baed84e..c8f7f0f 100644 --- a/src/data/seedData.js +++ b/src/data/seedData.js @@ -24,6 +24,9 @@ export default { name: 'Expense 2', oneTime: 200, monthly: 40 - }] - -}; + }], + oneTimeRevenue: 175, + oneTimeExpense: 700, + monthlyRevenue: 160, + monthlyExpense: 60 +}; \ No newline at end of file From 71ea5e5b006777ed4f0835aa90bca68cf9281085 Mon Sep 17 00:00:00 2001 From: Kelly Garry Date: Tue, 26 Mar 2019 21:38:35 -0600 Subject: [PATCH 5/5] submitting to Zayo --- src/App.css | 39 ------------------------- src/App.js | 6 ++-- src/components/Calculations.js | 9 +----- src/components/Data.css | 53 +++++++++++++++++----------------- src/components/DataEntry.js | 2 +- src/components/DataTable.js | 10 ++----- 6 files changed, 33 insertions(+), 86 deletions(-) delete mode 100644 src/App.css diff --git a/src/App.css b/src/App.css deleted file mode 100644 index 45b32df..0000000 --- a/src/App.css +++ /dev/null @@ -1,39 +0,0 @@ -/* .addExpenseOrRevenueForm { - padding-top: 3em; -} - -.input-field, .add-form-button { - padding-bottom: 1em; -} - -.roi-tables { - padding-top: 2em; - height: 100%; - display: flex; - flex-direction: column; - align-items: center; -} - -.expenses-table, .revenue-table, .totals-table { - margin-bottom: 3em; -} -.expenses-table th, .revenue-table th, .totals-table th { - width: 150px; -} -.expenses-table td, .revenue-table td, .totals-table td { - width: 100px -} - -.error { - color: red; -} - -@media only screen and (max-width:775px) { - .input-field, .add-form-button { - margin-left: .25em; - margin-right: .25em; - } - .roi-tables { - padding-left: 1.5em; - } -} */ diff --git a/src/App.js b/src/App.js index 17841ef..be71301 100644 --- a/src/App.js +++ b/src/App.js @@ -22,12 +22,12 @@ class App extends Component {

ROI Calculator

this.setState({ revenue })} /> this.setState({ expenses })} /> @@ -40,4 +40,4 @@ class App extends Component { } } -export default App; +export default App; \ No newline at end of file diff --git a/src/components/Calculations.js b/src/components/Calculations.js index 24efb10..8b82cea 100644 --- a/src/components/Calculations.js +++ b/src/components/Calculations.js @@ -1,12 +1,5 @@ import React, { Component } from 'react'; -import { - Row, - Col, - Button, - Form -} from 'react-bootstrap' import './Data.css'; -// import seedData from '../data/seedData'; class Calculations extends Component { constructor(props) { @@ -19,6 +12,7 @@ class Calculations extends Component { render() { const { monthTerm } = this.state; const { revenue, expenses } = this.props; + // Calculations for totals let oneTimeRevenue = revenue.reduce(function (prev, cur) { return prev + cur.oneTime; @@ -45,7 +39,6 @@ class Calculations extends Component { // handle case where totalExpense and totalRevenue are 0 (to avoid NaN) let capitalROI = (totalExpense === 0 && totalRevenue === 0) ? 0 : ((oneTimeExpense - oneTimeRevenue) / monthlyContributionProfit).toFixed(1) - return (
diff --git a/src/components/Data.css b/src/components/Data.css index 831719e..849a7aa 100644 --- a/src/components/Data.css +++ b/src/components/Data.css @@ -1,40 +1,39 @@ .addExpenseOrRevenueForm { - padding-top: 3em; + padding-top: .5em; } - .input-field, .add-form-button { - padding-bottom: 1em; +.input-field, .add-form-button { + padding-bottom: .5em; } - .roi-tables { - padding-top: 2em; - height: 100%; - display: flex; - flex-direction: column; - align-items: center; +.roi-tables { + padding-top: 1em; + height: 100%; + display: flex; + flex-direction: column; + align-items: center; } - .expenses-table, .revenue-table, .totals-table { - margin-bottom: 3em; +.expenses-table, .revenue-table, .totals-table { + margin-bottom: 3em; } - .expenses-table th, .revenue-table th, .totals-table th { - width: 150px; +.expenses-table th, .revenue-table th, .totals-table th { + width: 200px; } - .expenses-table td, .revenue-table td, .totals-table td { - width: 100px +.expenses-table td, .revenue-table td, .totals-table td { + width: 100px } - .error { - color: red; +.error { + color: red; } - @media only screen and (max-width:775px) { - .input-field, .add-form-button { - margin-left: .25em; - margin-right: .25em; - } - .roi-tables { - padding-left: 1.5em; - } - } - \ No newline at end of file +@media only screen and (max-width:775px) { + .input-field, .add-form-button { + margin-left: .25em; + margin-right: .25em; + } + .roi-tables { + padding-left: 1.5em; + } +} \ No newline at end of file diff --git a/src/components/DataEntry.js b/src/components/DataEntry.js index 18ec698..3828a6d 100644 --- a/src/components/DataEntry.js +++ b/src/components/DataEntry.js @@ -59,7 +59,7 @@ class DataEntry extends Component { } render() { - const { newName, newOneTime, newMonthly, error } = this.state; + const { newName, newOneTime, newMonthly } = this.state; return (
diff --git a/src/components/DataTable.js b/src/components/DataTable.js index e845ef6..d786769 100644 --- a/src/components/DataTable.js +++ b/src/components/DataTable.js @@ -1,12 +1,7 @@ import React, { Component } from 'react'; -import { - Row, - Col, - Button, - Form -} from 'react-bootstrap' -import './Data.css'; +import { Button } from 'react-bootstrap' import DataEntry from './DataEntry.js'; +import './Data.css'; class DataTable extends Component { constructor(props) { @@ -31,7 +26,6 @@ class DataTable extends Component { onUpdateTableData(data); } - render() { const { title, data } = this.props;
24 Month Term{monthTerm} Month Term
Total
Revenue${(this.state.oneTimeRevenue).toFixed(2)}${(this.state.monthlyRevenue).toFixed(2)}${(oneTimeRevenue).toFixed(2)}${(monthlyRevenue).toFixed(2)} ${totalRevenue.toFixed(2)}
Expenses${(this.state.oneTimeExpense).toFixed(2)}${(this.state.monthlyExpense).toFixed(2)}${(oneTimeExpense).toFixed(2)}${(monthlyExpense).toFixed(2)} ${totalExpense.toFixed(2)}