diff --git a/src/forms/Predictions.js b/src/forms/Predictions.js index 68404d61..71328eef 100644 --- a/src/forms/Predictions.js +++ b/src/forms/Predictions.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { Component, Fragment } from 'react'; import { Divider, Header, @@ -10,51 +10,125 @@ import { // PROJECT COMPONENTS import { FormPartsContainer } from './FormPartsContainer'; -import { IntervalColumnHeadings } from '../components/headings'; import { CashFlowInputsRow } from './cashflow'; -import { GraphHolder } from './output/GraphHolder'; -import { Summary } from './output/Summary'; -import { BenefitsTable } from './output/BenefitsTable'; -import { ResourcesColumns } from './output/ResourcesColumns'; -import { StackedResources } from './output/StackedResources'; -import { BenefitsLines } from './output/BenefitsLines'; +import { ShowOnYes } from './ShowOnYes'; +import { AttentionArrow } from './formHelpers'; +import { GraphHolder } from './predictions/GraphHolder'; +import { Summary } from './predictions/Summary'; +import { BenefitsTable } from './predictions/BenefitsTable'; +import { ResourcesColumns } from './predictions/ResourcesColumns'; +import { StackedResources } from './predictions/StackedResources'; +import { BenefitsLines } from './predictions/BenefitsLines'; +// NON-COMPONENTS +import { applyAndPushBenefits } from '../benefits/applyAndPushBenefits'; +import { benefitArrayDataToSingleData } from './predictions/build-resource-data'; +import { toMoneyStr } from '../utils/prettifiers'; +import { cloneDeep } from 'lodash'; -/** @todo Cash flow row for trying out different future incomes. - * - * As per Project Hope's input, for the first prototype - * we're only including the ability to change earned income. - * - * @function - * @param {object} props - * @param {object} props.future Client future/predictive data. - * @param {string} props.time Used in class names. Meant to make - * this more easily decoupled in future. - * @param {function} props.updateClientValue Update client state - * value. - * @param {object} props.translations Language-specific text - * - * @returns {object} React element - */ -const IncomeForm = function ({ future, time, updateClientValue, translations }) { - let type = `income`; +class PredictionsStep extends Component{ + // Accumulated data for rendering results + state = { + client: this.props.client, + currentBenefitData: {}, + }; - return ( -
- - - { translations.i_futureIncomeQuestion } - -
- ); -}; + componentDidMount () { + // Multiple things need the current benefit data + // to show results + this.setState((prevState) => { + let clone = cloneDeep(prevState.client), + accumulated = {}; + + let resourceKeys = [ + `earned`, + ...clone.current.benefits, + ], + calcData = { + activeBenefits: resourceKeys, + dataToAddTo: accumulated, + clientToChange: clone, + timeframe: `current`, + }; + + // mutates `accumulated` + applyAndPushBenefits(calcData); + + return { + client: clone, + currentBenefitData: accumulated, + }; + }); + } + + render () { + let { currentBenefitData } = this.state; + let { client, updateClientValue, navData, translations, openFeedback } = this.props; + + if (currentBenefitData.earned === undefined) { + return null; + } + + // Really quick returns if other calcs not needed + if (client.current.benefits.length === 0) { + return translations.i_noBenefitsChosen; + } + + return ( + + + {/* `predictions-form`: This whole div will be outside + the form in the future and then we'll be able to + access its style that way */} + + + +
+ + +
+
+
+ { translations.i_chartsHeader } +
+ + { translations.i_warningMessage } + + +
+ +
+ ); + } // End render() +}; // End const TabbedVisualizations = ({ client, openFeedback, translations }) => { @@ -156,53 +230,224 @@ const TabbedVisualizations = ({ client, openFeedback, translations }) => { }; // Ends -const PredictionsStep = function ({ updateClientValue, navData, client, translations, openFeedback }) { +// Recap of current info from client +let Recap = function ({ client, currentBenefitData, translations, openFeedback }) { + + // Get the data for the component + let current = client.current, + resourceKeys = [ + `earned`, + ...current.benefits, + ]; + + let data = benefitArrayDataToSingleData(resourceKeys, currentBenefitData, 0); + + // Build the contents of the component + let start = ( +

+ { `The tool is still being tested, so don't use it to make decisions. If it's right, it has calculated your money coming in as:` } +

+ ); + + // Stays put when printing. A take-home hint + // that the tool is still a prototype + let feedbackAsk = ( + + { translations.i_feedbackAsk } + + + ); return ( - - {/* `predictions-form`: This whole div will be outside - the form in the future and then we'll be able to - access its style that way */} -
- - -
-
-
- { translations.i_chartsHeader } -
- - { translations.i_warningMessage } - - -
- +
Right now
+ { start } + -
+ { feedbackAsk } + + ); -}; // End +}; // Ends + + +/** As per Project Hope's input, for the first prototype + * we're only including the ability to change earned income. + * + * @function + * @param {object} props + * @param {object} props.client Client current and future data. + * @param {function} props.updateClientValue Update client state + * value. + * @param {object} props.translations Language-specific text + * + * @returns {object} React element + */ +const Raise = function ({ client, updateClientValue, currentBenefitData, translations }) { + + let future = client.future, + key = `raise`, + type = `income`; + + let reset = function (event) { + updateClientValue(event, { + name: key, + value: 0, + }); + }; + + let inputs = ( +
+ + { `How much would your raise be?` } + +
+ ); + + return ( + +
+
What would happen with a raise?
+ 0 } + question = { `Do you want to see what would happen if you got a raise?` } + heading = { null } + onNo = { reset } + Left = { }> + { inputs } + +
+ + + ); +}; + + +let RaiseResults = function ({ client, currentBenefitData, translations }) { + // Add the data for the future of the client using the raise + let clone = cloneDeep(client), + futureBenefitData = {}; + + let resourceKeys = [ + `earned`, + ...clone.current.benefits, + ], + calcData = { + activeBenefits: resourceKeys, + dataToAddTo: futureBenefitData, + clientToChange: clone, + timeframe: `future`, + }; + + // mutates `accumulated` + applyAndPushBenefits(calcData); + let currentData = benefitArrayDataToSingleData(resourceKeys, currentBenefitData, 0), + futureData = benefitArrayDataToSingleData(resourceKeys, futureBenefitData, 0); + + let start = ( +

+ { `If you get a raise of ` } + { translations.i_beforeMoneyWithTime }{ round$(clone.future.raise) } { translations.i_eachTimeInterval } + { ` your money coming in could look like this:` } +

+ ); + + let diff = futureData.total - currentData.total, + changeStart = ({ ` That would be ` }), + amount = ( + + { translations.i_beforeMoneyWithTime }{ round$(Math.abs(diff)) } { translations.i_eachTimeInterval } + + ), + lessOrMore = null; + + if (diff === 0) { + lessOrMore = ({ `the same as before.` }); + } else if (diff > 0) { + lessOrMore = ({ amount }{ ` more than before.` }); + } else { + lessOrMore = ({ amount }{ ` less than before.` }); + } + + return ( + + { start } + + { changeStart } + { lessOrMore } + { translations.i_findHelp } + + ); +}; // Ends + + +let TextResults = function ({ client, data, translations }) { + // Benefit list items. Always starts with `earned`. + let resourceList = [ + ( +
  • { `Pay from work: ` }{translations.i_beforeMoneyWithTime}{round$(data.earned)} {translations.i_eachTimeInterval}
  • + ), + ]; + + let numBenefits = client.current.benefits.length; + for (let benefiti = 0; benefiti < numBenefits; benefiti++) { + + let cBenefit = data.benefits[ benefiti ]; + resourceList.push( +
  • + {cBenefit.label}: {translations.i_beforeMoneyWithTime}{round$(cBenefit.amount)} {translations.i_eachTimeInterval} +
  • + ); + } // ends for each benefit + + let totals = ( +

    + { `That's ` } + + { translations.i_beforeMoneyWithTime }{ round$(data.total) + ` ` } + + { translations.i_eachTimeInterval }{ translations.i_period } +

    + ); + + return ( + +
      { resourceList }
    + { totals } +
    + ); +}; + + +/** Rounds money values, turns them into money-formatted + * strings, then removes trailing '.00' + * + * @param {number} number Number to round and format + * @returns {string} + */ +let round$ = function (number) { + return toMoneyStr(Math.round(number)).replace(`.00`, ``); +}; export { PredictionsStep }; diff --git a/src/forms/output/BENEFIT_CHART_VALUES.js b/src/forms/predictions/BENEFIT_CHART_VALUES.js similarity index 100% rename from src/forms/output/BENEFIT_CHART_VALUES.js rename to src/forms/predictions/BENEFIT_CHART_VALUES.js diff --git a/src/forms/output/BenefitsLines.js b/src/forms/predictions/BenefitsLines.js similarity index 100% rename from src/forms/output/BenefitsLines.js rename to src/forms/predictions/BenefitsLines.js diff --git a/src/forms/output/BenefitsTable.js b/src/forms/predictions/BenefitsTable.js similarity index 100% rename from src/forms/output/BenefitsTable.js rename to src/forms/predictions/BenefitsTable.js diff --git a/src/forms/output/CHART_FROSTING.js b/src/forms/predictions/CHART_FROSTING.js similarity index 100% rename from src/forms/output/CHART_FROSTING.js rename to src/forms/predictions/CHART_FROSTING.js diff --git a/src/forms/output/GraphHolder.js b/src/forms/predictions/GraphHolder.js similarity index 100% rename from src/forms/output/GraphHolder.js rename to src/forms/predictions/GraphHolder.js diff --git a/src/forms/output/GraphTimeButtons.js b/src/forms/predictions/GraphTimeButtons.js similarity index 100% rename from src/forms/output/GraphTimeButtons.js rename to src/forms/predictions/GraphTimeButtons.js diff --git a/src/forms/output/ResourcesColumns.js b/src/forms/predictions/ResourcesColumns.js similarity index 100% rename from src/forms/output/ResourcesColumns.js rename to src/forms/predictions/ResourcesColumns.js diff --git a/src/forms/output/StackedResources.js b/src/forms/predictions/StackedResources.js similarity index 100% rename from src/forms/output/StackedResources.js rename to src/forms/predictions/StackedResources.js diff --git a/src/forms/output/Summary.js b/src/forms/predictions/Summary.js similarity index 77% rename from src/forms/output/Summary.js rename to src/forms/predictions/Summary.js index 8b08671c..1fe5ff4f 100644 --- a/src/forms/output/Summary.js +++ b/src/forms/predictions/Summary.js @@ -7,16 +7,11 @@ import { Button, } from 'semantic-ui-react'; -// DATA -// Colors and text for parts of the chart -import { BENEFIT_CHART_VALUES } from './BENEFIT_CHART_VALUES'; - -// DATA MANIPULATION -import { cloneDeep } from 'lodash'; -import { toMoneyStr } from '../../utils/prettifiers'; - -// BENEFIT LOGIC +// NON-COMPONENTS import { applyAndPushBenefits } from '../../benefits/applyAndPushBenefits'; +import { toMoneyStr } from '../../utils/prettifiers'; +import { benefitArrayDataToSingleData } from './build-resource-data'; +import { cloneDeep } from 'lodash'; const EARNED_MONTHLY_INCREMENT_AMOUNT = 50; // About a 25 cent raise in monthly amount for 40hrs/week? @@ -50,105 +45,6 @@ let totalLastItemsOfArraysInObject = function (accumulated) { return total; }; -/** Returns values representing earned income and benefit - * amounts at the given index, as well as the sum of all - * those benefits and the sum of the earned income and - * those benefits. - * - * @param {array} keys Contains keys to use on `sourceObject`. - * @param {object} sourceObject MUST CONTAIN `earned` property! - * Contains `earned` and benefit keys that each have an - * array of numerical values (which are meant to be money - * values right now). - * @param {array} sourceObject.earned Earned income values. - * @param {int} Which item in each array should be used to - * accumulate values. - * - * @example - * // In BENEFIT_CHART_VALUES.js - * let BENEFIT_CHART_VALUES = { - * benefit1: { name: "B1" }, - * benefit2: { name: "B2" }, - * }; - * - * // In here - * let keys = [ - * 'benefit1', - * 'benefit2', - * ]; - * - * let accumulated = { - * earned: [ 450, 500 ], - * benefit1: [ 80, 30 ], - * benefit2: [ 40, 10 ], - * }; - * - * let index = 1; - * - * var summaryData = fillInMoneyValues(keys, accumulated, index); - * - * console.log(summaryData); - * // { - * // earned: 500, - * // benefits: [ - * // { label: "B1", amount: 30 }, - * // { label: "B2", amount: 10 } - * // ], - * // benefitsTotal: 40, - * // total: 540, - * // } - * - * Unfortunately, stll relies on an outside value - - * BENEFIT_CHART_VALUES. - * - * @typedef {object} benefit - * @property {string} label Name to be displayed for the benefit - * @property {number} amount Value of the benefit/subsidy - * - * @typedef {object} moneyValues - * @property {number} earned Amount earned at a given index - * @property {array.} benefits - * @property {number} benefitsTotal Sum of all benefit values at - * the given index - * @property {number} total Sum of earned income and all benefits - * at the given index - * - * @returns {object} moneyValues - */ -let fillInMoneyValues = (keys, sourceObject, index) => { - - if (!Array.isArray(sourceObject.earned)) { - throw new TypeError(`The given resources object requires an 'earned' property that is an array of numbers.`); - } - - let moneyValues = { - earned: 0, - benefits: [], // [{ label, amount }] - benefitsTotal: 0, - total: 0, - }; - - // Item names can be `earned` or benefit keys - for (let itemKey of keys) { - let amount = sourceObject[ itemKey ][ index ]; - - if (itemKey === `earned`) { - moneyValues.earned = amount; - } else { - moneyValues.benefits.push({ - label: BENEFIT_CHART_VALUES[ itemKey ].name, - amount: amount, - }); - // Add up all benefits (we're not including earned income) - moneyValues.benefitsTotal += amount; - } - } // ends for every item key name - - moneyValues.total = moneyValues.earned + moneyValues.benefitsTotal; - - return moneyValues; -}; // Ends fillInMoneyValues() - /** Uses benefit data getter and reformats it to * a format useful for identifying cliffs. @@ -224,8 +120,8 @@ let getBenefitData = function(client, resourceKeys) { // 2. Get totals // Fill earned values for both current and future earned objects - result.current = fillInMoneyValues(resourceKeys, accumulated, 0); - result.future = fillInMoneyValues(resourceKeys, accumulated, 1); + result.current = benefitArrayDataToSingleData(resourceKeys, accumulated, 0); + result.future = benefitArrayDataToSingleData(resourceKeys, accumulated, 1); let resultCurr = result.current, resultFutr = result.future; @@ -434,6 +330,5 @@ const Summary = function ({ client, openFeedback, translations }) { export { Summary, totalLastItemsOfArraysInObject, - fillInMoneyValues, getBenefitData, }; diff --git a/src/forms/predictions/build-resource-data.js b/src/forms/predictions/build-resource-data.js new file mode 100644 index 00000000..80ad8906 --- /dev/null +++ b/src/forms/predictions/build-resource-data.js @@ -0,0 +1,107 @@ +/** Functions used to rearrange resource data into useful formats + * @module + */ + +import { BENEFIT_CHART_VALUES } from './BENEFIT_CHART_VALUES'; + +/** Returns values representing earned income and benefit + * amounts at the given index, as well as the sum of all + * those benefits and the sum of the earned income and + * those benefits. + * + * @param {array} keys Contains keys to use on `sourceObject`. + * @param {object} sourceObject MUST CONTAIN `earned` property! + * Contains `earned` and benefit keys that each have an + * array of numerical values (which are meant to be money + * values right now). + * @param {array} sourceObject.earned Earned income values. + * @param {int} index Which item in each array should be used to + * accumulate values. + * + * @example + * // In BENEFIT_CHART_VALUES.js + * let BENEFIT_CHART_VALUES = { + * benefit1: { name: "B1" }, + * benefit2: { name: "B2" }, + * }; + * + * // In here + * let keys = [ + * 'benefit1', + * 'benefit2', + * ]; + * + * let accumulated = { + * earned: [ 450, 500 ], + * benefit1: [ 80, 30 ], + * benefit2: [ 40, 10 ], + * }; + * + * let index = 1; + * + * var summaryData = fillInMoneyValues(keys, accumulated, index); + * + * console.log(summaryData); + * // { + * // earned: 500, + * // benefits: [ + * // { label: "B1", amount: 30 }, + * // { label: "B2", amount: 10 } + * // ], + * // benefitsTotal: 40, + * // total: 540, + * // } + * + * Unfortunately, stll relies on an outside value - + * BENEFIT_CHART_VALUES. + * + * @typedef {object} benefit + * @property {string} label Name to be displayed for the benefit + * @property {number} amount Value of the benefit/subsidy + * + * @typedef {object} moneyValues + * @property {number} earned Amount earned at a given index + * @property {array.} benefits + * @property {number} benefitsTotal Sum of all benefit values at + * the given index + * @property {number} total Sum of earned income and all benefits + * at the given index + * + * @returns {object} moneyValues + */ +let benefitArrayDataToSingleData = (keys, sourceObject, index) => { + + if (!Array.isArray(sourceObject.earned)) { + throw new TypeError(`The given resources object requires an 'earned' property that is an array of numbers.`); + } + + let moneyValues = { + earned: 0, + benefits: [], // [{ label, amount }] + benefitsTotal: 0, + total: 0, + }; + + // Item names can be `earned` or benefit keys + for (let itemKey of keys) { + let amount = sourceObject[ itemKey ][ index ]; + + if (itemKey === `earned`) { + moneyValues.earned = amount; + } else { + moneyValues.benefits.push({ + label: BENEFIT_CHART_VALUES[ itemKey ].name, + amount: amount, + }); + // Add up all benefits (we're not including earned income) + moneyValues.benefitsTotal += amount; + } + } // ends for every item key name + + moneyValues.total = moneyValues.earned + moneyValues.benefitsTotal; + + return moneyValues; +}; // Ends benefitArrayDataToSingleData() + + +export { benefitArrayDataToSingleData }; diff --git a/src/forms/output/chartFormatting.js b/src/forms/predictions/chartFormatting.js similarity index 100% rename from src/forms/output/chartFormatting.js rename to src/forms/predictions/chartFormatting.js diff --git a/src/forms/output/chartStringTransformers.js b/src/forms/predictions/chartStringTransformers.js similarity index 100% rename from src/forms/output/chartStringTransformers.js rename to src/forms/predictions/chartStringTransformers.js diff --git a/src/forms/output/getChartData.js b/src/forms/predictions/getChartData.js similarity index 100% rename from src/forms/output/getChartData.js rename to src/forms/predictions/getChartData.js diff --git a/src/forms/output/zoom-handlers.js b/src/forms/predictions/zoom-handlers.js similarity index 100% rename from src/forms/output/zoom-handlers.js rename to src/forms/predictions/zoom-handlers.js diff --git a/src/index.css b/src/index.css index b954eb50..9afd0a6e 100644 --- a/src/index.css +++ b/src/index.css @@ -508,7 +508,6 @@ i.icon.details-icon { /* =============== */ /* LAYOUT */ /* =============== */ -/* Surrounder (general) */ .question-spacer { display: block; height: 1em; @@ -518,6 +517,7 @@ i.icon.details-icon { margin-bottom: 1em; } +/* Surrounder (general) */ .surrounder .horizontal, .surrounder .vertical { display: flex; @@ -544,6 +544,10 @@ i.icon.details-icon { margin-bottom: 1em; } +.show-on-yes .surrounder .center.horizontal { + align-items: center; +} + /* HomePage.js styles */ #HomePage { diff --git a/src/test/components/GraphTimeButtons.test.js b/src/test/components/GraphTimeButtons.test.js index e1cbbb83..7bc8adbb 100644 --- a/src/test/components/GraphTimeButtons.test.js +++ b/src/test/components/GraphTimeButtons.test.js @@ -1,7 +1,7 @@ import React from 'react'; import { mount } from 'enzyme'; -import { GraphTimeButtons } from '../../forms/output/GraphTimeButtons'; +import { GraphTimeButtons } from '../../forms/predictions/GraphTimeButtons'; describe('', () => { it('renders Weekly, Monthly, and Yearly buttons', () => { diff --git a/src/test/forms/output/BenefitsLines.test.js b/src/test/forms/output/BenefitsLines.test.js index 030e6807..a8c01e85 100644 --- a/src/test/forms/output/BenefitsLines.test.js +++ b/src/test/forms/output/BenefitsLines.test.js @@ -2,7 +2,7 @@ import React from 'react'; import { mount } from 'enzyme'; import { cloneDeep, set } from 'lodash'; -import { BenefitsLines } from '../../../forms/output/BenefitsLines'; +import { BenefitsLines } from '../../../forms/predictions/BenefitsLines'; import { CLIENT_DEFAULTS } from '../../../utils/CLIENT_DEFAULTS'; // Skipping till highcharts testing is worked out diff --git a/src/test/forms/output/BenefitsTable.test.js b/src/test/forms/output/BenefitsTable.test.js index ada3b511..3a735591 100644 --- a/src/test/forms/output/BenefitsTable.test.js +++ b/src/test/forms/output/BenefitsTable.test.js @@ -2,7 +2,7 @@ import React from 'react'; import renderer from 'react-test-renderer'; import { cloneDeep, set } from 'lodash'; -import { BenefitsTable } from '../../../forms/output/BenefitsTable'; +import { BenefitsTable } from '../../../forms/predictions/BenefitsTable'; import { translations } from '../../helpers'; import { CLIENT_DEFAULTS } from '../../../utils/CLIENT_DEFAULTS'; diff --git a/src/test/forms/output/GraphHolder.test.js b/src/test/forms/output/GraphHolder.test.js index 0a382e20..00798576 100644 --- a/src/test/forms/output/GraphHolder.test.js +++ b/src/test/forms/output/GraphHolder.test.js @@ -3,7 +3,7 @@ import { mount } from 'enzyme'; import { cloneDeep, set } from 'lodash'; import { CLIENT_DEFAULTS } from '../../../utils/CLIENT_DEFAULTS'; -import { GraphHolder } from '../../../forms/output/GraphHolder'; +import { GraphHolder } from '../../../forms/predictions/GraphHolder'; const passedActivePrograms = (wrapper) => { return wrapper.find('Graph').prop('activePrograms'); diff --git a/src/test/forms/output/ResourcesColumns.test.js b/src/test/forms/output/ResourcesColumns.test.js index 3da639ed..00db1afd 100644 --- a/src/test/forms/output/ResourcesColumns.test.js +++ b/src/test/forms/output/ResourcesColumns.test.js @@ -2,7 +2,7 @@ import React from 'react'; import { mount } from 'enzyme'; import { cloneDeep, set } from 'lodash'; -import { ResourcesColumns } from '../../../forms/output/ResourcesColumns'; +import { ResourcesColumns } from '../../../forms/predictions/ResourcesColumns'; import { CLIENT_DEFAULTS } from '../../../utils/CLIENT_DEFAULTS'; // Skipping till highcharts testing is worked out diff --git a/src/test/forms/output/StackedResources.test.js b/src/test/forms/output/StackedResources.test.js index 3670ccd1..0fa98d25 100644 --- a/src/test/forms/output/StackedResources.test.js +++ b/src/test/forms/output/StackedResources.test.js @@ -2,7 +2,7 @@ import React from 'react'; import { mount } from 'enzyme'; import { cloneDeep, set } from 'lodash'; -import { StackedResources } from '../../../forms/output/StackedResources'; +import { StackedResources } from '../../../forms/predictions/StackedResources'; import { CLIENT_DEFAULTS } from '../../../utils/CLIENT_DEFAULTS'; // Skipping till highcharts testing is worked out diff --git a/src/utils/CLIENT_DEFAULTS.js b/src/utils/CLIENT_DEFAULTS.js index 8ab3a4ba..fa129f40 100644 --- a/src/utils/CLIENT_DEFAULTS.js +++ b/src/utils/CLIENT_DEFAULTS.js @@ -28,7 +28,8 @@ const CLIENT_DEFAULTS = { // Income earned: 0, // positive number (can have more than two decimal places) - TAFDC: 0, // positive number + raise: 0, // positive number (@todo doesn't really belong here, just in future) + TAFDC: 0, // positive number SSI: 0, // positive number SSDI: 0, // positive number childSupportIn: 0, // positive number diff --git a/src/utils/getSideEffects.js b/src/utils/getSideEffects.js index 393368b9..e8695458 100644 --- a/src/utils/getSideEffects.js +++ b/src/utils/getSideEffects.js @@ -11,13 +11,26 @@ const empty = function () { }; -const earnedBecauseOfChildCare = function (clientPartial) { - let sum = ( - clientPartial.childDirectCare + - clientPartial.childBeforeAndAfterSchoolCare + - clientPartial.childTransportation + - clientPartial.childOtherCare - ); +// Only changes future values +const applyRaise = function (client, timeframe) { + // Never change current value based on raise + if (timeframe === `current`) { + return {}; + } + + let newStateProps = { earned: client.current.earned + client.future.raise }; + return newStateProps; +}; + + +const earnedBecauseOfChildCare = function (client, timeframe) { + let clientPartial = client[ timeframe ], + sum = ( + clientPartial.childDirectCare + + clientPartial.childBeforeAndAfterSchoolCare + + clientPartial.childTransportation + + clientPartial.childOtherCare + ); if (sum === 0) { return { earnedBecauseOfChildCare: 0 }; @@ -26,7 +39,8 @@ const earnedBecauseOfChildCare = function (clientPartial) { } }; -const earnedBecauseOfAdultCare = function (clientPartial) { +const earnedBecauseOfAdultCare = function (client, timeframe) { + let clientPartial = client[ timeframe ]; if (clientPartial.disabledAssistance === 0) { return { earnedBecauseOfAdultCare: 0 }; } else { @@ -36,6 +50,8 @@ const earnedBecauseOfAdultCare = function (clientPartial) { const sideEffects = { + // Income + raise: applyRaise, // Expenses childDirectCare: earnedBecauseOfChildCare, childBeforeAndAfterSchoolCare: earnedBecauseOfChildCare, @@ -45,15 +61,16 @@ const sideEffects = { }; -const getSideEffects = function (clientPartial, itemID) { +const getSideEffects = function (client, timeframe, itemID) { let func = sideEffects[ itemID ] || empty; - return func(clientPartial); + return func(client, timeframe); }; export { sideEffects, empty, + applyRaise, earnedBecauseOfChildCare, earnedBecauseOfAdultCare, getSideEffects, diff --git a/src/utils/setNestedProperty.js b/src/utils/setNestedProperty.js index 2c51691d..f8e5eb4e 100644 --- a/src/utils/setNestedProperty.js +++ b/src/utils/setNestedProperty.js @@ -4,14 +4,15 @@ import { getSideEffects } from './getSideEffects'; const setNestedProperty = function ({ route, value, time }, { current, future }, previouslySetByUser) { - let itemID = route.shift(); + let itemID = route.shift(), + client = { current: current, future: future }; if (route.length <= 0) { let newEvent = { type: time, name: itemID, value: value }; setValidCurrent(newEvent, current); setValidFuture(newEvent, future, previouslySetByUser); - applySideEffects({ current, future, itemID }); + applySideEffects({ client, itemID }); } else { // Get this key or index and remove it from list @@ -20,7 +21,7 @@ const setNestedProperty = function ({ route, value, time }, { current, future }, future: future[ itemID ], }; setNestedProperty({ route, value, time }, next, previouslySetByUser); - applySideEffects({ current, future, itemID }); + applySideEffects({ client, itemID }); } // ends if last recursion because route is empty }; @@ -63,16 +64,15 @@ const setValidFuture = function (evnt, newFuture, setByUser) { * @param {object} future * @param {string} itemID */ -const applySideEffects = function ({ current, future, itemID }) { - - let changeInCurrent = getSideEffects(current, itemID), - changeInFuture = getSideEffects(future, itemID); - Object.assign(current, changeInCurrent); - Object.assign(future, changeInFuture); +const applySideEffects = function ({ client, itemID }) { + let changeInCurrent = getSideEffects(client, `current`, itemID), + changeInFuture = getSideEffects(client, `future`, itemID); + Object.assign(client.current, changeInCurrent); + Object.assign(client.future, changeInFuture); return { - current: current, - future: future, + current: client.current, + future: client.future, itemID: itemID, }; }; diff --git a/src/utils/valueFixers.js b/src/utils/valueFixers.js index bd7f4932..de5dd03b 100644 --- a/src/utils/valueFixers.js +++ b/src/utils/valueFixers.js @@ -57,6 +57,7 @@ const valueFixers = { // MONEY AMOUNTS // Income earned: toNumber, + raise: toNumber, TAFDC: toNumber, SSI: toNumber, SSDI: toNumber,