From 8fd0b77267ade5f0a6370cb255b74955102faad7 Mon Sep 17 00:00:00 2001 From: Turner Hayes Date: Wed, 24 Oct 2018 18:46:49 -0400 Subject: [PATCH 1/9] Add Redux store; seed it with initial state data --- package-lock.json | 3257 ++++++++++++++++++++++-- package.json | 8 + src/actions/client.js | 12 + src/actions/geography.js | 8 + src/actions/index.js | 3 + src/actions/localization.js | 8 + src/{ => components}/App.js | 29 +- src/configure-store.js | 31 + src/containers/App.js | 18 + src/containers/VisitPage.js | 18 +- src/containers/forms/output/Summary.js | 9 + src/forms/Predictions.js | 11 +- src/forms/output/Summary.js | 27 +- src/index.js | 16 +- src/reducers/client.js | 23 + src/reducers/geography.js | 23 + src/reducers/index.js | 17 + src/reducers/localization.js | 24 + src/store.js | 24 + src/test/App.test.js | 10 +- 20 files changed, 3316 insertions(+), 260 deletions(-) create mode 100644 src/actions/client.js create mode 100644 src/actions/geography.js create mode 100644 src/actions/index.js create mode 100644 src/actions/localization.js rename src/{ => components}/App.js (93%) create mode 100644 src/configure-store.js create mode 100644 src/containers/App.js create mode 100644 src/containers/forms/output/Summary.js create mode 100644 src/reducers/client.js create mode 100644 src/reducers/geography.js create mode 100644 src/reducers/index.js create mode 100644 src/reducers/localization.js create mode 100644 src/store.js diff --git a/package-lock.json b/package-lock.json index 3b2a374b..cedf0cfe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2385,6 +2385,16 @@ "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz", "integrity": "sha1-sGhzk0vF40T+9hGhlqb6rgruAVo=" }, + "connected-react-router": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/connected-react-router/-/connected-react-router-4.5.0.tgz", + "integrity": "sha512-SBBmAZrtmw4y7Rkl2PCct8lN/DuCftl7QSAFLgFyjjuYkeJKAzAvQjzNNNE4R3j2+6a4TUiv8qselxQ4+6H5eA==", + "requires": { + "immutable": "^3.8.1", + "redux-seamless-immutable": "^0.4.0", + "seamless-immutable": "^7.1.3" + } + }, "console-browserify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", @@ -4328,7 +4338,8 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "concat-map": { "version": "0.0.1", @@ -4336,7 +4347,8 @@ }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -4439,7 +4451,8 @@ }, "inherits": { "version": "2.0.3", - "bundled": true + "bundled": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -4449,6 +4462,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -4560,7 +4574,8 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -4675,6 +4690,7 @@ "string-width": { "version": "1.0.2", "bundled": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -5349,6 +5365,11 @@ "strip-url-auth": "^1.0.0" } }, + "i": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/i/-/i-0.3.6.tgz", + "integrity": "sha1-2WyScyB28HJxG2sQ/X1PZa2O4j0=" + }, "iconv-lite": { "version": "0.4.23", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", @@ -5389,6 +5410,11 @@ "minimatch": "^3.0.4" } }, + "immutable": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", + "integrity": "sha1-wkOZUUVbs5kT2vKBN28VMOEErfM=" + }, "import-lazy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", @@ -6586,6 +6612,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" }, + "lodash-es": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.11.tgz", + "integrity": "sha512-DHb1ub+rMjjrxqlB3H56/6MXtm1lSksDp2rA2cNWjG8mlDUYFhUj3Di2Zn5IwSU87xLv8tNIQ7sSwE/YOX/D/Q==" + }, "lodash._reinterpolate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", @@ -7149,236 +7180,2932 @@ "sort-keys": "^1.0.0" } }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "requires": { - "path-key": "^2.0.0" - } - }, - "nth-check": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz", - "integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=", - "requires": { - "boolbase": "~1.0.0" - } - }, - "num2fraction": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", - "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=" - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" - }, - "nwmatcher": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.4.tgz", - "integrity": "sha512-3iuY4N5dhgMpCUrOVnuAdGrgxVqV2cJpM+XNccjR2DKOB1RUP0aA+wGXEiNziG/UKboFyGBIoKOaNlJxx8bciQ==" - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "npm": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/npm/-/npm-6.4.1.tgz", + "integrity": "sha512-mXJL1NTVU136PtuopXCUQaNWuHlXCTp4McwlSW8S9/Aj8OEPAlSBgo8og7kJ01MjCDrkmqFQTvN5tTEhBMhXQg==", + "requires": { + "JSONStream": "^1.3.4", + "abbrev": "~1.1.1", + "ansicolors": "~0.3.2", + "ansistyles": "~0.1.3", + "aproba": "~1.2.0", + "archy": "~1.0.0", + "bin-links": "^1.1.2", + "bluebird": "~3.5.1", + "byte-size": "^4.0.3", + "cacache": "^11.2.0", + "call-limit": "~1.1.0", + "chownr": "~1.0.1", + "ci-info": "^1.4.0", + "cli-columns": "^3.1.2", + "cli-table3": "^0.5.0", + "cmd-shim": "~2.0.2", + "columnify": "~1.5.4", + "config-chain": "~1.1.11", + "debuglog": "*", + "detect-indent": "~5.0.0", + "detect-newline": "^2.1.0", + "dezalgo": "~1.0.3", + "editor": "~1.0.0", + "figgy-pudding": "^3.4.1", + "find-npm-prefix": "^1.0.2", + "fs-vacuum": "~1.2.10", + "fs-write-stream-atomic": "~1.0.10", + "gentle-fs": "^2.0.1", + "glob": "~7.1.2", + "graceful-fs": "~4.1.11", + "has-unicode": "~2.0.1", + "hosted-git-info": "^2.7.1", + "iferr": "^1.0.2", + "imurmurhash": "*", + "inflight": "~1.0.6", + "inherits": "~2.0.3", + "ini": "^1.3.5", + "init-package-json": "^1.10.3", + "is-cidr": "^2.0.6", + "json-parse-better-errors": "^1.0.2", + "lazy-property": "~1.0.0", + "libcipm": "^2.0.2", + "libnpmhook": "^4.0.1", + "libnpx": "^10.2.0", + "lock-verify": "^2.0.2", + "lockfile": "^1.0.4", + "lodash._baseindexof": "*", + "lodash._baseuniq": "~4.6.0", + "lodash._bindcallback": "*", + "lodash._cacheindexof": "*", + "lodash._createcache": "*", + "lodash._getnative": "*", + "lodash.clonedeep": "~4.5.0", + "lodash.restparam": "*", + "lodash.union": "~4.6.0", + "lodash.uniq": "~4.5.0", + "lodash.without": "~4.4.0", + "lru-cache": "^4.1.3", + "meant": "~1.0.1", + "mississippi": "^3.0.0", + "mkdirp": "~0.5.1", + "move-concurrently": "^1.0.1", + "node-gyp": "^3.8.0", + "nopt": "~4.0.1", + "normalize-package-data": "~2.4.0", + "npm-audit-report": "^1.3.1", + "npm-cache-filename": "~1.0.2", + "npm-install-checks": "~3.0.0", + "npm-lifecycle": "^2.1.0", + "npm-package-arg": "^6.1.0", + "npm-packlist": "^1.1.11", + "npm-pick-manifest": "^2.1.0", + "npm-profile": "^3.0.2", + "npm-registry-client": "^8.6.0", + "npm-registry-fetch": "^1.1.0", + "npm-user-validate": "~1.0.0", + "npmlog": "~4.1.2", + "once": "~1.4.0", + "opener": "^1.5.0", + "osenv": "^0.1.5", + "pacote": "^8.1.6", + "path-is-inside": "~1.0.2", + "promise-inflight": "~1.0.1", + "qrcode-terminal": "^0.12.0", + "query-string": "^6.1.0", + "qw": "~1.0.1", + "read": "~1.0.7", + "read-cmd-shim": "~1.0.1", + "read-installed": "~4.0.3", + "read-package-json": "^2.0.13", + "read-package-tree": "^5.2.1", + "readable-stream": "^2.3.6", + "readdir-scoped-modules": "*", + "request": "^2.88.0", + "retry": "^0.12.0", + "rimraf": "~2.6.2", + "safe-buffer": "^5.1.2", + "semver": "^5.5.0", + "sha": "~2.0.1", + "slide": "~1.1.6", + "sorted-object": "~2.0.1", + "sorted-union-stream": "~2.1.3", + "ssri": "^6.0.0", + "stringify-package": "^1.0.0", + "tar": "^4.4.6", + "text-table": "~0.2.0", + "tiny-relative-date": "^1.3.0", + "uid-number": "0.0.6", + "umask": "~1.1.0", + "unique-filename": "~1.1.0", + "unpipe": "~1.0.0", + "update-notifier": "^2.5.0", + "uuid": "^3.3.2", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "~3.0.0", + "which": "^1.3.1", + "worker-farm": "^1.6.0", + "write-file-atomic": "^2.3.0" + }, + "dependencies": { + "JSONStream": { + "version": "1.3.4", + "bundled": true, "requires": { - "is-descriptor": "^0.1.0" + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" } - } - } - }, - "object-hash": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.0.tgz", - "integrity": "sha512-05KzQ70lSeGSrZJQXE5wNDiTkBJDlUT/myi6RX9dVIvz7a7Qh4oH93BQdiPMn27nldYvVQCKMUaM83AfizZlsQ==" - }, - "object-inspect": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", - "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", - "dev": true - }, - "object-is": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.1.tgz", - "integrity": "sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY=", - "dev": true - }, - "object-keys": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", - "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=" - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "requires": { - "isobject": "^3.0.0" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - } - } - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "object.entries": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.0.4.tgz", - "integrity": "sha1-G/mk3SKI9bM/Opk9JXZh8F0WGl8=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.6.1", - "function-bind": "^1.1.0", - "has": "^1.0.1" - } - }, - "object.omit": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", - "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", - "requires": { - "for-own": "^0.1.4", - "is-extendable": "^0.1.1" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "requires": { - "isobject": "^3.0.1" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - } - } - }, - "object.values": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.0.4.tgz", - "integrity": "sha1-5STaCbT2b/Bd9FdUbscqyZ8TBpo=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.6.1", - "function-bind": "^1.1.0", - "has": "^1.0.1" - } - }, - "obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "requires": { - "ee-first": "1.1.1" - } - }, - "on-headers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", - "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "opn": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/opn/-/opn-5.2.0.tgz", - "integrity": "sha512-Jd/GpzPyHF4P2/aNOVmS3lfMSWV9J7cOhCG1s08XCEAsPkB7lp6ddiU0J7XzyQRDUh8BqJ7PchfINjR8jyofRQ==", - "requires": { - "is-wsl": "^1.1.0" - } - }, - "optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", - "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - }, - "dependencies": { - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" - } - } - }, - "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "wordwrap": "~1.0.0" - } - }, - "original": { + }, + "abbrev": { + "version": "1.1.1", + "bundled": true + }, + "agent-base": { + "version": "4.2.0", + "bundled": true, + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "agentkeepalive": { + "version": "3.4.1", + "bundled": true, + "requires": { + "humanize-ms": "^1.2.1" + } + }, + "ajv": { + "version": "5.5.2", + "bundled": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "ansi-align": { + "version": "2.0.0", + "bundled": true, + "requires": { + "string-width": "^2.0.0" + } + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true + }, + "ansi-styles": { + "version": "3.2.1", + "bundled": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "ansicolors": { + "version": "0.3.2", + "bundled": true + }, + "ansistyles": { + "version": "0.1.3", + "bundled": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true + }, + "archy": { + "version": "1.0.0", + "bundled": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "asap": { + "version": "2.0.6", + "bundled": true + }, + "asn1": { + "version": "0.2.4", + "bundled": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "bundled": true + }, + "asynckit": { + "version": "0.4.0", + "bundled": true + }, + "aws-sign2": { + "version": "0.7.0", + "bundled": true + }, + "aws4": { + "version": "1.8.0", + "bundled": true + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "bundled": true, + "optional": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "bin-links": { + "version": "1.1.2", + "bundled": true, + "requires": { + "bluebird": "^3.5.0", + "cmd-shim": "^2.0.2", + "gentle-fs": "^2.0.0", + "graceful-fs": "^4.1.11", + "write-file-atomic": "^2.3.0" + } + }, + "block-stream": { + "version": "0.0.9", + "bundled": true, + "requires": { + "inherits": "~2.0.0" + } + }, + "bluebird": { + "version": "3.5.1", + "bundled": true + }, + "boxen": { + "version": "1.3.0", + "bundled": true, + "requires": { + "ansi-align": "^2.0.0", + "camelcase": "^4.0.0", + "chalk": "^2.0.1", + "cli-boxes": "^1.0.0", + "string-width": "^2.0.0", + "term-size": "^1.2.0", + "widest-line": "^2.0.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer-from": { + "version": "1.0.0", + "bundled": true + }, + "builtin-modules": { + "version": "1.1.1", + "bundled": true + }, + "builtins": { + "version": "1.0.3", + "bundled": true + }, + "byline": { + "version": "5.0.0", + "bundled": true + }, + "byte-size": { + "version": "4.0.3", + "bundled": true + }, + "cacache": { + "version": "11.2.0", + "bundled": true, + "requires": { + "bluebird": "^3.5.1", + "chownr": "^1.0.1", + "figgy-pudding": "^3.1.0", + "glob": "^7.1.2", + "graceful-fs": "^4.1.11", + "lru-cache": "^4.1.3", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.2", + "ssri": "^6.0.0", + "unique-filename": "^1.1.0", + "y18n": "^4.0.0" + } + }, + "call-limit": { + "version": "1.1.0", + "bundled": true + }, + "camelcase": { + "version": "4.1.0", + "bundled": true + }, + "capture-stack-trace": { + "version": "1.0.0", + "bundled": true + }, + "caseless": { + "version": "0.12.0", + "bundled": true + }, + "chalk": { + "version": "2.4.1", + "bundled": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chownr": { + "version": "1.0.1", + "bundled": true + }, + "ci-info": { + "version": "1.4.0", + "bundled": true + }, + "cidr-regex": { + "version": "2.0.9", + "bundled": true, + "requires": { + "ip-regex": "^2.1.0" + } + }, + "cli-boxes": { + "version": "1.0.0", + "bundled": true + }, + "cli-columns": { + "version": "3.1.2", + "bundled": true, + "requires": { + "string-width": "^2.0.0", + "strip-ansi": "^3.0.1" + } + }, + "cli-table3": { + "version": "0.5.0", + "bundled": true, + "requires": { + "colors": "^1.1.2", + "object-assign": "^4.1.0", + "string-width": "^2.1.1" + } + }, + "cliui": { + "version": "4.1.0", + "bundled": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "bundled": true + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "clone": { + "version": "1.0.4", + "bundled": true + }, + "cmd-shim": { + "version": "2.0.2", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "mkdirp": "~0.5.0" + } + }, + "co": { + "version": "4.6.0", + "bundled": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true + }, + "color-convert": { + "version": "1.9.1", + "bundled": true, + "requires": { + "color-name": "^1.1.1" + } + }, + "color-name": { + "version": "1.1.3", + "bundled": true + }, + "colors": { + "version": "1.1.2", + "bundled": true, + "optional": true + }, + "columnify": { + "version": "1.5.4", + "bundled": true, + "requires": { + "strip-ansi": "^3.0.0", + "wcwidth": "^1.0.0" + } + }, + "combined-stream": { + "version": "1.0.6", + "bundled": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + }, + "concat-stream": { + "version": "1.6.2", + "bundled": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "config-chain": { + "version": "1.1.11", + "bundled": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "configstore": { + "version": "3.1.2", + "bundled": true, + "requires": { + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true + }, + "copy-concurrently": { + "version": "1.0.5", + "bundled": true, + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + }, + "dependencies": { + "iferr": { + "version": "0.1.5", + "bundled": true + } + } + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "create-error-class": { + "version": "3.0.2", + "bundled": true, + "requires": { + "capture-stack-trace": "^1.0.0" + } + }, + "cross-spawn": { + "version": "5.1.0", + "bundled": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "crypto-random-string": { + "version": "1.0.0", + "bundled": true + }, + "cyclist": { + "version": "0.2.2", + "bundled": true + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "debug": { + "version": "3.1.0", + "bundled": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "bundled": true + } + } + }, + "debuglog": { + "version": "1.0.1", + "bundled": true + }, + "decamelize": { + "version": "1.2.0", + "bundled": true + }, + "decode-uri-component": { + "version": "0.2.0", + "bundled": true + }, + "deep-extend": { + "version": "0.5.1", + "bundled": true + }, + "defaults": { + "version": "1.0.3", + "bundled": true, + "requires": { + "clone": "^1.0.2" + } + }, + "delayed-stream": { + "version": "1.0.0", + "bundled": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true + }, + "detect-indent": { + "version": "5.0.0", + "bundled": true + }, + "detect-newline": { + "version": "2.1.0", + "bundled": true + }, + "dezalgo": { + "version": "1.0.3", + "bundled": true, + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "dot-prop": { + "version": "4.2.0", + "bundled": true, + "requires": { + "is-obj": "^1.0.0" + } + }, + "dotenv": { + "version": "5.0.1", + "bundled": true + }, + "duplexer3": { + "version": "0.1.4", + "bundled": true + }, + "duplexify": { + "version": "3.6.0", + "bundled": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "bundled": true, + "optional": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "editor": { + "version": "1.0.0", + "bundled": true + }, + "encoding": { + "version": "0.1.12", + "bundled": true, + "requires": { + "iconv-lite": "~0.4.13" + } + }, + "end-of-stream": { + "version": "1.4.1", + "bundled": true, + "requires": { + "once": "^1.4.0" + } + }, + "err-code": { + "version": "1.1.2", + "bundled": true + }, + "errno": { + "version": "0.1.7", + "bundled": true, + "requires": { + "prr": "~1.0.1" + } + }, + "es6-promise": { + "version": "4.2.4", + "bundled": true + }, + "es6-promisify": { + "version": "5.0.0", + "bundled": true, + "requires": { + "es6-promise": "^4.0.3" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true + }, + "execa": { + "version": "0.7.0", + "bundled": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "extend": { + "version": "3.0.2", + "bundled": true + }, + "extsprintf": { + "version": "1.3.0", + "bundled": true + }, + "fast-deep-equal": { + "version": "1.1.0", + "bundled": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "bundled": true + }, + "figgy-pudding": { + "version": "3.4.1", + "bundled": true + }, + "find-npm-prefix": { + "version": "1.0.2", + "bundled": true + }, + "find-up": { + "version": "2.1.0", + "bundled": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "flush-write-stream": { + "version": "1.0.3", + "bundled": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.4" + } + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true + }, + "form-data": { + "version": "2.3.2", + "bundled": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "1.0.6", + "mime-types": "^2.1.12" + } + }, + "from2": { + "version": "2.3.0", + "bundled": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs-vacuum": { + "version": "1.2.10", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "path-is-inside": "^1.0.1", + "rimraf": "^2.5.2" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + }, + "dependencies": { + "iferr": { + "version": "0.1.5", + "bundled": true + } + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true + }, + "fstream": { + "version": "1.0.11", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + } + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "string-width": { + "version": "1.0.2", + "bundled": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "genfun": { + "version": "4.0.1", + "bundled": true + }, + "gentle-fs": { + "version": "2.0.1", + "bundled": true, + "requires": { + "aproba": "^1.1.2", + "fs-vacuum": "^1.2.10", + "graceful-fs": "^4.1.11", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "path-is-inside": "^1.0.2", + "read-cmd-shim": "^1.0.1", + "slide": "^1.1.6" + }, + "dependencies": { + "iferr": { + "version": "0.1.5", + "bundled": true + } + } + }, + "get-caller-file": { + "version": "1.0.2", + "bundled": true + }, + "get-stream": { + "version": "3.0.0", + "bundled": true + }, + "getpass": { + "version": "0.1.7", + "bundled": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "global-dirs": { + "version": "0.1.1", + "bundled": true, + "requires": { + "ini": "^1.3.4" + } + }, + "got": { + "version": "6.7.1", + "bundled": true, + "requires": { + "create-error-class": "^3.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "unzip-response": "^2.0.1", + "url-parse-lax": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true + }, + "har-schema": { + "version": "2.0.0", + "bundled": true + }, + "har-validator": { + "version": "5.1.0", + "bundled": true, + "requires": { + "ajv": "^5.3.0", + "har-schema": "^2.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "bundled": true + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true + }, + "hosted-git-info": { + "version": "2.7.1", + "bundled": true + }, + "http-cache-semantics": { + "version": "3.8.1", + "bundled": true + }, + "http-proxy-agent": { + "version": "2.1.0", + "bundled": true, + "requires": { + "agent-base": "4", + "debug": "3.1.0" + } + }, + "http-signature": { + "version": "1.2.0", + "bundled": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-proxy-agent": { + "version": "2.2.1", + "bundled": true, + "requires": { + "agent-base": "^4.1.0", + "debug": "^3.1.0" + } + }, + "humanize-ms": { + "version": "1.2.1", + "bundled": true, + "requires": { + "ms": "^2.0.0" + } + }, + "iconv-lite": { + "version": "0.4.23", + "bundled": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "iferr": { + "version": "1.0.2", + "bundled": true + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "import-lazy": { + "version": "2.1.0", + "bundled": true + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true + }, + "ini": { + "version": "1.3.5", + "bundled": true + }, + "init-package-json": { + "version": "1.10.3", + "bundled": true, + "requires": { + "glob": "^7.1.1", + "npm-package-arg": "^4.0.0 || ^5.0.0 || ^6.0.0", + "promzard": "^0.3.0", + "read": "~1.0.1", + "read-package-json": "1 || 2", + "semver": "2.x || 3.x || 4 || 5", + "validate-npm-package-license": "^3.0.1", + "validate-npm-package-name": "^3.0.0" + } + }, + "invert-kv": { + "version": "1.0.0", + "bundled": true + }, + "ip": { + "version": "1.1.5", + "bundled": true + }, + "ip-regex": { + "version": "2.1.0", + "bundled": true + }, + "is-builtin-module": { + "version": "1.0.0", + "bundled": true, + "requires": { + "builtin-modules": "^1.0.0" + } + }, + "is-ci": { + "version": "1.1.0", + "bundled": true, + "requires": { + "ci-info": "^1.0.0" + } + }, + "is-cidr": { + "version": "2.0.6", + "bundled": true, + "requires": { + "cidr-regex": "^2.0.8" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-installed-globally": { + "version": "0.1.0", + "bundled": true, + "requires": { + "global-dirs": "^0.1.0", + "is-path-inside": "^1.0.0" + } + }, + "is-npm": { + "version": "1.0.0", + "bundled": true + }, + "is-obj": { + "version": "1.0.1", + "bundled": true + }, + "is-path-inside": { + "version": "1.0.1", + "bundled": true, + "requires": { + "path-is-inside": "^1.0.1" + } + }, + "is-redirect": { + "version": "1.0.0", + "bundled": true + }, + "is-retry-allowed": { + "version": "1.1.0", + "bundled": true + }, + "is-stream": { + "version": "1.1.0", + "bundled": true + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true + }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "optional": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "bundled": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "bundled": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true + }, + "jsonparse": { + "version": "1.3.1", + "bundled": true + }, + "jsprim": { + "version": "1.4.1", + "bundled": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "latest-version": { + "version": "3.1.0", + "bundled": true, + "requires": { + "package-json": "^4.0.0" + } + }, + "lazy-property": { + "version": "1.0.0", + "bundled": true + }, + "lcid": { + "version": "1.0.0", + "bundled": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "libcipm": { + "version": "2.0.2", + "bundled": true, + "requires": { + "bin-links": "^1.1.2", + "bluebird": "^3.5.1", + "find-npm-prefix": "^1.0.2", + "graceful-fs": "^4.1.11", + "lock-verify": "^2.0.2", + "mkdirp": "^0.5.1", + "npm-lifecycle": "^2.0.3", + "npm-logical-tree": "^1.2.1", + "npm-package-arg": "^6.1.0", + "pacote": "^8.1.6", + "protoduck": "^5.0.0", + "read-package-json": "^2.0.13", + "rimraf": "^2.6.2", + "worker-farm": "^1.6.0" + } + }, + "libnpmhook": { + "version": "4.0.1", + "bundled": true, + "requires": { + "figgy-pudding": "^3.1.0", + "npm-registry-fetch": "^3.0.0" + }, + "dependencies": { + "npm-registry-fetch": { + "version": "3.1.1", + "bundled": true, + "requires": { + "bluebird": "^3.5.1", + "figgy-pudding": "^3.1.0", + "lru-cache": "^4.1.2", + "make-fetch-happen": "^4.0.0", + "npm-package-arg": "^6.0.0" + } + } + } + }, + "libnpx": { + "version": "10.2.0", + "bundled": true, + "requires": { + "dotenv": "^5.0.1", + "npm-package-arg": "^6.0.0", + "rimraf": "^2.6.2", + "safe-buffer": "^5.1.0", + "update-notifier": "^2.3.0", + "which": "^1.3.0", + "y18n": "^4.0.0", + "yargs": "^11.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "bundled": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lock-verify": { + "version": "2.0.2", + "bundled": true, + "requires": { + "npm-package-arg": "^5.1.2 || 6", + "semver": "^5.4.1" + } + }, + "lockfile": { + "version": "1.0.4", + "bundled": true, + "requires": { + "signal-exit": "^3.0.2" + } + }, + "lodash._baseindexof": { + "version": "3.1.0", + "bundled": true + }, + "lodash._baseuniq": { + "version": "4.6.0", + "bundled": true, + "requires": { + "lodash._createset": "~4.0.0", + "lodash._root": "~3.0.0" + } + }, + "lodash._bindcallback": { + "version": "3.0.1", + "bundled": true + }, + "lodash._cacheindexof": { + "version": "3.0.2", + "bundled": true + }, + "lodash._createcache": { + "version": "3.1.2", + "bundled": true, + "requires": { + "lodash._getnative": "^3.0.0" + } + }, + "lodash._createset": { + "version": "4.0.3", + "bundled": true + }, + "lodash._getnative": { + "version": "3.9.1", + "bundled": true + }, + "lodash._root": { + "version": "3.0.1", + "bundled": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "bundled": true + }, + "lodash.restparam": { + "version": "3.6.1", + "bundled": true + }, + "lodash.union": { + "version": "4.6.0", + "bundled": true + }, + "lodash.uniq": { + "version": "4.5.0", + "bundled": true + }, + "lodash.without": { + "version": "4.4.0", + "bundled": true + }, + "lowercase-keys": { + "version": "1.0.1", + "bundled": true + }, + "lru-cache": { + "version": "4.1.3", + "bundled": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "make-dir": { + "version": "1.3.0", + "bundled": true, + "requires": { + "pify": "^3.0.0" + } + }, + "make-fetch-happen": { + "version": "4.0.1", + "bundled": true, + "requires": { + "agentkeepalive": "^3.4.1", + "cacache": "^11.0.1", + "http-cache-semantics": "^3.8.1", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.1", + "lru-cache": "^4.1.2", + "mississippi": "^3.0.0", + "node-fetch-npm": "^2.0.2", + "promise-retry": "^1.1.1", + "socks-proxy-agent": "^4.0.0", + "ssri": "^6.0.0" + } + }, + "meant": { + "version": "1.0.1", + "bundled": true + }, + "mem": { + "version": "1.1.0", + "bundled": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "mime-db": { + "version": "1.35.0", + "bundled": true + }, + "mime-types": { + "version": "2.1.19", + "bundled": true, + "requires": { + "mime-db": "~1.35.0" + } + }, + "mimic-fn": { + "version": "1.2.0", + "bundled": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true + }, + "minipass": { + "version": "2.3.3", + "bundled": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + }, + "dependencies": { + "yallist": { + "version": "3.0.2", + "bundled": true + } + } + }, + "minizlib": { + "version": "1.1.0", + "bundled": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mississippi": { + "version": "3.0.0", + "bundled": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "requires": { + "minimist": "0.0.8" + } + }, + "move-concurrently": { + "version": "1.0.1", + "bundled": true, + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "ms": { + "version": "2.1.1", + "bundled": true + }, + "mute-stream": { + "version": "0.0.7", + "bundled": true + }, + "node-fetch-npm": { + "version": "2.0.2", + "bundled": true, + "requires": { + "encoding": "^0.1.11", + "json-parse-better-errors": "^1.0.0", + "safe-buffer": "^5.1.1" + } + }, + "node-gyp": { + "version": "3.8.0", + "bundled": true, + "requires": { + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "^2.87.0", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^2.0.0", + "which": "1" + }, + "dependencies": { + "nopt": { + "version": "3.0.6", + "bundled": true, + "requires": { + "abbrev": "1" + } + }, + "semver": { + "version": "5.3.0", + "bundled": true + }, + "tar": { + "version": "2.2.1", + "bundled": true, + "requires": { + "block-stream": "*", + "fstream": "^1.0.2", + "inherits": "2" + } + } + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "normalize-package-data": { + "version": "2.4.0", + "bundled": true, + "requires": { + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "npm-audit-report": { + "version": "1.3.1", + "bundled": true, + "requires": { + "cli-table3": "^0.5.0", + "console-control-strings": "^1.1.0" + } + }, + "npm-bundled": { + "version": "1.0.5", + "bundled": true + }, + "npm-cache-filename": { + "version": "1.0.2", + "bundled": true + }, + "npm-install-checks": { + "version": "3.0.0", + "bundled": true, + "requires": { + "semver": "^2.3.0 || 3.x || 4 || 5" + } + }, + "npm-lifecycle": { + "version": "2.1.0", + "bundled": true, + "requires": { + "byline": "^5.0.0", + "graceful-fs": "^4.1.11", + "node-gyp": "^3.8.0", + "resolve-from": "^4.0.0", + "slide": "^1.1.6", + "uid-number": "0.0.6", + "umask": "^1.1.0", + "which": "^1.3.1" + } + }, + "npm-logical-tree": { + "version": "1.2.1", + "bundled": true + }, + "npm-package-arg": { + "version": "6.1.0", + "bundled": true, + "requires": { + "hosted-git-info": "^2.6.0", + "osenv": "^0.1.5", + "semver": "^5.5.0", + "validate-npm-package-name": "^3.0.0" + } + }, + "npm-packlist": { + "version": "1.1.11", + "bundled": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npm-pick-manifest": { + "version": "2.1.0", + "bundled": true, + "requires": { + "npm-package-arg": "^6.0.0", + "semver": "^5.4.1" + } + }, + "npm-profile": { + "version": "3.0.2", + "bundled": true, + "requires": { + "aproba": "^1.1.2 || 2", + "make-fetch-happen": "^2.5.0 || 3 || 4" + } + }, + "npm-registry-client": { + "version": "8.6.0", + "bundled": true, + "requires": { + "concat-stream": "^1.5.2", + "graceful-fs": "^4.1.6", + "normalize-package-data": "~1.0.1 || ^2.0.0", + "npm-package-arg": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0", + "npmlog": "2 || ^3.1.0 || ^4.0.0", + "once": "^1.3.3", + "request": "^2.74.0", + "retry": "^0.10.0", + "safe-buffer": "^5.1.1", + "semver": "2 >=2.2.1 || 3.x || 4 || 5", + "slide": "^1.1.3", + "ssri": "^5.2.4" + }, + "dependencies": { + "retry": { + "version": "0.10.1", + "bundled": true + }, + "ssri": { + "version": "5.3.0", + "bundled": true, + "requires": { + "safe-buffer": "^5.1.1" + } + } + } + }, + "npm-registry-fetch": { + "version": "1.1.0", + "bundled": true, + "requires": { + "bluebird": "^3.5.1", + "figgy-pudding": "^2.0.1", + "lru-cache": "^4.1.2", + "make-fetch-happen": "^3.0.0", + "npm-package-arg": "^6.0.0", + "safe-buffer": "^5.1.1" + }, + "dependencies": { + "cacache": { + "version": "10.0.4", + "bundled": true, + "requires": { + "bluebird": "^3.5.1", + "chownr": "^1.0.1", + "glob": "^7.1.2", + "graceful-fs": "^4.1.11", + "lru-cache": "^4.1.1", + "mississippi": "^2.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.2", + "ssri": "^5.2.4", + "unique-filename": "^1.1.0", + "y18n": "^4.0.0" + }, + "dependencies": { + "mississippi": { + "version": "2.0.0", + "bundled": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^2.0.1", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + } + } + }, + "figgy-pudding": { + "version": "2.0.1", + "bundled": true + }, + "make-fetch-happen": { + "version": "3.0.0", + "bundled": true, + "requires": { + "agentkeepalive": "^3.4.1", + "cacache": "^10.0.4", + "http-cache-semantics": "^3.8.1", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.0", + "lru-cache": "^4.1.2", + "mississippi": "^3.0.0", + "node-fetch-npm": "^2.0.2", + "promise-retry": "^1.1.1", + "socks-proxy-agent": "^3.0.1", + "ssri": "^5.2.4" + } + }, + "pump": { + "version": "2.0.1", + "bundled": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "smart-buffer": { + "version": "1.1.15", + "bundled": true + }, + "socks": { + "version": "1.1.10", + "bundled": true, + "requires": { + "ip": "^1.1.4", + "smart-buffer": "^1.0.13" + } + }, + "socks-proxy-agent": { + "version": "3.0.1", + "bundled": true, + "requires": { + "agent-base": "^4.1.0", + "socks": "^1.1.10" + } + }, + "ssri": { + "version": "5.3.0", + "bundled": true, + "requires": { + "safe-buffer": "^5.1.1" + } + } + } + }, + "npm-run-path": { + "version": "2.0.2", + "bundled": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "npm-user-validate": { + "version": "1.0.0", + "bundled": true + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true + }, + "oauth-sign": { + "version": "0.9.0", + "bundled": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "requires": { + "wrappy": "1" + } + }, + "opener": { + "version": "1.5.0", + "bundled": true + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true + }, + "os-locale": { + "version": "2.1.0", + "bundled": true, + "requires": { + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "p-finally": { + "version": "1.0.0", + "bundled": true + }, + "p-limit": { + "version": "1.2.0", + "bundled": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "bundled": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "bundled": true + }, + "package-json": { + "version": "4.0.1", + "bundled": true, + "requires": { + "got": "^6.7.1", + "registry-auth-token": "^3.0.1", + "registry-url": "^3.0.3", + "semver": "^5.1.0" + } + }, + "pacote": { + "version": "8.1.6", + "bundled": true, + "requires": { + "bluebird": "^3.5.1", + "cacache": "^11.0.2", + "get-stream": "^3.0.0", + "glob": "^7.1.2", + "lru-cache": "^4.1.3", + "make-fetch-happen": "^4.0.1", + "minimatch": "^3.0.4", + "minipass": "^2.3.3", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "normalize-package-data": "^2.4.0", + "npm-package-arg": "^6.1.0", + "npm-packlist": "^1.1.10", + "npm-pick-manifest": "^2.1.0", + "osenv": "^0.1.5", + "promise-inflight": "^1.0.1", + "promise-retry": "^1.1.1", + "protoduck": "^5.0.0", + "rimraf": "^2.6.2", + "safe-buffer": "^5.1.2", + "semver": "^5.5.0", + "ssri": "^6.0.0", + "tar": "^4.4.3", + "unique-filename": "^1.1.0", + "which": "^1.3.0" + } + }, + "parallel-transform": { + "version": "1.1.0", + "bundled": true, + "requires": { + "cyclist": "~0.2.2", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "path-exists": { + "version": "3.0.0", + "bundled": true + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true + }, + "path-is-inside": { + "version": "1.0.2", + "bundled": true + }, + "path-key": { + "version": "2.0.1", + "bundled": true + }, + "performance-now": { + "version": "2.1.0", + "bundled": true + }, + "pify": { + "version": "3.0.0", + "bundled": true + }, + "prepend-http": { + "version": "1.0.4", + "bundled": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true + }, + "promise-inflight": { + "version": "1.0.1", + "bundled": true + }, + "promise-retry": { + "version": "1.1.1", + "bundled": true, + "requires": { + "err-code": "^1.0.0", + "retry": "^0.10.0" + }, + "dependencies": { + "retry": { + "version": "0.10.1", + "bundled": true + } + } + }, + "promzard": { + "version": "0.3.0", + "bundled": true, + "requires": { + "read": "1" + } + }, + "proto-list": { + "version": "1.2.4", + "bundled": true + }, + "protoduck": { + "version": "5.0.0", + "bundled": true, + "requires": { + "genfun": "^4.0.1" + } + }, + "prr": { + "version": "1.0.1", + "bundled": true + }, + "pseudomap": { + "version": "1.0.2", + "bundled": true + }, + "psl": { + "version": "1.1.29", + "bundled": true + }, + "pump": { + "version": "3.0.0", + "bundled": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "bundled": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "bundled": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "1.4.1", + "bundled": true + }, + "qrcode-terminal": { + "version": "0.12.0", + "bundled": true + }, + "qs": { + "version": "6.5.2", + "bundled": true + }, + "query-string": { + "version": "6.1.0", + "bundled": true, + "requires": { + "decode-uri-component": "^0.2.0", + "strict-uri-encode": "^2.0.0" + } + }, + "qw": { + "version": "1.0.1", + "bundled": true + }, + "rc": { + "version": "1.2.7", + "bundled": true, + "requires": { + "deep-extend": "^0.5.1", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true + } + } + }, + "read": { + "version": "1.0.7", + "bundled": true, + "requires": { + "mute-stream": "~0.0.4" + } + }, + "read-cmd-shim": { + "version": "1.0.1", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2" + } + }, + "read-installed": { + "version": "4.0.3", + "bundled": true, + "requires": { + "debuglog": "^1.0.1", + "graceful-fs": "^4.1.2", + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "slide": "~1.1.3", + "util-extend": "^1.0.1" + } + }, + "read-package-json": { + "version": "2.0.13", + "bundled": true, + "requires": { + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "json-parse-better-errors": "^1.0.1", + "normalize-package-data": "^2.0.0", + "slash": "^1.0.0" + } + }, + "read-package-tree": { + "version": "5.2.1", + "bundled": true, + "requires": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "once": "^1.3.0", + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdir-scoped-modules": { + "version": "1.0.2", + "bundled": true, + "requires": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "registry-auth-token": { + "version": "3.3.2", + "bundled": true, + "requires": { + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" + } + }, + "registry-url": { + "version": "3.1.0", + "bundled": true, + "requires": { + "rc": "^1.0.1" + } + }, + "request": { + "version": "2.88.0", + "bundled": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "require-directory": { + "version": "2.1.1", + "bundled": true + }, + "require-main-filename": { + "version": "1.0.1", + "bundled": true + }, + "resolve-from": { + "version": "4.0.0", + "bundled": true + }, + "retry": { + "version": "0.12.0", + "bundled": true + }, + "rimraf": { + "version": "2.6.2", + "bundled": true, + "requires": { + "glob": "^7.0.5" + } + }, + "run-queue": { + "version": "1.0.3", + "bundled": true, + "requires": { + "aproba": "^1.1.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true + }, + "semver": { + "version": "5.5.0", + "bundled": true + }, + "semver-diff": { + "version": "2.1.0", + "bundled": true, + "requires": { + "semver": "^5.0.3" + } + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true + }, + "sha": { + "version": "2.0.1", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "readable-stream": "^2.0.2" + } + }, + "shebang-command": { + "version": "1.2.0", + "bundled": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "bundled": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true + }, + "slash": { + "version": "1.0.0", + "bundled": true + }, + "slide": { + "version": "1.1.6", + "bundled": true + }, + "smart-buffer": { + "version": "4.0.1", + "bundled": true + }, + "socks": { + "version": "2.2.0", + "bundled": true, + "requires": { + "ip": "^1.1.5", + "smart-buffer": "^4.0.1" + } + }, + "socks-proxy-agent": { + "version": "4.0.1", + "bundled": true, + "requires": { + "agent-base": "~4.2.0", + "socks": "~2.2.0" + } + }, + "sorted-object": { + "version": "2.0.1", + "bundled": true + }, + "sorted-union-stream": { + "version": "2.1.3", + "bundled": true, + "requires": { + "from2": "^1.3.0", + "stream-iterate": "^1.1.0" + }, + "dependencies": { + "from2": { + "version": "1.3.0", + "bundled": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "~1.1.10" + } + }, + "isarray": { + "version": "0.0.1", + "bundled": true + }, + "readable-stream": { + "version": "1.1.14", + "bundled": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + } + } + }, + "spdx-correct": { + "version": "3.0.0", + "bundled": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.1.0", + "bundled": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "bundled": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.0", + "bundled": true + }, + "sshpk": { + "version": "1.14.2", + "bundled": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssri": { + "version": "6.0.0", + "bundled": true + }, + "stream-each": { + "version": "1.2.2", + "bundled": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-iterate": { + "version": "1.2.0", + "bundled": true, + "requires": { + "readable-stream": "^2.1.5", + "stream-shift": "^1.0.0" + } + }, + "stream-shift": { + "version": "1.0.0", + "bundled": true + }, + "strict-uri-encode": { + "version": "2.0.0", + "bundled": true + }, + "string-width": { + "version": "2.1.1", + "bundled": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "bundled": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "stringify-package": { + "version": "1.0.0", + "bundled": true + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "bundled": true + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true + }, + "supports-color": { + "version": "5.4.0", + "bundled": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "tar": { + "version": "4.4.6", + "bundled": true, + "requires": { + "chownr": "^1.0.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.3", + "minizlib": "^1.1.0", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + }, + "dependencies": { + "yallist": { + "version": "3.0.2", + "bundled": true + } + } + }, + "term-size": { + "version": "1.2.0", + "bundled": true, + "requires": { + "execa": "^0.7.0" + } + }, + "text-table": { + "version": "0.2.0", + "bundled": true + }, + "through": { + "version": "2.3.8", + "bundled": true + }, + "through2": { + "version": "2.0.3", + "bundled": true, + "requires": { + "readable-stream": "^2.1.5", + "xtend": "~4.0.1" + } + }, + "timed-out": { + "version": "4.0.1", + "bundled": true + }, + "tiny-relative-date": { + "version": "1.3.0", + "bundled": true + }, + "tough-cookie": { + "version": "2.4.3", + "bundled": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "optional": true + }, + "typedarray": { + "version": "0.0.6", + "bundled": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true + }, + "umask": { + "version": "1.1.0", + "bundled": true + }, + "unique-filename": { + "version": "1.1.0", + "bundled": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.0", + "bundled": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unique-string": { + "version": "1.0.0", + "bundled": true, + "requires": { + "crypto-random-string": "^1.0.0" + } + }, + "unpipe": { + "version": "1.0.0", + "bundled": true + }, + "unzip-response": { + "version": "2.0.1", + "bundled": true + }, + "update-notifier": { + "version": "2.5.0", + "bundled": true, + "requires": { + "boxen": "^1.2.1", + "chalk": "^2.0.1", + "configstore": "^3.0.0", + "import-lazy": "^2.1.0", + "is-ci": "^1.0.10", + "is-installed-globally": "^0.1.0", + "is-npm": "^1.0.0", + "latest-version": "^3.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, + "url-parse-lax": { + "version": "1.0.0", + "bundled": true, + "requires": { + "prepend-http": "^1.0.1" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + }, + "util-extend": { + "version": "1.0.3", + "bundled": true + }, + "uuid": { + "version": "3.3.2", + "bundled": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "bundled": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validate-npm-package-name": { + "version": "3.0.0", + "bundled": true, + "requires": { + "builtins": "^1.0.3" + } + }, + "verror": { + "version": "1.10.0", + "bundled": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "wcwidth": { + "version": "1.0.1", + "bundled": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "which": { + "version": "1.3.1", + "bundled": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "bundled": true + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "requires": { + "string-width": "^1.0.2" + }, + "dependencies": { + "string-width": { + "version": "1.0.2", + "bundled": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "widest-line": { + "version": "2.0.0", + "bundled": true, + "requires": { + "string-width": "^2.1.1" + } + }, + "worker-farm": { + "version": "1.6.0", + "bundled": true, + "requires": { + "errno": "~0.1.7" + } + }, + "wrap-ansi": { + "version": "2.1.0", + "bundled": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "string-width": { + "version": "1.0.2", + "bundled": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true + }, + "write-file-atomic": { + "version": "2.3.0", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "xdg-basedir": { + "version": "3.0.0", + "bundled": true + }, + "xtend": { + "version": "4.0.1", + "bundled": true + }, + "y18n": { + "version": "4.0.0", + "bundled": true + }, + "yallist": { + "version": "2.1.2", + "bundled": true + }, + "yargs": { + "version": "11.0.0", + "bundled": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.1.1", + "find-up": "^2.1.0", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^9.0.2" + }, + "dependencies": { + "y18n": { + "version": "3.2.1", + "bundled": true + } + } + }, + "yargs-parser": { + "version": "9.0.2", + "bundled": true, + "requires": { + "camelcase": "^4.1.0" + } + } + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "requires": { + "path-key": "^2.0.0" + } + }, + "nth-check": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz", + "integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=", + "requires": { + "boolbase": "~1.0.0" + } + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=" + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "nwmatcher": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.4.tgz", + "integrity": "sha512-3iuY4N5dhgMpCUrOVnuAdGrgxVqV2cJpM+XNccjR2DKOB1RUP0aA+wGXEiNziG/UKboFyGBIoKOaNlJxx8bciQ==" + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "object-hash": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.0.tgz", + "integrity": "sha512-05KzQ70lSeGSrZJQXE5wNDiTkBJDlUT/myi6RX9dVIvz7a7Qh4oH93BQdiPMn27nldYvVQCKMUaM83AfizZlsQ==" + }, + "object-inspect": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", + "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", + "dev": true + }, + "object-is": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.1.tgz", + "integrity": "sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY=", + "dev": true + }, + "object-keys": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", + "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=" + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "requires": { + "isobject": "^3.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + } + } + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.entries": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.0.4.tgz", + "integrity": "sha1-G/mk3SKI9bM/Opk9JXZh8F0WGl8=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.6.1", + "function-bind": "^1.1.0", + "has": "^1.0.1" + } + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "requires": { + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "requires": { + "isobject": "^3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + } + } + }, + "object.values": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.0.4.tgz", + "integrity": "sha1-5STaCbT2b/Bd9FdUbscqyZ8TBpo=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.6.1", + "function-bind": "^1.1.0", + "has": "^1.0.1" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", + "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "opn": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.2.0.tgz", + "integrity": "sha512-Jd/GpzPyHF4P2/aNOVmS3lfMSWV9J7cOhCG1s08XCEAsPkB7lp6ddiU0J7XzyQRDUh8BqJ7PchfINjR8jyofRQ==", + "requires": { + "is-wsl": "^1.1.0" + } + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + } + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + } + }, + "original": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", @@ -9130,6 +11857,11 @@ "react-side-effect": "^1.1.0" } }, + "react-immutable-proptypes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/react-immutable-proptypes/-/react-immutable-proptypes-2.1.0.tgz", + "integrity": "sha1-Aj1vObsVyXwHHp5g0A0TbqxfoLQ=" + }, "react-is": { "version": "16.3.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.3.2.tgz", @@ -9148,6 +11880,19 @@ "prop-types": "^15.6.0" } }, + "react-redux": { + "version": "5.0.7", + "resolved": "http://registry.npmjs.org/react-redux/-/react-redux-5.0.7.tgz", + "integrity": "sha512-5VI8EV5hdgNgyjfmWzBbdrqUkrVRKlyTKk1sGH3jzM2M2Mhj/seQgPXaz6gVAj2lz/nz688AdTqMO18Lr24Zhg==", + "requires": { + "hoist-non-react-statics": "^2.5.0", + "invariant": "^2.0.0", + "lodash": "^4.17.5", + "lodash-es": "^4.17.5", + "loose-envify": "^1.1.0", + "prop-types": "^15.6.0" + } + }, "react-router": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/react-router/-/react-router-4.2.0.tgz", @@ -9175,6 +11920,11 @@ "warning": "^3.0.0" } }, + "react-router-redux": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/react-router-redux/-/react-router-redux-4.0.8.tgz", + "integrity": "sha1-InQDWWtRUeGCN32rg1tdRfD4BU4=" + }, "react-scripts": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-1.1.5.tgz", @@ -9770,6 +12520,39 @@ } } }, + "redux": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.1.tgz", + "integrity": "sha512-R7bAtSkk7nY6O/OYMVR9RiBI+XghjF9rlbl5806HJbQph0LJVHZrU5oaO4q70eUKiqMRqm4y07KLTlMZ2BlVmg==", + "requires": { + "loose-envify": "^1.4.0", + "symbol-observable": "^1.2.0" + }, + "dependencies": { + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + } + } + }, + "redux-immutable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/redux-immutable/-/redux-immutable-4.0.0.tgz", + "integrity": "sha1-Ohoy32Y2ZGK2NpHw4dw15HK7yfM=" + }, + "redux-seamless-immutable": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/redux-seamless-immutable/-/redux-seamless-immutable-0.4.0.tgz", + "integrity": "sha512-/oS3fhrize9D3RSHemgJxVllohybRrad5IjccotFy8Ni4IKAPTtX1mqszpiCIl12+7v0dNqBpq6ES6R236AliQ==", + "requires": { + "react-router-redux": "^4.0.0", + "seamless-immutable": "^7.1.2" + } + }, "regenerate": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", @@ -10203,6 +12986,11 @@ } } }, + "seamless-immutable": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/seamless-immutable/-/seamless-immutable-7.1.4.tgz", + "integrity": "sha512-XiUO1QP4ki4E2PHegiGAlu6r82o5A+6tRh7IkGGTVg/h+UoeX4nFBeCGPOhb4CYjvkqsfm/TUtvOMYC1xmV30A==" + }, "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -10896,6 +13684,11 @@ "serviceworker-cache-polyfill": "^4.0.0" } }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" + }, "symbol-tree": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", diff --git a/package.json b/package.json index 1c98dd27..0fd5b0cb 100644 --- a/package.json +++ b/package.json @@ -5,15 +5,23 @@ "dependencies": { "ajv": "6.5.4", "chart.js": "2.7.2", + "connected-react-router": "^4.5.0", + "i": "^0.3.6", + "immutable": "^3.8.2", "lodash": "4.17.10", "moment": "2.22.1", + "npm": "^6.4.1", "react": "16.3.2", "react-chartjs-2": "2.7.2", "react-dom": "16.3.2", "react-helmet": "5.2.0", + "react-immutable-proptypes": "^2.1.0", + "react-redux": "^5.0.7", "react-router": "4.2.0", "react-router-dom": "4.2.2", "react-scripts": "1.1.5", + "redux": "^4.0.1", + "redux-immutable": "^4.0.0", "semantic-ui-css": "2.2.12", "semantic-ui-react": "0.75.1" }, diff --git a/src/actions/client.js b/src/actions/client.js new file mode 100644 index 00000000..28290bab --- /dev/null +++ b/src/actions/client.js @@ -0,0 +1,12 @@ +export const SET_CLIENT_VALUE = 'SET_CLIENT_VALUE'; + +export const setClientValue = ({ time, route, value }) => { + return { + type: SET_CLIENT_VALUE, + payload: { + time, + route, + value, + }, + }; +}; diff --git a/src/actions/geography.js b/src/actions/geography.js new file mode 100644 index 00000000..d06bd1a6 --- /dev/null +++ b/src/actions/geography.js @@ -0,0 +1,8 @@ +export const SET_US_STATE = 'SET_US_STATE'; + +export const setUSState = ({ state }) => { + return { + type: SET_US_STATE, + payload: { state }, + }; +}; diff --git a/src/actions/index.js b/src/actions/index.js new file mode 100644 index 00000000..a0273385 --- /dev/null +++ b/src/actions/index.js @@ -0,0 +1,3 @@ +export * from './geography'; +export * from './localization'; +export * from './client'; diff --git a/src/actions/localization.js b/src/actions/localization.js new file mode 100644 index 00000000..49cf2ad6 --- /dev/null +++ b/src/actions/localization.js @@ -0,0 +1,8 @@ +export const SET_LANGUAGE = 'SET_LANGUAGE'; + +export const setLanguage = ({ language }) => { + return { + type: SET_LANGUAGE, + payload: { language }, + }; +}; diff --git a/src/App.js b/src/components/App.js similarity index 93% rename from src/App.js rename to src/components/App.js index ab016b23..b0d15a7e 100644 --- a/src/App.js +++ b/src/components/App.js @@ -6,27 +6,29 @@ import { } from 'react-router-dom'; import { Helmet } from 'react-helmet'; -import { Confirmer } from './utils/getUserConfirmation'; +import { Confirmer } from '../utils/getUserConfirmation'; // CUSTOM COMPONENTS -import HomePage from './containers/HomePage'; -import AboutPage from './containers/AboutPage'; -import VisitPage from './containers/VisitPage'; -import Footer from './components/Footer'; -import Header from './components/Header'; +import HomePage from '../containers/HomePage'; +import AboutPage from '../containers/AboutPage'; +import VisitPage from '../containers/VisitPage'; +import Footer from './Footer'; +import Header from './Header'; // sort of a component -import { renderIfTrue } from './components/renderIfTrue'; +import { renderIfTrue } from './renderIfTrue'; // Development HUD -import { DevSwitch } from './containers/DevSwitch'; -import { DevHud } from './components/dev/DevHud'; +import { DevSwitch } from '../containers/DevSwitch'; +import { DevHud } from './dev/DevHud'; // Object Manipulation import { cloneDeep } from 'lodash'; -import { CLIENT_DEFAULTS } from './utils/CLIENT_DEFAULTS'; +import { CLIENT_DEFAULTS } from '../utils/CLIENT_DEFAULTS'; // LOCALIZATION -import { getTextForLanguage } from './utils/getTextForLanguage'; +import { getTextForLanguage } from '../utils/getTextForLanguage'; + + /** * Main top-level component of the app. Contains the router that controls access @@ -90,6 +92,9 @@ class App extends Component { }, termsAccepted: false, }; + + this.props.setLanguage({ language: this.state.langCode }); + this.props.setUSState({ state: 'MA' }); }; // End constructor() /** @@ -103,6 +108,7 @@ class App extends Component { setLanguage = (evnt, inputProps) => { var snippets = getTextForLanguage(inputProps.value); this.setState({ language: inputProps.value, snippets: snippets }); + this.props.setLanguage({ language: inputProps.value }); }; /** Set the value of a specified key in the app state's devProps. @@ -271,5 +277,4 @@ class App extends Component { }; // End render() } - export default App; diff --git a/src/configure-store.js b/src/configure-store.js new file mode 100644 index 00000000..59289b56 --- /dev/null +++ b/src/configure-store.js @@ -0,0 +1,31 @@ +/* global module, process */ + +import { createStore, compose } from 'redux'; +import { Map } from 'immutable'; +import createReducer from './reducers'; + + +export default function configureStore(initialState = Map()) { + // If Redux DevTools Extension is installed use it, otherwise use Redux compose + const composeEnhancers = process.env.NODE_ENV !== 'production' && + typeof window === 'object' && + window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ + ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) + : compose; + + const store = createStore( + createReducer(), + initialState, + composeEnhancers() + ); + + // Make reducers hot reloadable, see http://mxs.is/googmo + /* istanbul ignore next */ + if (module.hot) { + module.hot.accept('./reducers', () => { + store.replaceReducer(createReducer()); + }); + } + + return store; +} diff --git a/src/containers/App.js b/src/containers/App.js new file mode 100644 index 00000000..bda82712 --- /dev/null +++ b/src/containers/App.js @@ -0,0 +1,18 @@ +import { connect } from 'react-redux'; + +import App from '../components/App'; +import { setUSState, setLanguage } from '../actions'; + +const mapDispatchToProps = (dispatch) => { + return { + setUSState({ state }) { + dispatch(setUSState({ state })); + }, + + setLanguage({ language }) { + dispatch(setLanguage({ language })); + }, + }; +}; + +export default connect(null, mapDispatchToProps)(App); diff --git a/src/containers/VisitPage.js b/src/containers/VisitPage.js index 2599eccf..392f30e4 100644 --- a/src/containers/VisitPage.js +++ b/src/containers/VisitPage.js @@ -4,6 +4,7 @@ import { Responsive, } from 'semantic-ui-react'; import { Redirect } from 'react-router-dom'; +import { connect } from 'react-redux'; // DATA MANAGEMENT import { setNestedProperty } from '../utils/setNestedProperty'; @@ -32,6 +33,7 @@ import StepBar from '../components/StepBar'; import { BigButton } from '../forms/inputs'; import { ButtonReset } from '../forms/ButtonReset'; import PredictionsWarning from '../components/prompts/PredictionsWarning'; +import { setClientValue } from '../actions'; class VisitPage extends Component { constructor (props) { @@ -158,7 +160,9 @@ class VisitPage extends Component { routeList = route.split('/'), id = routeList[ 0 ], // `routeList` gets mutated newEvent = { time: time, route: routeList, value: value }; - + + this.props.setClientValue({ time, route: routeList, value }); + setNestedProperty(newEvent, clone, this.state.userChanged[ id ]); // Only set if the input was valid...? For now, always. // Also, userChanged should be only one step deep @@ -393,4 +397,14 @@ class VisitPage extends Component { } } -export default VisitPage; +const mapDispatchToProps = (dispatch) => { + return { + setClientValue({ time, route, value }) { + dispatch( + setClientValue({ time, route, value }) + ); + }, + }; +}; + +export default connect(null, mapDispatchToProps)(VisitPage); diff --git a/src/containers/forms/output/Summary.js b/src/containers/forms/output/Summary.js new file mode 100644 index 00000000..831026ab --- /dev/null +++ b/src/containers/forms/output/Summary.js @@ -0,0 +1,9 @@ +import { connect } from 'react-redux'; + +import { Summary } from '../../../forms/output/Summary'; + +const mapStateToProps = (state) => { + return { client: state.get('client') }; +}; + +export default connect(mapStateToProps)(Summary); diff --git a/src/forms/Predictions.js b/src/forms/Predictions.js index 0951c875..c12ffcc9 100644 --- a/src/forms/Predictions.js +++ b/src/forms/Predictions.js @@ -6,7 +6,7 @@ import { FormPartsContainer } from './FormPartsContainer'; import { IntervalColumnHeadings } from '../components/headings'; import { CashFlowInputsRow } from './cashflow'; import { GraphHolder } from './output/GraphHolder'; -import { Summary } from './output/Summary'; +import Summary from '../containers/forms/output/Summary'; import { BenefitsTable } from './output/BenefitsTable'; import { StackedBarGraph } from './output/StackedBarGraph'; import { StackedAreaGraph } from './output/StackedAreaGraph'; @@ -66,10 +66,10 @@ const TabbedVisualizations = ({ client, openFeedback, snippets }) => { ), render: () => {return ( - + + );}, }, @@ -184,4 +184,3 @@ const PredictionsStep = function ({ updateClientValue, navData, client, snippets }; // End FutureIncomeStep() Component export { PredictionsStep }; - diff --git a/src/forms/output/Summary.js b/src/forms/output/Summary.js index f74981ef..ce1b1b38 100644 --- a/src/forms/output/Summary.js +++ b/src/forms/output/Summary.js @@ -1,5 +1,7 @@ // REACT COMPONENTS import React from 'react'; +import PropTypes from 'prop-types'; +import ImmutablePropTypes from 'react-immutable-proptypes'; import { Header, Button } from 'semantic-ui-react'; // DATA @@ -56,7 +58,7 @@ var totalLastItemsOfArraysInObject = function (accumulated) { * array of numerical values (which are meant to be money * values right now). * @param {array} sourceObject.income Earned income values. - * @param {int} Which item in each array should be used to + * @param {int} index Which item in each array should be used to * accumulate values. * * @example @@ -274,10 +276,16 @@ const Summary = function ({ client, openFeedback, snippets }) { var resourceKeys = [ `income` ]; // Benefits, in order of appearance // So can't wait till `.benefits` is an array of benefit names... - if (client.current.hasSection8) { + if (client.getIn([ + 'current', + 'hasSection8', + ])) { resourceKeys.push(`section8`); } - if (client.current.hasSnap) { + if (client.getIn([ + 'current', + 'hasSnap', + ])) { resourceKeys.push(`snap`); } @@ -286,7 +294,13 @@ const Summary = function ({ client, openFeedback, snippets }) { if (resourceKeys.length <= 1) { return snippets.i_noBenefitsChosen; } - if (client.future.earned === client.current.earned) { + if (client.getIn([ + 'future', + 'earned', + ]) === client.getIn([ + 'current', + 'earned', + ])) { return snippets.i_noFutureChange; } @@ -418,6 +432,11 @@ const Summary = function ({ client, openFeedback, snippets }) { }; // Ends +Summary.propTypes = { + client: ImmutablePropTypes.map, + openFeedback: PropTypes.func, +}; + export { Summary, totalLastItemsOfArraysInObject, diff --git a/src/index.js b/src/index.js index 295c8e36..7d625d24 100644 --- a/src/index.js +++ b/src/index.js @@ -1,11 +1,23 @@ import React from 'react'; import ReactDOM from 'react-dom'; +import { Provider } from 'react-redux'; import './index.css'; import './styles/dev.css'; -import App from './App'; +import App from './containers/App'; +import getStore from './store'; import registerServiceWorker from './utils/registerServiceWorker'; import 'semantic-ui-css/semantic.min.css'; -ReactDOM.render(, document.getElementById('root')); +const store = getStore(); + +ReactDOM.render( + ( + + + + ) + , + document.getElementById('root') +); registerServiceWorker(); diff --git a/src/reducers/client.js b/src/reducers/client.js new file mode 100644 index 00000000..89376ca7 --- /dev/null +++ b/src/reducers/client.js @@ -0,0 +1,23 @@ +import { fromJS } from 'immutable'; + +import { CLIENT_DEFAULTS } from '../utils/CLIENT_DEFAULTS'; +import { SET_CLIENT_VALUE } from '../actions'; + +const clientReducer = ( + state = fromJS(CLIENT_DEFAULTS), + action +) => { + switch (action.type) { + case SET_CLIENT_VALUE: + const { time, route, value } = action.payload; + return state.setIn([ + time, + ...route, + ], fromJS(value)); + + default: + return state; + } +}; + +export default clientReducer; diff --git a/src/reducers/geography.js b/src/reducers/geography.js new file mode 100644 index 00000000..64b519d2 --- /dev/null +++ b/src/reducers/geography.js @@ -0,0 +1,23 @@ +import { Map } from 'immutable'; + +import { SET_US_STATE } from '../actions'; + + +/* +State shape: +{ + state: , +} + */ + +const geographyReducer = (state = Map(), action) => { + switch (action.type) { + case SET_US_STATE: { + return state.set('state', action.payload.state); + } + + default: return state; + } +}; + +export default geographyReducer; diff --git a/src/reducers/index.js b/src/reducers/index.js new file mode 100644 index 00000000..6eae2e91 --- /dev/null +++ b/src/reducers/index.js @@ -0,0 +1,17 @@ +/** + * Combine all reducers in this file and export the combined reducers. + */ + +import { combineReducers } from 'redux-immutable'; + +import geographyReducer from './geography'; +import localizationReducer from './localization'; +import clientReducer from './client'; + +export default function createReducer() { + return combineReducers({ + geography: geographyReducer, + localization: localizationReducer, + client: clientReducer, + }); +} diff --git a/src/reducers/localization.js b/src/reducers/localization.js new file mode 100644 index 00000000..f1f68d9c --- /dev/null +++ b/src/reducers/localization.js @@ -0,0 +1,24 @@ +import { Map } from 'immutable'; + +import { SET_LANGUAGE } from '../actions'; + + +/* +State shape: + +{ + currentLanguage: +} + */ + +const localizationReducer = (state = Map(), action) => { + switch (action.type) { + case SET_LANGUAGE: + return state.set('currentLanguage', action.payload.language); + + default: + return state; + } +}; + +export default localizationReducer; diff --git a/src/store.js b/src/store.js new file mode 100644 index 00000000..cfa3eb7f --- /dev/null +++ b/src/store.js @@ -0,0 +1,24 @@ +/** + * Configures the Redux store for use on the browser. Separate from configure-store.js both so + * that configure-store.js could be used server-side (without a DOM reference) and so that other + * client-side modules can get a reference to the store if needed. + */ + +import { Map } from 'immutable'; +import createHistory from 'history/createBrowserHistory'; +import configureStore from './configure-store'; + +export const history = createHistory(); + +const initialState = Map(); + +let store; + +export default function getStore() { + /* istanbul ignore else */ + if (!store) { + store = configureStore(initialState, history); + } + + return store; +} diff --git a/src/test/App.test.js b/src/test/App.test.js index 6dd87c0d..9eb6b8c4 100644 --- a/src/test/App.test.js +++ b/src/test/App.test.js @@ -1,7 +1,7 @@ import React from 'react'; import { shallow } from 'enzyme'; -import App from '../App'; +import App from '../components/App'; global.localStorage = { getItem: function (key) { return `false`; }, @@ -9,6 +9,12 @@ global.localStorage = { setItem: function (key, value) { return; }, }; +const NO_OP = () => {}; + it('renders without crashing', () => { - shallow(); + shallow( + + ); }); From 70d571f5f241ac82faa77f74e797f4b7c58f7020 Mon Sep 17 00:00:00 2001 From: Turner Hayes Date: Thu, 25 Oct 2018 20:13:42 -0400 Subject: [PATCH 2/9] Fix path resolution errors --- src/components/App.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/App.js b/src/components/App.js index a4507faa..f53474ed 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -9,11 +9,11 @@ import { Helmet } from 'react-helmet'; import { Confirmer } from '../utils/getUserConfirmation'; // CUSTOM COMPONENTS -import HomePage from './containers/HomePage'; -import AboutPage from './containers/AboutPage'; -import VisitPage from './containers/VisitPage'; -import Footer from './components/Footer'; -import Header from './components/Header'; +import HomePage from '../containers/HomePage'; +import AboutPage from '../containers/AboutPage'; +import VisitPage from '../containers/VisitPage'; +import Footer from './Footer'; +import Header from './Header'; // Development HUD import { DevSwitch } from '../containers/DevSwitch'; From 56c8af6edcdd1d514dcfe84962b7d21d3b089c59 Mon Sep 17 00:00:00 2001 From: Turner Hayes Date: Thu, 25 Oct 2018 22:13:00 -0400 Subject: [PATCH 3/9] Convert CurrentBenefitsStep to use Redux store --- src/containers/VisitPage.js | 7 ++-- src/containers/forms/CurrentBenefits.js | 31 ++++++++++++++++ src/forms/CurrentBenefits.js | 47 ++++++++++++++----------- 3 files changed, 60 insertions(+), 25 deletions(-) create mode 100644 src/containers/forms/CurrentBenefits.js diff --git a/src/containers/VisitPage.js b/src/containers/VisitPage.js index d0a02d43..e791eb65 100644 --- a/src/containers/VisitPage.js +++ b/src/containers/VisitPage.js @@ -27,7 +27,7 @@ import { CurrentIncomeStep } from '../forms/CurrentIncome'; import { CurrentExpensesStep } from '../forms/CurrentExpenses'; import { PredictionsStep } from '../forms/Predictions'; import { HouseholdStep } from '../forms/Household'; -import { CurrentBenefitsStep } from '../forms/CurrentBenefits'; +import { CurrentBenefitsStep } from './forms/CurrentBenefits'; import StepBar from '../components/StepBar'; import { BigButton } from '../forms/inputs'; import { ButtonReset } from '../forms/ButtonReset'; @@ -67,9 +67,8 @@ class VisitPage extends Component { this.steps = [ { - form: CurrentBenefitsStep, - key: 'currentBenefits', - updateClientValue: this.changeCurrent, + form: CurrentBenefitsStep, + key: 'currentBenefits', }, { form: HouseholdStep, diff --git a/src/containers/forms/CurrentBenefits.js b/src/containers/forms/CurrentBenefits.js new file mode 100644 index 00000000..d2cb7444 --- /dev/null +++ b/src/containers/forms/CurrentBenefits.js @@ -0,0 +1,31 @@ +import { connect } from 'react-redux'; + +import { CurrentBenefitsStep } from '../../forms/CurrentBenefits'; +import { setClientValue } from '../../actions'; + +const mapStateToProps = (state) => { + return { + currentClient: state.getIn([ + 'client', + 'current', + ]), + }; +}; + +const mapDispatchToProps = (dispatch) => { + return { + setHasBenefit({ benefit, value }) { + dispatch( + setClientValue({ + time: 'current', + route: [ benefit ], + value, + }) + ); + }, + }; +}; + +const CurrentBenefitsContainer = connect(mapStateToProps, mapDispatchToProps)(CurrentBenefitsStep); + +export { CurrentBenefitsContainer as CurrentBenefitsStep }; diff --git a/src/forms/CurrentBenefits.js b/src/forms/CurrentBenefits.js index 245d850d..09eaae93 100644 --- a/src/forms/CurrentBenefits.js +++ b/src/forms/CurrentBenefits.js @@ -6,15 +6,21 @@ import { FormPartsContainer } from './FormPartsContainer'; import { ControlledRadioYesNo } from './inputs'; -const LocalizedRadioYesNo = function ({ snippets, checked, name, updateClientValue }) { - return ( - - ); -}; +class LocalizedRadioYesNo extends React.PureComponent { + handleRadioChange = (event, data) => { + this.props.setHasBenefit({ benefit: this.props.name, value: data.checked }); + }; + + render() { + return ( + + ); + } +} /** Asks which benefits the user is currently receiving @@ -23,30 +29,30 @@ const LocalizedRadioYesNo = function ({ snippets, checked, name, updateClientVal * * @function * @param {object} props - * @property {object} props.current Client current info. - * @property {function} props.updateClientValue Updates state upstream. + * @property {Immutable.Map} props.currentClient Client current info. + * @property {function} props.setHasBenefit Sets whether the client has a particular benefit. * @property {function} props.snippets Uses user chosen language-specific * snippets. * * @returns {object} Component */ -const CurrentBenefitsContent = ({ current, updateClientValue, snippets }) => { +const CurrentBenefitsContent = ({ currentClient, setHasBenefit, snippets }) => { var sharedProps = { - updateClientValue: updateClientValue, - snippets: snippets, + setHasBenefit, + snippets, }; return (
); // end return @@ -58,15 +64,14 @@ const CurrentBenefitsContent = ({ current, updateClientValue, snippets }) => { * * @function * @param {object} props - * @property {function} props.updateClientValue Updates state upstream. * @property {object} props.navData Bottom row buttons - * @property {object} props.client JSON object with future and current values. + * @property {Immutable.Map} props.currentClient Immutable Map with current values. * @property {function} props.snippets Uses user chosen language-specific * snippets. * * @returns {object} Component */ -const CurrentBenefitsStep = ({ updateClientValue, navData, client, snippets }) => { +const CurrentBenefitsStep = ({ setHasBenefit, navData, currentClient, snippets }) => { return ( ); From 9b96f3ff44427e7b30aa3863bb718df61afa52bd Mon Sep 17 00:00:00 2001 From: Turner Hayes Date: Sun, 28 Oct 2018 22:28:38 -0400 Subject: [PATCH 4/9] Incorporate Redux store into Household, CurrentIncome and CurrentExpenses steps --- src/actions/client.js | 113 +++++ src/containers/VisitPage.js | 6 +- src/containers/forms/CurrentExpenses.js | 60 +++ src/containers/forms/CurrentIncome.js | 32 ++ src/containers/forms/Household.js | 78 ++++ src/forms/CurrentExpenses.js | 152 ++++--- src/forms/CurrentIncome.js | 30 +- src/forms/Household.js | 416 +++++++++--------- src/forms/cashflow.js | 107 ++++- src/forms/rentFields.js | 28 +- src/reducers/client.js | 132 +++++- .../CurrentExpenses.test.js.snap | 61 --- .../__snapshots__/CurrentIncome.test.js.snap | 61 --- .../__snapshots__/Household.test.js.snap | 61 --- 14 files changed, 847 insertions(+), 490 deletions(-) create mode 100644 src/containers/forms/CurrentExpenses.js create mode 100644 src/containers/forms/CurrentIncome.js create mode 100644 src/containers/forms/Household.js diff --git a/src/actions/client.js b/src/actions/client.js index 28290bab..42edddf4 100644 --- a/src/actions/client.js +++ b/src/actions/client.js @@ -10,3 +10,116 @@ export const setClientValue = ({ time, route, value }) => { }, }; }; + +export const REMOVE_MEMBER = 'REMOVE_MEMBER'; + +export const removeMember = ({ time = 'current', index }) => { + return { + type: REMOVE_MEMBER, + payload: { + time, + index, + }, + }; +}; + +export const ADD_MEMBER = 'ADD_MEMBER'; + +export const addMember = ({ time = 'current', member }) => { + return { + type: ADD_MEMBER, + payload: { + time, + member, + }, + }; +}; + +export const SET_MEMBER_IS_DISABLED = 'SET_MEMBER_IS_DISABLED'; + +export const setMemberIsDisabled = ({ time = 'current', index, isDisabled }) => { + return { + type: SET_MEMBER_IS_DISABLED, + payload: { + time, + index, + isDisabled: !!isDisabled, + }, + }; +}; + +export const SET_MEMBER_ROLE = 'SET_MEMBER_ROLE'; + +export const setMemberRole = ({ time = 'current', index, role }) => { + return { + type: SET_MEMBER_ROLE, + payload: { + time, + index, + role, + }, + }; +}; + +export const SET_MEMBER_AGE = 'SET_MEMBER_AGE'; + +export const setMemberAge = ({ time = 'current', index, age }) => { + return { + type: SET_MEMBER_AGE, + payload: { + time, + index, + age, + }, + }; +}; + +export const SET_CASH_VALUE = 'SET_CASH_VALUE'; + +export const setCashValue = ({ time, name, value }) => { + return { + type: SET_CASH_VALUE, + payload: { + time, + name, + value, + }, + }; +}; + +export const SET_HOUSING_TYPE = 'SET_HOUSING_TYPE'; + +export const setHousingType = ({ time, housingType }) => { + return { + type: SET_HOUSING_TYPE, + payload: { + time, + housingType, + }, + }; +}; + +export const SET_PAYS_UTILITY = 'SET_PAYS_UTILITY'; + +export const setPaysUtility = ({ time, utility, paysUtility }) => { + return { + type: SET_PAYS_UTILITY, + payload: { + time, + utility, + paysUtility, + }, + }; +}; + +export const SET_GETS_FUEL_ASSISTANCE = 'SET_GETS_FUEL_ASSISTANCE'; + +export const setGetsFuelAssistance = ({ time, getsAssistance }) => { + return { + type: SET_GETS_FUEL_ASSISTANCE, + payload: { + time, + getsAssistance, + }, + }; +}; diff --git a/src/containers/VisitPage.js b/src/containers/VisitPage.js index e791eb65..9077e357 100644 --- a/src/containers/VisitPage.js +++ b/src/containers/VisitPage.js @@ -23,10 +23,10 @@ import ErrorListener from '../components/prompts/ErrorListener'; import FeedbackPrompt from '../components/prompts/FeedbackPrompt'; import FeedbackForm from '../components/prompts/FeedbackForm'; import { FeedbackAnytime } from '../components/prompts/FeedbackAnytime'; -import { CurrentIncomeStep } from '../forms/CurrentIncome'; -import { CurrentExpensesStep } from '../forms/CurrentExpenses'; +import { CurrentIncomeStep } from '../containers/forms/CurrentIncome'; +import { CurrentExpensesStep } from '../containers/forms/CurrentExpenses'; import { PredictionsStep } from '../forms/Predictions'; -import { HouseholdStep } from '../forms/Household'; +import { HouseholdStep } from '../containers/forms/Household'; import { CurrentBenefitsStep } from './forms/CurrentBenefits'; import StepBar from '../components/StepBar'; import { BigButton } from '../forms/inputs'; diff --git a/src/containers/forms/CurrentExpenses.js b/src/containers/forms/CurrentExpenses.js new file mode 100644 index 00000000..cfa28f98 --- /dev/null +++ b/src/containers/forms/CurrentExpenses.js @@ -0,0 +1,60 @@ +import { connect } from 'react-redux'; + +import { CurrentExpensesStep } from '../../forms/CurrentExpenses'; + +import { setCashValue, setHousingType, setPaysUtility, setGetsFuelAssistance } from '../../actions'; + +const mapStateToProps = (state) => { + return { + currentClient: state.getIn([ + 'client', + 'current', + ]), + }; +}; + +const mapDispatchToProps = (dispatch) => { + return { + setExpenseValue({ name, value }) { + dispatch( + setCashValue({ + time: 'current', + name, + value, + }) + ); + }, + + setHousingType({ housingType }) { + dispatch( + setHousingType({ + time: 'current', + housingType, + }) + ); + }, + + setPaysUtility({ utility, paysUtility }) { + dispatch( + setPaysUtility({ + time: 'current', + utility, + paysUtility, + }) + ); + }, + + setGetsFuelAssistance({ getsAssistance }) { + dispatch( + setGetsFuelAssistance({ + time: 'current', + getsAssistance, + }) + ); + }, + }; +}; + +const CurrentExpensesStepContainer = connect(mapStateToProps, mapDispatchToProps)(CurrentExpensesStep); + +export { CurrentExpensesStepContainer as CurrentExpensesStep }; diff --git a/src/containers/forms/CurrentIncome.js b/src/containers/forms/CurrentIncome.js new file mode 100644 index 00000000..b42a5f5e --- /dev/null +++ b/src/containers/forms/CurrentIncome.js @@ -0,0 +1,32 @@ +import { connect } from 'react-redux'; + +import { CurrentIncomeStep } from '../../forms/CurrentIncome'; + +import { setCashValue } from '../../actions'; + +const mapStateToProps = (state) => { + return { + currentClient: state.getIn([ + 'client', + 'current', + ]), + }; +}; + +const mapDispatchToProps = (dispatch) => { + return { + setIncomeValue({ name, value }) { + dispatch( + setCashValue({ + time: 'current', + name, + value, + }) + ); + }, + }; +}; + +const CurrentIncomeStepContainer = connect(mapStateToProps, mapDispatchToProps)(CurrentIncomeStep); + +export { CurrentIncomeStepContainer as CurrentIncomeStep }; diff --git a/src/containers/forms/Household.js b/src/containers/forms/Household.js new file mode 100644 index 00000000..d8e22526 --- /dev/null +++ b/src/containers/forms/Household.js @@ -0,0 +1,78 @@ +import { connect } from 'react-redux'; + +import { HouseholdStep } from '../../forms/Household'; +import { + addMember, + removeMember, + setMemberIsDisabled, + setMemberRole, + setMemberAge, +} from '../../actions'; + +const time = 'current'; + +const mapStateToProps = (state) => { + return { + household: state.getIn([ + 'client', + 'current', + 'household', + ]), + }; +}; + +const mapDispatchToProps = (dispatch) => { + return { + setMemberAge({ index, age }) { + dispatch( + setMemberAge({ + time, + index, + age, + }) + ); + }, + + setMemberIsDisabled({ index, isDisabled }) { + dispatch( + setMemberIsDisabled({ + time, + index, + isDisabled, + }) + ); + }, + + setMemberRole({ index, role }) { + dispatch( + setMemberRole({ + time, + index, + role, + }) + ); + }, + + removeMember({ index }) { + dispatch( + removeMember({ + time, + index, + }) + ); + }, + + addMember({ member }) { + dispatch( + addMember({ + time, + member, + }) + ); + }, + }; +}; + +const HouseholdStepContainer = connect(mapStateToProps, mapDispatchToProps)(HouseholdStep); + +export { HouseholdStepContainer as HouseholdStep }; diff --git a/src/forms/CurrentExpenses.js b/src/forms/CurrentExpenses.js index 79ed52ef..e9f482bd 100644 --- a/src/forms/CurrentExpenses.js +++ b/src/forms/CurrentExpenses.js @@ -10,7 +10,7 @@ import { // PROJECT COMPONENTS import { FormPartsContainer } from './FormPartsContainer'; import { AttentionArrow } from './formHelpers'; -import { CashFlowInputsRow } from './cashflow'; +import { ImmutableCashFlowInputsRow as CashFlowInputsRow } from './cashflow'; import { ControlledRadioYesNo } from './inputs'; import { ContentH1, @@ -19,7 +19,7 @@ import { import { ContractRentField, RentShareField, - PlainRentRow, + ImmutablePlainRentRow as PlainRentRow, } from './rentFields'; import { HeadingWithDetail } from '../components/details'; // Premature feature temporarily hidden to avoid messy revert @@ -84,7 +84,7 @@ const EarnedFrom = function ({ hasExpenses, CashFlowRow, label, propData }) { var { childPropName, client } = propData; var showProps = { childName: childPropName, - showChildrenAtStart: client[ childPropName ] > 0, + showChildrenAtStart: client.get(childPropName) > 0, question: label, heading: null, onNo: reset, @@ -107,18 +107,24 @@ const EarnedFrom = function ({ hasExpenses, CashFlowRow, label, propData }) { }; // End EarnedFrom -const Utilities = function ({ current, type, time, updateClientValue }) { +const Utilities = function ({ client, setPaysUtility, setGetsFuelAssistance }) { - let hasClimate = current.climateControl, - hasElectricity = current.nonHeatElectricity, - hasPhone = current.phone, - hasFuelAssist = current.fuelAssistance; + let hasClimate = client.get('climateControl'), + hasElectricity = client.get('nonHeatElectricity'), + hasPhone = client.get('phone'), + hasFuelAssist = client.get('fuelAssistance'); - let setChecked = function (evnt, inputProps) { - var obj = { ...inputProps, value: inputProps.checked }; - updateClientValue(evnt, obj); + let setChecked = function (evnt, { name, checked }) { + setPaysUtility({ + utility: name, + paysUtility: checked, + }); }; // End setChecked() + const handleFuelAssistanceChanged = (event, { value }) => { + setGetsFuelAssistance({ getsAssistance: value }); + }; + // For keyboard access (already does spacebar) let onKeyDown = function (evnt) { if (evnt.key === `Enter`) { @@ -158,7 +164,7 @@ const Utilities = function ({ current, type, time, updateClientValue }) { labelText = { 'Do you get Fuel Assistance?' } checked = { hasFuelAssist } name = { 'fuelAssistance' } - onChange = { updateClientValue } /> + onChange = { handleFuelAssistanceChanged } />
@@ -166,23 +172,33 @@ const Utilities = function ({ current, type, time, updateClientValue }) { }; // End Utilities(<>) -const HousingDetails = function ({ current, type, time, updateClientValue }) { +const HousingDetails = function ({ client, type, setExpenseValue, setPaysUtility, setGetsFuelAssistance }) { + const time = 'current'; - let housing = current.housing, + let housing = client.get('housing'), sharedProps = { - timeState: current, - current: current, - type: type, - time: time, - updateClientValue: updateClientValue, + timeState: client, + client, + type: type, + time, + setValue: setExpenseValue, }; + + const utilitiesProps = { + timeState: client, + client, + type, + time, + setGetsFuelAssistance, + setPaysUtility, + }; - if (current.housing === 'voucher') { + if (housing === 'voucher') { return (
- +
); @@ -193,8 +209,10 @@ const HousingDetails = function ({ current, type, time, updateClientValue }) { return (

- - + +
); @@ -214,7 +232,7 @@ const HousingDetails = function ({ current, type, time, updateClientValue }) { { ...sharedProps } generic={ 'propertyTax' }> Property Tax - + ); @@ -222,7 +240,7 @@ const HousingDetails = function ({ current, type, time, updateClientValue }) { }; // End HousingDetails(<>) -const HousingRadio = function ({ currentValue, label, time, updateClientValue }) { +const HousingRadio = function ({ currentValue, label, updateClientValue }) { var value = label.toLowerCase(); @@ -243,26 +261,18 @@ const HousingRadio = function ({ currentValue, label, time, updateClientValue }) /** * @function * @param {object} props - * @param {object} props.current Client data of current user circumstances + * @param {object} props.client Client data of current user circumstances * @param {string} props.type 'expense' or 'income', etc., for classes * @param {string} props.time 'current' or 'future' * @param {function} props.updateClientValue Sets state values * * @returns React element */ -const Housing = function ({ current, type, time, updateClientValue }) { +const Housing = function ({ client, type, time, setHousingType, setExpenseValue, setGetsFuelAssistance, setPaysUtility }) { /** @deprecated This is handled differently now */ - let ensureRouteAndValue = function (evnt, inputProps) { - var obj = { ...inputProps, name: inputProps.name, value: inputProps.value, checked: null }; - updateClientValue(evnt, obj); - }; - - let sharedProps = { - current: current, - type: type, - time: time, - updateClientValue: ensureRouteAndValue, + const ensureRouteAndValue = function (evnt, { value }) { + setHousingType({ housingType: value }); }; return ( @@ -270,30 +280,36 @@ const Housing = function ({ current, type, time, updateClientValue }) { Housing - { current.housing === 'voucher' ? ( + { client.get('housing') === 'voucher' ? ( null ) : (
What is your housing situation?
) } - + ); @@ -306,20 +322,20 @@ const Housing = function ({ current, type, time, updateClientValue }) { * @param {object} props * @param {object} props.current Client data of current user circumstances * @param {string} props.time 'current' or 'future' - * @param {function} props.updateClientValue Sets state values + * @param {function} props.setExpenseValue Sets state values * @param {object} props.snippets Language-specific content * * @returns React element */ -const ExpensesFormContent = function ({ current, time, updateClientValue, snippets }) { +const ExpensesFormContent = function ({ client, setExpenseValue, setHousingType, setPaysUtility, setGetsFuelAssistance, snippets }) { let type = 'expense', - household = current.household, + household = client.get('household'), sharedProps = { - timeState: current, - type: type, - time: time, - updateClientValue: updateClientValue, + timeState: client, + type: type, + time: 'current', + setValue: setExpenseValue, }; /* @todo Make a more general age-checking function to keep @@ -335,7 +351,7 @@ const ExpensesFormContent = function ({ current, time, updateClientValue, snippe // 'Elderly' here is using the lowest common denominator - SNAP standards. var isElderlyOrDisabled = function (member) { - return isDisabled(member) || member.m_age >= 60; + return isDisabled(member) || member.get('m_age') >= 60; }; var elderlyOrDisabled = getEveryMember(household, isElderlyOrDisabled), elderlyOrDisabledHeadOrSpouse = getEveryMember(elderlyOrDisabled, isHeadOrSpouse); @@ -371,12 +387,12 @@ const ExpensesFormContent = function ({ current, time, updateClientValue, snippe Child Support @@ -448,12 +464,12 @@ const ExpensesFormContent = function ({ current, time, updateClientValue, snippe 0 || (current.hasSnap && elderlyOrDisabled.length > 0) ? ( + { elderlyOrDisabledHeadOrSpouse.length > 0 || (client.get('hasSnap') && elderlyOrDisabled.length > 0) ? (
Unreimbursed Medical Expenses @@ -506,10 +522,12 @@ const ExpensesFormContent = function ({ current, time, updateClientValue, snippe ) } + setPaysUtility={ setPaysUtility } + setGetsFuelAssistance={ setGetsFuelAssistance } + setExpenseValue={ setExpenseValue } + setHousingType={ setHousingType } /> {/* Premature feature temporarily hidden to avoid messy revert ); diff --git a/src/forms/CurrentIncome.js b/src/forms/CurrentIncome.js index 52d3532e..2390ec16 100644 --- a/src/forms/CurrentIncome.js +++ b/src/forms/CurrentIncome.js @@ -5,7 +5,7 @@ import { Form } from 'semantic-ui-react'; // PROJECT COMPONENTS import { FormPartsContainer } from './FormPartsContainer'; import { IntervalColumnHeadings } from '../components/headings'; -import { CashFlowInputsRow } from './cashflow'; +import { ImmutableCashFlowInputsRow as CashFlowInputsRow } from './cashflow'; // ======================================== @@ -38,7 +38,7 @@ import { CashFlowInputsRow } from './cashflow'; * * @function * @param {object} props - * @property {object} props.current Client current info. Could be + * @property {Immutable.Map} props.currentClient Client current info. Could be * changed to just 'client' to allow future values in abstraction. * @property {string} props.time 'current' or 'future'. (needed?) * @property {function} props.updateClientValue Updates state upstream. @@ -46,23 +46,14 @@ import { CashFlowInputsRow } from './cashflow'; * * @returns {object} React element */ -const IncomeForm = function ({ current, time, updateClientValue, snippets }) { +const IncomeForm = function ({ client, setIncomeValue, snippets }) { var type = 'income'; - /** Makes sure values are propagated to 'future' properties if needed - * @member - * @depricated - */ - var ensureFuture = function (evnt, inputProps) { - updateClientValue(evnt, { ...inputProps, fillFuture: true }); - }; // End ensureFuture() - var sharedProps = { - timeState: current, - time: time, - type: type, - updateClientValue: ensureFuture, + timeState: client, + type: type, + setValue: setIncomeValue, }; return ( @@ -138,14 +129,14 @@ const IncomeForm = function ({ current, time, updateClientValue, snippets }) { /** * @function * @param {object} props - * @property {function} props.updateClientValue Updates state upstream. + * @property {function} props.setIncomeValue Updates the state of an income value. * @property {object} props.navData Bottom row buttons. * @property {object} props.client JSON object with `future` and `current` props. * @property {function} props.snippets Uses user chosen language-specific text. * * @returns {object} React element */ -const CurrentIncomeStep = function ({ updateClientValue, navData, client, snippets }) { +const CurrentIncomeStep = function ({ setIncomeValue, navData, currentClient, snippets }) { // `props` is a cloned version of the original props. References broken. return ( @@ -155,9 +146,8 @@ const CurrentIncomeStep = function ({ updateClientValue, navData, client, snippe navData = { navData } formClass = { `income` }> ); diff --git a/src/forms/Household.js b/src/forms/Household.js index b2a89b93..1621d7ab 100644 --- a/src/forms/Household.js +++ b/src/forms/Household.js @@ -20,10 +20,6 @@ import { hasOnlyNonNegWholeNumberChars, } from '../utils/validators'; -// OBJECT MANIPULATION -import { cloneDeep } from 'lodash'; - - // ====================== // GENERICS // ====================== @@ -113,239 +109,228 @@ const MemberButton = function ({ basic, color, iconName, className, onClick }) { // UNIQUE // ====================== -const Role = function ({ member, setMember, snippets }) { - - var ThisRole = null, - margin = '0'; - - if (member.index === 0) { - - ThisRole = { snippets.i_headOfHousehold }; - - } else if (member.index === 1) { - - margin = '-1em'; - - var options = [ - { text: snippets.i_spouse, value: 'spouse' }, - { text: snippets.i_childOther, value: 'member' }, - ]; - - ThisRole = ; - - } else { +class Role extends React.PureComponent { + handleRoleChange = (event, { value }) => { + this.props.onChange({ role: value }); + }; - ThisRole = { snippets.i_childOther }; + render() { + const { member, snippets } = this.props; + + var ThisRole = null, + margin = '0'; + + if (this.props.index === 0) { + + ThisRole = { snippets.i_headOfHousehold }; + + } else if (this.props.index === 1) { + + margin = '-1em'; + + var options = [ + { text: snippets.i_spouse, value: 'spouse' }, + { text: snippets.i_childOther, value: 'member' }, + ]; + + ThisRole = ; + + } else { + + ThisRole = { snippets.i_childOther }; + + } + + // Styles will have to be adjusted. + return ( +
+ { ThisRole } +
+ ); } +} // End Role(<>) - // Styles will have to be adjusted. - return ( -
- { ThisRole } -
- ); -}; // End Role(<>) - - -const MemberField = function ({ household, time, setHousehold, updateClientValue, snippets }, indx) { - - var member = household[ indx ], - routeStart = 'household/' + indx + '/'; - member.index = indx; // Just needed as member prop in this file - - - var onMemberChange = function (evnt, inputProps) { - var route = routeStart + inputProps.name; - var data = { route: route, value: inputProps.value }; - updateClientValue(evnt, data); - }; - - - var onMemberChecked = function (evnt, inputProps) { - var route = routeStart + inputProps.name; - var data = { route: route, value: inputProps.checked }; - updateClientValue(evnt, data); +class MemberField extends React.PureComponent { + handleDisabledChecked = (event, { checked }) => { + this.props.onIsDisabledChange({ isDisabled: checked, index: this.props.index }); }; - - var removeMember = function (evnt, inputProps) { - household.splice(indx, 1); - setHousehold(evnt, household); - }; // End removeMember() - - - // For keyboard access (already does spacebar) - var onKeyDown = function (evnt) { - if (evnt.key === `Enter`) { - evnt.target.click(); + handleKeyDown = (event) => { + // For keyboard access (already does spacebar) + if (event.key === 'Enter') { + event.target.click(); } }; - - // The font size thing is a bit weird, but... later - return ( - - - - { indx > 0 ? ( - - ) : ( - - { household.length > 1 ? ( - - ) : ( - null - ) } - - ) } - - - - - - - - - - - - - - - - ); - -}; // End MemberField() - - -const getMembers = function (current, time, setHousehold, updateClientValue, snippets) { - - var household = current.household, - props = { - household: household, - time: time, - setHousehold: setHousehold, - updateClientValue: updateClientValue, - snippets: snippets, - }; - - var mems = []; - for (let memi = 0; memi < household.length; memi++) { - mems.push(MemberField(props, memi)); + handleRoleChange = ({ role }) => { + this.props.onRoleChange({ role, index: this.props.index }); }; - return mems; - -}; // End getMembers() - - -const HouseholdContent = function ({ current, time, updateClientValue, snippets }) { - - // Don't mutate state properties - var household = cloneDeep(current.household); - - - var setHousehold = function (evnt, newHousehold) { - - var obj = { - route: 'household', - value: newHousehold, - }; - - updateClientValue(evnt, obj); - - }; // End setHousehold() - + handleAgeChange = (event, { value }) => { + this.props.onAgeChange({ age: value, index: this.props.index }); + }; - var addMember = function (evnt, inputProps) { + handleRemove = () => { + this.props.remove({ index: this.props.index }); + }; + render() { + const { household, member, snippets, canRemove, index } = this.props; + + // The font size thing is a bit weird, but... later + return ( + + + + { canRemove ? ( + + ) : ( + + { household.length > 1 ? ( + + ) : ( + null + ) } + + ) } + + + + + + + + + + + + + + + + ); + } +} // End MemberField() + +class HouseholdContent extends React.PureComponent { + getMembers = () => { + const { household, setMemberAge, setMemberIsDisabled, setMemberRole, snippets } = this.props; + + return household.map( + (member, index) => { + return ( + 0 } + index = { index } + onIsDisabledChange = { setMemberIsDisabled } + onAgeChange = { setMemberAge } + onRoleChange = { setMemberRole } /> + ); + } + ).toArray(); + }; // End getMembers() + + addMember = () => { var member; - if (household.length === 1) { + if (this.props.household.size === 1) { member = { m_age: 30, m_role: 'spouse', m_disabled: false }; } else { member = { m_age: 12, m_role: 'member', m_disabled: false }; } - household.push(member); - setHousehold(evnt, household); - + this.props.addMember({ member }); }; // End addMember() + + render() { + const { snippets } = this.props; + + return ( +
+
+ + { snippets.i_role } + { snippets.i_age } + { snippets.i_disabled } +
+ + { this.getMembers() } + + - - return ( -
-
- - { snippets.i_role } - { snippets.i_age } - { snippets.i_disabled }
- - { getMembers(current, time, setHousehold, updateClientValue, snippets) } - - - -
- ); - -}; // End HouseholdContent() + ); + } +} // End HouseholdContent() // `props` is a cloned version of the original props. References broken. -const HouseholdStep = function ({ updateClientValue, navData, client, snippets }) { +const HouseholdStep = function ({ + setMemberIsDisabled, + setMemberRole, + setMemberAge, + addMember, + removeMember, + navData, + household, + snippets, +}) { return ( ); diff --git a/src/forms/cashflow.js b/src/forms/cashflow.js index 84e72c46..0cfa123f 100644 --- a/src/forms/cashflow.js +++ b/src/forms/cashflow.js @@ -11,7 +11,6 @@ import { toMonthlyAmount } from '../utils/math'; import { isNonNegNumber, hasOnlyNonNegNumberChars } from '../utils/validators'; import { toMoneyStr } from '../utils/prettifiers'; - /** Contains cash flow inputs, their label, and any user feedback * * @function @@ -46,6 +45,74 @@ const CashFlowContainer = function ({ children, label, validRow, message }) { const maximum_value_yearly = 999999.99; +export class ImmutableCashFlowInputsRow extends React.PureComponent { + constructor(...args) { + super(...args); + + this.state = { message: '' }; + } + + + // Special store validator that handles maximums and sets error message + cashFlowStoreValidator = (max) => { + return (str) => { + if (!isNonNegNumber(str)) { + this.setState({ message: 'Invalid number format' }); + return false; + } else if (parseFloat(str) > max) { + this.setState({ message: ('The input number exceeds the maximum of $' + maximum_value_yearly + '/yr') }); + return false; + } + this.setState({ message: '' }); + return true; + }; + }; + + setValue = (event, { value }, { interval }) => { + this.props.setValue({ + name: this.props.generic, + value: toMonthlyAmount[ interval ](event, value), + }); + }; + + render() { + const { children, generic, timeState } = this.props; + + const baseVal = timeState.get(generic); + + const baseProps = { + name: generic, + className: 'cashflow-column', + store: this.setValue, + displayValidator: hasOnlyNonNegNumberChars, + format: toMoneyStr, + }; + + return ( + + + + + + ); + } +} + // @todo Find elegant way to combine CashFlowInputsRow and MonthlyCashFlowRow // use `includes` array to include only certain columns perhaps. /** One row for cash flow inputs - weekly, monthly, yearly @@ -202,6 +269,44 @@ const MonthlyCashFlowRow = function ({ inputProps, baseValue, updateClientValue, }; // End +/** One row for _one_ cash flow input - a monthly value + * + * @function + * @param {object} props + * @param {object} props.inputProps Key name, validators, and onBlur + * @param {object} props.baseValue Start value of field? + * @param {object} props.updateClientValue Updates client state + * @param {object} props.rowProps `label`, `validRow`, `message` + * + * @returns Component + */ +export class ImmutableMonthlyCashFlowRow extends React.PureComponent { + + setValue = (event, { value }) => { + this.props.setValue({ + name: this.props.inputProps.name, + value: toMonthlyAmount.monthly(event, value), + }); + }; + + render() { + const { inputProps, baseValue, rowProps } = this.props; + + return ( + + + + ); + } +}; // End + + // Ideas of how to handle a different styling situation // (if we swap the input and label positions) diff --git a/src/forms/rentFields.js b/src/forms/rentFields.js index 4b75f422..30c48677 100644 --- a/src/forms/rentFields.js +++ b/src/forms/rentFields.js @@ -1,5 +1,5 @@ import React, { Component } from 'react'; -import { MonthlyCashFlowRow } from './cashflow'; +import { MonthlyCashFlowRow, ImmutableMonthlyCashFlowRow } from './cashflow'; import { isNonNegNumber, hasOnlyNonNegNumberChars } from '../utils/validators'; @@ -135,9 +135,35 @@ const PlainRentRow = function ({ timeState, updateClientValue }) { }; // End +const ImmutablePlainRentRow = function ({ timeState, setValue }) { + + const inputProps = { + name: 'rent', + displayValidator: hasOnlyNonNegNumberChars, + storeValidator: isNonNegNumber, + onBlur: function () {}, + }, + rowProps = { + label: 'Monthly Rent', + validRow: true, + message: null, + }; + + return ( + + ); + +}; // End + export { ContractRentField, RentShareField, PlainRentRow, + ImmutablePlainRentRow, }; diff --git a/src/reducers/client.js b/src/reducers/client.js index 89376ca7..e132589f 100644 --- a/src/reducers/client.js +++ b/src/reducers/client.js @@ -1,19 +1,147 @@ import { fromJS } from 'immutable'; import { CLIENT_DEFAULTS } from '../utils/CLIENT_DEFAULTS'; -import { SET_CLIENT_VALUE } from '../actions'; +import { + SET_CLIENT_VALUE, + ADD_MEMBER, + REMOVE_MEMBER, + SET_MEMBER_IS_DISABLED, + SET_MEMBER_ROLE, + SET_MEMBER_AGE, + SET_CASH_VALUE, + SET_HOUSING_TYPE, + SET_PAYS_UTILITY, + SET_GETS_FUEL_ASSISTANCE, +} from '../actions'; const clientReducer = ( state = fromJS(CLIENT_DEFAULTS), action ) => { switch (action.type) { - case SET_CLIENT_VALUE: + case SET_CLIENT_VALUE: { const { time, route, value } = action.payload; return state.setIn([ time, ...route, ], fromJS(value)); + } + + case REMOVE_MEMBER: { + const { index, time } = action.payload; + + return state.deleteIn( + [ + time, + 'household', + index, + ] + ); + } + + case ADD_MEMBER: { + const { member, time } = action.payload; + + return state.updateIn( + [ + time, + 'household', + ], + (members) => { + return members.push(fromJS(member)); + } + ); + } + + case SET_MEMBER_IS_DISABLED: { + const { time, index, isDisabled } = action.payload; + + return state.setIn( + [ + time, + 'household', + index, + 'm_disabled', + ], + isDisabled + ); + } + + case SET_MEMBER_ROLE: { + const { time, index, role } = action.payload; + + return state.setIn( + [ + time, + 'household', + index, + 'm_role', + ], + role + ); + } + + case SET_MEMBER_AGE: { + const { time, index, age } = action.payload; + + return state.setIn( + [ + time, + 'household', + index, + 'm_age', + ], + age + ); + } + + case SET_CASH_VALUE: { + const { time, name, value } = action.payload; + + return state.setIn( + [ + time, + name, + ], + value + ); + } + + case SET_HOUSING_TYPE: { + const { time, housingType } = action.payload; + + return state.setIn( + [ + time, + 'housing', + ], + housingType + ); + } + + case SET_PAYS_UTILITY: { + const { time, utility, paysUtility } = action.payload; + + return state.setIn( + [ + time, + utility, + ], + paysUtility + ); + } + + case SET_GETS_FUEL_ASSISTANCE: { + const { time, getsAssistance } = action.payload; + + return state.setIn( + [ + time, + 'fuelAssistance', + ], + getsAssistance + ); + } default: return state; diff --git a/src/test/forms/__snapshots__/CurrentExpenses.test.js.snap b/src/test/forms/__snapshots__/CurrentExpenses.test.js.snap index 18f7d2e2..5e55ca40 100644 --- a/src/test/forms/__snapshots__/CurrentExpenses.test.js.snap +++ b/src/test/forms/__snapshots__/CurrentExpenses.test.js.snap @@ -26,65 +26,6 @@ exports[`Expenses step component renders as snapshot correctly 1`] = ` } > `; diff --git a/src/test/forms/__snapshots__/CurrentIncome.test.js.snap b/src/test/forms/__snapshots__/CurrentIncome.test.js.snap index 16b5b3df..25a6f1ae 100644 --- a/src/test/forms/__snapshots__/CurrentIncome.test.js.snap +++ b/src/test/forms/__snapshots__/CurrentIncome.test.js.snap @@ -34,65 +34,6 @@ exports[`Income step component renders as snapshot correctly 1`] = ` } > `; diff --git a/src/test/forms/__snapshots__/Household.test.js.snap b/src/test/forms/__snapshots__/Household.test.js.snap index cbb02a75..85c69e42 100644 --- a/src/test/forms/__snapshots__/Household.test.js.snap +++ b/src/test/forms/__snapshots__/Household.test.js.snap @@ -34,65 +34,6 @@ exports[`Household step component renders as snapshot correctly 1`] = ` } > `; From 4b7e53a8e685dd9d96119d4687c08d70f3601311 Mon Sep 17 00:00:00 2001 From: Turner Hayes Date: Mon, 29 Oct 2018 22:23:19 -0400 Subject: [PATCH 5/9] Convert Predictions step to use Redux store --- src/containers/VisitPage.js | 8 +- src/containers/forms/Predictions.js | 27 +++ src/forms/CurrentExpenses.js | 15 +- src/forms/CurrentIncome.js | 2 +- src/forms/ExpensesOther.js | 168 ------------------ src/forms/FormPartsContainer.js | 3 +- src/forms/Predictions.js | 24 +-- src/forms/cashflow.js | 92 +--------- src/forms/output/Summary.js | 13 +- src/test/forms/ExpensesOther.test.js | 76 -------- .../CurrentBenefits.test.js.snap | 60 ------- .../forms/cashflow/CashFlowInputsRow.test.js | 39 ++-- .../forms/cashflow/MonthlyCashFlowRow.test.js | 2 +- .../folderHelpers/AttentionArrow.test.js | 2 +- .../forms/output/BenefitsLineGraph.test.js | 2 +- .../forms/output/StackedAreaGraph.test.js | 2 +- 16 files changed, 77 insertions(+), 458 deletions(-) create mode 100644 src/containers/forms/Predictions.js delete mode 100644 src/forms/ExpensesOther.js delete mode 100644 src/test/forms/ExpensesOther.test.js diff --git a/src/containers/VisitPage.js b/src/containers/VisitPage.js index 923a9a55..55022297 100644 --- a/src/containers/VisitPage.js +++ b/src/containers/VisitPage.js @@ -25,7 +25,7 @@ import FeedbackForm from '../components/prompts/FeedbackForm'; import { FeedbackAnytime } from '../components/prompts/FeedbackAnytime'; import { CurrentIncomeStep } from '../containers/forms/CurrentIncome'; import { CurrentExpensesStep } from '../containers/forms/CurrentExpenses'; -import { PredictionsStep } from '../forms/Predictions'; +import { PredictionsStep } from '../containers/forms/Predictions'; import { HouseholdStep } from '../containers/forms/Household'; import { CurrentBenefitsStep } from './forms/CurrentBenefits'; import StepBar from '../components/StepBar'; @@ -360,8 +360,7 @@ class VisitPage extends Component { className='flex-item flex-column'> + minWidth='874.5'>
+ className="flex-item flex-column current-step-component"> { this.getCurrentStep(navData) }
diff --git a/src/containers/forms/Predictions.js b/src/containers/forms/Predictions.js new file mode 100644 index 00000000..8f72d5f2 --- /dev/null +++ b/src/containers/forms/Predictions.js @@ -0,0 +1,27 @@ +import { connect } from 'react-redux'; + +import { PredictionsStep } from '../../forms/Predictions'; + +import { setCashValue } from '../../actions'; + +const mapStateToProps = (state) => { + return { client: state.get('client') }; +}; + +const mapDispatchToProps = (dispatch) => { + return { + setPredictionValue({ name, value }) { + dispatch( + setCashValue({ + time: 'future', + name, + value, + }) + ); + }, + }; +}; + +const PredictionsStepContainer = connect(mapStateToProps, mapDispatchToProps)(PredictionsStep); + +export { PredictionsStepContainer as PredictionsStep }; diff --git a/src/forms/CurrentExpenses.js b/src/forms/CurrentExpenses.js index e9f482bd..a8720e0e 100644 --- a/src/forms/CurrentExpenses.js +++ b/src/forms/CurrentExpenses.js @@ -10,7 +10,7 @@ import { // PROJECT COMPONENTS import { FormPartsContainer } from './FormPartsContainer'; import { AttentionArrow } from './formHelpers'; -import { ImmutableCashFlowInputsRow as CashFlowInputsRow } from './cashflow'; +import { CashFlowInputsRow } from './cashflow'; import { ControlledRadioYesNo } from './inputs'; import { ContentH1, @@ -22,8 +22,6 @@ import { ImmutablePlainRentRow as PlainRentRow, } from './rentFields'; import { HeadingWithDetail } from '../components/details'; -// Premature feature temporarily hidden to avoid messy revert -// import { ExpensesOther } from './ExpensesOther'; import { ShowOnYes } from './ShowOnYes'; // LOGIC @@ -528,17 +526,6 @@ const ExpensesFormContent = function ({ client, setExpenseValue, setHousingType, setGetsFuelAssistance={ setGetsFuelAssistance } setExpenseValue={ setExpenseValue } setHousingType={ setHousingType } /> - - {/* Premature feature temporarily hidden to avoid messy revert - - - - */}
); diff --git a/src/forms/CurrentIncome.js b/src/forms/CurrentIncome.js index 2390ec16..8ce76b7d 100644 --- a/src/forms/CurrentIncome.js +++ b/src/forms/CurrentIncome.js @@ -5,7 +5,7 @@ import { Form } from 'semantic-ui-react'; // PROJECT COMPONENTS import { FormPartsContainer } from './FormPartsContainer'; import { IntervalColumnHeadings } from '../components/headings'; -import { ImmutableCashFlowInputsRow as CashFlowInputsRow } from './cashflow'; +import { CashFlowInputsRow } from './cashflow'; // ======================================== diff --git a/src/forms/ExpensesOther.js b/src/forms/ExpensesOther.js deleted file mode 100644 index ef5a2996..00000000 --- a/src/forms/ExpensesOther.js +++ /dev/null @@ -1,168 +0,0 @@ -// REACT COMPONENTS -import React from 'react'; - -// PROJECT COMPONENTS -import { - CashFlowInputsRow, - CashFlowDisplayRow, -} from './cashflow'; -import { IntervalColumnHeadings } from '../components/headings'; - -// // LOGIC -import { - getMedicalExpenses, - getNonTransportCareCosts, - getTransportDependentCosts, - getHousingCosts, -} from '../utils/cashflow'; - - -/* From https://drive.google.com/drive/folders/0B61uzoaPZg7qUXJuRFhndTFkaTA - * (the bugdet assessment from the last page) - * which is Project Hope's own assessment worksheet. - * It's a weird name, but I want the file to sit - * next to other expenses stuff we're breaking out - * in the future. The alternative is to make a folder. - */ -const ExpensesOther = function ({ timeState, type, time, updateClientValue }) { - - var sharedProps = { - timeState: timeState, - current: timeState, - type: `expense`, - time: time, - updateClientValue: updateClientValue, - }; - - var housing = timeState.housing, - housingCosts = getHousingCosts(timeState), - dependentCare = getNonTransportCareCosts(timeState), - dependentTransport = getTransportDependentCosts(timeState), - medExpenses = getMedicalExpenses(timeState); - - return ( -
- - - {/* Is this complexity really required? Can we just - * have children and include a warning in the docs? */} - { housingCosts > 0 ? ( - Payments for housing - - ) : ( - null - ) - } - - { dependentCare > 0 ? ( - Dependent care (other than transportation) - - ) : ( - null - ) - } - - { dependentTransport > 0 ? ( - Transportation for dependents - - ) : ( - null - ) - } - - - { dependentTransport > 0 ? ( - `Money you spend on other transportation` - ) : ( - `Money you spend on transportation` - ) } - - - { medExpenses > 0 ? ( - Medical expenses you wrote in earlier - - ) : ( - null - ) - } - - - { medExpenses > 0 ? ( - `Money you spend because of other medical problems` - ) : ( - `Money you spend because of medical problems` - ) } - - Money you spend on food - - {/* Utilities are complicated because the housing - * voucher could be taking them into account and - * there isn't a way to know the amount that is - * specifically for that. The client is still - * spending that cash, though, so if we're looking - * at out of pocket expenses, it's still relevant. */} - Any phone costs - - - { housing !== `homeless` ? ( - Cable/internet costs - - ) : ( - null - ) - } - - { housing !== `homeless` ? ( - Other utility costs - - ) : ( - null - ) - } - - Other entertainment costs - - Personal care and household goods costs - - Money you spend on clothing - - Any other money you spend - -
- ); -}; - - -export { ExpensesOther }; diff --git a/src/forms/FormPartsContainer.js b/src/forms/FormPartsContainer.js index 4d01ba8b..3e813b24 100644 --- a/src/forms/FormPartsContainer.js +++ b/src/forms/FormPartsContainer.js @@ -61,8 +61,7 @@ const FormBottomRow = function({ left, middle, right }) { /* @todo Move styles to CSS */ return (
+ className = { `form-section-bottom-row` }> { children }
); diff --git a/src/forms/Predictions.js b/src/forms/Predictions.js index 907ad0ef..8673bf06 100644 --- a/src/forms/Predictions.js +++ b/src/forms/Predictions.js @@ -23,15 +23,13 @@ import { BenefitsLineGraph } from './output/BenefitsLineGraph'; * @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 + * @param {function} props.setPredictionValue Update client state * value. * @param {object} props.snippets Language-specific text * * @returns {object} React element */ -const IncomeForm = function ({ future, time, updateClientValue, snippets }) { +const IncomeForm = function ({ future, setPredictionValue, snippets }) { var type = 'income'; @@ -41,8 +39,8 @@ const IncomeForm = function ({ future, time, updateClientValue, snippets }) { { snippets.i_futureIncomeQuestion } @@ -142,7 +140,7 @@ const TabbedVisualizations = ({ client, openFeedback, snippets }) => { }; -const PredictionsStep = function ({ updateClientValue, navData, client, snippets, openFeedback }) { +const PredictionsStep = function ({ setPredictionValue, navData, client, snippets, openFeedback }) { return (
@@ -182,8 +179,11 @@ const PredictionsStep = function ({ updateClientValue, navData, client, snippets - diff --git a/src/forms/cashflow.js b/src/forms/cashflow.js index 0cfa123f..5362ca63 100644 --- a/src/forms/cashflow.js +++ b/src/forms/cashflow.js @@ -1,5 +1,5 @@ // REACT COMPONENTS -import React, { Component } from 'react'; +import React from 'react'; import { Form } from 'semantic-ui-react'; // PROJECT COMPONENTS @@ -45,7 +45,7 @@ const CashFlowContainer = function ({ children, label, validRow, message }) { const maximum_value_yearly = 999999.99; -export class ImmutableCashFlowInputsRow extends React.PureComponent { +class CashFlowInputsRow extends React.PureComponent { constructor(...args) { super(...args); @@ -113,94 +113,6 @@ export class ImmutableCashFlowInputsRow extends React.PureComponent { } } -// @todo Find elegant way to combine CashFlowInputsRow and MonthlyCashFlowRow -// use `includes` array to include only certain columns perhaps. -/** One row for cash flow inputs - weekly, monthly, yearly - * - * @param {object} props - * @param {object} props.generic Base name for the client property that - * needs to be updated (now the code has changed, this may be a misnomer) - * @param {object} props.timeState Client, either future values or current values - * @param {object} props.updateClientValue Updates client state - * @param {object} props.children Text for the row label - */ -class CashFlowInputsRow extends Component { - constructor(props) { - super(props); - this.state = { message: '' }; - } - - // Special store validator that handles maximums and sets error message - cashFlowStoreValidator = (max) => { - return (str) => { - if (!isNonNegNumber(str)) { - this.setState({ message: 'Invalid number format' }); - return false; - } - else if (parseFloat(str) > max) { - this.setState({ message: ('The input number exceeds the maximum of $' + maximum_value_yearly + '/yr') }); - return false; - } - this.setState({ message: '' }); - return true; - }; - }; - - render() { - var { generic, timeState, updateClientValue, children } = this.props; - - var updateClient = function (evnt, inputProps, data) { - var monthly = toMonthlyAmount[ data.interval ](evnt, inputProps.value), - obj = { name: generic, value: monthly }; - updateClientValue(evnt, obj); - }; - - - - /* Get the time ('future' or 'current') monthly value unless there is - * none, in which case, get the 'current' monthly cash flow value - * (to prefill future values with 'current' ones if needed). - * - * @todo Add some kind of UI indication when it's the same as the 'current' - * value. What if some of the row's values are the same and some are - * different? */ - var baseVal = timeState[ generic ], - baseProps = { - name: generic, - className: 'cashflow-column', - store: updateClient, - displayValidator: hasOnlyNonNegNumberChars, - format: toMoneyStr, - }; - - var cashFlowStoreValidator = this.cashFlowStoreValidator; - - return ( - - - - - - ); - } -} - - /** Show a value, or the sum of multiple values, of data * that the user has already put in from another input. * diff --git a/src/forms/output/Summary.js b/src/forms/output/Summary.js index 7aaf0eb0..91b31812 100644 --- a/src/forms/output/Summary.js +++ b/src/forms/output/Summary.js @@ -9,7 +9,6 @@ import { Header, Button } from 'semantic-ui-react'; import { PROGRAM_CHART_VALUES } from '../../utils/charts/PROGRAM_CHART_VALUES'; // DATA MANIPULATION -import { cloneDeep } from 'lodash'; import { toMoneyStr } from '../../utils/prettifiers'; // BENEFIT LOGIC @@ -194,10 +193,10 @@ var fillInMoneyValues = (keys, sourceObject, index) => { * @returns {object} */ var getBenefitData = function(client, resourceKeys) { - - var clone = cloneDeep(client), - // This is the data we need in the groupings we need it - result = { + // @todo: refactor to use Immutable collections + client = client.toJS(); + // This is the data we need in the groupings we need it + var result = { current: null, // current money values, future: null, // future money values, diff: 0, @@ -209,7 +208,7 @@ var getBenefitData = function(client, resourceKeys) { var defaultProps = { activeBenefits: resourceKeys, dataToAddTo: accumulated, - clientToChange: clone, + clientToChange: client, timeframe: `current`, }; var currentCalcData = defaultProps; @@ -238,7 +237,7 @@ var getBenefitData = function(client, resourceKeys) { // till the client is making more money than they are now while (recoveryAmount - resultCurr.total <= 0) { - clone.future.earned += EARNED_MONTHLY_INCREMENT_AMOUNT; + client.future.earned += EARNED_MONTHLY_INCREMENT_AMOUNT; applyAndPushBenefits(futureCalcData); // If has dramatic cliff, must have recovery recoveryAmount = totalLastItemsOfArraysInObject(accumulated); diff --git a/src/test/forms/ExpensesOther.test.js b/src/test/forms/ExpensesOther.test.js deleted file mode 100644 index fe994cb0..00000000 --- a/src/test/forms/ExpensesOther.test.js +++ /dev/null @@ -1,76 +0,0 @@ -import React from 'react'; -import { mount } from 'enzyme'; -import { defaultsDeep } from 'lodash'; - -import { ExpensesOther } from '../../forms/ExpensesOther'; -import { CLIENT_DEFAULTS } from '../../utils/CLIENT_DEFAULTS'; - -const GREATER_THAN_ZERO = 1; - -const displayRow = (page, generic) => { - return page.find(`CashFlowDisplayRow[generic="${generic}"]`); -}; -const inputRow = (page, generic) => { - return page.find(`CashFlowInputsRow[generic="${generic}"]`); -}; - -describe('', () => { - const defaultProps = { - time: 'monthly', - updateClientValue: jest.fn(), - }; - - const buildPage = (clientValues = {}) => { - const client = defaultsDeep({}, clientValues, CLIENT_DEFAULTS.current); - return mount(); - }; - - it('renders housing costs control when related costs', () => { - const homeless = { housing: 'homeless' }; // no housing costs - expect(displayRow(buildPage(homeless), 'housingCosts')).toHaveLength(0); - - const renter = { housing: 'renter', rent: GREATER_THAN_ZERO }; - expect(displayRow(buildPage(renter), 'housingCosts')).toHaveLength(1); - }); - - it('renders dependent care control when costs unrelated to transportation', () => { - const transportCosts = { childTransportation: GREATER_THAN_ZERO }; - expect(displayRow(buildPage(transportCosts), 'dependentCare')).toHaveLength(0); - - const childCare = { childDirectCare: GREATER_THAN_ZERO }; - expect(displayRow(buildPage(childCare), 'dependentCare')).toHaveLength(1); - }); - - it('renders dependent transport control when related costs', () => { - const childCare = { childDirectCare: GREATER_THAN_ZERO }; - expect(displayRow(buildPage(childCare), 'dependentTransport')).toHaveLength(0); - - const transportCosts = { childTransportation: GREATER_THAN_ZERO }; - expect(displayRow(buildPage(transportCosts), 'dependentTransport')).toHaveLength(1); - }); - - it('renders medical costs control when related costs', () => { - expect(displayRow(buildPage(), 'medicalTotal')).toHaveLength(0); - - const medicalCosts = { otherMedical: GREATER_THAN_ZERO }; - expect(displayRow(buildPage(medicalCosts), 'medicalTotal')).toHaveLength(1); - }); - - it('renders cable and internet costs control when not homeless', () => { - const homeless = { housing: 'homeless' }; - expect(inputRow(buildPage(homeless), 'otherExpensesCable')).toHaveLength(0); - - const renter = { housing: 'renter' }; - expect(inputRow(buildPage(renter), 'otherExpensesCable')).toHaveLength(1); - }); - - it('renders utilities costs control when not homeless', () => { - const homeless = { housing: 'homeless' }; - expect(inputRow(buildPage(homeless), 'otherExpensesUtilities')).toHaveLength(0); - - const renter = { housing: 'renter' }; - expect(inputRow(buildPage(renter), 'otherExpensesUtilities')).toHaveLength(1); - }); -}); diff --git a/src/test/forms/__snapshots__/CurrentBenefits.test.js.snap b/src/test/forms/__snapshots__/CurrentBenefits.test.js.snap index 5a2838ca..16a2eb94 100644 --- a/src/test/forms/__snapshots__/CurrentBenefits.test.js.snap +++ b/src/test/forms/__snapshots__/CurrentBenefits.test.js.snap @@ -32,65 +32,6 @@ exports[`Benefits step component renders as snapshot correctly 1`] = ` } > `; diff --git a/src/test/forms/cashflow/CashFlowInputsRow.test.js b/src/test/forms/cashflow/CashFlowInputsRow.test.js index 4715c07f..87942290 100644 --- a/src/test/forms/cashflow/CashFlowInputsRow.test.js +++ b/src/test/forms/cashflow/CashFlowInputsRow.test.js @@ -1,14 +1,15 @@ import React from 'react'; import { shallow } from 'enzyme'; +import { fromJS } from 'immutable'; import { CashFlowInputsRow } from '../../../forms/cashflow'; test('CashFlowInputsRow should match snapshot', () => { const wrapper = shallow( {} } > + generic="name" + timeState={ fromJS({ name: 0 }) } + setValue={ () => {} } > label ); @@ -19,9 +20,9 @@ test('Second ManagedNumberField child should have value of timeState[ generic ]' const monthlyVal = 200.0; const wrapper = shallow( {} } /> + generic="name" + timeState={ fromJS({ name: monthlyVal }) } + setValue={ () => {} } /> ); const monthlyInput = wrapper.childAt(1); expect(monthlyInput.prop('value')).toBe(monthlyVal); @@ -31,9 +32,9 @@ test('First ManagedNumberField child should have weekly value', () => { const monthlyVal = 200.0; const wrapper = shallow( {} } /> + generic="name" + timeState={ fromJS({ name: monthlyVal }) } + setValue={ () => {} } /> ); const weeklyInput = wrapper.childAt(0); expect(weeklyInput.prop('value')).toBeCloseTo(monthlyVal / (4 + 1 / 3)); @@ -43,21 +44,21 @@ test('Third ManagedNumberField child should have yearly value', () => { const monthlyVal = 200.0; const wrapper = shallow( {} } /> + generic="name" + timeState={ fromJS({ name: monthlyVal }) } + setValue={ () => {} } /> ); const yearlyInput = wrapper.childAt(2); expect(yearlyInput.prop('value')).toBeCloseTo(monthlyVal * 12); }); -test('updateClientValue gets called correctly when each value is changed', () => { +test('setValue gets called correctly when each value is changed', () => { const mockSetClientProperty = jest.fn(); const wrapper = shallow( + generic="name" + timeState={ fromJS({ name: 200.0 }) } + setValue={ mockSetClientProperty } /> ); const multipliers = [ @@ -65,6 +66,7 @@ test('updateClientValue gets called correctly when each value is changed', () => 1, 1 / 12, ]; + for (var i = 0; i < 3; i++) { // `input` is an actual `` node const input = wrapper.childAt(i).shallow(); @@ -73,8 +75,7 @@ test('updateClientValue gets called correctly when each value is changed', () => input.prop('onChange')(evnt, { value: newValue }); expect(mockSetClientProperty.mock.calls).toHaveLength(i + 1); - expect(mockSetClientProperty.mock.calls[ i ][ 0 ]).toBe(evnt); - expect(mockSetClientProperty.mock.calls[ i ][ 1 ].name).toBe('name'); - expect(mockSetClientProperty.mock.calls[ i ][ 1 ].value).toBeCloseTo(newValue * multipliers[ i ]); + expect(mockSetClientProperty.mock.calls[ i ][ 0 ].name).toBe('name'); + expect(mockSetClientProperty.mock.calls[ i ][ 0 ].value).toBeCloseTo(newValue * multipliers[ i ]); } }); diff --git a/src/test/forms/cashflow/MonthlyCashFlowRow.test.js b/src/test/forms/cashflow/MonthlyCashFlowRow.test.js index d5a07848..f4a6614c 100644 --- a/src/test/forms/cashflow/MonthlyCashFlowRow.test.js +++ b/src/test/forms/cashflow/MonthlyCashFlowRow.test.js @@ -12,7 +12,7 @@ describe('', () => { rowProps: {}, }; expect(() => { - mount() + mount(); }).not.toThrow(); }); }); diff --git a/src/test/forms/folderHelpers/AttentionArrow.test.js b/src/test/forms/folderHelpers/AttentionArrow.test.js index aad7b50e..8809dea8 100644 --- a/src/test/forms/folderHelpers/AttentionArrow.test.js +++ b/src/test/forms/folderHelpers/AttentionArrow.test.js @@ -6,7 +6,7 @@ import { AttentionArrow } from '../../../forms/formHelpers'; describe('', () => { it('renders', () => { expect(() => { - mount() + mount(); }).not.toThrow(); }); }); diff --git a/src/test/forms/output/BenefitsLineGraph.test.js b/src/test/forms/output/BenefitsLineGraph.test.js index 4ddbf8dd..a776131b 100644 --- a/src/test/forms/output/BenefitsLineGraph.test.js +++ b/src/test/forms/output/BenefitsLineGraph.test.js @@ -70,7 +70,7 @@ describe('', () => { it('renders with both snap and section8', () => { activePrograms.push('snap'); - activePrograms.push('section8') + activePrograms.push('section8'); set(client, 'current.earned', 100); set(client, 'future.earned', 200); diff --git a/src/test/forms/output/StackedAreaGraph.test.js b/src/test/forms/output/StackedAreaGraph.test.js index 1bc7a8b4..0e811d81 100644 --- a/src/test/forms/output/StackedAreaGraph.test.js +++ b/src/test/forms/output/StackedAreaGraph.test.js @@ -62,7 +62,7 @@ describe('', () => { it('renders with both snap and section8', () => { activePrograms.push('snap'); - activePrograms.push('section8') + activePrograms.push('section8'); set(client, 'current.earned', 100); set(client, 'future.earned', 200); From c935fb47842ef0b8c661e70e91cc52516b7bb199 Mon Sep 17 00:00:00 2001 From: Turner Hayes Date: Tue, 30 Oct 2018 20:32:39 -0400 Subject: [PATCH 6/9] Remove unused package --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index a29b243f..309350f5 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,6 @@ "dependencies": { "ajv": "6.5.4", "chart.js": "2.7.2", - "connected-react-router": "^4.5.0", "i": "^0.3.6", "immutable": "^3.8.2", "lodash": "4.17.10", From 2d32a5ea5260a3862246ab774f720216d6b6c677 Mon Sep 17 00:00:00 2001 From: Turner Hayes Date: Tue, 6 Nov 2018 18:27:12 -0500 Subject: [PATCH 7/9] Change STEP_VALS.js to use containers for steps --- src/forms/STEP_VALS.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/forms/STEP_VALS.js b/src/forms/STEP_VALS.js index 8253c7d9..9ff807fb 100644 --- a/src/forms/STEP_VALS.js +++ b/src/forms/STEP_VALS.js @@ -1,8 +1,8 @@ -import { CurrentIncomeStep } from './CurrentIncome'; -import { CurrentExpensesStep } from './CurrentExpenses'; -import { PredictionsStep } from './Predictions'; -import { HouseholdStep } from './Household'; -import { CurrentBenefitsStep } from './CurrentBenefits'; +import { CurrentIncomeStep } from '../containers/forms/CurrentIncome'; +import { CurrentExpensesStep } from '../containers/forms/CurrentExpenses'; +import { PredictionsStep } from '../containers/forms/Predictions'; +import { HouseholdStep } from '../containers/forms/Household'; +import { CurrentBenefitsStep } from '../containers/forms/CurrentBenefits'; export const STEP_VALS = [ { From e8ff25715f839abf636b72d5b2df7b7f0c2a013f Mon Sep 17 00:00:00 2001 From: Turner Hayes Date: Sat, 10 Nov 2018 20:41:37 -0500 Subject: [PATCH 8/9] Fix unit tests for step components --- src/test/forms/CurrentBenefits.test.js | 18 ++++++---- src/test/forms/CurrentExpenses.test.js | 30 ++++++++++------- src/test/forms/CurrentIncome.test.js | 18 ++++++---- src/test/forms/Household.test.js | 33 +++++++++++++------ .../forms/cashflow/CashFlowInputsRow.test.js | 10 +++--- 5 files changed, 69 insertions(+), 40 deletions(-) diff --git a/src/test/forms/CurrentBenefits.test.js b/src/test/forms/CurrentBenefits.test.js index 9d7f8aef..8f560275 100644 --- a/src/test/forms/CurrentBenefits.test.js +++ b/src/test/forms/CurrentBenefits.test.js @@ -3,11 +3,11 @@ import { mount } from 'enzyme'; import { CurrentBenefitsStep } from '../../forms/CurrentBenefits'; -import { CLIENT_DEFAULTS } from '../../utils/CLIENT_DEFAULTS'; - // LOCALIZATION import { getTextForLanguage } from '../../utils/getTextForLanguage'; +import createReducer from '../../reducers'; + var snippets = getTextForLanguage(`en`); test('Benefits step component should render without error', () => { @@ -16,19 +16,23 @@ test('Benefits step component should render without error', () => { middle: null, right: (
CB right
), }, - updateClientValue = jest.fn(), - saveForm = jest.fn(), askToResetClient = jest.fn(), openFeedback = jest.fn(), benefitsSnippets = snippets.visitPage.currentBenefits; expect(() => { + const reducer = createReducer(); + + const state = reducer(undefined, {}); + mount( {} } navData = { navData } - updateClientValue = { updateClientValue } - saveForm = { saveForm } askToResetClient = { askToResetClient } openFeedback = { openFeedback } snippets = { benefitsSnippets } /> diff --git a/src/test/forms/CurrentExpenses.test.js b/src/test/forms/CurrentExpenses.test.js index 4c4baa56..7c9b334b 100644 --- a/src/test/forms/CurrentExpenses.test.js +++ b/src/test/forms/CurrentExpenses.test.js @@ -3,11 +3,12 @@ import { mount } from 'enzyme'; import { CurrentExpensesStep } from '../../forms/CurrentExpenses'; -import { CLIENT_DEFAULTS } from '../../utils/CLIENT_DEFAULTS'; - // LOCALIZATION import { getTextForLanguage } from '../../utils/getTextForLanguage'; +import createReducer from '../../reducers'; + +const NO_OP = () => {}; var snippets = getTextForLanguage(`en`); test('Expenses step component should render without error', () => { @@ -16,22 +17,29 @@ test('Expenses step component should render without error', () => { middle: null, right: (
Exp right
), }, - updateClientValue = jest.fn(), - saveForm = jest.fn(), askToResetClient = jest.fn(), openFeedback = jest.fn(), formSnippets = snippets.visitPage.currentExpenses; + + const reducer = createReducer(); + + const state = reducer(undefined, {}); expect(() => { mount( + currentClient = { state.getIn([ + 'client', + 'current', + ]) } + navData = { navData } + askToResetClient = { askToResetClient } + openFeedback = { openFeedback } + setExpenseValue = { NO_OP } + setHousingType = { NO_OP } + setPaysUtility = { NO_OP } + setGetsFuelAssistance = { NO_OP } + snippets = { formSnippets } /> ); }).not.toThrow(); }); diff --git a/src/test/forms/CurrentIncome.test.js b/src/test/forms/CurrentIncome.test.js index bd398981..c206161b 100644 --- a/src/test/forms/CurrentIncome.test.js +++ b/src/test/forms/CurrentIncome.test.js @@ -3,11 +3,11 @@ import { mount } from 'enzyme'; import { CurrentIncomeStep } from '../../forms/CurrentIncome'; -import { CLIENT_DEFAULTS } from '../../utils/CLIENT_DEFAULTS'; - // LOCALIZATION import { getTextForLanguage } from '../../utils/getTextForLanguage'; +import createReducer from '../../reducers'; + var snippets = getTextForLanguage(`en`); test('Income step component should render without error', () => { @@ -16,19 +16,23 @@ test('Income step component should render without error', () => { middle: null, right: (
Inc right
), }, - updateClientValue = jest.fn(), - saveForm = jest.fn(), askToResetClient = jest.fn(), openFeedback = jest.fn(), formSnippets = snippets.visitPage.currentIncome; expect(() => { + const reducer = createReducer(); + + const state = reducer(undefined, {}); + mount( {} } navData = { navData } - updateClientValue = { updateClientValue } - saveForm = { saveForm } askToResetClient = { askToResetClient } openFeedback = { openFeedback } snippets = { formSnippets } /> diff --git a/src/test/forms/Household.test.js b/src/test/forms/Household.test.js index 236c63dc..dc3290b0 100644 --- a/src/test/forms/Household.test.js +++ b/src/test/forms/Household.test.js @@ -3,11 +3,13 @@ import { mount } from 'enzyme'; import { HouseholdStep } from '../../forms/Household'; -import { CLIENT_DEFAULTS } from '../../utils/CLIENT_DEFAULTS'; - // LOCALIZATION import { getTextForLanguage } from '../../utils/getTextForLanguage'; +import createReducer from '../../reducers'; + +const NO_OP = () => {}; + var snippets = getTextForLanguage(`en`); test('Household step component should render without error', () => { @@ -16,22 +18,33 @@ test('Household step component should render without error', () => { middle: null, right: (
House right
), }, - updateClientValue = jest.fn(), saveForm = jest.fn(), askToResetClient = jest.fn(), openFeedback = jest.fn(), formSnippets = snippets.visitPage.household; + + const reducer = createReducer(); + + const state = reducer(undefined, {}); expect(() => { mount( + household = { state.getIn([ + 'client', + 'current', + 'household', + ]) } + setMemberAge = { NO_OP } + setMemberIsDisabled = { NO_OP } + setMemberRole = { NO_OP } + removeMember = { NO_OP } + addMember = { NO_OP } + navData = { navData } + saveForm = { saveForm } + askToResetClient = { askToResetClient } + openFeedback = { openFeedback } + snippets = { formSnippets } /> ); }).not.toThrow(); }); diff --git a/src/test/forms/cashflow/CashFlowInputsRow.test.js b/src/test/forms/cashflow/CashFlowInputsRow.test.js index c50e77f1..a2aa0aea 100644 --- a/src/test/forms/cashflow/CashFlowInputsRow.test.js +++ b/src/test/forms/cashflow/CashFlowInputsRow.test.js @@ -15,7 +15,7 @@ test('CashFlowInputsRow should render', () => { mount( {} } > label @@ -27,7 +27,7 @@ test(`Second ManagedNumberField child should have value of timeState[ 'clientPro const wrapper = mount( {} }> label @@ -40,7 +40,7 @@ test('First ManagedNumberField child should have weekly value', () => { const wrapper = mount( {} }> label @@ -53,7 +53,7 @@ test('Third ManagedNumberField child should have yearly value', () => { const wrapper = mount( {} }> label @@ -67,7 +67,7 @@ test('setValue gets called correctly when each value is changed', () => { const wrapper = shallow( label From da08f857391d74ddf6e52e3ae973583b64d6c589 Mon Sep 17 00:00:00 2001 From: Turner Hayes Date: Thu, 15 Nov 2018 21:12:22 -0500 Subject: [PATCH 9/9] Fix steps to work with Redux again; update unit tests --- src/actions/client.js | 13 + src/containers/VisitPage.js | 2 +- src/containers/forms/CurrentBenefits.js | 13 +- src/forms/CurrentBenefits.js | 13 +- src/forms/CurrentExpenses.js | 20 +- src/forms/Predictions.js | 5 +- src/forms/cashflow.js | 48 +- src/forms/inputs.js | 5 + src/forms/output/BenefitsLineGraph.js | 11 +- src/forms/output/BenefitsLines.js | 8 +- src/forms/output/BenefitsTable.js | 6 +- src/forms/output/GraphHolder.js | 11 +- src/forms/output/StackedAreaGraph.js | 10 +- src/forms/output/StackedBarGraph.js | 7 +- src/forms/output/Summary.js | 10 +- src/forms/rentFields.js | 66 +- src/reducers/client.js | 58 +- src/test/forms/CurrentBenefits.test.js | 12 +- .../forms/cashflow/CashFlowDisplayRow.test.js | 21 +- .../forms/cashflow/CashFlowInputsRow.test.js | 2 +- .../CashFlowDisplayRow.test.js.snap | 59 +- .../forms/inputs/ManagedNumberField.test.js | 2 +- .../forms/output/BenefitsLineGraph.test.js | 124 ++- src/test/forms/output/BenefitsTable.test.js | 80 +- .../forms/output/StackedAreaGraph.test.js | 93 +- src/test/forms/output/StackedBarGraph.test.js | 160 +++- .../BenefitsLineGraph.test.js.snap | 877 +++++++++--------- .../StackedAreaGraph.test.js.snap | 872 ++++++++--------- .../StackedBarGraph.test.js.snap | 868 ++++++++--------- .../rentFields/ContractRentField.test.js | 52 +- .../forms/rentFields/PlainRentRow.test.js | 15 +- .../forms/rentFields/RentShareField.test.js | 53 +- 32 files changed, 2036 insertions(+), 1560 deletions(-) diff --git a/src/actions/client.js b/src/actions/client.js index 42edddf4..a20593d0 100644 --- a/src/actions/client.js +++ b/src/actions/client.js @@ -123,3 +123,16 @@ export const setGetsFuelAssistance = ({ time, getsAssistance }) => { }, }; }; + +export const SET_HAS_BENEFIT = 'SET_HAS_BENEFIT'; + +export const setHasBenefit = ({ time, benefit, value }) => { + return { + type: SET_HAS_BENEFIT, + payload: { + time, + benefit, + value: !!value, + }, + }; +}; diff --git a/src/containers/VisitPage.js b/src/containers/VisitPage.js index d18f2652..442c434b 100644 --- a/src/containers/VisitPage.js +++ b/src/containers/VisitPage.js @@ -140,7 +140,7 @@ class VisitPage extends Component { oldHousing = clone.current.housing; } - if (clone.current.benefits.includes('section8')) { + if (clone.current.get('benefits').includes('section8')) { clone.current.housing = 'voucher'; } else { // Restore housing to previous value diff --git a/src/containers/forms/CurrentBenefits.js b/src/containers/forms/CurrentBenefits.js index d2cb7444..601dc862 100644 --- a/src/containers/forms/CurrentBenefits.js +++ b/src/containers/forms/CurrentBenefits.js @@ -1,7 +1,7 @@ import { connect } from 'react-redux'; import { CurrentBenefitsStep } from '../../forms/CurrentBenefits'; -import { setClientValue } from '../../actions'; +import { setHasBenefit } from '../../actions'; const mapStateToProps = (state) => { return { @@ -9,6 +9,11 @@ const mapStateToProps = (state) => { 'client', 'current', ]), + + USState: state.getIn([ + 'geography', + 'state', + ]), }; }; @@ -16,9 +21,9 @@ const mapDispatchToProps = (dispatch) => { return { setHasBenefit({ benefit, value }) { dispatch( - setClientValue({ - time: 'current', - route: [ benefit ], + setHasBenefit({ + time: 'current', + benefit, value, }) ); diff --git a/src/forms/CurrentBenefits.js b/src/forms/CurrentBenefits.js index 67192af3..63e3dbb0 100644 --- a/src/forms/CurrentBenefits.js +++ b/src/forms/CurrentBenefits.js @@ -22,13 +22,11 @@ import { allBenefitOrders } from '../programs/allBenefitOrders'; */ class CurrentBenefitsContent extends React.Component { handleRadioChange = (event, inputProps) => { - const benefitName = inputProps.name; - - this.props.setHasBenefit(benefitName, inputProps.value); + this.props.setHasBenefit({ benefit: inputProps.name, value: inputProps.value }); }; render() { - const { current, snippets, benefits } = this.props; + const { currentClient, snippets, benefits } = this.props; const components = []; @@ -49,7 +47,7 @@ class CurrentBenefitsContent extends React.Component { snippets={ snippets } labelText={ labelText } onChange={ this.handleRadioChange } - checked = { current.get('benefits').includes(benefit) } + checked = { currentClient.get('benefits').includes(benefit) } name = { benefit } /> ); } @@ -69,12 +67,13 @@ class CurrentBenefitsContent extends React.Component { * @param {object} props * @property {object} props.navData Bottom row buttons * @property {Immutable.Map} props.currentClient Immutable Map with current values. + * @property {string} props.USState the US state that the client lives in * @property {function} props.snippets Uses user chosen language-specific * snippets. * * @returns {object} Component */ -const CurrentBenefitsStep = ({ setHasBenefit, navData, currentClient, snippets }) => { +const CurrentBenefitsStep = ({ setHasBenefit, navData, currentClient, USState, snippets }) => { return ( + benefits = { allBenefitOrders[ USState ] } /> ); diff --git a/src/forms/CurrentExpenses.js b/src/forms/CurrentExpenses.js index 81b0f5c1..a1ea2086 100644 --- a/src/forms/CurrentExpenses.js +++ b/src/forms/CurrentExpenses.js @@ -19,7 +19,7 @@ import { import { ContractRentField, RentShareField, - ImmutablePlainRentRow as PlainRentRow, + PlainRentRow, } from './rentFields'; import { HeadingWithDetail } from '../components/details'; // Premature feature temporarily hidden to avoid messy revert @@ -278,6 +278,7 @@ const ChildSupport = function ({ type, sharedProps }) { Legally obligated child support @@ -470,6 +471,8 @@ const HousingDetails = function ({ type, time, setExpenseValue, + setPaysUtility, + setGetsFuelAssistance, }) { let housing = client.get('housing'), @@ -486,7 +489,10 @@ const HousingDetails = function ({
- +
); @@ -527,15 +533,15 @@ const HousingDetails = function ({ const Utilities = function ({ - current, + client, setGetsFuelAssistance, setPaysUtility, }) { - let hasClimate = current.get('climateControl'), - hasElectricity = current.get('nonHeatElectricity'), - hasPhone = current.get('phone'), - hasFuelAssist = current.get('fuelAssistance'); + let hasClimate = client.get('climateControl'), + hasElectricity = client.get('nonHeatElectricity'), + hasPhone = client.get('phone'), + hasFuelAssist = client.get('fuelAssistance'); let setChecked = function (evnt, { name, checked }) { diff --git a/src/forms/Predictions.js b/src/forms/Predictions.js index b1f548e5..281daf77 100644 --- a/src/forms/Predictions.js +++ b/src/forms/Predictions.js @@ -187,11 +187,8 @@ const PredictionsStep = function ({ setPredictionValue, navData, client, snippet - {/* - @todo: refactor visualizations to use Immutable collections - */} diff --git a/src/forms/cashflow.js b/src/forms/cashflow.js index f6c9509e..37a6e051 100644 --- a/src/forms/cashflow.js +++ b/src/forms/cashflow.js @@ -170,7 +170,7 @@ class CashFlowInputsRow extends React.Component { */ const CashFlowDisplayRow = function ({ generic, value, timeState, children }) { - let baseVal = value || timeState[ generic ], + let baseVal = value || timeState.get(generic), colClassName = `cashflow-column`, weekly = toMoneyStr(baseVal / (4 + 1 / 3)), monthly = toMoneyStr(baseVal), @@ -203,18 +203,17 @@ const CashFlowDisplayRow = function ({ generic, value, timeState, children }) { * @param {object} props * @param {object} props.inputProps Key name, validators, and onBlur * @param {object} props.baseValue Start value of field? - * @param {object} props.updateClientValue Updates client state + * @param {object} props.setValue Updates client state * @param {object} props.rowProps `label`, `validRow`, `message` * * @returns Component */ -const MonthlyCashFlowRow = function ({ inputProps, baseValue, updateClientValue, rowProps }) { - +const MonthlyCashFlowRow = function ({ inputProps, baseValue, setValue, rowProps }) { inputProps = { ...inputProps, // name, validators, and onBlur className: 'cashflow-column', format: toMoneyStr, - store: updateClientValue, + store: setValue, }; return ( @@ -228,45 +227,6 @@ const MonthlyCashFlowRow = function ({ inputProps, baseValue, updateClientValue, }; // End - -/** One row for _one_ cash flow input - a monthly value - * - * @function - * @param {object} props - * @param {object} props.inputProps Key name, validators, and onBlur - * @param {object} props.baseValue Start value of field? - * @param {object} props.updateClientValue Updates client state - * @param {object} props.rowProps `label`, `validRow`, `message` - * - * @returns Component - */ -export class ImmutableMonthlyCashFlowRow extends React.PureComponent { - - setValue = (event, { value }) => { - this.props.setValue({ - name: this.props.inputProps.name, - value: toMonthlyAmount.monthly(event, value), - }); - }; - - render() { - const { inputProps, baseValue, rowProps } = this.props; - - return ( - - - - ); - } -}; // End - - // Ideas of how to handle a different styling situation // (if we swap the input and label positions) diff --git a/src/forms/inputs.js b/src/forms/inputs.js index d687c959..b6598e99 100644 --- a/src/forms/inputs.js +++ b/src/forms/inputs.js @@ -175,6 +175,11 @@ class ManagedNumberField extends Component { let valid = storeValidator(inputProps.value); if (valid) { + inputProps = { + ...inputProps, + value: Number(inputProps.value), + }; + store(evnt, inputProps, otherData); } this.setState({ focusedVal: focusedVal, valid: valid }); diff --git a/src/forms/output/BenefitsLineGraph.js b/src/forms/output/BenefitsLineGraph.js index daa0bb33..4697730b 100644 --- a/src/forms/output/BenefitsLineGraph.js +++ b/src/forms/output/BenefitsLineGraph.js @@ -54,7 +54,8 @@ class BenefitsLineGraph extends Component { } const xRange = _.range(limits.min, max, interval), // x-axis/earned income numbers - datasets = getChartData(xRange, multiplier, client, activePrograms, extraProps); + // @todo: make this use Immutable.js collections + datasets = getChartData(xRange, multiplier, client.toJS(), activePrograms, extraProps); // If there's no data to show, don't show the table if (datasets.length === 0) { @@ -63,8 +64,12 @@ class BenefitsLineGraph extends Component { // react-chartjs-2 keeps references to plugins, so we // have to mutate that reference - const earned = client.future.earned * multiplier, - hack = this.state.verticalLine; + const earned = client.getIn([ + 'future', + 'earned', + ]) * multiplier; + + const hack = this.state.verticalLine; hack.xRange = xRange; hack.earned = earned; diff --git a/src/forms/output/BenefitsLines.js b/src/forms/output/BenefitsLines.js index 5946bcfa..6791c7e9 100644 --- a/src/forms/output/BenefitsLines.js +++ b/src/forms/output/BenefitsLines.js @@ -102,7 +102,10 @@ class BenefitsLinesComp extends Component { const multiplier = multipliers[ timescale ], resources = activePrograms, - currentEarned = client.current.earned * multiplier, + currentEarned = client.getIn([ + 'current', + 'earned', + ]) * multiplier, getText = this.getTranslatedText; // Adjust to time-interval. Highcharts will round @@ -111,7 +114,8 @@ class BenefitsLinesComp extends Component { interval = ((max / 100) / 10) * 30; const xRange = range(limits.min, max, interval), // x-axis/earned income numbers - datasets = getChartData(xRange, multiplier, client, resources, {}); + // @todo make this use Immutable.js collections + datasets = getChartData(xRange, multiplier, client.toJS(), resources, {}); // Individual benefit lines const lines = []; diff --git a/src/forms/output/BenefitsTable.js b/src/forms/output/BenefitsTable.js index 9e67f2e0..17ce29b1 100644 --- a/src/forms/output/BenefitsTable.js +++ b/src/forms/output/BenefitsTable.js @@ -5,9 +5,6 @@ import { Table } from 'semantic-ui-react'; // BENEFIT LOGIC import { applyAndPushBenefits } from '../../programs/applyAndPushBenefits'; -// OBJECT MANIPULATION -import { cloneDeep } from 'lodash'; - const getSignSymbol = function (num) { if (num > 0) { @@ -21,7 +18,8 @@ const getSignSymbol = function (num) { const BenefitsTable = function ({ client, snippets }) { - const clone = cloneDeep(client); + // @todo: make applyAndPushBenefits() work with Immutable.js collections + const clone = client.toJS(); const curr = clone.current; let allData = {}, diff --git a/src/forms/output/GraphHolder.js b/src/forms/output/GraphHolder.js index 7cfbf99e..87bf755b 100644 --- a/src/forms/output/GraphHolder.js +++ b/src/forms/output/GraphHolder.js @@ -19,11 +19,12 @@ class GraphHolder extends Component { render () { const { activeID } = this.state, - { Graph, client, snippets } = this.props, - { current } = client, - // The ids later used to access all program-specific data and functions - // Only active programs are added - activePrograms = [ ...current.benefits ]; + { Graph, client, snippets } = this.props; + const current = client.get('current'); + + // The ids later used to access all program-specific data and functions + // Only active programs are added + const activePrograms = current.get('benefits').toArray(); if (activePrograms.length === 0) { return { snippets.i_noBenefitsSelected }; diff --git a/src/forms/output/StackedAreaGraph.js b/src/forms/output/StackedAreaGraph.js index 707e4f85..c667d74f 100644 --- a/src/forms/output/StackedAreaGraph.js +++ b/src/forms/output/StackedAreaGraph.js @@ -51,14 +51,18 @@ class StackedAreaGraph extends Component { withEarned.unshift('earned'); // Adjust to time-interval, round to hundreds - const earned = client.future.earned * multiplier, - max = Math.max(earned, limits.max * multiplier), + const earned = client.getIn([ + 'future', + 'earned', + ]) * multiplier; + const max = Math.max(earned, limits.max * multiplier), xMax = Math.ceil(max / 100) * 100, xMin = Math.ceil(limits.min * multiplier / 100) * 100, interval = Math.ceil(((xMax - xMin) / 100) / 10) * 10, xRange = _.range(xMin, xMax + interval, interval), extraProps = { earned: { fill: 'origin' }}, - datasets = getChartData(xRange, multiplier, client, withEarned, extraProps); + // @todo: refactor visualizations to use Immutable collections + datasets = getChartData(xRange, multiplier, client.toJS(), withEarned, extraProps); // react-chartjs-2 keeps references to plugins, so we // have to mutate that reference diff --git a/src/forms/output/StackedBarGraph.js b/src/forms/output/StackedBarGraph.js index 754751c0..bd42b156 100644 --- a/src/forms/output/StackedBarGraph.js +++ b/src/forms/output/StackedBarGraph.js @@ -13,9 +13,6 @@ import { applyAndPushBenefits } from '../../programs/applyAndPushBenefits'; // Colors and text for parts of the chart import { PROGRAM_CHART_VALUES } from '../../utils/charts/PROGRAM_CHART_VALUES'; -// OBJECT MANIPULATION -import { cloneDeep } from 'lodash'; - /** Visual representation of the table * @@ -27,8 +24,8 @@ import { cloneDeep } from 'lodash'; * and future. All client props are needed. */ const StackedBarGraph = function({ client }) { - - let clone = cloneDeep(client), + // @todo make applyAndPushBenefits() use Immutable.js collections + let clone = client.toJS(), curr = clone.current; const allData = {}, diff --git a/src/forms/output/Summary.js b/src/forms/output/Summary.js index 14fbdc2a..f3b7183b 100644 --- a/src/forms/output/Summary.js +++ b/src/forms/output/Summary.js @@ -274,7 +274,10 @@ const Summary = function ({ client, openFeedback, snippets }) { const resourceKeys = [ `earned`, - ...client.current.benefits, + ...client.getIn([ + 'current', + 'benefits', + ]).toArray(), ]; // Really quick returns if other calcs not needed @@ -333,8 +336,9 @@ const Summary = function ({ client, openFeedback, snippets }) { let numBenefits = current.benefits.length; for (let benefiti = 0; benefiti < numBenefits; benefiti++) { - let cBenefit = current.benefits[ benefiti ], - fBenefit = future.benefits[ benefiti ]; + let cBenefit = current.benefits[ benefiti ]; + + let fBenefit = future.benefits[ benefiti ]; benefitList.push(
  • diff --git a/src/forms/rentFields.js b/src/forms/rentFields.js index 4408f926..3570f44f 100644 --- a/src/forms/rentFields.js +++ b/src/forms/rentFields.js @@ -1,5 +1,5 @@ import React, { Component } from 'react'; -import { MonthlyCashFlowRow, ImmutableMonthlyCashFlowRow } from './cashflow'; +import { MonthlyCashFlowRow } from './cashflow'; import { isNonNegNumber, hasOnlyNonNegNumberChars } from '../utils/validators'; @@ -7,6 +7,13 @@ import { isNonNegNumber, hasOnlyNonNegNumberChars } from '../utils/validators'; class RentShareField extends Component { state = { valid: true, message: null }; + setValue = (event, inputProps) => { + this.props.setValue({ + name: inputProps.name, + value: inputProps.value, + }); + }; + storeValidator = (ownValue) => { let message = null, valid = true; @@ -14,7 +21,7 @@ class RentShareField extends Component { if (!isPosNum) { valid = false; } else { - valid = Number(ownValue) <= this.props.timeState[ 'contractRent' ]; + valid = Number(ownValue) <= this.props.timeState.get('contractRent'); if (!valid) { message = 'Rent share must be less than contract rent'; } @@ -29,7 +36,7 @@ class RentShareField extends Component { }; render() { - const { timeState, updateClientValue } = this.props, + const { timeState } = this.props, { valid, message } = this.state; const inputProps = { @@ -47,11 +54,11 @@ class RentShareField extends Component { return ( + inputProps = { inputProps } + baseValue = { timeState.get('rentShare') } + includes = { [ 'monthly' ] } + setValue = { this.setValue } + rowProps = { rowProps } /> ); } }; // End @@ -60,6 +67,13 @@ class RentShareField extends Component { class ContractRentField extends Component { state = { valid: true, message: null }; + setValue = (event, inputProps) => { + this.props.setValue({ + name: inputProps.name, + value: inputProps.value, + }); + }; + storeValidator = (ownValue) => { let message = null, valid = true; @@ -67,7 +81,7 @@ class ContractRentField extends Component { if (!isPosNum) { valid = false; } else { - valid = ownValue >= this.props.timeState[ 'rentShare' ]; + valid = ownValue >= this.props.timeState.get('rentShare'); if (!valid) { message = 'Contract rent must be more than rent share'; } @@ -82,7 +96,7 @@ class ContractRentField extends Component { }; render() { - const { timeState, updateClientValue } = this.props, + const { timeState } = this.props, { valid, message } = this.state; const inputProps = { @@ -101,16 +115,16 @@ class ContractRentField extends Component { return ( ); } }; // End -const PlainRentRow = function ({ timeState, updateClientValue }) { +const PlainRentRow = function ({ timeState, setValue }) { const inputProps = { name: 'rent', @@ -126,31 +140,6 @@ const PlainRentRow = function ({ timeState, updateClientValue }) { return ( - ); - -}; // End - -const ImmutablePlainRentRow = function ({ timeState, setValue }) { - - const inputProps = { - name: 'rent', - displayValidator: hasOnlyNonNegNumberChars, - storeValidator: isNonNegNumber, - onBlur: function () {}, - }, - rowProps = { - label: 'Monthly Rent', - validRow: true, - message: null, - }; - - return ( - { + return fromJS(CLIENT_DEFAULTS) + .updateIn( + [ + 'current', + 'benefits', + ], + (benefits) => { + return Set(benefits); + } + ).updateIn( + [ + 'future', + 'benefits', + ], + (benefits) => { + return Set(benefits); + } + ); +}; + const clientReducer = ( - state = fromJS(CLIENT_DEFAULTS), + state = getDefaultClients(), action ) => { switch (action.type) { @@ -142,6 +164,38 @@ const clientReducer = ( getsAssistance ); } + + case SET_HAS_BENEFIT: { + const { time, benefit, value } = action.payload; + + state = state.updateIn( + [ + time, + 'benefits', + ], + (benefits) => { + if (value) { + return benefits.add(benefit); + } + else { + return benefits.delete(benefit); + } + } + ); + + // Side effect--might be better if this could be decoupled from the reducer? + if (benefit === 'section8') { + state = state.setIn( + [ + time, + 'housing', + ], + 'voucher' + ); + } + + return state; + } default: return state; diff --git a/src/test/forms/CurrentBenefits.test.js b/src/test/forms/CurrentBenefits.test.js index 6e662062..97f5ae28 100644 --- a/src/test/forms/CurrentBenefits.test.js +++ b/src/test/forms/CurrentBenefits.test.js @@ -7,7 +7,9 @@ import { CurrentBenefitsStep } from '../../forms/CurrentBenefits'; import { getTextForLanguage } from '../../utils/getTextForLanguage'; import createReducer from '../../reducers'; +import { setUSState } from '../../actions'; +const reducer = createReducer(); const snippets = getTextForLanguage(`en`); test('Benefits step component should render without error', () => { @@ -21,9 +23,11 @@ test('Benefits step component should render without error', () => { benefitsSnippets = snippets.visitPage.currentBenefits; expect(() => { - const reducer = createReducer(); - const state = reducer(undefined, {}); + const state = reducer( + undefined, + setUSState({ state: 'MA' }) + ); mount( { 'client', 'current', ]) } + USState = { state.getIn([ + 'geography', + 'state', + ]) } setHasBenefit = { () => {} } navData = { navData } askToResetClient = { askToResetClient } diff --git a/src/test/forms/cashflow/CashFlowDisplayRow.test.js b/src/test/forms/cashflow/CashFlowDisplayRow.test.js index fcad3101..2412b750 100644 --- a/src/test/forms/cashflow/CashFlowDisplayRow.test.js +++ b/src/test/forms/cashflow/CashFlowDisplayRow.test.js @@ -3,6 +3,11 @@ import { mount } from 'enzyme'; import { CashFlowDisplayRow } from '../../../forms/cashflow'; +import createReducer from '../../../reducers'; +import { setCashValue } from '../../../actions'; + +const reducer = createReducer(); + describe('', () => { it('renders using provided value', () => { const propsWithValue = { @@ -14,10 +19,22 @@ describe('', () => { }); it('renders using value in timeState', () => { + const state = reducer( + undefined, + setCashValue({ + time: 'current', + name: 'potatoes', + value: 15, + }) + ); + const propsWithTimeState = { generic: 'potatoes', - timeState: { potatoes: 15 }, - children: More potatoes, huh?, + timeState: state.getIn([ + 'client', + 'current', + ]), + children: More potatoes, huh?, }; expect(mount()).toMatchSnapshot(); }); diff --git a/src/test/forms/cashflow/CashFlowInputsRow.test.js b/src/test/forms/cashflow/CashFlowInputsRow.test.js index 1155f3a1..beb3f5b3 100644 --- a/src/test/forms/cashflow/CashFlowInputsRow.test.js +++ b/src/test/forms/cashflow/CashFlowInputsRow.test.js @@ -23,7 +23,7 @@ test('CashFlowInputsRow should render', () => { }).not.toThrow(); }); -test(`Second ManagedNumberField child should have value of timeState[ 'clientProp' ]`, () => { +test(`Second ManagedNumberField child should have value of timeState.get(clientProp)`, () => { const wrapper = mount( renders using value in timeState 1`] = ` diff --git a/src/test/forms/inputs/ManagedNumberField.test.js b/src/test/forms/inputs/ManagedNumberField.test.js index a495218e..261852ab 100644 --- a/src/test/forms/inputs/ManagedNumberField.test.js +++ b/src/test/forms/inputs/ManagedNumberField.test.js @@ -93,7 +93,7 @@ test('should change local and app state correctly to 0 when user inputs empty st // sending the proper call to change the application's state // Since value is empty string, store should be given 0 as value - expect(mockStore.mock.calls[ 0 ][ 1 ].value).toEqual(`0`); + expect(mockStore.mock.calls[ 0 ][ 1 ].value).toEqual(0); // changes to this.state's focusedVal and valid variables expect(wrapper.state('focusedVal')).toBe(userInput); diff --git a/src/test/forms/output/BenefitsLineGraph.test.js b/src/test/forms/output/BenefitsLineGraph.test.js index a776131b..f6e50ef3 100644 --- a/src/test/forms/output/BenefitsLineGraph.test.js +++ b/src/test/forms/output/BenefitsLineGraph.test.js @@ -1,9 +1,12 @@ import React from 'react'; import { mount } from 'enzyme'; -import { cloneDeep, set } from 'lodash'; import { BenefitsLineGraph } from '../../../forms/output/BenefitsLineGraph'; -import { CLIENT_DEFAULTS } from '../../../utils/CLIENT_DEFAULTS'; + +import createReducer from '../../../reducers'; +import { setHasBenefit, setCashValue } from '../../../actions'; + +const reducer = createReducer(); jest.mock('react-chartjs-2', () => { const LineMock = () => { @@ -19,26 +22,27 @@ jest.mock('react-chartjs-2', () => { describe('', () => { let activePrograms; - let client; let defaultProps; - const buildGraph = () => { - return mount(); + const buildGraph = (state) => { + return mount(); }; beforeEach(() => { activePrograms = []; - client = cloneDeep(CLIENT_DEFAULTS); defaultProps = { activePrograms: activePrograms, - client: client, timescale: 'Monthly', className: 'some-class', }; }); it('renders message when no benefits selected', () => { - const graph = buildGraph(); + const state = reducer(undefined, {}); + + const graph = buildGraph(state); expect(graph.children).toHaveLength(1); expect(graph.childAt(0).is('Message')).toBe(true); @@ -46,34 +50,112 @@ describe('', () => { it('renders with snap and current earned less than future earned', () => { activePrograms.push('snap'); - set(client, 'current.earned', 100); - set(client, 'future.earned', 200); - expect(buildGraph()).toMatchSnapshot(); + const state = [ + setHasBenefit({ + time: 'current', + benefit: 'snap', + value: true, + }), + + setCashValue({ + time: 'current', + name: 'earned', + value: 100, + }), + + setCashValue({ + time: 'future', + name: 'earned', + value: 200, + }), + ].reduce(reducer, undefined); + + expect(buildGraph(state)).toMatchSnapshot(); }); it('renders with snap and current earned greater than future earned', () => { activePrograms.push('snap'); - set(client, 'current.earned', 200); - set(client, 'future.earned', 100); - - expect(buildGraph()).toMatchSnapshot(); + + const state = [ + setHasBenefit({ + time: 'current', + benefit: 'snap', + value: true, + }), + + setCashValue({ + time: 'current', + name: 'earned', + value: 200, + }), + + setCashValue({ + time: 'future', + name: 'earned', + value: 100, + }), + ].reduce(reducer, undefined); + + expect(buildGraph(state)).toMatchSnapshot(); }); it('renders with section8', () => { activePrograms.push('section8'); - set(client, 'current.earned', 100); - set(client, 'future.earned', 200); - expect(buildGraph()).toMatchSnapshot(); + const state = [ + setHasBenefit({ + time: 'current', + benefit: 'section8', + value: true, + }), + + setCashValue({ + time: 'current', + name: 'earned', + value: 100, + }), + + setCashValue({ + time: 'future', + name: 'earned', + value: 200, + }), + ].reduce(reducer, undefined); + + expect(buildGraph(state)).toMatchSnapshot(); }); it('renders with both snap and section8', () => { activePrograms.push('snap'); activePrograms.push('section8'); - set(client, 'current.earned', 100); - set(client, 'future.earned', 200); - expect(buildGraph()).toMatchSnapshot(); + const state = [ + setHasBenefit({ + time: 'current', + benefit: 'snap', + value: true, + }), + + setHasBenefit({ + time: 'current', + benefit: 'section8', + value: true, + }), + + setCashValue({ + time: 'current', + name: 'earned', + value: 100, + }), + + setCashValue({ + time: 'future', + name: 'earned', + value: 200, + }), + ].reduce(reducer, undefined); + + expect(buildGraph(state)).toMatchSnapshot(); }); }); diff --git a/src/test/forms/output/BenefitsTable.test.js b/src/test/forms/output/BenefitsTable.test.js index 7c842b6e..4cb0cc18 100644 --- a/src/test/forms/output/BenefitsTable.test.js +++ b/src/test/forms/output/BenefitsTable.test.js @@ -1,15 +1,18 @@ import React from 'react'; import renderer from 'react-test-renderer'; -import { cloneDeep, set } from 'lodash'; import { BenefitsTable } from '../../../forms/output/BenefitsTable'; import { snippets } from '../../helpers'; -import { CLIENT_DEFAULTS } from '../../../utils/CLIENT_DEFAULTS'; -const buildSnapshot = (client) => { +import createReducer from '../../../reducers'; +import { setHasBenefit, setCashValue } from '../../../actions'; + +const reducer = createReducer(); + +const buildSnapshot = (state) => { const rendered = renderer.create( ); @@ -17,23 +20,66 @@ const buildSnapshot = (client) => { }; test('Benefits table renders correctly', () => { - const client = cloneDeep(CLIENT_DEFAULTS); - expect(buildSnapshot(client)).toMatchSnapshot(); + let state = reducer(undefined, {}); - const benefits = [ 'snap' ]; + expect(buildSnapshot(state)).toMatchSnapshot(); - set(client, 'current.benefits', benefits); - expect(buildSnapshot(client)).toMatchSnapshot(); + state = [ + setHasBenefit({ + time: 'current', + benefit: 'snap', + value: true, + }), + ].reduce(reducer, state); - set(client, 'current.earned', 100); - expect(buildSnapshot(client)).toMatchSnapshot(); + state = reducer( + state, + setHasBenefit({ + time: 'current', + benefit: 'snap', + value: true, + }) + ); - set(client, 'future.earned', 200); - expect(buildSnapshot(client)).toMatchSnapshot(); + expect(buildSnapshot(state)).toMatchSnapshot(); - set(client, 'current.earned', 300); - expect(buildSnapshot(client)).toMatchSnapshot(); + state = reducer( + state, + setCashValue({ + time: 'current', + name: 'earned', + value: 100, + }) + ); + expect(buildSnapshot(state)).toMatchSnapshot(); - set(client, 'future.earned', 400); - expect(buildSnapshot(client)).toMatchSnapshot(); + state = reducer( + state, + setCashValue({ + time: 'future', + name: 'earned', + value: 200, + }) + ); + expect(buildSnapshot(state)).toMatchSnapshot(); + + state = reducer( + state, + setCashValue({ + time: 'current', + name: 'earned', + value: 300, + }) + ); + expect(buildSnapshot(state)).toMatchSnapshot(); + + state = reducer( + state, + setCashValue({ + time: 'future', + name: 'earned', + value: 400, + }) + ); + expect(buildSnapshot(state)).toMatchSnapshot(); }); diff --git a/src/test/forms/output/StackedAreaGraph.test.js b/src/test/forms/output/StackedAreaGraph.test.js index 0e811d81..405f83d2 100644 --- a/src/test/forms/output/StackedAreaGraph.test.js +++ b/src/test/forms/output/StackedAreaGraph.test.js @@ -1,9 +1,12 @@ import React from 'react'; import { mount } from 'enzyme'; -import { cloneDeep, set } from 'lodash'; import { StackedAreaGraph } from '../../../forms/output/StackedAreaGraph'; -import { CLIENT_DEFAULTS } from '../../../utils/CLIENT_DEFAULTS'; + +import createReducer from '../../../reducers'; +import { setCashValue } from '../../../actions'; + +const reducer = createReducer(); jest.mock('react-chartjs-2', () => { const LineMock = () => { @@ -19,53 +22,99 @@ jest.mock('react-chartjs-2', () => { describe('', () => { let activePrograms; - let client; let defaultProps; - const buildGraph = () => { - return mount(); + const buildGraph = (state) => { + return mount(); }; beforeEach(() => { activePrograms = []; - client = cloneDeep(CLIENT_DEFAULTS); defaultProps = { activePrograms: activePrograms, - client: client, timescale: 'Monthly', }; }); it('renders with snap and current earned less than future earned', () => { activePrograms.push('snap'); - set(client, 'current.earned', 100); - set(client, 'future.earned', 200); - expect(buildGraph()).toMatchSnapshot(); + const state = [ + setCashValue({ + time: 'current', + name: 'earned', + value: 100, + }), + + setCashValue({ + time: 'future', + name: 'earned', + value: 200, + }), + ].reduce(reducer, undefined); + + expect(buildGraph(state)).toMatchSnapshot(); }); it('renders with snap and current earned greater than future earned', () => { activePrograms.push('snap'); - set(client, 'current.earned', 200); - set(client, 'future.earned', 100); - - expect(buildGraph()).toMatchSnapshot(); + + const state = [ + setCashValue({ + time: 'current', + name: 'earned', + value: 200, + }), + + setCashValue({ + time: 'future', + name: 'earned', + value: 100, + }), + ].reduce(reducer, undefined); + + expect(buildGraph(state)).toMatchSnapshot(); }); it('renders with section8', () => { activePrograms.push('section8'); - set(client, 'current.earned', 100); - set(client, 'future.earned', 200); - expect(buildGraph()).toMatchSnapshot(); + const state = [ + setCashValue({ + time: 'current', + name: 'earned', + value: 100, + }), + + setCashValue({ + time: 'future', + name: 'earned', + value: 200, + }), + ].reduce(reducer, undefined); + + expect(buildGraph(state)).toMatchSnapshot(); }); it('renders with both snap and section8', () => { - activePrograms.push('snap'); - activePrograms.push('section8'); - set(client, 'current.earned', 100); - set(client, 'future.earned', 200); + activePrograms.push('snap', 'section8'); + + const state = [ + setCashValue({ + time: 'current', + name: 'earned', + value: 100, + }), + + setCashValue({ + time: 'future', + name: 'earned', + value: 200, + }), + ].reduce(reducer, undefined); - expect(buildGraph()).toMatchSnapshot(); + expect(buildGraph(state)).toMatchSnapshot(); }); }); diff --git a/src/test/forms/output/StackedBarGraph.test.js b/src/test/forms/output/StackedBarGraph.test.js index 2d7b179b..4592b075 100644 --- a/src/test/forms/output/StackedBarGraph.test.js +++ b/src/test/forms/output/StackedBarGraph.test.js @@ -1,9 +1,12 @@ import React from 'react'; import { mount } from 'enzyme'; -import { cloneDeep, set } from 'lodash'; import { StackedBarGraph } from '../../../forms/output/StackedBarGraph'; -import { CLIENT_DEFAULTS } from '../../../utils/CLIENT_DEFAULTS'; + +import createReducer from '../../../reducers'; +import { setHasBenefit, setCashValue } from '../../../actions'; + +const reducer = createReducer(); jest.mock('react-chartjs-2', () => { const BarMock = () => { @@ -18,56 +21,131 @@ jest.mock('react-chartjs-2', () => { }); describe('', () => { - let client; - - const buildGraph = () => { - return mount(); + const buildGraph = (state) => { + return mount(); }; - beforeEach(() => { - client = cloneDeep(CLIENT_DEFAULTS); - }); - it('renders with snap and current earned less than future earned', () => { - const benefits = [ 'snap' ]; - - set(client, 'current.benefits', benefits); - set(client, 'current.earned', 100); - set(client, 'future.earned', 200); - - expect(buildGraph()).toMatchSnapshot(); + /* + * Break down what's happening here; we're applying a series of actions through the + * reducer to create a state object. This is essentially what Redux does through dispatch(). + * The way a reducer function works (not unique to Redux) is that it takes at leat two arguments: + * + * function reducer(currentState, iteratorValue) { + * return changeCurrentState(currentState, iteratorValue); + * } + * + * Each time through the loop, the function takes the return value of the previous iteration, and the + * value being iterated, and returns some value, until it's done iterating, at which point it returns + * the final return value. Since we're iterating over an array of actions, each time through the loop + * the second argument will be an action. The reducer then takes that action, and the previous state, + * and returns a new state. At the end of the iteration, we'll have a state object exactly as is Redux + * had dispatched each of these actions in succession. + */ + + const state = [ + setHasBenefit({ + time: 'current', + benefit: 'snap', + value: true, + }), + + setCashValue({ + time: 'current', + name: 'earned', + value: 100, + }), + + setCashValue({ + time: 'future', + name: 'earned', + value: 200, + }), + ].reduce( + reducer, + // Since we don't have an initial value, we have to pass `undefined` here; otherwise Javascript's + // Array.reduce() uses the object being iterated over (in this case, the array of actions) as the initial value. + undefined + ); + + expect(buildGraph(state)).toMatchSnapshot(); }); it('renders with snap and current earned greater than future earned', () => { - const benefits = [ 'snap' ]; - - set(client, 'current.benefits', benefits); - set(client, 'current.earned', 200); - set(client, 'future.earned', 100); - - expect(buildGraph()).toMatchSnapshot(); + const state = [ + setHasBenefit({ + time: 'current', + benefit: 'snap', + value: true, + }), + + setCashValue({ + time: 'current', + name: 'earned', + value: 200, + }), + + setCashValue({ + time: 'future', + name: 'earned', + value: 100, + }), + ].reduce(reducer, undefined); + + expect(buildGraph(state)).toMatchSnapshot(); }); it('renders with section8', () => { - const benefits = [ 'section8' ]; - - set(client, 'current.benefits', benefits); - set(client, 'current.earned', 100); - set(client, 'future.earned', 200); - - expect(buildGraph()).toMatchSnapshot(); + const state = [ + setHasBenefit({ + time: 'current', + benefit: 'section8', + value: true, + }), + + setCashValue({ + time: 'current', + name: 'earned', + value: 100, + }), + + setCashValue({ + time: 'future', + name: 'earned', + value: 200, + }), + ].reduce(reducer, undefined); + + expect(buildGraph(state)).toMatchSnapshot(); }); it('renders with both snap and section8', () => { - const benefits = [ - 'snap', - 'section8', - ]; - - set(client, 'current.benefits', benefits); - set(client, 'current.earned', 100); - set(client, 'future.earned', 200); - - expect(buildGraph()).toMatchSnapshot(); + const state = [ + setHasBenefit({ + time: 'current', + benefit: 'snap', + value: true, + }), + + setHasBenefit({ + time: 'current', + benefit: 'section8', + value: true, + }), + + setCashValue({ + time: 'current', + name: 'earned', + value: 100, + }), + + setCashValue({ + time: 'future', + name: 'earned', + value: 200, + }), + ].reduce(reducer, undefined); + + expect(buildGraph(state)).toMatchSnapshot(); }); }); diff --git a/src/test/forms/output/__snapshots__/BenefitsLineGraph.test.js.snap b/src/test/forms/output/__snapshots__/BenefitsLineGraph.test.js.snap index 3180e9b7..184eaa05 100644 --- a/src/test/forms/output/__snapshots__/BenefitsLineGraph.test.js.snap +++ b/src/test/forms/output/__snapshots__/BenefitsLineGraph.test.js.snap @@ -10,119 +10,123 @@ exports[` renders with both snap and section8 1`] = ` } className="some-class" client={ - Object { - "USState": "MA", - "current": Object { - "SSDI": 0, - "SSI": 0, - "TAFDC": 0, - "adultDirectCare": 0, - "adultOtherCare": 0, - "adultTransportation": 0, - "alimony": 0, - "benefits": Array [], - "childBeforeAndAfterSchoolCare": 0, - "childDirectCare": 0, - "childOtherCare": 0, - "childSupportIn": 0, - "childSupportPaidOut": 0, - "childTransportation": 0, - "climateControl": false, - "contractRent": 0, - "disabledAssistance": 0, - "disabledMedical": 0, - "earned": 100, - "earnedBecauseOfAdultCare": 0, - "earnedBecauseOfChildCare": 0, - "fuelAssistance": false, - "household": Array [ - Object { - "m_age": 30, - "m_disabled": false, - "m_role": "head", + Immutable.Map { + USState: "MA", + current: Immutable.Map { + otherExpensesCareProducts: 0, + otherMedical: 0, + otherExpensesPhone: 0, + workersComp: 0, + childOtherCare: 0, + earnedBecauseOfAdultCare: 0, + SSDI: 0, + unemployment: 0, + otherExpensesOther: 0, + childBeforeAndAfterSchoolCare: 0, + rentShare: 0, + otherExpensesMedical: 0, + adultTransportation: 0, + adultOtherCare: 0, + earnedBecauseOfChildCare: 0, + childTransportation: 0, + otherExpensesFood: 0, + SSI: 0, + alimony: 0, + contractRent: 0, + socialSecurity: 0, + phone: false, + fuelAssistance: false, + pension: 0, + childSupportPaidOut: 0, + otherExpensesCable: 0, + disabledAssistance: 0, + nonHeatElectricity: false, + adultDirectCare: 0, + disabledMedical: 0, + childDirectCare: 0, + propertyTax: 0, + wantsToSeeOtherExpenses: false, + earned: 100, + climateControl: false, + TAFDC: 0, + childSupportIn: 0, + otherIncome: 0, + rent: 0, + mortgage: 0, + benefits: Immutable.Set [ + "snap", + "section8", + ], + otherExpensesEntertainment: 0, + housingInsurance: 0, + otherExpensesClothes: 0, + housing: "voucher", + otherExpensesTransport: 0, + otherExpensesUtilities: 0, + household: Immutable.List [ + Immutable.Map { + m_age: 30, + m_role: "head", + m_disabled: false, }, ], - "housing": "homeless", - "housingInsurance": 0, - "mortgage": 0, - "nonHeatElectricity": false, - "otherExpensesCable": 0, - "otherExpensesCareProducts": 0, - "otherExpensesClothes": 0, - "otherExpensesEntertainment": 0, - "otherExpensesFood": 0, - "otherExpensesMedical": 0, - "otherExpensesOther": 0, - "otherExpensesPhone": 0, - "otherExpensesTransport": 0, - "otherExpensesUtilities": 0, - "otherIncome": 0, - "otherMedical": 0, - "pension": 0, - "phone": false, - "propertyTax": 0, - "rent": 0, - "rentShare": 0, - "socialSecurity": 0, - "unemployment": 0, - "wantsToSeeOtherExpenses": false, - "workersComp": 0, }, - "future": Object { - "SSDI": 0, - "SSI": 0, - "TAFDC": 0, - "adultDirectCare": 0, - "adultOtherCare": 0, - "adultTransportation": 0, - "alimony": 0, - "benefits": Array [], - "childBeforeAndAfterSchoolCare": 0, - "childDirectCare": 0, - "childOtherCare": 0, - "childSupportIn": 0, - "childSupportPaidOut": 0, - "childTransportation": 0, - "climateControl": false, - "contractRent": 0, - "disabledAssistance": 0, - "disabledMedical": 0, - "earned": 200, - "earnedBecauseOfAdultCare": 0, - "earnedBecauseOfChildCare": 0, - "fuelAssistance": false, - "household": Array [ - Object { - "m_age": 30, - "m_disabled": false, - "m_role": "head", + future: Immutable.Map { + otherExpensesCareProducts: 0, + otherMedical: 0, + otherExpensesPhone: 0, + workersComp: 0, + childOtherCare: 0, + earnedBecauseOfAdultCare: 0, + SSDI: 0, + unemployment: 0, + otherExpensesOther: 0, + childBeforeAndAfterSchoolCare: 0, + rentShare: 0, + otherExpensesMedical: 0, + adultTransportation: 0, + adultOtherCare: 0, + earnedBecauseOfChildCare: 0, + childTransportation: 0, + otherExpensesFood: 0, + SSI: 0, + alimony: 0, + contractRent: 0, + socialSecurity: 0, + phone: false, + fuelAssistance: false, + pension: 0, + childSupportPaidOut: 0, + otherExpensesCable: 0, + disabledAssistance: 0, + nonHeatElectricity: false, + adultDirectCare: 0, + disabledMedical: 0, + childDirectCare: 0, + propertyTax: 0, + wantsToSeeOtherExpenses: false, + earned: 200, + climateControl: false, + TAFDC: 0, + childSupportIn: 0, + otherIncome: 0, + rent: 0, + mortgage: 0, + benefits: Immutable.Set [ + ], + otherExpensesEntertainment: 0, + housingInsurance: 0, + otherExpensesClothes: 0, + housing: "homeless", + otherExpensesTransport: 0, + otherExpensesUtilities: 0, + household: Immutable.List [ + Immutable.Map { + m_age: 30, + m_role: "head", + m_disabled: false, }, ], - "housing": "homeless", - "housingInsurance": 0, - "mortgage": 0, - "nonHeatElectricity": false, - "otherExpensesCable": 0, - "otherExpensesCareProducts": 0, - "otherExpensesClothes": 0, - "otherExpensesEntertainment": 0, - "otherExpensesFood": 0, - "otherExpensesMedical": 0, - "otherExpensesOther": 0, - "otherExpensesPhone": 0, - "otherExpensesTransport": 0, - "otherExpensesUtilities": 0, - "otherIncome": 0, - "otherMedical": 0, - "pension": 0, - "phone": false, - "propertyTax": 0, - "rent": 0, - "rentShare": 0, - "socialSecurity": 0, - "unemployment": 0, - "wantsToSeeOtherExpenses": false, - "workersComp": 0, }, } } @@ -1045,119 +1049,122 @@ exports[` renders with section8 1`] = ` } className="some-class" client={ - Object { - "USState": "MA", - "current": Object { - "SSDI": 0, - "SSI": 0, - "TAFDC": 0, - "adultDirectCare": 0, - "adultOtherCare": 0, - "adultTransportation": 0, - "alimony": 0, - "benefits": Array [], - "childBeforeAndAfterSchoolCare": 0, - "childDirectCare": 0, - "childOtherCare": 0, - "childSupportIn": 0, - "childSupportPaidOut": 0, - "childTransportation": 0, - "climateControl": false, - "contractRent": 0, - "disabledAssistance": 0, - "disabledMedical": 0, - "earned": 100, - "earnedBecauseOfAdultCare": 0, - "earnedBecauseOfChildCare": 0, - "fuelAssistance": false, - "household": Array [ - Object { - "m_age": 30, - "m_disabled": false, - "m_role": "head", + Immutable.Map { + USState: "MA", + current: Immutable.Map { + otherExpensesCareProducts: 0, + otherMedical: 0, + otherExpensesPhone: 0, + workersComp: 0, + childOtherCare: 0, + earnedBecauseOfAdultCare: 0, + SSDI: 0, + unemployment: 0, + otherExpensesOther: 0, + childBeforeAndAfterSchoolCare: 0, + rentShare: 0, + otherExpensesMedical: 0, + adultTransportation: 0, + adultOtherCare: 0, + earnedBecauseOfChildCare: 0, + childTransportation: 0, + otherExpensesFood: 0, + SSI: 0, + alimony: 0, + contractRent: 0, + socialSecurity: 0, + phone: false, + fuelAssistance: false, + pension: 0, + childSupportPaidOut: 0, + otherExpensesCable: 0, + disabledAssistance: 0, + nonHeatElectricity: false, + adultDirectCare: 0, + disabledMedical: 0, + childDirectCare: 0, + propertyTax: 0, + wantsToSeeOtherExpenses: false, + earned: 100, + climateControl: false, + TAFDC: 0, + childSupportIn: 0, + otherIncome: 0, + rent: 0, + mortgage: 0, + benefits: Immutable.Set [ + "section8", + ], + otherExpensesEntertainment: 0, + housingInsurance: 0, + otherExpensesClothes: 0, + housing: "voucher", + otherExpensesTransport: 0, + otherExpensesUtilities: 0, + household: Immutable.List [ + Immutable.Map { + m_age: 30, + m_role: "head", + m_disabled: false, }, ], - "housing": "homeless", - "housingInsurance": 0, - "mortgage": 0, - "nonHeatElectricity": false, - "otherExpensesCable": 0, - "otherExpensesCareProducts": 0, - "otherExpensesClothes": 0, - "otherExpensesEntertainment": 0, - "otherExpensesFood": 0, - "otherExpensesMedical": 0, - "otherExpensesOther": 0, - "otherExpensesPhone": 0, - "otherExpensesTransport": 0, - "otherExpensesUtilities": 0, - "otherIncome": 0, - "otherMedical": 0, - "pension": 0, - "phone": false, - "propertyTax": 0, - "rent": 0, - "rentShare": 0, - "socialSecurity": 0, - "unemployment": 0, - "wantsToSeeOtherExpenses": false, - "workersComp": 0, }, - "future": Object { - "SSDI": 0, - "SSI": 0, - "TAFDC": 0, - "adultDirectCare": 0, - "adultOtherCare": 0, - "adultTransportation": 0, - "alimony": 0, - "benefits": Array [], - "childBeforeAndAfterSchoolCare": 0, - "childDirectCare": 0, - "childOtherCare": 0, - "childSupportIn": 0, - "childSupportPaidOut": 0, - "childTransportation": 0, - "climateControl": false, - "contractRent": 0, - "disabledAssistance": 0, - "disabledMedical": 0, - "earned": 200, - "earnedBecauseOfAdultCare": 0, - "earnedBecauseOfChildCare": 0, - "fuelAssistance": false, - "household": Array [ - Object { - "m_age": 30, - "m_disabled": false, - "m_role": "head", + future: Immutable.Map { + otherExpensesCareProducts: 0, + otherMedical: 0, + otherExpensesPhone: 0, + workersComp: 0, + childOtherCare: 0, + earnedBecauseOfAdultCare: 0, + SSDI: 0, + unemployment: 0, + otherExpensesOther: 0, + childBeforeAndAfterSchoolCare: 0, + rentShare: 0, + otherExpensesMedical: 0, + adultTransportation: 0, + adultOtherCare: 0, + earnedBecauseOfChildCare: 0, + childTransportation: 0, + otherExpensesFood: 0, + SSI: 0, + alimony: 0, + contractRent: 0, + socialSecurity: 0, + phone: false, + fuelAssistance: false, + pension: 0, + childSupportPaidOut: 0, + otherExpensesCable: 0, + disabledAssistance: 0, + nonHeatElectricity: false, + adultDirectCare: 0, + disabledMedical: 0, + childDirectCare: 0, + propertyTax: 0, + wantsToSeeOtherExpenses: false, + earned: 200, + climateControl: false, + TAFDC: 0, + childSupportIn: 0, + otherIncome: 0, + rent: 0, + mortgage: 0, + benefits: Immutable.Set [ + ], + otherExpensesEntertainment: 0, + housingInsurance: 0, + otherExpensesClothes: 0, + housing: "homeless", + otherExpensesTransport: 0, + otherExpensesUtilities: 0, + household: Immutable.List [ + Immutable.Map { + m_age: 30, + m_role: "head", + m_disabled: false, }, ], - "housing": "homeless", - "housingInsurance": 0, - "mortgage": 0, - "nonHeatElectricity": false, - "otherExpensesCable": 0, - "otherExpensesCareProducts": 0, - "otherExpensesClothes": 0, - "otherExpensesEntertainment": 0, - "otherExpensesFood": 0, - "otherExpensesMedical": 0, - "otherExpensesOther": 0, - "otherExpensesPhone": 0, - "otherExpensesTransport": 0, - "otherExpensesUtilities": 0, - "otherIncome": 0, - "otherMedical": 0, - "pension": 0, - "phone": false, - "propertyTax": 0, - "rent": 0, - "rentShare": 0, - "socialSecurity": 0, - "unemployment": 0, - "wantsToSeeOtherExpenses": false, - "workersComp": 0, }, } } @@ -1876,119 +1883,122 @@ exports[` renders with snap and current earned greater than f } className="some-class" client={ - Object { - "USState": "MA", - "current": Object { - "SSDI": 0, - "SSI": 0, - "TAFDC": 0, - "adultDirectCare": 0, - "adultOtherCare": 0, - "adultTransportation": 0, - "alimony": 0, - "benefits": Array [], - "childBeforeAndAfterSchoolCare": 0, - "childDirectCare": 0, - "childOtherCare": 0, - "childSupportIn": 0, - "childSupportPaidOut": 0, - "childTransportation": 0, - "climateControl": false, - "contractRent": 0, - "disabledAssistance": 0, - "disabledMedical": 0, - "earned": 200, - "earnedBecauseOfAdultCare": 0, - "earnedBecauseOfChildCare": 0, - "fuelAssistance": false, - "household": Array [ - Object { - "m_age": 30, - "m_disabled": false, - "m_role": "head", + Immutable.Map { + USState: "MA", + current: Immutable.Map { + otherExpensesCareProducts: 0, + otherMedical: 0, + otherExpensesPhone: 0, + workersComp: 0, + childOtherCare: 0, + earnedBecauseOfAdultCare: 0, + SSDI: 0, + unemployment: 0, + otherExpensesOther: 0, + childBeforeAndAfterSchoolCare: 0, + rentShare: 0, + otherExpensesMedical: 0, + adultTransportation: 0, + adultOtherCare: 0, + earnedBecauseOfChildCare: 0, + childTransportation: 0, + otherExpensesFood: 0, + SSI: 0, + alimony: 0, + contractRent: 0, + socialSecurity: 0, + phone: false, + fuelAssistance: false, + pension: 0, + childSupportPaidOut: 0, + otherExpensesCable: 0, + disabledAssistance: 0, + nonHeatElectricity: false, + adultDirectCare: 0, + disabledMedical: 0, + childDirectCare: 0, + propertyTax: 0, + wantsToSeeOtherExpenses: false, + earned: 200, + climateControl: false, + TAFDC: 0, + childSupportIn: 0, + otherIncome: 0, + rent: 0, + mortgage: 0, + benefits: Immutable.Set [ + "snap", + ], + otherExpensesEntertainment: 0, + housingInsurance: 0, + otherExpensesClothes: 0, + housing: "homeless", + otherExpensesTransport: 0, + otherExpensesUtilities: 0, + household: Immutable.List [ + Immutable.Map { + m_age: 30, + m_role: "head", + m_disabled: false, }, ], - "housing": "homeless", - "housingInsurance": 0, - "mortgage": 0, - "nonHeatElectricity": false, - "otherExpensesCable": 0, - "otherExpensesCareProducts": 0, - "otherExpensesClothes": 0, - "otherExpensesEntertainment": 0, - "otherExpensesFood": 0, - "otherExpensesMedical": 0, - "otherExpensesOther": 0, - "otherExpensesPhone": 0, - "otherExpensesTransport": 0, - "otherExpensesUtilities": 0, - "otherIncome": 0, - "otherMedical": 0, - "pension": 0, - "phone": false, - "propertyTax": 0, - "rent": 0, - "rentShare": 0, - "socialSecurity": 0, - "unemployment": 0, - "wantsToSeeOtherExpenses": false, - "workersComp": 0, }, - "future": Object { - "SSDI": 0, - "SSI": 0, - "TAFDC": 0, - "adultDirectCare": 0, - "adultOtherCare": 0, - "adultTransportation": 0, - "alimony": 0, - "benefits": Array [], - "childBeforeAndAfterSchoolCare": 0, - "childDirectCare": 0, - "childOtherCare": 0, - "childSupportIn": 0, - "childSupportPaidOut": 0, - "childTransportation": 0, - "climateControl": false, - "contractRent": 0, - "disabledAssistance": 0, - "disabledMedical": 0, - "earned": 100, - "earnedBecauseOfAdultCare": 0, - "earnedBecauseOfChildCare": 0, - "fuelAssistance": false, - "household": Array [ - Object { - "m_age": 30, - "m_disabled": false, - "m_role": "head", + future: Immutable.Map { + otherExpensesCareProducts: 0, + otherMedical: 0, + otherExpensesPhone: 0, + workersComp: 0, + childOtherCare: 0, + earnedBecauseOfAdultCare: 0, + SSDI: 0, + unemployment: 0, + otherExpensesOther: 0, + childBeforeAndAfterSchoolCare: 0, + rentShare: 0, + otherExpensesMedical: 0, + adultTransportation: 0, + adultOtherCare: 0, + earnedBecauseOfChildCare: 0, + childTransportation: 0, + otherExpensesFood: 0, + SSI: 0, + alimony: 0, + contractRent: 0, + socialSecurity: 0, + phone: false, + fuelAssistance: false, + pension: 0, + childSupportPaidOut: 0, + otherExpensesCable: 0, + disabledAssistance: 0, + nonHeatElectricity: false, + adultDirectCare: 0, + disabledMedical: 0, + childDirectCare: 0, + propertyTax: 0, + wantsToSeeOtherExpenses: false, + earned: 100, + climateControl: false, + TAFDC: 0, + childSupportIn: 0, + otherIncome: 0, + rent: 0, + mortgage: 0, + benefits: Immutable.Set [ + ], + otherExpensesEntertainment: 0, + housingInsurance: 0, + otherExpensesClothes: 0, + housing: "homeless", + otherExpensesTransport: 0, + otherExpensesUtilities: 0, + household: Immutable.List [ + Immutable.Map { + m_age: 30, + m_role: "head", + m_disabled: false, }, ], - "housing": "homeless", - "housingInsurance": 0, - "mortgage": 0, - "nonHeatElectricity": false, - "otherExpensesCable": 0, - "otherExpensesCareProducts": 0, - "otherExpensesClothes": 0, - "otherExpensesEntertainment": 0, - "otherExpensesFood": 0, - "otherExpensesMedical": 0, - "otherExpensesOther": 0, - "otherExpensesPhone": 0, - "otherExpensesTransport": 0, - "otherExpensesUtilities": 0, - "otherIncome": 0, - "otherMedical": 0, - "pension": 0, - "phone": false, - "propertyTax": 0, - "rent": 0, - "rentShare": 0, - "socialSecurity": 0, - "unemployment": 0, - "wantsToSeeOtherExpenses": false, - "workersComp": 0, }, } } @@ -2707,119 +2717,122 @@ exports[` renders with snap and current earned less than futu } className="some-class" client={ - Object { - "USState": "MA", - "current": Object { - "SSDI": 0, - "SSI": 0, - "TAFDC": 0, - "adultDirectCare": 0, - "adultOtherCare": 0, - "adultTransportation": 0, - "alimony": 0, - "benefits": Array [], - "childBeforeAndAfterSchoolCare": 0, - "childDirectCare": 0, - "childOtherCare": 0, - "childSupportIn": 0, - "childSupportPaidOut": 0, - "childTransportation": 0, - "climateControl": false, - "contractRent": 0, - "disabledAssistance": 0, - "disabledMedical": 0, - "earned": 100, - "earnedBecauseOfAdultCare": 0, - "earnedBecauseOfChildCare": 0, - "fuelAssistance": false, - "household": Array [ - Object { - "m_age": 30, - "m_disabled": false, - "m_role": "head", + Immutable.Map { + USState: "MA", + current: Immutable.Map { + otherExpensesCareProducts: 0, + otherMedical: 0, + otherExpensesPhone: 0, + workersComp: 0, + childOtherCare: 0, + earnedBecauseOfAdultCare: 0, + SSDI: 0, + unemployment: 0, + otherExpensesOther: 0, + childBeforeAndAfterSchoolCare: 0, + rentShare: 0, + otherExpensesMedical: 0, + adultTransportation: 0, + adultOtherCare: 0, + earnedBecauseOfChildCare: 0, + childTransportation: 0, + otherExpensesFood: 0, + SSI: 0, + alimony: 0, + contractRent: 0, + socialSecurity: 0, + phone: false, + fuelAssistance: false, + pension: 0, + childSupportPaidOut: 0, + otherExpensesCable: 0, + disabledAssistance: 0, + nonHeatElectricity: false, + adultDirectCare: 0, + disabledMedical: 0, + childDirectCare: 0, + propertyTax: 0, + wantsToSeeOtherExpenses: false, + earned: 100, + climateControl: false, + TAFDC: 0, + childSupportIn: 0, + otherIncome: 0, + rent: 0, + mortgage: 0, + benefits: Immutable.Set [ + "snap", + ], + otherExpensesEntertainment: 0, + housingInsurance: 0, + otherExpensesClothes: 0, + housing: "homeless", + otherExpensesTransport: 0, + otherExpensesUtilities: 0, + household: Immutable.List [ + Immutable.Map { + m_age: 30, + m_role: "head", + m_disabled: false, }, ], - "housing": "homeless", - "housingInsurance": 0, - "mortgage": 0, - "nonHeatElectricity": false, - "otherExpensesCable": 0, - "otherExpensesCareProducts": 0, - "otherExpensesClothes": 0, - "otherExpensesEntertainment": 0, - "otherExpensesFood": 0, - "otherExpensesMedical": 0, - "otherExpensesOther": 0, - "otherExpensesPhone": 0, - "otherExpensesTransport": 0, - "otherExpensesUtilities": 0, - "otherIncome": 0, - "otherMedical": 0, - "pension": 0, - "phone": false, - "propertyTax": 0, - "rent": 0, - "rentShare": 0, - "socialSecurity": 0, - "unemployment": 0, - "wantsToSeeOtherExpenses": false, - "workersComp": 0, }, - "future": Object { - "SSDI": 0, - "SSI": 0, - "TAFDC": 0, - "adultDirectCare": 0, - "adultOtherCare": 0, - "adultTransportation": 0, - "alimony": 0, - "benefits": Array [], - "childBeforeAndAfterSchoolCare": 0, - "childDirectCare": 0, - "childOtherCare": 0, - "childSupportIn": 0, - "childSupportPaidOut": 0, - "childTransportation": 0, - "climateControl": false, - "contractRent": 0, - "disabledAssistance": 0, - "disabledMedical": 0, - "earned": 200, - "earnedBecauseOfAdultCare": 0, - "earnedBecauseOfChildCare": 0, - "fuelAssistance": false, - "household": Array [ - Object { - "m_age": 30, - "m_disabled": false, - "m_role": "head", + future: Immutable.Map { + otherExpensesCareProducts: 0, + otherMedical: 0, + otherExpensesPhone: 0, + workersComp: 0, + childOtherCare: 0, + earnedBecauseOfAdultCare: 0, + SSDI: 0, + unemployment: 0, + otherExpensesOther: 0, + childBeforeAndAfterSchoolCare: 0, + rentShare: 0, + otherExpensesMedical: 0, + adultTransportation: 0, + adultOtherCare: 0, + earnedBecauseOfChildCare: 0, + childTransportation: 0, + otherExpensesFood: 0, + SSI: 0, + alimony: 0, + contractRent: 0, + socialSecurity: 0, + phone: false, + fuelAssistance: false, + pension: 0, + childSupportPaidOut: 0, + otherExpensesCable: 0, + disabledAssistance: 0, + nonHeatElectricity: false, + adultDirectCare: 0, + disabledMedical: 0, + childDirectCare: 0, + propertyTax: 0, + wantsToSeeOtherExpenses: false, + earned: 200, + climateControl: false, + TAFDC: 0, + childSupportIn: 0, + otherIncome: 0, + rent: 0, + mortgage: 0, + benefits: Immutable.Set [ + ], + otherExpensesEntertainment: 0, + housingInsurance: 0, + otherExpensesClothes: 0, + housing: "homeless", + otherExpensesTransport: 0, + otherExpensesUtilities: 0, + household: Immutable.List [ + Immutable.Map { + m_age: 30, + m_role: "head", + m_disabled: false, }, ], - "housing": "homeless", - "housingInsurance": 0, - "mortgage": 0, - "nonHeatElectricity": false, - "otherExpensesCable": 0, - "otherExpensesCareProducts": 0, - "otherExpensesClothes": 0, - "otherExpensesEntertainment": 0, - "otherExpensesFood": 0, - "otherExpensesMedical": 0, - "otherExpensesOther": 0, - "otherExpensesPhone": 0, - "otherExpensesTransport": 0, - "otherExpensesUtilities": 0, - "otherIncome": 0, - "otherMedical": 0, - "pension": 0, - "phone": false, - "propertyTax": 0, - "rent": 0, - "rentShare": 0, - "socialSecurity": 0, - "unemployment": 0, - "wantsToSeeOtherExpenses": false, - "workersComp": 0, }, } } diff --git a/src/test/forms/output/__snapshots__/StackedAreaGraph.test.js.snap b/src/test/forms/output/__snapshots__/StackedAreaGraph.test.js.snap index 66090f74..24e579e2 100644 --- a/src/test/forms/output/__snapshots__/StackedAreaGraph.test.js.snap +++ b/src/test/forms/output/__snapshots__/StackedAreaGraph.test.js.snap @@ -9,119 +9,121 @@ exports[` renders with both snap and section8 1`] = ` ] } client={ - Object { - "USState": "MA", - "current": Object { - "SSDI": 0, - "SSI": 0, - "TAFDC": 0, - "adultDirectCare": 0, - "adultOtherCare": 0, - "adultTransportation": 0, - "alimony": 0, - "benefits": Array [], - "childBeforeAndAfterSchoolCare": 0, - "childDirectCare": 0, - "childOtherCare": 0, - "childSupportIn": 0, - "childSupportPaidOut": 0, - "childTransportation": 0, - "climateControl": false, - "contractRent": 0, - "disabledAssistance": 0, - "disabledMedical": 0, - "earned": 100, - "earnedBecauseOfAdultCare": 0, - "earnedBecauseOfChildCare": 0, - "fuelAssistance": false, - "household": Array [ - Object { - "m_age": 30, - "m_disabled": false, - "m_role": "head", + Immutable.Map { + USState: "MA", + current: Immutable.Map { + otherExpensesCareProducts: 0, + otherMedical: 0, + otherExpensesPhone: 0, + workersComp: 0, + childOtherCare: 0, + earnedBecauseOfAdultCare: 0, + SSDI: 0, + unemployment: 0, + otherExpensesOther: 0, + childBeforeAndAfterSchoolCare: 0, + rentShare: 0, + otherExpensesMedical: 0, + adultTransportation: 0, + adultOtherCare: 0, + earnedBecauseOfChildCare: 0, + childTransportation: 0, + otherExpensesFood: 0, + SSI: 0, + alimony: 0, + contractRent: 0, + socialSecurity: 0, + phone: false, + fuelAssistance: false, + pension: 0, + childSupportPaidOut: 0, + otherExpensesCable: 0, + disabledAssistance: 0, + nonHeatElectricity: false, + adultDirectCare: 0, + disabledMedical: 0, + childDirectCare: 0, + propertyTax: 0, + wantsToSeeOtherExpenses: false, + earned: 100, + climateControl: false, + TAFDC: 0, + childSupportIn: 0, + otherIncome: 0, + rent: 0, + mortgage: 0, + benefits: Immutable.Set [ + ], + otherExpensesEntertainment: 0, + housingInsurance: 0, + otherExpensesClothes: 0, + housing: "homeless", + otherExpensesTransport: 0, + otherExpensesUtilities: 0, + household: Immutable.List [ + Immutable.Map { + m_age: 30, + m_role: "head", + m_disabled: false, }, ], - "housing": "homeless", - "housingInsurance": 0, - "mortgage": 0, - "nonHeatElectricity": false, - "otherExpensesCable": 0, - "otherExpensesCareProducts": 0, - "otherExpensesClothes": 0, - "otherExpensesEntertainment": 0, - "otherExpensesFood": 0, - "otherExpensesMedical": 0, - "otherExpensesOther": 0, - "otherExpensesPhone": 0, - "otherExpensesTransport": 0, - "otherExpensesUtilities": 0, - "otherIncome": 0, - "otherMedical": 0, - "pension": 0, - "phone": false, - "propertyTax": 0, - "rent": 0, - "rentShare": 0, - "socialSecurity": 0, - "unemployment": 0, - "wantsToSeeOtherExpenses": false, - "workersComp": 0, }, - "future": Object { - "SSDI": 0, - "SSI": 0, - "TAFDC": 0, - "adultDirectCare": 0, - "adultOtherCare": 0, - "adultTransportation": 0, - "alimony": 0, - "benefits": Array [], - "childBeforeAndAfterSchoolCare": 0, - "childDirectCare": 0, - "childOtherCare": 0, - "childSupportIn": 0, - "childSupportPaidOut": 0, - "childTransportation": 0, - "climateControl": false, - "contractRent": 0, - "disabledAssistance": 0, - "disabledMedical": 0, - "earned": 200, - "earnedBecauseOfAdultCare": 0, - "earnedBecauseOfChildCare": 0, - "fuelAssistance": false, - "household": Array [ - Object { - "m_age": 30, - "m_disabled": false, - "m_role": "head", + future: Immutable.Map { + otherExpensesCareProducts: 0, + otherMedical: 0, + otherExpensesPhone: 0, + workersComp: 0, + childOtherCare: 0, + earnedBecauseOfAdultCare: 0, + SSDI: 0, + unemployment: 0, + otherExpensesOther: 0, + childBeforeAndAfterSchoolCare: 0, + rentShare: 0, + otherExpensesMedical: 0, + adultTransportation: 0, + adultOtherCare: 0, + earnedBecauseOfChildCare: 0, + childTransportation: 0, + otherExpensesFood: 0, + SSI: 0, + alimony: 0, + contractRent: 0, + socialSecurity: 0, + phone: false, + fuelAssistance: false, + pension: 0, + childSupportPaidOut: 0, + otherExpensesCable: 0, + disabledAssistance: 0, + nonHeatElectricity: false, + adultDirectCare: 0, + disabledMedical: 0, + childDirectCare: 0, + propertyTax: 0, + wantsToSeeOtherExpenses: false, + earned: 200, + climateControl: false, + TAFDC: 0, + childSupportIn: 0, + otherIncome: 0, + rent: 0, + mortgage: 0, + benefits: Immutable.Set [ + ], + otherExpensesEntertainment: 0, + housingInsurance: 0, + otherExpensesClothes: 0, + housing: "homeless", + otherExpensesTransport: 0, + otherExpensesUtilities: 0, + household: Immutable.List [ + Immutable.Map { + m_age: 30, + m_role: "head", + m_disabled: false, }, ], - "housing": "homeless", - "housingInsurance": 0, - "mortgage": 0, - "nonHeatElectricity": false, - "otherExpensesCable": 0, - "otherExpensesCareProducts": 0, - "otherExpensesClothes": 0, - "otherExpensesEntertainment": 0, - "otherExpensesFood": 0, - "otherExpensesMedical": 0, - "otherExpensesOther": 0, - "otherExpensesPhone": 0, - "otherExpensesTransport": 0, - "otherExpensesUtilities": 0, - "otherIncome": 0, - "otherMedical": 0, - "pension": 0, - "phone": false, - "propertyTax": 0, - "rent": 0, - "rentShare": 0, - "socialSecurity": 0, - "unemployment": 0, - "wantsToSeeOtherExpenses": false, - "workersComp": 0, }, } } @@ -1277,119 +1279,121 @@ exports[` renders with section8 1`] = ` ] } client={ - Object { - "USState": "MA", - "current": Object { - "SSDI": 0, - "SSI": 0, - "TAFDC": 0, - "adultDirectCare": 0, - "adultOtherCare": 0, - "adultTransportation": 0, - "alimony": 0, - "benefits": Array [], - "childBeforeAndAfterSchoolCare": 0, - "childDirectCare": 0, - "childOtherCare": 0, - "childSupportIn": 0, - "childSupportPaidOut": 0, - "childTransportation": 0, - "climateControl": false, - "contractRent": 0, - "disabledAssistance": 0, - "disabledMedical": 0, - "earned": 100, - "earnedBecauseOfAdultCare": 0, - "earnedBecauseOfChildCare": 0, - "fuelAssistance": false, - "household": Array [ - Object { - "m_age": 30, - "m_disabled": false, - "m_role": "head", + Immutable.Map { + USState: "MA", + current: Immutable.Map { + otherExpensesCareProducts: 0, + otherMedical: 0, + otherExpensesPhone: 0, + workersComp: 0, + childOtherCare: 0, + earnedBecauseOfAdultCare: 0, + SSDI: 0, + unemployment: 0, + otherExpensesOther: 0, + childBeforeAndAfterSchoolCare: 0, + rentShare: 0, + otherExpensesMedical: 0, + adultTransportation: 0, + adultOtherCare: 0, + earnedBecauseOfChildCare: 0, + childTransportation: 0, + otherExpensesFood: 0, + SSI: 0, + alimony: 0, + contractRent: 0, + socialSecurity: 0, + phone: false, + fuelAssistance: false, + pension: 0, + childSupportPaidOut: 0, + otherExpensesCable: 0, + disabledAssistance: 0, + nonHeatElectricity: false, + adultDirectCare: 0, + disabledMedical: 0, + childDirectCare: 0, + propertyTax: 0, + wantsToSeeOtherExpenses: false, + earned: 100, + climateControl: false, + TAFDC: 0, + childSupportIn: 0, + otherIncome: 0, + rent: 0, + mortgage: 0, + benefits: Immutable.Set [ + ], + otherExpensesEntertainment: 0, + housingInsurance: 0, + otherExpensesClothes: 0, + housing: "homeless", + otherExpensesTransport: 0, + otherExpensesUtilities: 0, + household: Immutable.List [ + Immutable.Map { + m_age: 30, + m_role: "head", + m_disabled: false, }, ], - "housing": "homeless", - "housingInsurance": 0, - "mortgage": 0, - "nonHeatElectricity": false, - "otherExpensesCable": 0, - "otherExpensesCareProducts": 0, - "otherExpensesClothes": 0, - "otherExpensesEntertainment": 0, - "otherExpensesFood": 0, - "otherExpensesMedical": 0, - "otherExpensesOther": 0, - "otherExpensesPhone": 0, - "otherExpensesTransport": 0, - "otherExpensesUtilities": 0, - "otherIncome": 0, - "otherMedical": 0, - "pension": 0, - "phone": false, - "propertyTax": 0, - "rent": 0, - "rentShare": 0, - "socialSecurity": 0, - "unemployment": 0, - "wantsToSeeOtherExpenses": false, - "workersComp": 0, }, - "future": Object { - "SSDI": 0, - "SSI": 0, - "TAFDC": 0, - "adultDirectCare": 0, - "adultOtherCare": 0, - "adultTransportation": 0, - "alimony": 0, - "benefits": Array [], - "childBeforeAndAfterSchoolCare": 0, - "childDirectCare": 0, - "childOtherCare": 0, - "childSupportIn": 0, - "childSupportPaidOut": 0, - "childTransportation": 0, - "climateControl": false, - "contractRent": 0, - "disabledAssistance": 0, - "disabledMedical": 0, - "earned": 200, - "earnedBecauseOfAdultCare": 0, - "earnedBecauseOfChildCare": 0, - "fuelAssistance": false, - "household": Array [ - Object { - "m_age": 30, - "m_disabled": false, - "m_role": "head", + future: Immutable.Map { + otherExpensesCareProducts: 0, + otherMedical: 0, + otherExpensesPhone: 0, + workersComp: 0, + childOtherCare: 0, + earnedBecauseOfAdultCare: 0, + SSDI: 0, + unemployment: 0, + otherExpensesOther: 0, + childBeforeAndAfterSchoolCare: 0, + rentShare: 0, + otherExpensesMedical: 0, + adultTransportation: 0, + adultOtherCare: 0, + earnedBecauseOfChildCare: 0, + childTransportation: 0, + otherExpensesFood: 0, + SSI: 0, + alimony: 0, + contractRent: 0, + socialSecurity: 0, + phone: false, + fuelAssistance: false, + pension: 0, + childSupportPaidOut: 0, + otherExpensesCable: 0, + disabledAssistance: 0, + nonHeatElectricity: false, + adultDirectCare: 0, + disabledMedical: 0, + childDirectCare: 0, + propertyTax: 0, + wantsToSeeOtherExpenses: false, + earned: 200, + climateControl: false, + TAFDC: 0, + childSupportIn: 0, + otherIncome: 0, + rent: 0, + mortgage: 0, + benefits: Immutable.Set [ + ], + otherExpensesEntertainment: 0, + housingInsurance: 0, + otherExpensesClothes: 0, + housing: "homeless", + otherExpensesTransport: 0, + otherExpensesUtilities: 0, + household: Immutable.List [ + Immutable.Map { + m_age: 30, + m_role: "head", + m_disabled: false, }, ], - "housing": "homeless", - "housingInsurance": 0, - "mortgage": 0, - "nonHeatElectricity": false, - "otherExpensesCable": 0, - "otherExpensesCareProducts": 0, - "otherExpensesClothes": 0, - "otherExpensesEntertainment": 0, - "otherExpensesFood": 0, - "otherExpensesMedical": 0, - "otherExpensesOther": 0, - "otherExpensesPhone": 0, - "otherExpensesTransport": 0, - "otherExpensesUtilities": 0, - "otherIncome": 0, - "otherMedical": 0, - "pension": 0, - "phone": false, - "propertyTax": 0, - "rent": 0, - "rentShare": 0, - "socialSecurity": 0, - "unemployment": 0, - "wantsToSeeOtherExpenses": false, - "workersComp": 0, }, } } @@ -2341,119 +2345,121 @@ exports[` renders with snap and current earned greater than fu ] } client={ - Object { - "USState": "MA", - "current": Object { - "SSDI": 0, - "SSI": 0, - "TAFDC": 0, - "adultDirectCare": 0, - "adultOtherCare": 0, - "adultTransportation": 0, - "alimony": 0, - "benefits": Array [], - "childBeforeAndAfterSchoolCare": 0, - "childDirectCare": 0, - "childOtherCare": 0, - "childSupportIn": 0, - "childSupportPaidOut": 0, - "childTransportation": 0, - "climateControl": false, - "contractRent": 0, - "disabledAssistance": 0, - "disabledMedical": 0, - "earned": 200, - "earnedBecauseOfAdultCare": 0, - "earnedBecauseOfChildCare": 0, - "fuelAssistance": false, - "household": Array [ - Object { - "m_age": 30, - "m_disabled": false, - "m_role": "head", + Immutable.Map { + USState: "MA", + current: Immutable.Map { + otherExpensesCareProducts: 0, + otherMedical: 0, + otherExpensesPhone: 0, + workersComp: 0, + childOtherCare: 0, + earnedBecauseOfAdultCare: 0, + SSDI: 0, + unemployment: 0, + otherExpensesOther: 0, + childBeforeAndAfterSchoolCare: 0, + rentShare: 0, + otherExpensesMedical: 0, + adultTransportation: 0, + adultOtherCare: 0, + earnedBecauseOfChildCare: 0, + childTransportation: 0, + otherExpensesFood: 0, + SSI: 0, + alimony: 0, + contractRent: 0, + socialSecurity: 0, + phone: false, + fuelAssistance: false, + pension: 0, + childSupportPaidOut: 0, + otherExpensesCable: 0, + disabledAssistance: 0, + nonHeatElectricity: false, + adultDirectCare: 0, + disabledMedical: 0, + childDirectCare: 0, + propertyTax: 0, + wantsToSeeOtherExpenses: false, + earned: 200, + climateControl: false, + TAFDC: 0, + childSupportIn: 0, + otherIncome: 0, + rent: 0, + mortgage: 0, + benefits: Immutable.Set [ + ], + otherExpensesEntertainment: 0, + housingInsurance: 0, + otherExpensesClothes: 0, + housing: "homeless", + otherExpensesTransport: 0, + otherExpensesUtilities: 0, + household: Immutable.List [ + Immutable.Map { + m_age: 30, + m_role: "head", + m_disabled: false, }, ], - "housing": "homeless", - "housingInsurance": 0, - "mortgage": 0, - "nonHeatElectricity": false, - "otherExpensesCable": 0, - "otherExpensesCareProducts": 0, - "otherExpensesClothes": 0, - "otherExpensesEntertainment": 0, - "otherExpensesFood": 0, - "otherExpensesMedical": 0, - "otherExpensesOther": 0, - "otherExpensesPhone": 0, - "otherExpensesTransport": 0, - "otherExpensesUtilities": 0, - "otherIncome": 0, - "otherMedical": 0, - "pension": 0, - "phone": false, - "propertyTax": 0, - "rent": 0, - "rentShare": 0, - "socialSecurity": 0, - "unemployment": 0, - "wantsToSeeOtherExpenses": false, - "workersComp": 0, }, - "future": Object { - "SSDI": 0, - "SSI": 0, - "TAFDC": 0, - "adultDirectCare": 0, - "adultOtherCare": 0, - "adultTransportation": 0, - "alimony": 0, - "benefits": Array [], - "childBeforeAndAfterSchoolCare": 0, - "childDirectCare": 0, - "childOtherCare": 0, - "childSupportIn": 0, - "childSupportPaidOut": 0, - "childTransportation": 0, - "climateControl": false, - "contractRent": 0, - "disabledAssistance": 0, - "disabledMedical": 0, - "earned": 100, - "earnedBecauseOfAdultCare": 0, - "earnedBecauseOfChildCare": 0, - "fuelAssistance": false, - "household": Array [ - Object { - "m_age": 30, - "m_disabled": false, - "m_role": "head", + future: Immutable.Map { + otherExpensesCareProducts: 0, + otherMedical: 0, + otherExpensesPhone: 0, + workersComp: 0, + childOtherCare: 0, + earnedBecauseOfAdultCare: 0, + SSDI: 0, + unemployment: 0, + otherExpensesOther: 0, + childBeforeAndAfterSchoolCare: 0, + rentShare: 0, + otherExpensesMedical: 0, + adultTransportation: 0, + adultOtherCare: 0, + earnedBecauseOfChildCare: 0, + childTransportation: 0, + otherExpensesFood: 0, + SSI: 0, + alimony: 0, + contractRent: 0, + socialSecurity: 0, + phone: false, + fuelAssistance: false, + pension: 0, + childSupportPaidOut: 0, + otherExpensesCable: 0, + disabledAssistance: 0, + nonHeatElectricity: false, + adultDirectCare: 0, + disabledMedical: 0, + childDirectCare: 0, + propertyTax: 0, + wantsToSeeOtherExpenses: false, + earned: 100, + climateControl: false, + TAFDC: 0, + childSupportIn: 0, + otherIncome: 0, + rent: 0, + mortgage: 0, + benefits: Immutable.Set [ + ], + otherExpensesEntertainment: 0, + housingInsurance: 0, + otherExpensesClothes: 0, + housing: "homeless", + otherExpensesTransport: 0, + otherExpensesUtilities: 0, + household: Immutable.List [ + Immutable.Map { + m_age: 30, + m_role: "head", + m_disabled: false, }, ], - "housing": "homeless", - "housingInsurance": 0, - "mortgage": 0, - "nonHeatElectricity": false, - "otherExpensesCable": 0, - "otherExpensesCareProducts": 0, - "otherExpensesClothes": 0, - "otherExpensesEntertainment": 0, - "otherExpensesFood": 0, - "otherExpensesMedical": 0, - "otherExpensesOther": 0, - "otherExpensesPhone": 0, - "otherExpensesTransport": 0, - "otherExpensesUtilities": 0, - "otherIncome": 0, - "otherMedical": 0, - "pension": 0, - "phone": false, - "propertyTax": 0, - "rent": 0, - "rentShare": 0, - "socialSecurity": 0, - "unemployment": 0, - "wantsToSeeOtherExpenses": false, - "workersComp": 0, }, } } @@ -3405,119 +3411,121 @@ exports[` renders with snap and current earned less than futur ] } client={ - Object { - "USState": "MA", - "current": Object { - "SSDI": 0, - "SSI": 0, - "TAFDC": 0, - "adultDirectCare": 0, - "adultOtherCare": 0, - "adultTransportation": 0, - "alimony": 0, - "benefits": Array [], - "childBeforeAndAfterSchoolCare": 0, - "childDirectCare": 0, - "childOtherCare": 0, - "childSupportIn": 0, - "childSupportPaidOut": 0, - "childTransportation": 0, - "climateControl": false, - "contractRent": 0, - "disabledAssistance": 0, - "disabledMedical": 0, - "earned": 100, - "earnedBecauseOfAdultCare": 0, - "earnedBecauseOfChildCare": 0, - "fuelAssistance": false, - "household": Array [ - Object { - "m_age": 30, - "m_disabled": false, - "m_role": "head", + Immutable.Map { + USState: "MA", + current: Immutable.Map { + otherExpensesCareProducts: 0, + otherMedical: 0, + otherExpensesPhone: 0, + workersComp: 0, + childOtherCare: 0, + earnedBecauseOfAdultCare: 0, + SSDI: 0, + unemployment: 0, + otherExpensesOther: 0, + childBeforeAndAfterSchoolCare: 0, + rentShare: 0, + otherExpensesMedical: 0, + adultTransportation: 0, + adultOtherCare: 0, + earnedBecauseOfChildCare: 0, + childTransportation: 0, + otherExpensesFood: 0, + SSI: 0, + alimony: 0, + contractRent: 0, + socialSecurity: 0, + phone: false, + fuelAssistance: false, + pension: 0, + childSupportPaidOut: 0, + otherExpensesCable: 0, + disabledAssistance: 0, + nonHeatElectricity: false, + adultDirectCare: 0, + disabledMedical: 0, + childDirectCare: 0, + propertyTax: 0, + wantsToSeeOtherExpenses: false, + earned: 100, + climateControl: false, + TAFDC: 0, + childSupportIn: 0, + otherIncome: 0, + rent: 0, + mortgage: 0, + benefits: Immutable.Set [ + ], + otherExpensesEntertainment: 0, + housingInsurance: 0, + otherExpensesClothes: 0, + housing: "homeless", + otherExpensesTransport: 0, + otherExpensesUtilities: 0, + household: Immutable.List [ + Immutable.Map { + m_age: 30, + m_role: "head", + m_disabled: false, }, ], - "housing": "homeless", - "housingInsurance": 0, - "mortgage": 0, - "nonHeatElectricity": false, - "otherExpensesCable": 0, - "otherExpensesCareProducts": 0, - "otherExpensesClothes": 0, - "otherExpensesEntertainment": 0, - "otherExpensesFood": 0, - "otherExpensesMedical": 0, - "otherExpensesOther": 0, - "otherExpensesPhone": 0, - "otherExpensesTransport": 0, - "otherExpensesUtilities": 0, - "otherIncome": 0, - "otherMedical": 0, - "pension": 0, - "phone": false, - "propertyTax": 0, - "rent": 0, - "rentShare": 0, - "socialSecurity": 0, - "unemployment": 0, - "wantsToSeeOtherExpenses": false, - "workersComp": 0, }, - "future": Object { - "SSDI": 0, - "SSI": 0, - "TAFDC": 0, - "adultDirectCare": 0, - "adultOtherCare": 0, - "adultTransportation": 0, - "alimony": 0, - "benefits": Array [], - "childBeforeAndAfterSchoolCare": 0, - "childDirectCare": 0, - "childOtherCare": 0, - "childSupportIn": 0, - "childSupportPaidOut": 0, - "childTransportation": 0, - "climateControl": false, - "contractRent": 0, - "disabledAssistance": 0, - "disabledMedical": 0, - "earned": 200, - "earnedBecauseOfAdultCare": 0, - "earnedBecauseOfChildCare": 0, - "fuelAssistance": false, - "household": Array [ - Object { - "m_age": 30, - "m_disabled": false, - "m_role": "head", + future: Immutable.Map { + otherExpensesCareProducts: 0, + otherMedical: 0, + otherExpensesPhone: 0, + workersComp: 0, + childOtherCare: 0, + earnedBecauseOfAdultCare: 0, + SSDI: 0, + unemployment: 0, + otherExpensesOther: 0, + childBeforeAndAfterSchoolCare: 0, + rentShare: 0, + otherExpensesMedical: 0, + adultTransportation: 0, + adultOtherCare: 0, + earnedBecauseOfChildCare: 0, + childTransportation: 0, + otherExpensesFood: 0, + SSI: 0, + alimony: 0, + contractRent: 0, + socialSecurity: 0, + phone: false, + fuelAssistance: false, + pension: 0, + childSupportPaidOut: 0, + otherExpensesCable: 0, + disabledAssistance: 0, + nonHeatElectricity: false, + adultDirectCare: 0, + disabledMedical: 0, + childDirectCare: 0, + propertyTax: 0, + wantsToSeeOtherExpenses: false, + earned: 200, + climateControl: false, + TAFDC: 0, + childSupportIn: 0, + otherIncome: 0, + rent: 0, + mortgage: 0, + benefits: Immutable.Set [ + ], + otherExpensesEntertainment: 0, + housingInsurance: 0, + otherExpensesClothes: 0, + housing: "homeless", + otherExpensesTransport: 0, + otherExpensesUtilities: 0, + household: Immutable.List [ + Immutable.Map { + m_age: 30, + m_role: "head", + m_disabled: false, }, ], - "housing": "homeless", - "housingInsurance": 0, - "mortgage": 0, - "nonHeatElectricity": false, - "otherExpensesCable": 0, - "otherExpensesCareProducts": 0, - "otherExpensesClothes": 0, - "otherExpensesEntertainment": 0, - "otherExpensesFood": 0, - "otherExpensesMedical": 0, - "otherExpensesOther": 0, - "otherExpensesPhone": 0, - "otherExpensesTransport": 0, - "otherExpensesUtilities": 0, - "otherIncome": 0, - "otherMedical": 0, - "pension": 0, - "phone": false, - "propertyTax": 0, - "rent": 0, - "rentShare": 0, - "socialSecurity": 0, - "unemployment": 0, - "wantsToSeeOtherExpenses": false, - "workersComp": 0, }, } } diff --git a/src/test/forms/output/__snapshots__/StackedBarGraph.test.js.snap b/src/test/forms/output/__snapshots__/StackedBarGraph.test.js.snap index 29f5f53f..b681b906 100644 --- a/src/test/forms/output/__snapshots__/StackedBarGraph.test.js.snap +++ b/src/test/forms/output/__snapshots__/StackedBarGraph.test.js.snap @@ -3,122 +3,123 @@ exports[` renders with both snap and section8 1`] = ` renders with both snap and section8 1`] = ` exports[` renders with section8 1`] = ` renders with section8 1`] = ` exports[` renders with snap and current earned greater than future earned 1`] = ` renders with snap and current earned greater than fut exports[` renders with snap and current earned less than future earned 1`] = ` { +import createReducer from '../../../reducers'; +import { setCashValue } from '../../../actions'; + +const reducer = createReducer(); + +const buildField = (state) => { const props = { - timeState: defaultsDeep({}, values, CLIENT_DEFAULTS.current), - updateClientValue: jest.fn(), + timeState: state.getIn([ + 'client', + 'current', + ]), + updateClientValue: function() {}, }; return mount(); }; describe('ContractRentField.storeValidator()', () => { it('when input valid, sets state to valid', () => { - const field = buildField({ rentShare: 0 }); + const state = reducer( + undefined, + setCashValue({ + time: 'current', + name: 'rentShare', + value: 0, + }) + ); + + const field = buildField(state); expect(field.state()).toEqual({ valid: true, message: null }); field.instance().storeValidator(1); @@ -24,7 +39,12 @@ describe('ContractRentField.storeValidator()', () => { }); it('when input negative, sets state to invalid', () => { - const field = buildField(); + const state = reducer( + undefined, + {} + ); + + const field = buildField(state); expect(field.state()).toEqual({ valid: true, message: null }); field.instance().storeValidator(-1); @@ -33,7 +53,16 @@ describe('ContractRentField.storeValidator()', () => { }); it('when contract rent less than rent share, sets state to invalid', () => { - const field = buildField({ rentShare: 2 }); + const state = reducer( + undefined, + setCashValue({ + time: 'current', + name: 'rentShare', + value: 2, + }) + ); + + const field = buildField(state); expect(field.state()).toEqual({ valid: true, message: null }); field.instance().storeValidator(1); @@ -44,7 +73,12 @@ describe('ContractRentField.storeValidator()', () => { describe('ContractRentField.onBlur', () => { it('resets state', () => { - const field = buildField(); + const state = reducer( + undefined, + {} + ); + + const field = buildField(state); field.setState({ valid: false, message: 'Not the default value' }); field.instance().onBlur(); diff --git a/src/test/forms/rentFields/PlainRentRow.test.js b/src/test/forms/rentFields/PlainRentRow.test.js index 3ff07736..31352ed8 100644 --- a/src/test/forms/rentFields/PlainRentRow.test.js +++ b/src/test/forms/rentFields/PlainRentRow.test.js @@ -1,15 +1,22 @@ import React from 'react'; import { mount } from 'enzyme'; -import { cloneDeep } from 'lodash'; -import { CLIENT_DEFAULTS } from '../../../utils/CLIENT_DEFAULTS'; import { PlainRentRow } from '../../../forms/rentFields'; +import createReducer from '../../../reducers'; + +const reducer = createReducer(); + describe('', () => { it('renders', () => { + const state = reducer(undefined, {}); + const props = { - timeState: cloneDeep(CLIENT_DEFAULTS.current), - updateClientValue: jest.fn(), + timeState: state.getIn([ + 'client', + 'current', + ]), + setValue: function() {}, }; expect(() => { mount(); diff --git a/src/test/forms/rentFields/RentShareField.test.js b/src/test/forms/rentFields/RentShareField.test.js index 50265230..4a482d32 100644 --- a/src/test/forms/rentFields/RentShareField.test.js +++ b/src/test/forms/rentFields/RentShareField.test.js @@ -1,21 +1,37 @@ import React from 'react'; import { mount } from 'enzyme'; -import { defaultsDeep } from 'lodash'; -import { CLIENT_DEFAULTS } from '../../../utils/CLIENT_DEFAULTS'; import { RentShareField } from '../../../forms/rentFields'; -const buildField = (values = {}) => { +import createReducer from '../../../reducers'; +import { setCashValue } from '../../../actions'; + +const reducer = createReducer(); + +const buildField = (state) => { const props = { - timeState: defaultsDeep({}, values, CLIENT_DEFAULTS.current), - updateClientValue: jest.fn(), + timeState: state.getIn([ + 'client', + 'current', + ]), + updateClientValue: function() {}, }; + return mount(); }; describe('RentShareField.storeValidator()', () => { it('when input valid, sets state to valid', () => { - const field = buildField({ contractRent: 2 }); + const state = reducer( + undefined, + setCashValue({ + time: 'current', + name: 'contractRent', + value: 2, + }) + ); + + const field = buildField(state); expect(field.state()).toEqual({ valid: true, message: null }); field.instance().storeValidator(1); @@ -24,7 +40,12 @@ describe('RentShareField.storeValidator()', () => { }); it('when input negative, sets state to invalid', () => { - const field = buildField(); + const state = reducer( + undefined, + {} + ); + + const field = buildField(state); expect(field.state()).toEqual({ valid: true, message: null }); field.instance().storeValidator(-1); @@ -33,7 +54,16 @@ describe('RentShareField.storeValidator()', () => { }); it('when rent share greater than contract rent, sets state to invalid', () => { - const field = buildField({ contractRent: 1 }); + const state = reducer( + undefined, + setCashValue({ + time: 'current', + name: 'contractRent', + value: 1, + }) + ); + + const field = buildField(state); expect(field.state()).toEqual({ valid: true, message: null }); field.instance().storeValidator(2); @@ -44,7 +74,12 @@ describe('RentShareField.storeValidator()', () => { describe('RentShareField.onBlur', () => { it('resets state', () => { - const field = buildField(); + const state = reducer( + undefined, + {} + ); + + const field = buildField(state); field.setState({ valid: false, message: 'Not the default value' }); field.instance().onBlur();