diff --git a/package-lock.json b/package-lock.json
index d26d98eea0d41766ed2bd1e8348799f014d34731..6f645d6359816e70a86080ba3db4c3cf143959bf 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -343,10 +343,13 @@
"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
},
"asn1": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
- "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=",
- "dev": true
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
+ "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+ "dev": true,
+ "requires": {
+ "safer-buffer": "~2.1.0"
+ }
},
"asn1.js": {
"version": "4.9.2",
@@ -1732,11 +1735,10 @@
"dev": true
},
"bcrypt-pbkdf": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
- "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+ "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
"dev": true,
- "optional": true,
"requires": {
"tweetnacl": "0.14.5"
}
@@ -2378,9 +2380,9 @@
"integrity": "sha1-+zgB1FNGdknvNgPH1hoCvRKb3m0="
},
"clean-css": {
- "version": "4.1.9",
- "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.1.9.tgz",
- "integrity": "sha1-Nc7ornaHpJuYA09w3gDE7dOCYwE=",
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.1.11.tgz",
+ "integrity": "sha1-Ls3xRaujj1R0DybO/Q/z4D4SXWo=",
"dev": true,
"requires": {
"source-map": "0.5.7"
@@ -3713,11 +3715,10 @@
"dev": true
},
"ecc-jsbn": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
- "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+ "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
"dev": true,
- "optional": true,
"requires": {
"jsbn": "0.1.1"
}
@@ -4138,9 +4139,9 @@
}
},
"esprima": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz",
- "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==",
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true
},
"globals": {
@@ -4150,9 +4151,9 @@
"dev": true
},
"js-yaml": {
- "version": "3.10.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz",
- "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==",
+ "version": "3.13.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.0.tgz",
+ "integrity": "sha512-pZZoSxcCYco+DIKBTimr67J6Hy+EYGZDY/HCWC+iAEA9h1ByhMXAIVUXMcMFpOCxQ/xjXmPI2MkDL5HRm5eFrQ==",
"dev": true,
"requires": {
"argparse": "1.0.9",
@@ -4421,9 +4422,9 @@
}
},
"esprima": {
- "version": "2.7.3",
- "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz",
- "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=",
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true
},
"esquery": {
@@ -4802,9 +4803,9 @@
"dev": true
},
"fill-range": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz",
- "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=",
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz",
+ "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==",
"dev": true,
"requires": {
"is-number": "2.1.0",
@@ -5006,9 +5007,9 @@
"dev": true
},
"fsevents": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.3.tgz",
- "integrity": "sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q==",
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.7.tgz",
+ "integrity": "sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw==",
"dev": true,
"optional": true,
"requires": {
@@ -5017,34 +5018,25 @@
},
"dependencies": {
"abbrev": {
- "version": "1.1.0",
+ "version": "1.1.1",
"bundled": true,
"dev": true,
"optional": true
},
- "ajv": {
- "version": "4.11.8",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "co": "^4.6.0",
- "json-stable-stringify": "^1.0.1"
- }
- },
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"aproba": {
- "version": "1.1.1",
+ "version": "1.2.0",
"bundled": true,
"dev": true,
"optional": true
},
"are-we-there-yet": {
- "version": "1.1.4",
+ "version": "1.1.5",
"bundled": true,
"dev": true,
"optional": true,
@@ -5053,36 +5045,6 @@
"readable-stream": "2.2.9"
}
},
- "asn1": {
- "version": "0.2.3",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "assert-plus": {
- "version": "0.2.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "asynckit": {
- "version": "0.4.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "aws-sign2": {
- "version": "0.6.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "aws4": {
- "version": "1.6.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
"balanced-match": {
"version": "0.4.2",
"bundled": true,
@@ -5109,32 +5071,20 @@
"version": "2.10.1",
"bundled": true,
"dev": true,
- "requires": {
- "hoek": "2.x.x"
- }
+ "optional": true
},
"brace-expansion": {
- "version": "1.1.7",
+ "version": "1.1.11",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
- "balanced-match": "^0.4.1",
+ "balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
- "buffer-shims": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true
- },
- "caseless": {
- "version": "0.12.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "co": {
- "version": "4.6.0",
+ "chownr": {
+ "version": "1.1.1",
"bundled": true,
"dev": true,
"optional": true
@@ -5142,11 +5092,6 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
- "dev": true
- },
- "combined-stream": {
- "version": "1.0.5",
- "bundled": true,
"dev": true,
"requires": {
"delayed-stream": "~1.0.0"
@@ -5155,45 +5100,23 @@
"concat-map": {
"version": "0.0.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"core-util-is": {
"version": "1.0.2",
"bundled": true,
- "dev": true
- },
- "cryptiles": {
- "version": "2.0.5",
- "bundled": true,
"dev": true,
- "requires": {
- "boom": "2.x.x"
- }
- },
- "dashdash": {
- "version": "1.14.1",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "assert-plus": "^1.0.0"
- },
- "dependencies": {
- "assert-plus": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true,
- "optional": true
- }
- }
+ "optional": true
},
"debug": {
- "version": "2.6.8",
+ "version": "2.6.9",
"bundled": true,
"dev": true,
"optional": true,
@@ -5202,13 +5125,7 @@
}
},
"deep-extend": {
- "version": "0.4.2",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "delayed-stream": {
- "version": "1.0.0",
+ "version": "0.6.0",
"bundled": true,
"dev": true
},
@@ -5219,46 +5136,18 @@
"optional": true
},
"detect-libc": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "ecc-jsbn": {
- "version": "0.1.1",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "jsbn": "~0.1.0"
- }
- },
- "extend": {
- "version": "3.0.1",
+ "version": "1.0.3",
"bundled": true,
"dev": true,
"optional": true
},
- "extsprintf": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true
- },
- "forever-agent": {
- "version": "0.6.1",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "form-data": {
- "version": "2.1.4",
+ "fs-minipass": {
+ "version": "1.2.5",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.5",
- "mime-types": "^2.1.12"
+ "minipass": "^2.2.1"
}
},
"fs.realpath": {
@@ -5304,27 +5193,11 @@
"wide-align": "1.1.2"
}
},
- "getpass": {
- "version": "0.1.7",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "assert-plus": "^1.0.0"
- },
- "dependencies": {
- "assert-plus": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true,
- "optional": true
- }
- }
- },
"glob": {
- "version": "7.1.2",
+ "version": "7.1.3",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"fs.realpath": "1.0.0",
"inflight": "1.0.6",
@@ -5334,37 +5207,17 @@
"path-is-absolute": "1.0.1"
}
},
- "graceful-fs": {
- "version": "4.1.11",
- "bundled": true,
- "dev": true
- },
- "har-schema": {
- "version": "1.0.5",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "har-validator": {
- "version": "4.2.1",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "ajv": "^4.9.1",
- "har-schema": "^1.0.5"
- }
- },
"has-unicode": {
"version": "2.0.1",
"bundled": true,
"dev": true,
"optional": true
},
- "hawk": {
- "version": "3.1.3",
+ "iconv-lite": {
+ "version": "0.4.24",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"boom": "2.10.1",
"cryptiles": "2.0.5",
@@ -5372,13 +5225,8 @@
"sntp": "1.0.9"
}
},
- "hoek": {
- "version": "2.16.3",
- "bundled": true,
- "dev": true
- },
- "http-signature": {
- "version": "1.1.1",
+ "ignore-walk": {
+ "version": "3.0.1",
"bundled": true,
"dev": true,
"optional": true,
@@ -5392,6 +5240,7 @@
"version": "1.0.6",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"once": "1.4.0",
"wrappy": "1.0.2"
@@ -5400,10 +5249,11 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"ini": {
- "version": "1.3.4",
+ "version": "1.3.5",
"bundled": true,
"dev": true,
"optional": true
@@ -5412,68 +5262,76 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
},
- "is-typedarray": {
+ "isarray": {
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true
},
- "isarray": {
- "version": "1.0.0",
+ "minimatch": {
+ "version": "3.0.4",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
},
- "isstream": {
- "version": "0.1.2",
+ "minimist": {
+ "version": "0.0.8",
"bundled": true,
"dev": true,
"optional": true
},
- "jodid25519": {
- "version": "1.0.2",
+ "minipass": {
+ "version": "2.3.5",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
- "jsbn": "~0.1.0"
+ "safe-buffer": "^5.1.2",
+ "yallist": "^3.0.0"
}
},
- "jsbn": {
- "version": "0.1.1",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "json-schema": {
- "version": "0.2.3",
+ "minizlib": {
+ "version": "1.2.1",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "minipass": "^2.2.1"
+ }
},
- "json-stable-stringify": {
- "version": "1.0.1",
+ "mkdirp": {
+ "version": "0.5.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
- "jsonify": "~0.0.0"
+ "minimist": "0.0.8"
}
},
- "json-stringify-safe": {
- "version": "5.0.1",
+ "ms": {
+ "version": "2.0.0",
"bundled": true,
"dev": true,
"optional": true
},
- "jsonify": {
- "version": "0.0.0",
+ "needle": {
+ "version": "2.2.4",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "debug": "^2.1.2",
+ "iconv-lite": "^0.4.4",
+ "sax": "^1.2.4"
+ }
},
"jsprim": {
"version": "1.4.0",
@@ -5564,8 +5422,24 @@
"osenv": "^0.1.4"
}
},
+ "npm-bundled": {
+ "version": "1.0.5",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "npm-packlist": {
+ "version": "1.2.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "ignore-walk": "^3.0.1",
+ "npm-bundled": "^1.0.1"
+ }
+ },
"npmlog": {
- "version": "4.1.0",
+ "version": "4.1.2",
"bundled": true,
"dev": true,
"optional": true,
@@ -5581,12 +5455,6 @@
"bundled": true,
"dev": true
},
- "oauth-sign": {
- "version": "0.8.2",
- "bundled": true,
- "dev": true,
- "optional": true
- },
"object-assign": {
"version": "4.1.1",
"bundled": true,
@@ -5597,6 +5465,7 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"wrappy": "1.0.2"
}
@@ -5614,7 +5483,7 @@
"optional": true
},
"osenv": {
- "version": "0.1.4",
+ "version": "0.1.5",
"bundled": true,
"dev": true,
"optional": true,
@@ -5626,33 +5495,17 @@
"path-is-absolute": {
"version": "1.0.1",
"bundled": true,
- "dev": true
- },
- "performance-now": {
- "version": "0.2.0",
- "bundled": true,
"dev": true,
"optional": true
},
"process-nextick-args": {
- "version": "1.0.7",
- "bundled": true,
- "dev": true
- },
- "punycode": {
- "version": "1.4.1",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "qs": {
- "version": "6.4.0",
+ "version": "2.0.0",
"bundled": true,
"dev": true,
"optional": true
},
"rc": {
- "version": "1.2.1",
+ "version": "1.2.8",
"bundled": true,
"dev": true,
"optional": true,
@@ -5672,9 +5525,10 @@
}
},
"readable-stream": {
- "version": "2.2.9",
+ "version": "2.3.6",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"buffer-shims": "1.0.0",
"core-util-is": "1.0.2",
@@ -5685,8 +5539,8 @@
"util-deprecate": "1.0.2"
}
},
- "request": {
- "version": "2.81.0",
+ "rimraf": {
+ "version": "2.6.3",
"bundled": true,
"dev": true,
"optional": true,
@@ -5715,21 +5569,28 @@
"uuid": "3.0.1"
}
},
- "rimraf": {
- "version": "2.6.1",
+ "safe-buffer": {
+ "version": "5.1.2",
"bundled": true,
"dev": true,
"requires": {
"glob": "7.1.2"
}
},
- "safe-buffer": {
- "version": "5.0.1",
+ "safer-buffer": {
+ "version": "2.1.2",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
+ },
+ "sax": {
+ "version": "1.2.4",
+ "bundled": true,
+ "dev": true,
+ "optional": true
},
"semver": {
- "version": "5.3.0",
+ "version": "5.6.0",
"bundled": true,
"dev": true,
"optional": true
@@ -5783,6 +5644,7 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"code-point-at": "1.1.0",
"is-fullwidth-code-point": "1.0.0",
@@ -5790,23 +5652,19 @@
}
},
"string_decoder": {
- "version": "1.0.1",
+ "version": "1.1.1",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"safe-buffer": "5.0.1"
}
},
- "stringstream": {
- "version": "0.0.5",
- "bundled": true,
- "dev": true,
- "optional": true
- },
"strip-ansi": {
"version": "3.0.1",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"ansi-regex": "2.1.1"
}
@@ -5861,40 +5719,14 @@
"safe-buffer": "5.0.1"
}
},
- "tweetnacl": {
- "version": "0.14.5",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "uid-number": {
- "version": "0.0.6",
- "bundled": true,
- "dev": true,
- "optional": true
- },
"util-deprecate": {
"version": "1.0.2",
"bundled": true,
- "dev": true
- },
- "uuid": {
- "version": "3.0.1",
- "bundled": true,
"dev": true,
"optional": true
},
- "verror": {
- "version": "1.3.6",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "extsprintf": "1.0.2"
- }
- },
"wide-align": {
- "version": "1.1.2",
+ "version": "1.1.3",
"bundled": true,
"dev": true,
"optional": true,
@@ -5905,7 +5737,14 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
+ },
+ "yallist": {
+ "version": "3.0.3",
+ "bundled": true,
+ "dev": true,
+ "optional": true
}
}
},
@@ -8025,9 +7864,9 @@
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
},
"js-yaml": {
- "version": "3.7.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz",
- "integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=",
+ "version": "3.13.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.0.tgz",
+ "integrity": "sha512-pZZoSxcCYco+DIKBTimr67J6Hy+EYGZDY/HCWC+iAEA9h1ByhMXAIVUXMcMFpOCxQ/xjXmPI2MkDL5HRm5eFrQ==",
"dev": true,
"requires": {
"argparse": "1.0.9",
@@ -8703,6 +8542,12 @@
"resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz",
"integrity": "sha1-3oGf282E3M2PrlnGrreWFbnSZqw="
},
+ "math-random": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz",
+ "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==",
+ "dev": true
+ },
"md5.js": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz",
@@ -8921,9 +8766,9 @@
"dev": true
},
"nan": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz",
- "integrity": "sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY=",
+ "version": "2.13.1",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.1.tgz",
+ "integrity": "sha512-I6YB/YEuDeUZMmhscXKxGgZlFnhsn5y0hgOZBadkzfTRrZBtJDZeg6eQf7PYMIEclwmorTKK8GztsyOUSVBREA==",
"dev": true,
"optional": true
},
@@ -8993,6 +8838,12 @@
"integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=",
"dev": true
},
+ "neo-async": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz",
+ "integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==",
+ "dev": true
+ },
"no-case": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz",
@@ -10766,9 +10617,9 @@
}
},
"original": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/original/-/original-1.0.0.tgz",
- "integrity": "sha1-kUf5P6FpbQS+YeAb1QuurKZWvTs=",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz",
+ "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==",
"dev": true,
"requires": {
"url-parse": "1.0.5"
@@ -12613,23 +12464,23 @@
"dev": true
},
"querystringify": {
- "version": "0.0.4",
- "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-0.0.4.tgz",
- "integrity": "sha1-DPf4T5Rj/wrlHExLFC2VvjdyTZw=",
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz",
+ "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==",
"dev": true
},
"raf": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.0.tgz",
- "integrity": "sha512-pDP/NMRAXoTfrhCfyfSEwJAKLaxBU9eApMeBPB1TkDouZmvPerIClV8lTAd+uF8ZiTaVl69e1FCxQrAd/VTjGw==",
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
+ "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
"requires": {
"performance-now": "2.1.0"
}
},
"randomatic": {
- "version": "1.1.7",
- "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz",
- "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==",
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz",
+ "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==",
"dev": true,
"requires": {
"is-number": "3.0.0",
@@ -14083,6 +13934,12 @@
"ret": "0.1.15"
}
},
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "dev": true
+ },
"sane": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/sane/-/sane-1.6.0.tgz",
@@ -14785,9 +14642,9 @@
"dev": true
},
"sshpk": {
- "version": "1.13.1",
- "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz",
- "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=",
+ "version": "1.16.1",
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
+ "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
"dev": true,
"requires": {
"asn1": "0.2.3",
@@ -15333,9 +15190,9 @@
}
},
"test-exclude": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.1.1.tgz",
- "integrity": "sha512-35+Asrsk3XHJDBgf/VRFexPgh3UyETv8IAn/LRTiZjVy6rjPVqdEk8dJcJYBzl1w0XCJM48lvTy8SfEsCWS4nA==",
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.2.3.tgz",
+ "integrity": "sha512-SYbXgY64PT+4GAL2ocI3HwPa4Q4TBKm0cwAVeKOt/Aoc0gSpNRjJX8w0pA1LMKZ3LBmd8pYBqApFNQLII9kavA==",
"dev": true,
"requires": {
"arrify": "1.0.1",
@@ -15554,8 +15411,7 @@
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
- "dev": true,
- "optional": true
+ "dev": true
},
"type-check": {
"version": "0.3.2",
@@ -15980,9 +15836,9 @@
}
},
"url-parse": {
- "version": "1.1.9",
- "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.1.9.tgz",
- "integrity": "sha1-xn8dd11R8KGJEd17P/rSe7nlvRk=",
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.4.tgz",
+ "integrity": "sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==",
"dev": true,
"requires": {
"querystringify": "1.0.0",
@@ -16118,9 +15974,9 @@
"dev": true
},
"watchpack": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.4.0.tgz",
- "integrity": "sha1-ShRyvLuVK9Cpu0A2gB+VTfs5+qw=",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz",
+ "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==",
"dev": true,
"requires": {
"async": "2.5.0",
diff --git a/src/components/Blocnote/BudgetSimulator/BudgetChart.js b/src/components/Blocnote/BudgetSimulator/BudgetChart.js
new file mode 100644
index 0000000000000000000000000000000000000000..516b8e71b11569735bc597c94ce2a511d660af92
--- /dev/null
+++ b/src/components/Blocnote/BudgetSimulator/BudgetChart.js
@@ -0,0 +1,91 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import {
+ LineChart,
+ Line,
+ CartesianGrid,
+ XAxis,
+ YAxis,
+ Tooltip,
+ Legend,
+ ResponsiveContainer,
+} from 'recharts';
+
+
+class BudgetChart extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ successMessages: [],
+ error: false,
+ loading: false,
+ };
+ }
+
+ render() {
+ const data = [];
+ this.props.savingPotentialList.forEach((saving, index) => {
+ data.push({
+ x_name: `${saving * 100}%`,
+ loan_only: this.props.budgets[0][index],
+ loan_first: this.props.budgets[1][index],
+ sf_first: this.props.budgets[2][index],
+ sf_max: this.props.budgets[3][index],
+ });
+ });
+
+ const CustomizedLabel = React.createClass({
+ render() {
+ const { x, y, stroke, value } = this.props;
+
+ return (
+
+ {value}
+
+ );
+ },
+ });
+
+ const renderLineChart = (
+
+
+
+
+
+
+
+ } />
+
+
+
+
+
+
+
+ );
+
+ return renderLineChart;
+ }
+}
+
+BudgetChart.propTypes = {
+ x: PropTypes.number,
+ y: PropTypes.number,
+ stroke: PropTypes.number,
+ value: PropTypes.number,
+ savingPotentialList: PropTypes.arrayOf,
+ budgets: PropTypes.arrayOf,
+ blockStyle: PropTypes.string,
+};
+
+export default BudgetChart;
diff --git a/src/components/Blocnote/BudgetSimulator/BugetTable.js b/src/components/Blocnote/BudgetSimulator/BugetTable.js
new file mode 100644
index 0000000000000000000000000000000000000000..85f575ee3e8ea6938fd21bdf1332df0dc07fdb45
--- /dev/null
+++ b/src/components/Blocnote/BudgetSimulator/BugetTable.js
@@ -0,0 +1,93 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import {
+ Table,
+} from 'reactstrap';
+
+
+class BudgetTable extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ successMessages: [],
+ error: false,
+ loading: false,
+ };
+ }
+
+ render() {
+ const tableHeaderStyle = {
+ textAlign: 'center',
+ backgroundColor: '#EEEEEE',
+ color: '#000000',
+ fontWeight: 'bold',
+ };
+ const header = [...['Savings'], ...this.props.savingPotentialList]
+ .map((columnName) => {
+ let cellValue = columnName;
+ if (typeof columnName !== 'string') {
+ cellValue *= 100;
+ cellValue = `${cellValue}%`;
+ }
+ return (
+
+ {cellValue}
+ |
+ );
+ });
+
+ let rows = [];
+ if (this.props.data !== null) {
+ rows = this.props.data.map((row) => {
+ const cells = row.map((cell) => {
+ let cellValue = cell;
+ if (typeof cellValue !== 'string') {
+ cellValue = Math.round(cellValue * 100) / 100;
+ cellValue = cellValue.toLocaleString();
+ cellValue = `$${cellValue}`;
+ }
+
+ return (
+
+ {cellValue}
+ |
+ );
+ });
+ return (
+
+ {cells}
+
+ );
+ });
+ }
+
+ return (
+
+
+
+
+ |
+ {this.props.tableName}
+ |
+
+
+ {header}
+
+
+
+ {rows}
+
+
+
+ );
+ }
+}
+
+BudgetTable.propTypes = {
+ tableName: PropTypes.string,
+ savingPotentialList: PropTypes.arrayOf,
+ data: PropTypes.arrayOf,
+};
+
+export default BudgetTable;
diff --git a/src/components/Blocnote/FinancialInputs/Bills.js b/src/components/Blocnote/FinancialInputs/Bills.js
new file mode 100644
index 0000000000000000000000000000000000000000..e37b1d6a64dd71c6b6f0b1461172af17f762f6cd
--- /dev/null
+++ b/src/components/Blocnote/FinancialInputs/Bills.js
@@ -0,0 +1,69 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import {
+ Row,
+} from 'reactstrap';
+import BillsTable from './BillsTable';
+
+
+const Bills = (props) => {
+ const BillsTables = [];
+ const billsExist = {
+ gas: false,
+ oil: false,
+ water: false,
+ electric: false,
+ };
+
+ if (props.data !== null) {
+ console.log(props.data); // eslint-disable-line
+ Object.keys(props.data).forEach(billName => {
+ BillsTables.push(
+
+
+
+ );
+ billsExist[billName] = true;
+ });
+ }
+
+ Object.entries(billsExist).forEach(billExist => {
+ if (billExist[1] === false) {
+ BillsTables.push(
+
+
+
+ );
+ }
+ });
+
+ return (
+
+
+ Energy Bills
+
+
+ {BillsTables}
+
+
+ );
+};
+
+Bills.propTypes = {
+ blockStyle: PropTypes.shape({
+ marginBottom: PropTypes.string,
+ }),
+ headerStyle: PropTypes.shape({
+ textAlign: PropTypes.string,
+ marginBottom: PropTypes.string,
+ }),
+ data: PropTypes.objectOf,
+};
+
+export default Bills;
diff --git a/src/components/Blocnote/FinancialInputs/BillsOverview.js b/src/components/Blocnote/FinancialInputs/BillsOverview.js
new file mode 100644
index 0000000000000000000000000000000000000000..1fa5a241447d45ee2e4b46e74ee22d213c9c226b
--- /dev/null
+++ b/src/components/Blocnote/FinancialInputs/BillsOverview.js
@@ -0,0 +1,283 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import {
+ Dropdown,
+ DropdownToggle,
+ DropdownMenu,
+ DropdownItem,
+ Button,
+ Table,
+} from 'reactstrap';
+import ResultMessage from './ResultMessage';
+
+
+class BillsOverview extends Component {
+ constructor(props) {
+ super(props);
+ this.toggleEstimation = this.toggleEstimation.bind(this);
+ this.changeEstimation = this.changeEstimation.bind(this);
+ const data = {};
+ if (Object.keys(this.props.data).length !== 0) {
+ ['electric', 'water', 'gas', 'oil'].forEach((billName) => {
+ Object.entries(this.props.data[billName]).forEach((bill) => {
+ const keyName = `${billName}-value-${bill[0]}`;
+ data[keyName] = bill[1];
+ });
+ });
+ }
+
+ this.state = {
+ estimationDropdownOpen: false,
+ estimationDropDownValue: 'Select Estimation',
+ estimationOptions: [
+ { id: 'RoughEstimation', key: 'RoughEstimation', name: 'Rough Estimation' },
+ { id: 'Fancy Estimation', key: 'FancyEstimation', name: 'Fancy Estimation' },
+ ],
+ action: null,
+ postBills: data,
+ };
+ }
+
+ toggleEstimation() {
+ this.setState({
+ estimationDropdownOpen: !this.state.estimationDropdownOpen,
+ });
+ }
+
+ changeEstimation(e) {
+ this.setState({ estimationDropDownValue: e.currentTarget.textContent });
+ }
+
+ handleCreateBillsOverview = () => {
+ this.props.createBillsOverview(
+ this.props.buildingId,
+ this.state.postBills,
+ );
+ this.setState({ action: 'created' });
+ }
+
+ handleUpdateBillsOverview = () => {
+ const data = {};
+ data['Estimation Model'] = this.state.estimationDropDownValue;
+
+ if (data['Estimation Model'] === 'Select Estimation') {
+ alert('Please select an estimation model');
+ } else {
+ this.props.updateBillsOverview(
+ this.props.buildingId,
+ data,
+ );
+ this.setState({ action: 'updated' });
+ }
+ }
+
+ buildHeader = (headerNames) => {
+ return [...headerNames, ...Object.keys(this.props.data.electric)].map((name, key) => {
+ return (
+
+ {name}
+ |
+ );
+ });
+ }
+
+ buildFooter = (footerNames) => {
+ const cellValues = Object.values(this.props.data.total_annual_charge).map((amount) => {
+ let cellValue = amount;
+ cellValue = Math.round(cellValue * 100) / 100;
+ cellValue = cellValue.toLocaleString();
+ return `$${cellValue}`;
+ });
+ return [...footerNames, ...cellValues].map((name, key) => {
+ return (
+
+ {name}
+ |
+ );
+ });
+ }
+
+ render() {
+ const validBillNames = ['electric', 'water', 'gas', 'oil'];
+ const estimationOptions = this.state.estimationOptions.map(e => {
+ return (
+
+ {e.name}
+
+ );
+ });
+ let header = [];
+ let footer = [];
+ let rows = [];
+ let saveButton = '';
+
+ if (Object.keys(this.props.data).length !== 0) {
+ const headerNames = ['Data Source', 'Utility'];
+ const footerNames = ['', 'Total Annual Charge'];
+ header = this.buildHeader(headerNames);
+ footer = this.buildFooter(footerNames);
+ rows = Object.keys(this.props.data)
+ .filter(billName => validBillNames.includes(billName))
+ .map((billName, trKey) => {
+ const cells = [
+ ...['Annual Estimate', billName.charAt(0).toUpperCase() + billName.slice(1)],
+ ...Object.values(this.props.data[billName]),
+ ];
+ const cellsData = Object.values(cells).map((amount, tdKey) => {
+ let cellValue = amount;
+
+ if (!isNaN(cellValue)) {
+ cellValue = Math.round(cellValue * 100) / 100;
+ cellValue = cellValue.toLocaleString();
+ cellValue = `$${cellValue}`;
+ }
+
+ return (
+
+
+ {cellValue}
+
+ |
+ );
+ });
+
+ return (
+
+ {cellsData}
+
+ );
+ });
+
+ saveButton = (
+
+ );
+ }
+
+ let messageStyle = {};
+ let messageContent = null;
+
+ if (this.props.loading) {
+ messageContent = 'Processing ...';
+ messageStyle = this.props.defaultMessageStyle;
+ }
+
+ if (this.props.error && typeof this.props.error === 'object') {
+ messageContent = this.props.error.response.statusText;
+ messageStyle = this.props.errorMessageStyle;
+ }
+
+ if (!this.props.error && !this.props.loading
+ && this.props.data !== null
+ && this.state.action !== null) {
+ messageContent = this.state.action.charAt(0).toUpperCase() + this.state.action.slice(1);
+ messageStyle = this.props.successMessageStyle;
+ }
+
+ return (
+
+
+ Energy Bills Overview
+
+
+
+
+
+ {this.state.estimationDropDownValue}
+
+
+ {estimationOptions}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {header}
+
+
+ {rows}
+ {footer}
+
+
+
+
+ {saveButton}
+
+ );
+ }
+}
+
+BillsOverview.propTypes = {
+ data: PropTypes.shape({
+ electric: PropTypes.objectOf,
+ electric_user: PropTypes.string,
+ gas: PropTypes.objectOf,
+ gas_user: PropTypes.string,
+ oil: PropTypes.objectOf,
+ oil_user: PropTypes.string,
+ water: PropTypes.objectOf,
+ water_user: PropTypes.string,
+ total_annual_charge: PropTypes.objectOf,
+ }),
+ successMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ errorMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ defaultMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ headerStyle: PropTypes.shape({
+ textAlign: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ marginBottom: PropTypes.string,
+ }),
+ buildingId: PropTypes.number,
+ createBillsOverview: PropTypes.func,
+ updateBillsOverview: PropTypes.func,
+ error: PropTypes.bool,
+ loading: PropTypes.bool,
+};
+
+export default BillsOverview;
diff --git a/src/components/Blocnote/FinancialInputs/BillsRow.js b/src/components/Blocnote/FinancialInputs/BillsRow.js
new file mode 100644
index 0000000000000000000000000000000000000000..d0a59b29e8a5c58a2b29b8bad9063f31f0613cbb
--- /dev/null
+++ b/src/components/Blocnote/FinancialInputs/BillsRow.js
@@ -0,0 +1,31 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+
+const BillsRow = (props) => {
+ return (
+
+ |
+ {props.dateFrom}
+ |
+
+ {props.dateTo}
+ |
+
+ {props.usage}
+ |
+
+ $ {props.charge}
+ |
+
+ );
+};
+
+BillsRow.propTypes = {
+ dateFrom: PropTypes.number,
+ dateTo: PropTypes.number,
+ usage: PropTypes.func,
+ charge: PropTypes.func,
+};
+
+export default BillsRow;
diff --git a/src/components/Blocnote/FinancialInputs/BillsSummary.js b/src/components/Blocnote/FinancialInputs/BillsSummary.js
new file mode 100644
index 0000000000000000000000000000000000000000..05b6b1ba4b27932cc471cb0f2937ae149cc85e0c
--- /dev/null
+++ b/src/components/Blocnote/FinancialInputs/BillsSummary.js
@@ -0,0 +1,115 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import {
+ Row,
+} from 'reactstrap';
+import BillsSummaryTable from './BillsSummaryTable';
+
+
+class BillsSummary extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ billsSummary: props.data,
+ };
+ }
+
+ render() {
+ const BillsSummaryTables = [];
+
+ if (this.state.billsSummary !== null) {
+ console.log(this.state.billsSummary); // eslint-disable-line
+ Object.keys(this.state.billsSummary).forEach(billName => {
+ BillsSummaryTables.push(
+
+
+
+ );
+ });
+ }
+
+ return (
+
+
+ Bills Summary
+
+
+ {BillsSummaryTables}
+
+
+ );
+ }
+}
+
+BillsSummary.propTypes = {
+ data: PropTypes.shape({
+ electric: PropTypes.arrayOf(
+ PropTypes.shape({
+ year: PropTypes.string,
+ charge: PropTypes.string,
+ id: PropTypes.number,
+ })
+ ),
+ gas: PropTypes.arrayOf(
+ PropTypes.shape({
+ year: PropTypes.string,
+ charge: PropTypes.string,
+ id: PropTypes.number,
+ })
+ ),
+ oil: PropTypes.arrayOf(
+ PropTypes.shape({
+ year: PropTypes.string,
+ charge: PropTypes.string,
+ id: PropTypes.number,
+ })
+ ),
+ water: PropTypes.arrayOf(
+ PropTypes.shape({
+ year: PropTypes.string,
+ charge: PropTypes.string,
+ id: PropTypes.number,
+ })
+ ),
+ }),
+ successMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ errorMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ defaultMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ headerStyle: PropTypes.shape({
+ textAlign: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ marginBottom: PropTypes.string,
+ }),
+ buildingId: PropTypes.number,
+ createBillsSummary: PropTypes.func,
+ updateBillsSummary: PropTypes.func,
+ deleteBillsSummary: PropTypes.func,
+};
+
+BillsSummary.defaultProps = {
+ data: null,
+};
+
+export default BillsSummary;
diff --git a/src/components/Blocnote/FinancialInputs/BillsSummaryRow.js b/src/components/Blocnote/FinancialInputs/BillsSummaryRow.js
new file mode 100644
index 0000000000000000000000000000000000000000..b7479d8d08cdc67d2e2549de1d34c484f9d587c7
--- /dev/null
+++ b/src/components/Blocnote/FinancialInputs/BillsSummaryRow.js
@@ -0,0 +1,98 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import {
+ Button,
+ InputGroup,
+ InputGroupAddon,
+ Input,
+} from 'reactstrap';
+
+
+class BillsSummaryRow extends Component {
+ constructor(props) {
+ super(props);
+ this.handleOnChange = this.handleOnChange.bind(this);
+ this.handleUpdateBillsSummary = this.handleUpdateBillsSummary.bind(this);
+ this.handleDeleteBillsSummary = this.handleDeleteBillsSummary.bind(this);
+ this.state = {
+ id: props.id,
+ year: props.year,
+ charge: props.charge,
+ };
+ }
+
+ handleUpdateBillsSummary() {
+ console.log(this.state); // eslint-disable-line
+ this.props.updateBillsSummary(this.state);
+ }
+
+ handleDeleteBillsSummary() {
+ this.props.deleteBillsSummary(this.props.id);
+ }
+
+ handleOnChange = (event) => {
+ this.setState({ [event.target.name]: event.target.value });
+ }
+
+ render() {
+ return (
+
+ |
+
+
+ Year
+
+
+
+ |
+
+
+
+ $
+
+
+
+ |
+
+ {' '}
+
+ |
+
+ );
+ }
+}
+
+BillsSummaryRow.propTypes = {
+ id: PropTypes.number,
+ year: PropTypes.number,
+ charge: PropTypes.number,
+ updateBillsSummary: PropTypes.func,
+ deleteBillsSummary: PropTypes.func,
+};
+
+export default BillsSummaryRow;
diff --git a/src/components/Blocnote/FinancialInputs/BillsSummaryTable.js b/src/components/Blocnote/FinancialInputs/BillsSummaryTable.js
new file mode 100644
index 0000000000000000000000000000000000000000..a165391d5cae2459566eae7084d31ac7789754be
--- /dev/null
+++ b/src/components/Blocnote/FinancialInputs/BillsSummaryTable.js
@@ -0,0 +1,233 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import {
+ Table,
+ Button,
+} from 'reactstrap';
+import BillsSummaryRow from './BillsSummaryRow';
+import ResultMessage from './../../../components/Blocnote/FinancialInputs/ResultMessage';
+
+
+class BillsSummaryTable extends Component {
+ constructor(props) {
+ super(props);
+ this.handleCreateBillsSummary = this.handleCreateBillsSummary.bind(this);
+ this.state = {
+ billName: props.billName,
+ billData: props.billData,
+ year: '',
+ charge: '',
+ action: null,
+ };
+ }
+
+ handleCreateBillsSummary = () => {
+ this.props.createBillsSummary(
+ this.props.buildingId,
+ {
+ utility_type: this.props.billName,
+ year: this.state.year,
+ charge: this.state.charge,
+ }, () => {
+ console.log('saga done!'); // eslint-disable-line
+ }
+ );
+ const newBill = {
+ id: 100,
+ utility_type: this.props.billName,
+ year: this.state.year,
+ charge: this.state.charge,
+ };
+ this.setState({ billData: [...this.state.billData, newBill] }, () => {
+ console.log(this.state.billData, 'bill added!'); // eslint-disable-line
+ this.setState({
+ year: '',
+ charge: '',
+ action: 'created',
+ });
+ });
+ }
+
+ updateBillsSummary = (billData) => {
+ this.props.updateBillsSummary(
+ this.props.buildingId,
+ billData,
+ );
+ this.setState({ action: 'updated' });
+ }
+
+ deleteBillsSummary = id => {
+ if (confirm('Are you sure to delete this bill?') === true) {
+ this.props.deleteBillsSummary(
+ this.props.buildingId,
+ { id },
+ );
+ const billDataCopy = this.state.billData.filter(bill => bill.id !== id);
+ this.setState({
+ billData: billDataCopy,
+ action: 'deleted',
+ });
+ }
+ }
+
+ handleOnChange = (event) => {
+ this.setState({ [event.target.name]: event.target.value });
+ }
+
+ addRow = () => {
+ const newBillData = {
+ id: this.state.id,
+ year: this.state.year,
+ charge: this.state.charge,
+ };
+ const billDataCopy = this.state.billData;
+ billDataCopy.push(newBillData);
+ this.setState({ billData: billDataCopy }, () => {
+ console.log(this.state.billData, 'New bill added!'); // eslint-disable-line
+ this.setState({
+ id: this.state.id + 1,
+ year: '',
+ charge: '',
+ });
+ });
+ }
+
+ render() {
+ let rows = [];
+
+ if (this.state.billData.length !== 0) {
+ rows = this.state.billData.map((bill) => {
+ // charge = charge.toLocaleString();
+ return (
+
+ );
+ });
+ } else {
+ rows = (
+
+ |
+ Currently no bill.
+ |
+
+ );
+ }
+
+ let messageStyle = {};
+ let messageContent = null;
+
+ if (this.props.loading) {
+ messageContent = 'Processing ...';
+ messageStyle = this.props.defaultMessageStyle;
+ }
+
+ if (this.props.error && typeof this.props.error === 'object') {
+ messageContent = this.props.error.response.statusText;
+ messageStyle = this.props.errorMessageStyle;
+ }
+
+ if (!this.props.error && !this.props.loading
+ && this.props.billData !== null
+ && this.state.action !== null) {
+ messageContent = this.state.action.charAt(0).toUpperCase() + this.state.action.slice(1);
+ messageStyle = this.props.successMessageStyle;
+ }
+
+ const billName = this.props.billName.charAt(0).toUpperCase() + this.props.billName.slice(1);
+ return (
+
+
+
+ {billName} Annual Charge
+
+
+ {' '}{' '}
+
+
+
+
+
+ );
+ }
+}
+
+BillsSummaryTable.propTypes = {
+ buildingId: PropTypes.number,
+ billName: PropTypes.string,
+ billData: PropTypes.arrayOf(
+ PropTypes.shape({
+ year: PropTypes.string,
+ charge: PropTypes.string,
+ id: PropTypes.number,
+ })
+ ),
+ successMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ errorMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ defaultMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ createBillsSummary: PropTypes.func,
+ updateBillsSummary: PropTypes.func,
+ deleteBillsSummary: PropTypes.func,
+ error: PropTypes.bool,
+ loading: PropTypes.bool,
+};
+
+BillsSummaryTable.defaultProps = {
+ billData: [],
+};
+
+export default BillsSummaryTable;
diff --git a/src/components/Blocnote/FinancialInputs/BillsTable.js b/src/components/Blocnote/FinancialInputs/BillsTable.js
new file mode 100644
index 0000000000000000000000000000000000000000..1a2f32a48ae1e855e6f919e87431b1d37e7dde6d
--- /dev/null
+++ b/src/components/Blocnote/FinancialInputs/BillsTable.js
@@ -0,0 +1,198 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import {
+ Table,
+ Button,
+} from 'reactstrap';
+import BillsRow from './BillsRow';
+
+
+class BillsTable extends Component {
+
+ constructor(props) {
+ global.expandNum = 15;
+ super(props);
+ this.state = {
+ billsData: (this.props.billsData.length > global.expandNum) ?
+ this.props.billsData.slice(0, global.expandNum) : this.props.billsData,
+ showExpandButton: (this.props.billsData.length > global.expandNum) === true,
+ showCollapseButton: false,
+ };
+ }
+
+ expandBills = () => {
+ console.log(this.props.billsData.slice(0, this.state.billsData.length + global.expandNum)); // eslint-disable-line
+ this.setState({
+ billsData: this.props.billsData.slice(0, this.state.billsData.length + global.expandNum),
+ }, () => {
+ console.log('Expanded'); // eslint-disable-line
+ this.setState({
+ showCollapseButton: true,
+ });
+ if (this.state.billsData.length === this.props.billsData.length) {
+ console.log(this.props.billsData.length); // eslint-disable-line
+ this.setState({
+ showExpandButton: false,
+ });
+ }
+ });
+ }
+
+ collapeBills = () => {
+ const collapeNum = this.state.billsData.length === this.props.billsData.length ?
+ this.state.billsData.length % global.expandNum : global.expandNum;
+ this.setState({
+ billsData: this.props.billsData.slice(0, this.state.billsData.length - collapeNum),
+ }, () => {
+ console.log('Collapsed'); // eslint-disable-line
+ this.setState({
+ showExpandButton: true,
+ });
+ if (this.state.billsData.length <= global.expandNum) {
+ this.setState({
+ showCollapseButton: false,
+ });
+ }
+ });
+ }
+
+ render() {
+ const headerStyle = {
+ textAlign: 'center',
+ fontWeight: 'bold',
+ // marginBottom: '15px',
+ padding: '15px',
+ borderBottom: '1px solid #999999',
+ background: '#EEEEEE',
+ };
+ const tdStyle = {
+ textAlign: 'center',
+ fontSize: '13px',
+ };
+ const buttonStyle = {
+ textAlign: 'center',
+ marginBottom: '30px',
+ marginRight: '-10px',
+ cursor: 'pointer',
+ };
+
+ const billsName = this.props.billsName.charAt(0).toUpperCase() + this.props.billsName.slice(1);
+ let header = (
+
+ | Date From |
+ Date To |
+ Usage (kWh) |
+ Amount |
+
+ );
+ let rows = [];
+ let expandButton = null;
+ let collapseButton = null;
+ const showBillNum = this.props.billsData.length > 0 ?
+ `Showing ${this.state.billsData.length} of ${this.props.billsData.length}` : null;
+
+ if (this.state.billsData.length !== 0) {
+ rows = this.state.billsData.map((bill) => {
+ // charge = charge.toLocaleString();
+ return (
+
+ );
+ });
+ } else {
+ header = '';
+ rows = (
+
+ |
+ There is no bill.
+ |
+
+ );
+ }
+
+ if (this.state.showExpandButton) {
+ expandButton = (
+
+ );
+ }
+ if (this.state.showCollapseButton) {
+ collapseButton = (
+
+ );
+ }
+
+ return (
+
+
+
+ |
+ {billsName} Bills
+ |
+
+ {showBillNum}
+ |
+
+ {header}
+
+ {rows}
+
+
+
+ {expandButton}
+ {collapseButton}
+
+
+ );
+ }
+}
+
+BillsTable.propTypes = {
+ billsName: PropTypes.string,
+ billsData: PropTypes.arrayOf(
+ PropTypes.shape({
+ year: PropTypes.string,
+ charge: PropTypes.string,
+ id: PropTypes.number,
+ })
+ ),
+ // deleteRow: PropTypes.func,
+};
+
+BillsTable.defaultProps = {
+ billsData: [],
+};
+
+export default BillsTable;
diff --git a/src/components/Blocnote/FinancialInputs/CashBalance.js b/src/components/Blocnote/FinancialInputs/CashBalance.js
new file mode 100644
index 0000000000000000000000000000000000000000..2434ee26ee983d862725b63139c1a221ef1ec619
--- /dev/null
+++ b/src/components/Blocnote/FinancialInputs/CashBalance.js
@@ -0,0 +1,254 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import {
+ Button,
+ Table,
+} from 'reactstrap';
+import CashBalanceRow from './CashBalanceRow';
+import ResultMessage from './ResultMessage';
+
+
+class CashBalance extends Component {
+ constructor(props) {
+ super(props);
+ this.deleteRow = this.deleteRow.bind(this);
+ this.addRow = this.addRow.bind(this);
+ this.state = {
+ cashBalance: this.props.data,
+ id: this.props.data.length,
+ balance_amount: null,
+ statement_date: null,
+ is_from_balance_sheet: false,
+ action: null,
+ };
+ }
+
+ validateInputs = () => {
+ const emptyFields = [];
+ if (this.state.cashBalance.length > 0) {
+ Object.values(this.state.cashBalance).forEach(statement => {
+ if (statement.balance_amount === null &&
+ !emptyFields.includes('Balance Amount')) {
+ emptyFields.push('Balance Amount');
+ }
+ if (statement.statement_date === null &&
+ !emptyFields.includes('Statement Date')) {
+ emptyFields.push('Statement Date');
+ }
+ });
+ }
+
+ if (emptyFields.length > 0) {
+ alert(`Please fill in ${emptyFields.join(', ')} fields`);
+ return false;
+ }
+ return true;
+ }
+
+ deleteRow = id => {
+ if (this.state.cashBalance.length === 1) {
+ alert('Sorry, you need at least one statement!');
+ } else if (confirm('Are you sure to delete this statement?') === true) {
+ const cashBalanceCopy = this.state.cashBalance.filter((statement, index) => {
+ console.log(statement); // eslint-disable-line
+ return index !== id;
+ });
+ this.setState({ cashBalance: cashBalanceCopy }, () => {
+ console.log('Statement deleted!'); // eslint-disable-line
+ });
+ }
+ }
+
+ addRow = () => {
+ if (this.validateInputs() === true) {
+ const newStatement = {
+ id: this.state.id,
+ balance_amount: this.state.balance_amount,
+ statement_date: this.state.statement_date,
+ is_from_balance_dheet: this.state.is_from_balance_dheet,
+ };
+ const cashBalanceCopy = this.state.cashBalance;
+ cashBalanceCopy.push(newStatement);
+ this.setState({ cashBalance: cashBalanceCopy }, () => {
+ console.log(this.state.cashBalance, 'New statement added!'); // eslint-disable-line
+ this.setState({
+ id: this.state.id + 1,
+ balance_amount: null,
+ statement_date: null,
+ is_fromBalance_sheet: false,
+ });
+ });
+ }
+ }
+
+ updateRow = (row) => {
+ const cashBalance = this.state.cashBalance.map((statement, id) => {
+ if (id === row.id) {
+ const tmp = { id };
+ tmp.balance_amount = row.balance_amount;
+ tmp.statement_date = row.statement_date;
+ tmp.is_from_balance_sheet = row.is_from_balance_sheet;
+ return tmp;
+ }
+ return statement;
+ });
+ this.setState({ cashBalance }, () => {
+ console.log(cashBalance); // eslint-disable-line
+ });
+ }
+
+ handleUpdateCashBalance = () => {
+ if (this.validateInputs() === true) {
+ this.props.updateCashBalance(
+ this.props.buildingId,
+ this.state.cashBalance,
+ );
+ this.setState({
+ loading: false,
+ action: 'updated',
+ });
+ }
+ }
+
+ render() {
+ const header = [
+ '#Statement',
+ 'Balance Amount',
+ 'Statement Date',
+ 'Balance Sheet',
+ 'Option'].map((title, key) => {
+ return (
+
+ {title}
+ |
+ );
+ });
+
+ let saveButton = null;
+ let rows = [];
+ if (Object.keys(this.state.cashBalance).length !== 0) {
+ rows = this.state.cashBalance.map((statement, index) => {
+ return (
+
+ );
+ });
+ saveButton = (
+
+ );
+ } else {
+ rows = (
+
+ |
+ Currently no statements.
+ |
+
+ );
+ }
+
+ let messageStyle = {};
+ let messageContent = null;
+
+ if (this.props.loading) {
+ messageContent = 'Updating ...';
+ messageStyle = this.props.defaultMessageStyle;
+ }
+
+ if (this.props.error && typeof this.props.error === 'object') {
+ messageContent = this.props.error.response.statusText;
+ messageStyle = this.props.errorMessageStyle;
+ }
+
+ if (!this.props.error && !this.props.loading
+ && this.props.data !== null
+ && this.state.action) {
+ messageContent = 'Saved!';
+ messageStyle = this.props.successMessageStyle;
+ }
+
+ return (
+
+
+ Cash Balance
+
+
+
+
+
+ {header}
+
+
+ {rows}
+
+
+
+
+
+
+
+
+ {saveButton}
+
+
+
+ );
+ }
+}
+
+CashBalance.propTypes = {
+ blockStyle: PropTypes.shape({
+ marginBottom: PropTypes.string,
+ }),
+ headerStyle: PropTypes.shape({
+ textAlign: PropTypes.string,
+ marginBottom: PropTypes.string,
+ }),
+ data: PropTypes.arrayOf(
+ PropTypes.shape({
+ balance_amount: PropTypes.string,
+ is_from_balance_sheet: PropTypes.boolean,
+ statement_date: PropTypes.string,
+ }),
+ ),
+ successMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ errorMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ defaultMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ buildingId: PropTypes.number,
+ updateCashBalance: PropTypes.func,
+ error: PropTypes.bool,
+ loading: PropTypes.bool,
+};
+
+export default CashBalance;
diff --git a/src/components/Blocnote/FinancialInputs/CashBalanceRow.js b/src/components/Blocnote/FinancialInputs/CashBalanceRow.js
new file mode 100644
index 0000000000000000000000000000000000000000..332bbfc68682f06ef0159946ae2190d32d0f728c
--- /dev/null
+++ b/src/components/Blocnote/FinancialInputs/CashBalanceRow.js
@@ -0,0 +1,99 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import {
+ InputGroup,
+ InputGroupAddon,
+ Input,
+ Button,
+} from 'reactstrap';
+
+
+class CashBalanceRow extends Component {
+ constructor(props) {
+ super(props);
+ this.handleOnChange = this.handleOnChange.bind(this);
+ this.onDelEvent = this.onDelEvent.bind(this);
+ this.state = {
+ id: props.id,
+ balance_amount: props.balanceAmount,
+ statement_date: props.statementDate,
+ is_from_balance_sheet: props.isFromBalanceSheet,
+ };
+ }
+
+ onDelEvent() {
+ this.props.onDelEvent(this.props.id);
+ }
+
+ handleOnChange = (event) => {
+ this.setState({ [event.target.name]:
+ event.target.name === 'is_from_balance_sheet' ? event.target.checked : event.target.value },
+ () => {
+ this.props.onChangeEvent(this.state);
+ });
+ }
+
+ render() {
+ return (
+
+ |
+ {this.props.id + 1}
+ |
+
+
+
+ $
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+ );
+ }
+}
+
+CashBalanceRow.propTypes = {
+ id: PropTypes.number,
+ balanceAmount: PropTypes.number,
+ statementDate: PropTypes.string,
+ isFromBalanceSheet: PropTypes.bool,
+ onDelEvent: PropTypes.func,
+ onChangeEvent: PropTypes.func,
+};
+
+export default CashBalanceRow;
diff --git a/src/components/Blocnote/FinancialInputs/CustomerPreference.js b/src/components/Blocnote/FinancialInputs/CustomerPreference.js
new file mode 100644
index 0000000000000000000000000000000000000000..5741596caa05d82192d025ecf563917fda2b6b9d
--- /dev/null
+++ b/src/components/Blocnote/FinancialInputs/CustomerPreference.js
@@ -0,0 +1,213 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import {
+ Button,
+ Table,
+ Input,
+ InputGroup,
+ InputGroupAddon,
+} from 'reactstrap';
+import ResultMessage from './ResultMessage';
+
+
+class CustomerPreference extends Component {
+ constructor(props) {
+ super(props);
+ this.handleOnChange = this.handleOnChange.bind(this);
+ this.state = {
+ downpayment: this.props.data.downpayment,
+ expectedNetNoiDscr: this.props.data.expected_net_noi_dscr,
+ expectedPayback: this.props.data.expected_payback,
+ updated: false,
+ };
+ }
+
+ handleOnChange = (event) => {
+ this.setState({ [event.target.name]: event.target.value });
+ }
+
+ handleUpdateCustomerPreference = () => {
+ this.props.updateCustomerPreference(
+ this.props.buildingId,
+ {
+ downpayment: parseFloat(this.state.downpayment).toFixed(2),
+ expected_net_noi_dscr: parseInt(this.state.expectedNetNoiDscr, 10),
+ expected_payback: this.state.expectedPayback,
+ },
+ );
+ this.setState({ updated: true });
+ }
+
+ render() {
+ const header = [
+ 'Preference',
+ 'Value (if values is not known, please leave it blank)',
+ ].map((title, key) => {
+ return (
+
+ {title}
+ |
+ );
+ });
+
+ const rows = [];
+ const style = { fontWeight: 'bold' };
+ if (this.props.data !== null) {
+ rows.push(
+
+ |
+ Affordable Downpayment (?)
+ |
+
+
+
+ $
+
+
+
+ |
+
+ );
+ rows.push(
+
+ |
+ Expected Payback (?)
+ |
+
+
+
+
+ Months
+
+
+ |
+
+ );
+ rows.push(
+
+ |
+ Expected Saving DSCR (?)
+ |
+
+
+
+
+ X
+
+
+ |
+
+ );
+ }
+
+ let messageStyle = {};
+ let messageContent = null;
+
+ if (this.props.loading) {
+ messageContent = 'Updating ...';
+ messageStyle = this.props.defaultMessageStyle;
+ }
+
+ if (this.props.error && typeof this.props.error === 'object') {
+ messageContent = this.props.error.response.statusText;
+ messageStyle = this.props.errorMessageStyle;
+ }
+
+ if (!this.props.error && !this.props.loading
+ && this.props.data !== null
+ && this.state.updated) {
+ messageContent = 'Saved!';
+ messageStyle = this.props.successMessageStyle;
+ }
+
+ return (
+
+
+ Customer Preference
+
+
+
+
+
+ {header}
+
+
+ {rows}
+
+
+
+
+
+
+ );
+ }
+}
+
+CustomerPreference.propTypes = {
+ blockStyle: PropTypes.shape({
+ marginBottom: PropTypes.string,
+ }),
+ headerStyle: PropTypes.shape({
+ textAlign: PropTypes.string,
+ marginBottom: PropTypes.string,
+ }),
+ data: PropTypes.shape({
+ downpayment: PropTypes.string,
+ expected_net_noi_dscr: PropTypes.string,
+ expected_payback: PropTypes.string,
+ }),
+ successMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ errorMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ defaultMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ buildingId: PropTypes.number,
+ updateCustomerPreference: PropTypes.func,
+ error: PropTypes.bool,
+ loading: PropTypes.bool,
+};
+
+export default CustomerPreference;
diff --git a/src/components/Blocnote/FinancialInputs/FinanceOverview.js b/src/components/Blocnote/FinancialInputs/FinanceOverview.js
new file mode 100644
index 0000000000000000000000000000000000000000..8e25a112ad651cd55431a1ded48ffad849627157
--- /dev/null
+++ b/src/components/Blocnote/FinancialInputs/FinanceOverview.js
@@ -0,0 +1,406 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import {
+ Dropdown,
+ DropdownToggle,
+ DropdownMenu,
+ DropdownItem,
+ Button,
+ Form,
+ FormGroup,
+ Input,
+ InputGroup,
+ InputGroupAddon,
+ Label,
+} from 'reactstrap';
+// import CSRFToken from './csrftoken';
+import ResultMessage from './ResultMessage';
+
+
+class FinanceOverview extends Component {
+ constructor(props) {
+ super(props);
+ this.handleOnChange = this.handleOnChange.bind(this);
+ this.toggleFund = this.toggleFund.bind(this);
+ this.changeFund = this.changeFund.bind(this);
+ this.submitForm = this.submitForm.bind(this);
+ this.state = {
+ fundOptions: props.fundOptions,
+ fundDropDownId: props.fundDropDownId,
+ fundDropDownValue: props.fundDropDownValue,
+ fundDropdownOpen: false,
+ didFundChange: false,
+ isFirstTime: false,
+ csrftoken: null,
+ showLoanOptionsTable: false,
+ messageStyle: {},
+ messageContent: null,
+ proFormaStartDate: props.proFormaStartDate,
+ proFormaDuration: props.proFormaDuration,
+ analysisDate: props.analysisDate,
+ anticipatedConstructionStartDate: props.anticipatedConstructionStartDate,
+ anticipatedCommissioningDate: props.anticipatedCommissioningDate,
+ anticipatedConstructionPeriod: props.anticipatedConstructionPeriod,
+ };
+ }
+
+ toggleFund = () => {
+ this.setState({
+ fundDropdownOpen: !this.state.fundDropdownOpen,
+ });
+ }
+
+ changeFund = (event) => {
+ this.setState({ fundDropDownValue: event.currentTarget.textContent });
+ this.setState({ fundDropDownId: event.currentTarget.id });
+ }
+
+ submitForm = (event) => {
+ event.preventDefault();
+ const formData = new FormData(event.target);
+ formData.set('fund_id', this.state.fundDropDownId);
+
+ // this.setState({
+ // csrftoken: formData.get('csrfmiddlewaretoken'),
+ // });
+
+ if (formData.get('fund_id') === '0') {
+ this.setState({
+ messageContent: 'Please select a fund type',
+ messageStyle: this.props.errorMessageStyle,
+ });
+ } else {
+ fetch(`${this.props.baseURL}/loan-options/?loans=all-loans`)
+ .then((res) => {
+ this.setState({
+ isFirstTime: !res.load,
+ });
+ const result = {};
+ formData.forEach((value, field) => {
+ const key = field.split(/(?=[A-Z])/).join('_').toLowerCase();
+ result[key] = value;
+ });
+ const constructionStartDate = new Date(result.anticipated_construction_start_date);
+ const constructionCommissioningDate = new Date(result.anticipated_commissioning_date);
+ if (constructionStartDate > constructionCommissioningDate) {
+ this.setState({
+ messageContent: 'Anticipated Commissioning date has to be after Anticipated Construction start date',
+ messageStyle: this.props.errorMessageStyle,
+ });
+ } else {
+ this.loadFinancialOverview(result);
+ }
+ });
+ }
+ }
+
+ loadFinancialOverview = (result) => {
+ fetch(`${this.props.baseURL}/finance-overview/`, {
+ method: 'PUT',
+ credentials: 'same-origin',
+ body: JSON.stringify(result),
+ headers: new Headers({
+ 'Content-Type': 'application/json',
+ 'X-CSRFToken': this.state.csrftoken,
+ }),
+ }).then((res) => {
+ if (!res.err) {
+ this.setState({
+ messageContent: 'Saved.',
+ messageStyle: this.props.successMessageStyle,
+ });
+
+ if (this.state.didFundChange) {
+ this.setState({
+ messageContent: `${this.state.responseMessage} Loan Options table is reloaded.`,
+ messageStyle: this.props.errorMessageStyle,
+ });
+ }
+
+ if (this.state.didFundChange || this.state.isFirstTime) {
+ this.setState({
+ didFundChange: false,
+ });
+ this.deleteLoanOptions();
+ }
+ } else {
+ const errors = [];
+ res.err.responseBody.then((error) => {
+ Object.keys(error).forEach((key) => {
+ errors.push(`${error[key][0]}`);
+ });
+ });
+ this.setState({
+ errorMessage: errors,
+ });
+ }
+ });
+ }
+
+ deleteLoanOptions = () => {
+ fetch(`${this.props.baseURL}/loan-options/?loans=delete-loan-options`, {
+ method: 'GET',
+ credentials: 'same-origin',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ }).then(() => {
+ this.setState({
+ showLoanOptionsTable: false,
+ });
+ });
+ }
+
+ handleOnChange = (event) => {
+ this.setState({ [event.target.name]: event.target.value });
+ }
+
+ render() {
+ const labelStyle = {
+ fontSize: '13px',
+ textAlign: 'left',
+ fontWeight: 'bold',
+ paddingLeft: '15px',
+ };
+ let mainContent = '';
+
+ if (this.props.fundOptions !== null) {
+ const fundOptions = [];
+ this.props.fundOptions.forEach((fund) => {
+ fundOptions.push(
+
+ {fund.fund_name}
+
+ );
+ });
+
+ mainContent = (
+
+ );
+ }
+
+ return (
+
+ {mainContent}
+
+ );
+ }
+}
+
+FinanceOverview.propTypes = {
+ fundDropDownId: PropTypes.number,
+ fundDropDownValue: PropTypes.string,
+ fundOptions: PropTypes.arrayOf(
+ PropTypes.shape({
+ fund_id: PropTypes.number,
+ fund_name: PropTypes.string,
+ })
+ ),
+ proFormaStartDate: PropTypes.string,
+ proFormaDuration: PropTypes.string,
+ analysisDate: PropTypes.string,
+ anticipatedConstructionStartDate: PropTypes.string,
+ anticipatedCommissioningDate: PropTypes.string,
+ anticipatedConstructionPeriod: PropTypes.number,
+ baseURL: PropTypes.string,
+ successMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ errorMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ headerStyle: PropTypes.shape({
+ textAlign: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ marginBottom: PropTypes.string,
+ }),
+};
+
+FinanceOverview.defaultProps = {
+ analysis_date: '',
+ anticipated_commissioning_date: '',
+ anticipated_construction_period: '',
+ anticipated_construction_start_date: '',
+ fund_id: 0,
+ pro_forma_duration: '',
+ pro_forma_start_date: '',
+ fundDropDownId: 0,
+ fundDropDownValue: 'Select Fund',
+ fundOptions: null,
+};
+
+export default FinanceOverview;
diff --git a/src/components/Blocnote/FinancialInputs/IncomeStatements.js b/src/components/Blocnote/FinancialInputs/IncomeStatements.js
new file mode 100644
index 0000000000000000000000000000000000000000..04a58767ca3f7f2698952f7758954ef21a2ea507
--- /dev/null
+++ b/src/components/Blocnote/FinancialInputs/IncomeStatements.js
@@ -0,0 +1,608 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import {
+ Dropdown,
+ DropdownToggle,
+ DropdownMenu,
+ DropdownItem,
+ Button,
+ Input,
+ InputGroup,
+ InputGroupAddon,
+ Table,
+} from 'reactstrap';
+import ResultMessage from './ResultMessage';
+
+
+class IncomeStatements extends Component {
+ constructor(props) {
+ super(props);
+ this.toggleGrowthRate = this.toggleGrowthRate.bind(this);
+ this.changeGrowthRate = this.changeGrowthRate.bind(this);
+ this.handleOnChange = this.handleOnChange.bind(this);
+ // this.handleOnChangeNew = this.handleOnChangeNew.bind(this);
+
+ const obj = {
+ GRDropdownOpen: false,
+ GRDropdownValue: 'Select Growth Rate',
+ selectedDropdownId: 0,
+ growthRateOptions: [
+ { id: '-2', key: '-2', name: 'CAGR=1.58%' },
+ { id: '-1', key: '-1', name: 'Average' },
+ { id: '0', key: '0', name: '0%' },
+ { id: '1', key: '1', name: '1%' },
+ { id: '2', key: '2', name: '2%' },
+ { id: '3', key: '3', name: '3%' },
+ { id: '4', key: '4', name: '4%' },
+ { id: '5', key: '5', name: '5%' },
+ { id: '6', key: '6', name: '6%' },
+ { id: '7', key: '7', name: '7%' },
+ { id: '8', key: '8', name: '8%' },
+ { id: '9', key: '9', name: '9%' },
+ { id: '10', key: '10', name: '10%' },
+ { id: '11', key: '11', name: '11%' },
+ { id: '12', key: '12', name: '12%' },
+ { id: '13', key: '13', name: '13%' },
+ { id: '14', key: '14', name: '14%' },
+ { id: '15', key: '15', name: '15%' },
+ ],
+ incomeStatements: props.data,
+ incomeStatementsNew: null,
+ error: false,
+ loading: false,
+ action: null,
+ };
+
+ const histYears = {};
+ const incomeStatementsNew = { incomeStatementsNew: [] };
+ if (props.data.hist !== null) {
+ Object.keys(props.data.hist).forEach((year, id) => {
+ const histYear = `Year-${id + 1}`;
+ histYears[histYear] = parseInt(year, 10);
+ });
+ } else {
+ [0, 1, 2].forEach(id => {
+ const histYear = `Year-${id + 1}`;
+ histYears[histYear] = null;
+ });
+
+ const growthRate = {};
+ growthRate['growth-rate'] = props.data.cagr;
+ incomeStatementsNew.incomeStatementsNew.push(this.initIncomeStatement());
+ incomeStatementsNew.incomeStatementsNew.push(this.initIncomeStatement());
+ incomeStatementsNew.incomeStatementsNew.push(this.initIncomeStatement());
+ incomeStatementsNew.incomeStatementsNew.push(growthRate);
+ }
+
+ this.state = Object.assign(obj, histYears, incomeStatementsNew);
+ console.log(this.state); // eslint-disable-line
+ }
+
+ initIncomeStatement = () => {
+ const statement = {
+ year: null,
+ revenue: null,
+ };
+ statement['utility-expense'] = null;
+ statement['non-utility-operating-expense'] = null;
+ return statement;
+ }
+
+ handleOnChange = (event) => {
+ const year = event.target.id;
+ const targetName = event.target.name;
+ const copyIS = this.state.incomeStatements;
+ Object.entries(copyIS.hist).forEach((incomeStatement) => {
+ if (incomeStatement[0] === year) {
+ copyIS.hist[year][targetName] = parseFloat(event.target.value);
+ }
+ });
+
+ this.setState({ incomeStatements: copyIS }, () => {
+ console.log(this.state.incomeStatements); // eslint-disable-line
+ });
+ }
+
+ handleOnChangeNew = (event) => {
+ const id = event.target.id;
+ const targetName = event.target.name.includes('Year') ? 'year' : event.target.name;
+ const targetValue = event.target.value;
+ const copyISNew = this.state.incomeStatementsNew.map((item, key) => {
+ if (parseInt(key, 10) === parseInt(id, 10)) {
+ const tmp = item;
+ tmp[targetName] = targetValue;
+ return tmp;
+ }
+ return item;
+ });
+ this.setState({ incomeStatementsNew: copyISNew }, () => {
+ console.log(this.state.incomeStatementsNew); // eslint-disable-line
+ });
+ }
+
+ toggleGrowthRate() {
+ this.setState({
+ GRDropdownOpen: !this.state.GRDropdownOpen,
+ });
+ }
+
+ changeGrowthRate(e) {
+ this.setState({ GRDropdownValue: e.currentTarget.textContent });
+ this.setState({ selectedDropdownId: e.currentTarget.id });
+ }
+
+ buildHeader = () => {
+ const headers = [];
+ const year = 'year';
+ headers.push(
+
+ Year
+ |
+ );
+
+ Object.entries(this.state).forEach((entry, key) => {
+ if (entry[0].includes('Year')) {
+ headers.push(
+
+
+ |
+ );
+ }
+ });
+ const futureYear = this.state.incomeStatements.future.year;
+ headers.push(
+
+ {futureYear}
+ |
+ );
+ const average = 'average';
+ headers.push(
+
+ Average
+ |
+ );
+ return headers;
+ }
+
+ buildEmptyHeader = () => {
+ const headers = [];
+ const year = 'year';
+ headers.push(
+
+ Year
+ |
+ );
+ let id = 0;
+ Object.entries(this.state).forEach((entry, key) => {
+ if (entry[0].includes('Year')) {
+ headers.push(
+
+
+ |
+ );
+ id += 1;
+ }
+ });
+ headers.push(
+
+ {' '}Next Year{' '}
+ |
+ );
+ headers.push(
+
+ {' '}Average{' '}
+ |
+ );
+ return headers;
+ }
+
+ handleUpdateIncomeStatements = () => {
+ this.setState({ loading: true });
+ const hist = [];
+ Object.entries(this.state.incomeStatements.hist).forEach(incomeStatement => {
+ const obj = {
+ year: String(incomeStatement[0]),
+ revenue: String(incomeStatement[1].revenue),
+ };
+ obj['non-utility-operating-expense'] = String(incomeStatement[1].non_utility_expense);
+ obj['utility-expense'] = String(incomeStatement[1].utility_expense);
+ hist.push(obj);
+ });
+ const growthRate = {};
+ growthRate['growth-rate'] = String(this.state.selectedDropdownId);
+ hist.push(growthRate);
+ this.props.updateIncomeStatements(
+ this.props.buildingId,
+ hist,
+ );
+ this.setState({
+ loading: false,
+ action: 'updated',
+ });
+ }
+
+ handleCreateIncomeStatements = () => {
+ const emptyMessages = [];
+ const incomeStatementsNew = Object.values(this.state.incomeStatementsNew.slice(0, 3))
+ .map(statement => {
+ if (statement.year === null &&
+ !emptyMessages.includes('Year')) {
+ emptyMessages.push('Year');
+ }
+ if (statement.revenue === null &&
+ !emptyMessages.includes('Revenue')) {
+ emptyMessages.push('Revenue');
+ }
+ if (statement['utility-expense'] === null &&
+ !emptyMessages.includes('Utility Expense')) {
+ emptyMessages.push('Utility Expense');
+ }
+ if (statement['non-utility-operating-expense'] === null &&
+ !emptyMessages.includes('Non-Utility Operating Expense')) {
+ emptyMessages.push('Non-Utility Operating Expense');
+ }
+
+ const newStatement = {};
+ newStatement.year = String(statement.year);
+ newStatement.revenue = String(statement.revenue);
+ newStatement['utility-expense'] = String(statement['utility-expense']);
+ newStatement['non-utility-operating-expense'] = String(statement['non-utility-operating-expense']);
+ return newStatement;
+ });
+
+ if (this.state.GRDropdownValue === 'Select Growth Rate') {
+ emptyMessages.push('Growth Rate');
+ }
+
+ if (emptyMessages.length !== 0) {
+ const msg = `Please fill in ${emptyMessages.join(', ')} fields.`;
+ alert(msg);
+ } else {
+ const growthRate = {};
+ growthRate['growth-rate'] = String(this.state.incomeStatementsNew[3]['growth-rate']);
+ incomeStatementsNew.push(growthRate);
+ this.setState({ loading: true });
+ this.props.updateIncomeStatements(
+ this.props.buildingId,
+ incomeStatementsNew,
+ );
+ this.setState({
+ loading: false,
+ action: 'updated',
+ });
+ }
+ }
+
+ render() {
+ let header = [];
+ let rows = [];
+ let calculateSaveButton = null;
+
+ const columnKeys = [
+ 'revenue',
+ 'utility_expense',
+ 'energy_opex',
+ 'electric_opex',
+ 'gas_opex',
+ 'oil_opex',
+ 'water_opex',
+ 'other_utility',
+ 'non_utility_expense',
+ 'net_non_energy_opex',
+ 'total_opex',
+ 'noi',
+ ];
+
+ const columnNames = {
+ revenue: 'Revenue',
+ utility_expense: 'Utility Expense',
+ energy_opex: 'Energy Expense',
+ electric_opex: 'Electric Bill',
+ gas_opex: 'Gas Bill',
+ oil_opex: 'Oil Bill',
+ water_opex: 'Water Bill',
+ other_utility: 'Other Utility Expense',
+ non_utility_expense: 'Non-Utility Operating Expense',
+ net_non_energy_opex: 'Net Non-Energy Expense',
+ total_opex: 'Total Expense',
+ noi: 'Net Operating Income',
+ };
+
+ const growthRateOptions = this.state.growthRateOptions.map(e => {
+ return (
+
+ {e.name}
+
+ );
+ });
+
+ if (this.state.incomeStatements.hist !== null &&
+ this.state.incomeStatements.future !== null) {
+ header = this.buildHeader();
+ const histYears = Object.keys(this.state.incomeStatements.hist).sort();
+ rows = columnKeys.map((columnKey, id) => {
+ const cells = [
+ ...[columnNames[columnKey]],
+ ...histYears.map((histYear) => {
+ let cellValue = this.state.incomeStatements.hist[histYear][columnKey];
+ cellValue = Math.round(cellValue * 100) / 100;
+ if (['utility_expense', 'revenue', 'non_utility_expense'].includes(columnKey)) {
+ return (
+
+
+ $
+
+
+
+ );
+ }
+ cellValue = cellValue.toLocaleString();
+ cellValue = `$${cellValue}`;
+ return cellValue;
+ }),
+ ...[this.state.incomeStatements.future[columnKey]].map((amount) => {
+ let cellValue = amount;
+ cellValue = Math.round(cellValue * 100) / 100;
+ cellValue = cellValue.toLocaleString();
+ cellValue = `$${cellValue}`;
+ return cellValue;
+ }),
+ ...Object.values([this.state.incomeStatements.average[columnKey]]).map((amount) => {
+ let cellValue = amount;
+ cellValue = Math.round(cellValue * 100) / 100;
+ cellValue = cellValue.toLocaleString();
+ cellValue = `$${cellValue}`;
+ return cellValue;
+ }),
+ ];
+
+ const cellsData = Object.values(cells).map((celldata, key) => {
+ return (
+
+
+ {celldata}
+
+ |
+ );
+ });
+
+ return (
+
+ {cellsData}
+
+ );
+ });
+
+ calculateSaveButton = (
+
+ );
+ } else {
+ header = this.buildEmptyHeader();
+ const ids = Object.keys(this.state.incomeStatementsNew).slice(0, 3).sort();
+ rows = columnKeys.map((columnKey, id) => {
+ const cells = [
+ ...[columnNames[columnKey]],
+ ...ids.map((index) => {
+ const keyMapping = {
+ revenue: 'revenue',
+ utility_expense: 'utility-expense',
+ non_utility_expense: 'non-utility-operating-expense',
+ };
+
+ if (['revenue', 'utility_expense', 'non_utility_expense'].includes(columnKey)) {
+ const newColumnKey = keyMapping[columnKey];
+ return (
+
+
+ $
+
+
+
+ );
+ }
+ return null;
+ }),
+ ...['', ''],
+ ];
+
+ const cellsData = Object.values(cells).map((celldata, key) => {
+ return (
+
+
+ {celldata}
+
+ |
+ );
+ });
+
+ return (
+
+ {cellsData}
+
+ );
+ });
+
+ calculateSaveButton = (
+
+ );
+ }
+
+ let messageStyle = {};
+ let messageContent = null;
+
+ if (this.state.loading) {
+ messageContent = 'Processing ...';
+ messageStyle = this.props.defaultMessageStyle;
+ }
+
+ if (this.state.error && typeof this.state.error === 'object') {
+ messageContent = this.state.error.response.statusText;
+ messageStyle = this.props.errorMessageStyle;
+ }
+
+ if (!this.state.error && !this.state.loading
+ && this.state.incomeStatements !== null
+ && this.state.action !== null) {
+ messageContent = this.state.action.charAt(0).toUpperCase() + this.state.action.slice(1);
+ messageStyle = this.props.successMessageStyle;
+ }
+
+ return (
+
+
+ Income Statements (in $, End of Year)
+
+
+
+
+
+ {this.state.GRDropdownValue}
+
+
+ {growthRateOptions}
+
+
+
+
+
+ {calculateSaveButton}
+
+
+
+
+
+
+ {header}
+
+
+ {rows}
+
+
+
+
+
+ );
+ }
+}
+
+IncomeStatements.propTypes = {
+ blockStyle: PropTypes.shape({
+ marginBottom: PropTypes.string,
+ }),
+ headerStyle: PropTypes.shape({
+ textAlign: PropTypes.string,
+ marginBottom: PropTypes.string,
+ }),
+ buildingId: PropTypes.number,
+ data: PropTypes.shape({
+ average: PropTypes.shape({
+ electric_opex: PropTypes.number,
+ energy_opex: PropTypes.number,
+ gas_opex: PropTypes.number,
+ net_non_energy_opex: PropTypes.number,
+ noi: PropTypes.number,
+ non_utility_expense: PropTypes.number,
+ oil_opex: PropTypes.number,
+ other_utility: PropTypes.number,
+ revenue: PropTypes.number,
+ total_opex: PropTypes.number,
+ utility_expense: PropTypes.number,
+ water_opex: PropTypes.number,
+ year: null,
+ }),
+ cagr: PropTypes.number,
+ future: PropTypes.shape({
+ electric_opex: PropTypes.number,
+ energy_opex: PropTypes.number,
+ gas_opex: PropTypes.number,
+ net_non_energy_opex: PropTypes.number,
+ noi: PropTypes.number,
+ non_utility_expense: PropTypes.number,
+ oil_opex: PropTypes.number,
+ other_utility: PropTypes.number,
+ revenue: PropTypes.number,
+ total_opex: PropTypes.number,
+ utility_expense: PropTypes.number,
+ water_opex: PropTypes.number,
+ year: null,
+ }),
+ growth_rate: PropTypes.number,
+ hist: PropTypes.objectOf,
+ result: PropTypes.arrayOf(PropTypes.shape({
+ year: PropTypes.string,
+ revenue: PropTypes.string,
+ utility_expense: PropTypes.string,
+ non_utility_operating_expense: PropTypes.string,
+ })),
+ }),
+ successMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ errorMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ defaultMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ updateIncomeStatements: PropTypes.func,
+};
+
+export default IncomeStatements;
diff --git a/src/components/Blocnote/FinancialInputs/LoanOptions.js b/src/components/Blocnote/FinancialInputs/LoanOptions.js
new file mode 100644
index 0000000000000000000000000000000000000000..3b40ddb19f9aad2f9fa98024e33a417ff2269cf8
--- /dev/null
+++ b/src/components/Blocnote/FinancialInputs/LoanOptions.js
@@ -0,0 +1,331 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import {
+ Button,
+ Input,
+ Table,
+ InputGroup,
+ InputGroupAddon,
+} from 'reactstrap';
+import LoanOptionsRow from './LoanOptionsRow';
+import ResultMessage from './ResultMessage';
+
+
+class LoanOptions extends Component {
+ constructor(props) {
+ super(props);
+ this.deleteRow = this.deleteRow.bind(this);
+ this.addRow = this.addRow.bind(this);
+ this.updateRow = this.updateRow.bind(this);
+ this.state = {
+ loanOptions: props.data,
+ lenders: props.lenders,
+ noi: props.noi,
+ cash: props.cash,
+ id: 99,
+ lender: null,
+ interest_rate: null,
+ duration: null,
+ max_loan_amount: null,
+ action: null,
+ };
+ }
+
+ validateInputs = () => {
+ const emptyFields = [];
+ if (this.state.loanOptions.length > 0) {
+ Object.values(this.state.loanOptions).forEach(loanOption => {
+ console.log(loanOption); // eslint-disable-line
+ if (loanOption.lender === null &&
+ !emptyFields.includes('Lender')) {
+ emptyFields.push('Lender');
+ }
+ if (loanOption.interest_rate === null &&
+ !emptyFields.includes('Interest Rate')) {
+ emptyFields.push('Interest Rate');
+ }
+ if (loanOption.duration === null &&
+ !emptyFields.includes('Duration')) {
+ emptyFields.push('Duration');
+ }
+ if (loanOption.max_loan_amount === null &&
+ !emptyFields.includes('Max Loan Amount')) {
+ emptyFields.push('Max Loan Amount');
+ }
+ });
+ }
+
+ if (emptyFields.length > 0) {
+ alert(`Please fill in ${emptyFields.join(', ')} fields`);
+ return false;
+ }
+ return true;
+ }
+
+ deleteRow = id => {
+ if (this.state.loanOptions.length === 1) {
+ alert('Sorry, you need at least one loan option!');
+ } else if (confirm('Are you sure to delete this loan option?') === true) {
+ const loanOptionsCopy = this.state.loanOptions.filter((loanOption, index) => {
+ console.log(loanOption); // eslint-disable-line
+ return index !== id;
+ });
+ this.setState({ loanOptions: loanOptionsCopy }, () => {
+ console.log('Statement deleted!'); // eslint-disable-line
+ });
+ }
+ }
+
+ addRow = () => {
+ if (this.validateInputs() === true) {
+ if (this.props.financeOverviewExist === true) {
+ const loanOption = {
+ id: this.state.id,
+ lender: this.state.lender,
+ interest_rate: this.state.interest_rate,
+ duration: this.state.duration,
+ max_loan_amount: this.state.max_loan_amount,
+ };
+ console.log(this.state.loanOptions); // eslint-disable-line
+ const loanOptions = this.state.loanOptions;
+ loanOptions.push(loanOption);
+ this.setState({ loanOptions }, () => {
+ console.log(this.state.loanOptions, 'New loan option added!'); // eslint-disable-line
+ this.setState({
+ id: this.state.id + 1,
+ lender: null,
+ interest_rate: null,
+ duration: null,
+ max_loan_amount: null,
+ });
+ });
+ } else {
+ alert('Please fill in Financial Overview first');
+ }
+ }
+ }
+
+ updateRow = (row) => {
+ const loanOptions = this.state.loanOptions.map((loanOption, id) => {
+ console.log(id); // eslint-disable-line
+ console.log(row.id); // eslint-disable-line
+ if (id === row.id) {
+ const tmp = { id };
+ tmp.lender = row.lender;
+ tmp.interest_rate = row.interest_rate;
+ tmp.duration = row.duration;
+ tmp.max_loan_amount = row.max_loan_amount;
+ return tmp;
+ }
+ return loanOption;
+ });
+ this.setState({ loanOptions }, () => {
+ console.log(loanOptions); // eslint-disable-line
+ });
+ }
+
+ handleUpdateLoanOptions = () => {
+ if (this.validateInputs() === true) {
+ const formData = {};
+ formData['noi-dscr'] = parseFloat(this.state.noi).toFixed(2);
+ formData['cash-dscr'] = parseFloat(this.state.cash).toFixed(2);
+ formData.instance = this.state.loanOptions;
+ this.props.updateLoanOptions(
+ this.props.buildingId,
+ formData,
+ );
+ this.setState({
+ loading: false,
+ action: 'updated',
+ });
+ }
+ }
+
+ render() {
+ const header = [
+ 'Loan Options',
+ 'Lender',
+ 'Interest Rate',
+ 'Duration',
+ 'Maximum Loan Amount',
+ 'Option',
+ ].map((title, key) => {
+ return (
+
+ {title}
+ |
+ );
+ });
+
+ let loans = [];
+ let saveButton = null;
+ if (Object.keys(this.state.loanOptions).length !== 0) {
+ loans = this.state.loanOptions.map((loanOption, index) => {
+ return (
+
+ );
+ });
+ saveButton = (
+
+ );
+ } else {
+ loans = (
+
+ |
+ Currently no loans.
+ |
+
+ );
+ }
+
+ let messageStyle = {};
+ let messageContent = null;
+
+ if (this.props.loading) {
+ messageContent = 'Updating ...';
+ messageStyle = this.props.defaultMessageStyle;
+ }
+
+ if (this.props.error && typeof this.props.error === 'object') {
+ messageContent = this.props.error.response.statusText;
+ messageStyle = this.props.errorMessageStyle;
+ }
+
+ if (!this.props.error && !this.props.loading
+ && this.props.data !== null
+ && this.state.updated) {
+ messageContent = 'Saved!';
+ messageStyle = this.props.successMessageStyle;
+ }
+
+ return (
+
+
+ Loan Options
+
+
+
+
+
+ |
+
+ |
+
+
+ {header}
+
+
+ {loans}
+
+
+
+
+
+
+
+
+ {saveButton}
+
+
+
+ );
+ }
+}
+
+LoanOptions.propTypes = {
+ blockStyle: PropTypes.shape({
+ marginBottom: PropTypes.string,
+ }),
+ headerStyle: PropTypes.shape({
+ textAlign: PropTypes.string,
+ marginBottom: PropTypes.string,
+ }),
+ cash: PropTypes.number,
+ noi: PropTypes.number,
+ lenders: PropTypes.arrayOf,
+ data: PropTypes.arrayOf(
+ PropTypes.shape({
+ duration: PropTypes.string,
+ interest_rate: PropTypes.string,
+ lender: PropTypes.string,
+ max_loan_amount: PropTypes.string,
+ }),
+ ),
+ successMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ errorMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ defaultMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ buildingId: PropTypes.number,
+ financeOverviewExist: PropTypes.bool,
+ updateLoanOptions: PropTypes.func,
+ error: PropTypes.bool,
+ loading: PropTypes.bool,
+};
+
+export default LoanOptions;
diff --git a/src/components/Blocnote/FinancialInputs/LoanOptionsRow.js b/src/components/Blocnote/FinancialInputs/LoanOptionsRow.js
new file mode 100644
index 0000000000000000000000000000000000000000..bf54384b3dbc851e3f740e07a4c17b8b4ef942b8
--- /dev/null
+++ b/src/components/Blocnote/FinancialInputs/LoanOptionsRow.js
@@ -0,0 +1,160 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import {
+ Button,
+ InputGroup,
+ InputGroupAddon,
+ Input,
+ Dropdown,
+ DropdownToggle,
+ DropdownMenu,
+ DropdownItem,
+} from 'reactstrap';
+
+
+class LoanOptionsRow extends Component {
+ constructor(props) {
+ super(props);
+ this.handleOnChange = this.handleOnChange.bind(this);
+ this.onDelEvent = this.onDelEvent.bind(this);
+ this.toggleLender = this.toggleLender.bind(this);
+ this.changeLender = this.changeLender.bind(this);
+ this.state = {
+ id: props.id,
+ lender: props.lender,
+ lenders: props.lenders,
+ interest_rate: props.interestRate,
+ duration: props.duration,
+ max_loan_amount: props.maxLoanAmount,
+ lenderDropdownOpen: false,
+ lenderDropDownValue: props.lender,
+ lenderOptions: props.lenders !== undefined ? props.lenders.map((lender, id) => {
+ return { id, key: id, name: lender };
+ }) : [],
+ };
+ }
+
+ onDelEvent() {
+ this.props.onDelEvent(this.props.id);
+ }
+
+ handleOnChange = (event) => {
+ this.setState({ [event.target.name]: event.target.value },
+ () => {
+ console.log(this.state); // eslint-disable-line
+ this.props.onChangeEvent(this.state);
+ });
+ }
+
+ toggleLender() {
+ this.setState({
+ lenderDropdownOpen: !this.state.lenderDropdownOpen,
+ });
+ }
+
+ changeLender(e) {
+ this.setState({ lenderDropDownValue: e.currentTarget.textContent });
+ }
+
+ render() {
+ const style = { textAlign: 'left' };
+ const lenderOptions = this.state.lenderOptions.map(e => {
+ return (
+
+ {e.name}
+
+ );
+ });
+ return (
+
+ |
+ Loan {this.state.id + 1}
+ |
+
+
+
+ {this.state.lenderDropDownValue}
+
+
+ {lenderOptions}
+
+
+ |
+
+
+
+
+ %
+
+
+ |
+
+
+
+
+ Months
+
+
+ |
+
+
+
+ $
+
+
+
+ |
+
+
+ |
+
+ );
+ }
+}
+
+LoanOptionsRow.propTypes = {
+ id: PropTypes.number,
+ lender: PropTypes.string,
+ interestRate: PropTypes.number,
+ duration: PropTypes.string,
+ maxLoanAmount: PropTypes.number,
+ onDelEvent: PropTypes.func,
+ lenders: PropTypes.arrayOf,
+ onChangeEvent: PropTypes.func,
+};
+
+export default LoanOptionsRow;
diff --git a/src/components/Blocnote/FinancialInputs/MortgageLiabilities.js b/src/components/Blocnote/FinancialInputs/MortgageLiabilities.js
new file mode 100644
index 0000000000000000000000000000000000000000..58d2c9b9dcce547673c55048167929551a07c2b6
--- /dev/null
+++ b/src/components/Blocnote/FinancialInputs/MortgageLiabilities.js
@@ -0,0 +1,272 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import {
+ Button,
+ Table,
+} from 'reactstrap';
+import MortgageLiabilitiesRow from './MortgageLiabilitiesRow';
+import ResultMessage from './ResultMessage';
+
+
+class MortgageLiabilities extends Component {
+ constructor(props) {
+ super(props);
+ this.deleteRow = this.deleteRow.bind(this);
+ this.addRow = this.addRow.bind(this);
+ this.state = {
+ liabilities: this.props.data,
+ id: this.props.data.length,
+ lender: null,
+ input_date: null,
+ monthly_service: null,
+ remaining_term: null,
+ };
+ }
+
+ validateInputs = () => {
+ const emptyFields = [];
+ if (this.state.liabilities.length > 0) {
+ Object.values(this.state.liabilities).forEach(liability => {
+ console.log(liability); // eslint-disable-line
+ if (liability.lender === null &&
+ !emptyFields.includes('Lender')) {
+ emptyFields.push('Lender');
+ }
+ if (liability.monthly_service === null &&
+ !emptyFields.includes('Monthly Service')) {
+ emptyFields.push('Monthly Service');
+ }
+ if (liability.remaining_term === null &&
+ !emptyFields.includes('Remaining Term')) {
+ emptyFields.push('Remaining Term');
+ }
+ if (liability.input_date === null &&
+ !emptyFields.includes('Input Date')) {
+ emptyFields.push('Input Date');
+ }
+ });
+ }
+
+ if (emptyFields.length > 0) {
+ alert(`Please fill in ${emptyFields.join(', ')} fields`);
+ return false;
+ }
+ return true;
+ }
+
+ deleteRow = id => {
+ if (confirm('Are you sure to delete this liability?') === true) {
+ const liabilitiesCopy = this.state.liabilities.filter((liability, index) => {
+ console.log(liability); // eslint-disable-line
+ return index !== id;
+ });
+ this.setState({ liabilities: liabilitiesCopy }, () => {
+ console.log('Liability deleted!'); // eslint-disable-line
+ });
+ }
+ }
+
+ addRow = () => {
+ if (this.validateInputs() === true) {
+ const newLiability = {
+ id: this.state.id,
+ lender: this.state.lender,
+ input_date: this.state.input_date,
+ monthly_service: this.state.monthly_service,
+ remaining_term: this.state.remaining_term,
+ };
+ const liabilitiesCopy = this.state.liabilities;
+ liabilitiesCopy.push(newLiability);
+ this.setState({ liabilities: liabilitiesCopy }, () => {
+ console.log(this.state.liabilities, 'New liability added!'); // eslint-disable-line
+ this.setState({
+ id: this.state.id + 1,
+ lender: null,
+ input_date: null,
+ monthly_service: null,
+ remaining_term: null,
+ });
+ });
+ }
+ }
+
+ updateRow = (row) => {
+ const liabilities = this.state.liabilities.map((liability, id) => {
+ console.log(id); // eslint-disable-line
+ console.log(row.id); // eslint-disable-line
+ if (id === row.id) {
+ const tmp = { id };
+ tmp.lender = row.lender;
+ tmp.input_date = row.input_date;
+ tmp.monthly_service = row.monthly_service;
+ tmp.remaining_term = row.remaining_term;
+ return tmp;
+ }
+ return liability;
+ });
+ this.setState({ liabilities }, () => {
+ console.log(liabilities); // eslint-disable-line
+ });
+ }
+
+ handleUpdateLiabilities = () => {
+ if (this.validateInputs() === true) {
+ this.props.updateLiabilities(
+ this.props.buildingId,
+ this.state.liabilities,
+ );
+ this.setState({
+ loading: false,
+ action: 'updated',
+ });
+ }
+ }
+
+ render() {
+ const header = [
+ '#Debt',
+ 'Lender Name',
+ 'Monthly Service',
+ 'Remaining Terms',
+ 'Input Date',
+ 'Option',
+ ].map((title, key) => {
+ return (
+
+ {title}
+ |
+ );
+ });
+
+ let rows = [];
+ let saveButton = null;
+ if (this.state.liabilities.length !== 0) {
+ console.log(this.state.liabilities); // eslint-disable-line
+ rows = this.state.liabilities.map((liability, index) => {
+ return (
+
+ );
+ });
+ saveButton = (
+
+ );
+ } else {
+ rows = (
+
+ |
+ Currently no liabilities.
+ |
+
+ );
+ }
+
+ let messageStyle = {};
+ let messageContent = null;
+
+ if (this.props.loading) {
+ messageContent = 'Updating ...';
+ messageStyle = this.props.defaultMessageStyle;
+ }
+
+ if (this.props.error && typeof this.props.error === 'object') {
+ messageContent = this.props.error.response.statusText;
+ messageStyle = this.props.errorMessageStyle;
+ }
+
+ if (!this.props.error && !this.props.loading
+ && this.props.data !== null
+ && this.state.updated) {
+ messageContent = 'Saved!';
+ messageStyle = this.props.successMessageStyle;
+ }
+
+ return (
+
+
+ Mortgage and Liabilities
+
+
+
+
+
+ {header}
+
+
+ {rows}
+
+
+
+
+
+
+
+
+ {saveButton}
+
+
+
+ );
+ }
+}
+
+MortgageLiabilities.propTypes = {
+ blockStyle: PropTypes.shape({
+ marginBottom: PropTypes.string,
+ }),
+ headerStyle: PropTypes.shape({
+ textAlign: PropTypes.string,
+ marginBottom: PropTypes.string,
+ }),
+ data: PropTypes.arrayOf(
+ PropTypes.shape({
+ lender: PropTypes.string,
+ monthly_service: PropTypes.boolean,
+ input_date: PropTypes.string,
+ remaining_term: PropTypes.string,
+ }),
+ ),
+ successMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ errorMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ defaultMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ buildingId: PropTypes.number,
+ updateLiabilities: PropTypes.func,
+ error: PropTypes.bool,
+ loading: PropTypes.bool,
+};
+
+export default MortgageLiabilities;
diff --git a/src/components/Blocnote/FinancialInputs/MortgageLiabilitiesRow.js b/src/components/Blocnote/FinancialInputs/MortgageLiabilitiesRow.js
new file mode 100644
index 0000000000000000000000000000000000000000..fbb2b838139b9437499d42263b56ba439e10213d
--- /dev/null
+++ b/src/components/Blocnote/FinancialInputs/MortgageLiabilitiesRow.js
@@ -0,0 +1,120 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import {
+ Button,
+ InputGroup,
+ InputGroupAddon,
+ Input,
+} from 'reactstrap';
+
+
+class MortgageLiabilitiesRow extends Component {
+ constructor(props) {
+ super(props);
+ this.handleOnChange = this.handleOnChange.bind(this);
+ this.onDelEvent = this.onDelEvent.bind(this);
+ this.state = {
+ id: props.id,
+ lender: props.lender,
+ input_date: props.inputDate,
+ monthly_service: props.monthlyService,
+ remaining_term: props.remainingTerm,
+ };
+ }
+
+ onDelEvent() {
+ this.props.onDelEvent(this.props.id);
+ }
+
+ handleOnChange = (event) => {
+ this.setState({ [event.target.name]: event.target.value },
+ () => {
+ console.log(this.state); // eslint-disable-line
+ this.props.onChangeEvent(this.state);
+ });
+ }
+
+ render() {
+ const style = { textAlign: 'left' };
+ return (
+
+ |
+ {this.props.id + 1}
+ |
+
+
+ |
+
+
+
+ $
+
+
+
+ |
+
+
+
+
+ Months
+
+
+ |
+
+
+ |
+
+
+ |
+
+ );
+ }
+}
+
+MortgageLiabilitiesRow.propTypes = {
+ id: PropTypes.number,
+ lender: PropTypes.string,
+ inputDate: PropTypes.string,
+ monthlyService: PropTypes.string,
+ remainingTerm: PropTypes.string,
+ onDelEvent: PropTypes.func,
+ onChangeEvent: PropTypes.func,
+};
+
+export default MortgageLiabilitiesRow;
diff --git a/src/components/Blocnote/FinancialInputs/ResultMessage.js b/src/components/Blocnote/FinancialInputs/ResultMessage.js
new file mode 100644
index 0000000000000000000000000000000000000000..22e20eea442a147cb6d5f14fc85ed4b5c97e7574
--- /dev/null
+++ b/src/components/Blocnote/FinancialInputs/ResultMessage.js
@@ -0,0 +1,22 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+
+const ResultMessage = (props) => {
+ return (
+
+ {props.messageContent}
+
+ );
+};
+
+ResultMessage.propTypes = {
+ messageStyle: PropTypes.shape({
+ downpayment: PropTypes.string,
+ expected_net_noi_dscr: PropTypes.string,
+ expected_payback: PropTypes.string,
+ }),
+ messageContent: PropTypes.string,
+};
+
+export default ResultMessage;
diff --git a/src/components/Blocnote/FinancialInputs/csrftoken.js b/src/components/Blocnote/FinancialInputs/csrftoken.js
new file mode 100644
index 0000000000000000000000000000000000000000..7c7bc44c5d20c8c439db5b956fe50f625c5ed3a3
--- /dev/null
+++ b/src/components/Blocnote/FinancialInputs/csrftoken.js
@@ -0,0 +1,25 @@
+import React from 'react';
+
+const getCookie = (name) => {
+ let cookieValue = null;
+ if (document.cookie && document.cookie !== '') {
+ const cookies = document.cookie.split(';');
+ for (let i = 0; i < cookies.length; i += 1) {
+ let cookie = cookies[i];
+ cookie = cookie.trim();
+ // console.log(cookie); // eslint-disable-line
+ if (cookie.substring(0, name.length + 1) === `${name}=`) {
+ cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
+ break;
+ }
+ }
+ }
+ return cookieValue;
+};
+const csrftoken = getCookie('csrftoken');
+const CSRFToken = () => {
+ return (
+
+ );
+};
+export default CSRFToken;
diff --git a/src/components/Blocnote/PreliminaryFinance/BudgetChart.js b/src/components/Blocnote/PreliminaryFinance/BudgetChart.js
new file mode 100644
index 0000000000000000000000000000000000000000..53c0d6000d1182e5b3b4ced917e039c82bfebd9c
--- /dev/null
+++ b/src/components/Blocnote/PreliminaryFinance/BudgetChart.js
@@ -0,0 +1,90 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import {
+ LineChart,
+ Line,
+ CartesianGrid,
+ XAxis,
+ YAxis,
+ Tooltip,
+ Legend,
+ ResponsiveContainer,
+} from 'recharts';
+
+
+class BudgetChart extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ successMessages: [],
+ error: false,
+ loading: false,
+ };
+ }
+
+ render() {
+ const data = [];
+ this.props.savingPotentialList.forEach((saving, index) => {
+ data.push({
+ x_name: `${saving * 100}%`,
+ loan_only: this.props.budgets[0][index],
+ loan_first: this.props.budgets[1][index],
+ sf_first: this.props.budgets[2][index],
+ sf_max: this.props.budgets[3][index],
+ });
+ });
+
+ const CustomizedLabel = React.createClass({
+ render() {
+ const { x, y, stroke, value } = this.props;
+
+ return (
+
+ {value}
+
+ );
+ },
+ });
+
+ const renderLineChart = (
+
+
+
+
+
+
+ } />
+
+
+
+
+
+
+ );
+
+ return renderLineChart;
+ }
+}
+
+BudgetChart.propTypes = {
+ // blockStyle: PropTypes.string,
+ // headerStyle: PropTypes.string,
+ x: PropTypes.number,
+ y: PropTypes.number,
+ stroke: PropTypes.number,
+ value: PropTypes.number,
+ savingPotentialList: PropTypes.arrayOf,
+ budgets: PropTypes.arrayOf,
+};
+
+export default BudgetChart;
diff --git a/src/components/Blocnote/PreliminaryFinance/CostEstimation.js b/src/components/Blocnote/PreliminaryFinance/CostEstimation.js
new file mode 100644
index 0000000000000000000000000000000000000000..6f561c3613d6e1d7bd90e5e8a7bce0d019727511
--- /dev/null
+++ b/src/components/Blocnote/PreliminaryFinance/CostEstimation.js
@@ -0,0 +1,169 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import {
+ Table,
+ Button,
+} from 'reactstrap';
+import CostEstimationRow from './CostEstimationRow';
+
+
+class CostEstimation extends Component {
+ constructor(props) {
+ super(props);
+ this.addRow = this.addRow.bind();
+ this.state = {
+ costEstimation: props.data.map((estimation) => {
+ return { item: estimation.cost_item, cost: String(estimation.cost) };
+ }),
+ id: props.data.length,
+ cost_item: null,
+ cost: null,
+ };
+ }
+
+ validateInputs = () => {
+ const emptyFields = [];
+ if (this.state.costEstimation.length > 0) {
+ Object.values(this.state.costEstimation).forEach(estimation => {
+ if (estimation.item === null &&
+ !emptyFields.includes('Item name')) {
+ emptyFields.push('Item name');
+ }
+ if (estimation.cost === null &&
+ !emptyFields.includes('Cost')) {
+ emptyFields.push('Cost');
+ }
+ });
+ }
+
+ if (emptyFields.length > 0) {
+ alert(`Please fill in ${emptyFields.join(', ')} fields`);
+ return false;
+ }
+ return true;
+ }
+
+ addRow = () => {
+ if (this.validateInputs() === true) {
+ const newEstimation = {
+ item: this.state.item,
+ cost: this.state.cost,
+ };
+ const costEstimation = this.state.costEstimation;
+ costEstimation.push(newEstimation);
+ this.setState({ costEstimation }, () => {
+ console.log(this.state.costEstimation, 'New cost estimation added!'); // eslint-disable-line
+ this.setState({
+ cost_item: null,
+ cost: null,
+ });
+ });
+ }
+ }
+
+ delRow = id => {
+ if (confirm('Are you sure to delete this estimation?') === true) {
+ const costEstimation = this.state.costEstimation.filter((estimation, index) => {
+ console.log(estimation); // eslint-disable-line
+ return index !== id;
+ });
+ this.setState({ costEstimation }, () => {
+ console.log('Estimation deleted!'); // eslint-disable-line
+ });
+ }
+ }
+
+ updRow = (row) => {
+ const costEstimation = this.state.costEstimation.map((estimation, index) => {
+ if (index === row.id) {
+ return { item: row.item, cost: String(row.cost) };
+ }
+ return estimation;
+ });
+ this.setState({ costEstimation }, () => {
+ this.props.updateCostEstimation(this.state.costEstimation);
+ console.log(costEstimation); // eslint-disable-line
+ });
+ }
+
+ render() {
+ let rows = [];
+ const tdStyle = {
+ textAlign: 'center',
+ padding: '10px 0 10px',
+ fontSize: '13px',
+ };
+
+ if (this.state.costEstimation !== null) {
+ rows = this.state.costEstimation.map((costItem, id) => {
+ return (
+
+ );
+ });
+ }
+
+ return (
+
+
+
+ |
+ Cost Estimation
+ |
+
+
+ | Item |
+ Estimated Cost |
+ Option |
+
+
+ {rows}
+
+
+
+ |
+
+ |
+
+
+
+
+ );
+ }
+}
+
+CostEstimation.propTypes = {
+ blockStyle: PropTypes.string,
+ // headerStyle: PropTypes.string,
+ data: PropTypes.arrayOf,
+ updateCostEstimation: PropTypes.func,
+};
+
+export default CostEstimation;
diff --git a/src/components/Blocnote/PreliminaryFinance/CostEstimationRow.js b/src/components/Blocnote/PreliminaryFinance/CostEstimationRow.js
new file mode 100644
index 0000000000000000000000000000000000000000..bf270674020ef5178cd0bf7ef8a56b08ab133e17
--- /dev/null
+++ b/src/components/Blocnote/PreliminaryFinance/CostEstimationRow.js
@@ -0,0 +1,81 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import {
+ Input,
+ Button,
+} from 'reactstrap';
+
+class CostEstimationRow extends Component {
+ constructor(props) {
+ super(props);
+ this.handleOnChange = this.handleOnChange.bind();
+ this.handleDelRow = this.handleDelRow.bind();
+ this.state = {
+ id: props.id,
+ item: props.item,
+ cost: props.cost,
+ };
+ }
+
+ handleDelRow = () => {
+ this.props.onDelEvent(this.props.id);
+ }
+
+ handleOnChange = (event) => {
+ this.setState({ [event.target.name]: event.target.value }, () => {
+ this.props.onUpdEvent(this.state);
+ });
+ }
+
+ render() {
+ return (
+
+ |
+
+ |
+
+
+ |
+
+
+ |
+
+ );
+ }
+}
+
+CostEstimationRow.propTypes = {
+ id: PropTypes.number,
+ item: PropTypes.string,
+ cost: PropTypes.number,
+ onUpdEvent: PropTypes.func,
+ onDelEvent: PropTypes.func,
+};
+
+export default CostEstimationRow;
diff --git a/src/components/Blocnote/PreliminaryFinance/DownPayment.js b/src/components/Blocnote/PreliminaryFinance/DownPayment.js
new file mode 100644
index 0000000000000000000000000000000000000000..5443c29f3fe15ac3de0ee33c7683cc28e83e6755
--- /dev/null
+++ b/src/components/Blocnote/PreliminaryFinance/DownPayment.js
@@ -0,0 +1,36 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+
+
+class DownPayment extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ successMessages: [],
+ error: false,
+ loading: false,
+ };
+ }
+
+ render() {
+ return (
+
+
+ Downpayment
+
+
+ {this.props.paymentAmount}
+
+
+ );
+ }
+}
+
+DownPayment.propTypes = {
+ blockStyle: PropTypes.string,
+ headerStyle: PropTypes.string,
+ paymentAmount: PropTypes.string,
+};
+
+export default DownPayment;
diff --git a/src/components/Blocnote/PreliminaryFinance/InputScenario.js b/src/components/Blocnote/PreliminaryFinance/InputScenario.js
new file mode 100644
index 0000000000000000000000000000000000000000..a31f7c5a5cc520d6587bbb0c507f7ea1587a8c68
--- /dev/null
+++ b/src/components/Blocnote/PreliminaryFinance/InputScenario.js
@@ -0,0 +1,164 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import {
+ Input,
+ Button,
+} from 'reactstrap';
+import CostEstimation from './CostEstimation';
+import SavingEstimation from './SavingEstimation';
+import ResultMessage from './../../../components/Blocnote/FinancialInputs/ResultMessage';
+
+class InputScenario extends Component {
+ constructor(props) {
+ super(props);
+ this.handleOnChange = this.handleOnChange.bind();
+ this.state = {
+ scenarioName: props.scenarioName,
+ costs: props.costs,
+ savings: props.savings,
+ loading: false,
+ action: null,
+ };
+ }
+
+ handleUpdateScenario = () => {
+ const data = {
+ scenario: this.state.scenarioName,
+ cost: this.state.costs,
+ savings: Object.values(this.state.savings),
+ };
+ console.log(data); // eslint-disable-line
+ this.props.updateScenario(
+ this.props.buildingId,
+ data,
+ );
+ this.setState({ action: 'updated' });
+ }
+
+ handleOnChange = (event) => {
+ this.setState({ [event.target.name]: event.target.value });
+ }
+
+ handleUpdateCostEstimation = (costEstiomation) => {
+ this.setState({ costs: costEstiomation }, () => {
+ console.log(this.state.costs); // eslint-disable-line
+ });
+ }
+
+ handleUpdateSavingEstimation = (savingEstiomation) => {
+ this.setState({ savings: savingEstiomation }, () => {
+ console.log(this.state.savings); // eslint-disable-line
+ });
+ }
+
+ render() {
+ let messageStyle = {};
+ let messageContent = null;
+
+ if (this.props.loading) {
+ messageContent = 'Processing ...';
+ messageStyle = this.props.defaultMessageStyle;
+ }
+
+ if (this.props.error && typeof this.props.error === 'object') {
+ messageContent = this.props.error.response.statusText;
+ messageStyle = this.props.errorMessageStyle;
+ }
+
+ if (!this.props.error && !this.props.loading
+ && this.props.data !== null
+ && this.state.action !== null) {
+ messageContent = this.state.action.charAt(0).toUpperCase() + this.state.action.slice(1);
+ messageStyle = this.props.successMessageStyle;
+ }
+
+ return (
+
+
+
+
+ {' '}{' '}
+
+
+ {' '}
+
+
+
+
+
+
+ );
+ }
+}
+
+InputScenario.propTypes = {
+ buildingId: PropTypes.number,
+ scenarioName: PropTypes.string,
+ data: PropTypes.objectOf,
+ blockStyle: PropTypes.shape({
+ marginBottom: PropTypes.string,
+ }),
+ headerStyle: PropTypes.shape({
+ textAlign: PropTypes.string,
+ marginBottom: PropTypes.string,
+ }),
+ successMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ errorMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ defaultMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ costs: PropTypes.objectOf,
+ savings: PropTypes.objectOf,
+ updateScenario: PropTypes.func,
+ error: PropTypes.bool,
+ loading: PropTypes.bool,
+};
+
+export default InputScenario;
diff --git a/src/components/Blocnote/PreliminaryFinance/LoanSummary.js b/src/components/Blocnote/PreliminaryFinance/LoanSummary.js
new file mode 100644
index 0000000000000000000000000000000000000000..eca34032e9a58c48c1f51cfc963e4bb2321b6873
--- /dev/null
+++ b/src/components/Blocnote/PreliminaryFinance/LoanSummary.js
@@ -0,0 +1,65 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import {
+ Table,
+} from 'reactstrap';
+import LoanSummaryRow from './LoanSummaryRow';
+
+
+const LoanSummary = (props) => {
+ let header = [];
+ let rows = [];
+
+ if (props.data !== null && props.data !== undefined) {
+ header = props.data[0].map((item) => {
+ return (
+ {item} |
+ );
+ });
+ props.data.shift();
+ rows = props.data.map((item) => {
+ let amountBorrowed = Math.round(item[1] * 100) / 100;
+ amountBorrowed = amountBorrowed.toLocaleString();
+ let amountUpperLimit = Math.round(item[2] * 100) / 100;
+ amountUpperLimit = amountUpperLimit.toLocaleString();
+ const annualInterestRate = item[3][1] + item[3][0];
+ const duration = `${item[4][1]} ${item[4][0]}`;
+ const monthlyDebtService = item[5].toLocaleString();
+ return (
+
+ );
+ });
+ }
+
+ return (
+
+
+ Loan Summary
+
+
+
+ {header}
+
+
+ {rows}
+
+
+
+ );
+};
+
+LoanSummary.propTypes = {
+ blockStyle: PropTypes.string,
+ headerStyle: PropTypes.string,
+ data: PropTypes.arrayOf,
+};
+
+export default LoanSummary;
diff --git a/src/components/Blocnote/PreliminaryFinance/LoanSummaryRow.js b/src/components/Blocnote/PreliminaryFinance/LoanSummaryRow.js
new file mode 100644
index 0000000000000000000000000000000000000000..2b3da2b25fed6fc54d9aa392c0a573f29f7e3871
--- /dev/null
+++ b/src/components/Blocnote/PreliminaryFinance/LoanSummaryRow.js
@@ -0,0 +1,39 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+
+const LoanSummaryRow = (props) => {
+ return (
+
+ |
+ {props.lender}
+ |
+
+ ${props.amountBorrowed}
+ |
+
+ ${props.amountUpperLimit}
+ |
+
+ {props.annualInterestRate}
+ |
+
+ {props.duration}
+ |
+
+ ${props.monthlyDebtService}
+ |
+
+ );
+};
+
+LoanSummaryRow.propTypes = {
+ lender: PropTypes.string,
+ amountBorrowed: PropTypes.number,
+ amountUpperLimit: PropTypes.number,
+ annualInterestRate: PropTypes.number,
+ duration: PropTypes.number,
+ monthlyDebtService: PropTypes.number,
+};
+
+export default LoanSummaryRow;
diff --git a/src/components/Blocnote/PreliminaryFinance/PostRetrofitBalanceSheet.js b/src/components/Blocnote/PreliminaryFinance/PostRetrofitBalanceSheet.js
new file mode 100644
index 0000000000000000000000000000000000000000..e27c3f5f7da3b13f63c790e439ac3cb69f6bd0f1
--- /dev/null
+++ b/src/components/Blocnote/PreliminaryFinance/PostRetrofitBalanceSheet.js
@@ -0,0 +1,44 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import {
+ Table,
+} from 'reactstrap';
+import TableContent from './TableContent';
+
+
+const PostRetrofitBalanceSheet = (props) => {
+ let header = [];
+
+ if (props.data !== null) {
+ header = props.data[0].map((item) => {
+ return (
+ {item} |
+ );
+ });
+ props.data.shift();
+ }
+
+ return (
+
+
+ Post Retrofit Balance Sheet
+
+
+
+ );
+};
+
+PostRetrofitBalanceSheet.propTypes = {
+ blockStyle: PropTypes.string,
+ headerStyle: PropTypes.string,
+ data: PropTypes.arrayOf,
+};
+
+export default PostRetrofitBalanceSheet;
diff --git a/src/components/Blocnote/PreliminaryFinance/PostRetrofitIncomeStatement.js b/src/components/Blocnote/PreliminaryFinance/PostRetrofitIncomeStatement.js
new file mode 100644
index 0000000000000000000000000000000000000000..c949d8967f9c130d6e8decc56de6d217e037b6c8
--- /dev/null
+++ b/src/components/Blocnote/PreliminaryFinance/PostRetrofitIncomeStatement.js
@@ -0,0 +1,44 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import {
+ Table,
+} from 'reactstrap';
+import TableContent from './TableContent';
+
+
+const PostRetrofitIncomeStatement = (props) => {
+ let header = [];
+
+ if (props.data !== null) {
+ header = props.data[0].map((item) => {
+ return (
+ {item} |
+ );
+ });
+ props.data.shift();
+ }
+
+ return (
+
+
+ Post Retrofit Income Statement
+
+
+
+ );
+};
+
+PostRetrofitIncomeStatement.propTypes = {
+ blockStyle: PropTypes.string,
+ headerStyle: PropTypes.string,
+ data: PropTypes.arrayOf,
+};
+
+export default PostRetrofitIncomeStatement;
diff --git a/src/components/Blocnote/PreliminaryFinance/PriorRetrofitBalanceSheet.js b/src/components/Blocnote/PreliminaryFinance/PriorRetrofitBalanceSheet.js
new file mode 100644
index 0000000000000000000000000000000000000000..cde948567212f1ed1c7317003a214e4bf88c2bf7
--- /dev/null
+++ b/src/components/Blocnote/PreliminaryFinance/PriorRetrofitBalanceSheet.js
@@ -0,0 +1,44 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import {
+ Table,
+} from 'reactstrap';
+import TableContent from './TableContent';
+
+
+const PriorRetrofitBalanceSheet = (props) => {
+ let header = [];
+
+ if (props.data !== null) {
+ header = props.data[0].map((item) => {
+ return (
+ {item} |
+ );
+ });
+ props.data.shift();
+ }
+
+ return (
+
+
+ Prior Retrofit Balance Sheet
+
+
+
+ );
+};
+
+PriorRetrofitBalanceSheet.propTypes = {
+ blockStyle: PropTypes.string,
+ headerStyle: PropTypes.string,
+ data: PropTypes.arrayOf,
+};
+
+export default PriorRetrofitBalanceSheet;
diff --git a/src/components/Blocnote/PreliminaryFinance/PriorRetrofitIncomeStatement.js b/src/components/Blocnote/PreliminaryFinance/PriorRetrofitIncomeStatement.js
new file mode 100644
index 0000000000000000000000000000000000000000..0a03858103592702d1f02e561cb825d3e126498f
--- /dev/null
+++ b/src/components/Blocnote/PreliminaryFinance/PriorRetrofitIncomeStatement.js
@@ -0,0 +1,44 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import {
+ Table,
+} from 'reactstrap';
+import TableContent from './TableContent';
+
+
+const PriorRetrofitIncomeStatement = (props) => {
+ let header = [];
+
+ if (props.data !== null) {
+ header = props.data[0].map((item) => {
+ return (
+ {item} |
+ );
+ });
+ props.data.shift();
+ }
+
+ return (
+
+
+ Prior Retrofit Income Statement
+
+
+
+ );
+};
+
+PriorRetrofitIncomeStatement.propTypes = {
+ blockStyle: PropTypes.string,
+ headerStyle: PropTypes.string,
+ data: PropTypes.arrayOf,
+};
+
+export default PriorRetrofitIncomeStatement;
diff --git a/src/components/Blocnote/PreliminaryFinance/ProjectEconomics.js b/src/components/Blocnote/PreliminaryFinance/ProjectEconomics.js
new file mode 100644
index 0000000000000000000000000000000000000000..9332a32d777ab330fe4278b26edfcde8539a8c86
--- /dev/null
+++ b/src/components/Blocnote/PreliminaryFinance/ProjectEconomics.js
@@ -0,0 +1,51 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import ProjectEconomicsRow from './ProjectEconomicsRow';
+
+class ProjectEconomics extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ successMessages: [],
+ };
+ }
+
+ render() {
+ let rows = [];
+
+ if (this.props.data !== null) {
+ rows = this.props.data.filter((item) => {
+ if (item.length === 0) {
+ return false; // skip
+ }
+ return true;
+ }).map((item) => {
+ return (
+
+ );
+ });
+ }
+
+ return (
+
+
+ Project Economics
+
+
+
+ );
+ }
+}
+
+ProjectEconomics.propTypes = {
+ blockStyle: PropTypes.string,
+ headerStyle: PropTypes.string,
+ data: PropTypes.arrayOf,
+};
+
+export default ProjectEconomics;
diff --git a/src/components/Blocnote/PreliminaryFinance/ProjectEconomicsRow.js b/src/components/Blocnote/PreliminaryFinance/ProjectEconomicsRow.js
new file mode 100644
index 0000000000000000000000000000000000000000..5315d9b9ae14fbce39551afd17030261e7bb2ae1
--- /dev/null
+++ b/src/components/Blocnote/PreliminaryFinance/ProjectEconomicsRow.js
@@ -0,0 +1,35 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+
+
+class ProjectEconomicsRow extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ successMessages: [],
+ error: false,
+ loading: false,
+ };
+ }
+
+ render() {
+ return (
+
+ |
+ {this.props.row_name}
+ |
+
+ {this.props.amount}
+ |
+
+ );
+ }
+}
+
+ProjectEconomicsRow.propTypes = {
+ row_name: PropTypes.string,
+ amount: PropTypes.number,
+};
+
+export default ProjectEconomicsRow;
diff --git a/src/components/Blocnote/PreliminaryFinance/SavingEstimation.js b/src/components/Blocnote/PreliminaryFinance/SavingEstimation.js
new file mode 100644
index 0000000000000000000000000000000000000000..904edc0c962e88c7965d044ef15d4e97586d1844
--- /dev/null
+++ b/src/components/Blocnote/PreliminaryFinance/SavingEstimation.js
@@ -0,0 +1,92 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import {
+ Table,
+} from 'reactstrap';
+import SavingEstimationRow from './SavingEstimationRow';
+
+
+class SavingEstimation extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ savingEstimation: props.data,
+ };
+ }
+
+ updRow = (row) => {
+ const newRow = row;
+ const savingEstimation = this.state.savingEstimation;
+ newRow.estimated_savings = String(row.estimated_savings);
+ savingEstimation[row.utilityType] = newRow;
+ this.setState({ savingEstimation }, () => {
+ this.props.updateSavingEstimation(this.state.savingEstimation);
+ console.log(this.state.savingEstimation); // eslint-disable-line
+ });
+ }
+
+ render() {
+ const tdStyle = {
+ textAlign: 'center',
+ padding: '10px 0 10px',
+ fontSize: '13px',
+ };
+ const rows = [];
+ console.log(this.state.savingEstimation); // eslint-disable-line
+
+ if (this.state.savingEstimation !== null) {
+ Object.entries(this.state.savingEstimation).forEach(([utilityName, utilityData]) => {
+ rows.push(
+
+ );
+ });
+ }
+
+ return (
+
+
+
+ |
+ Saving Estimation
+ |
+
+
+ | Utility |
+ Estimated Savings |
+ Used Before Retrofit |
+ Used After Retrofit |
+
+
+ {rows}
+
+
+
+ );
+ }
+}
+
+SavingEstimation.propTypes = {
+ blockStyle: PropTypes.string,
+ // headerStyle: PropTypes.string,
+ data: PropTypes.objectOf,
+ updateSavingEstimation: PropTypes.func,
+};
+
+export default SavingEstimation;
diff --git a/src/components/Blocnote/PreliminaryFinance/SavingEstimationRow.js b/src/components/Blocnote/PreliminaryFinance/SavingEstimationRow.js
new file mode 100644
index 0000000000000000000000000000000000000000..fe346d30ac7d7b6bb8355f787e379e7ff9586c43
--- /dev/null
+++ b/src/components/Blocnote/PreliminaryFinance/SavingEstimationRow.js
@@ -0,0 +1,94 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import {
+ FormGroup,
+ Label,
+ Input,
+} from 'reactstrap';
+
+
+class SavingEstimationRow extends Component {
+ constructor(props) {
+ super(props);
+ this.handleOnChange = this.handleOnChange.bind();
+ this.state = {
+ estimatedSavings: props.estimatedSavings,
+ usedBeforeRetrofit: props.usedBeforeRetrofit,
+ usedAfterRetrofit: props.usedAfterRetrofit,
+ utilityType: props.utilityType,
+ };
+ console.log(props); // eslint-disable-line
+ }
+
+ handleOnChange = (event) => {
+ this.setState({ [event.target.name]:
+ ['usedBeforeRetrofit', 'usedAfterRetrofit'].includes(event.target.name) ?
+ event.target.checked : event.target.value },
+ () => {
+ this.props.updRow(this.state);
+ });
+ }
+
+ render() {
+ console.log(this.state); // eslint-disable-line
+ return (
+
+ |
+ {this.props.utilityName}
+ |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+ |
+
+ );
+ }
+}
+
+SavingEstimationRow.propTypes = {
+ tdStyle: PropTypes.string,
+ utilityType: PropTypes.string,
+ utilityName: PropTypes.string,
+ estimatedSavings: PropTypes.number,
+ usedBeforeRetrofit: PropTypes.bool,
+ usedAfterRetrofit: PropTypes.bool,
+ updRow: PropTypes.func,
+};
+
+export default SavingEstimationRow;
diff --git a/src/components/Blocnote/PreliminaryFinance/SavingsScheduleChart.js b/src/components/Blocnote/PreliminaryFinance/SavingsScheduleChart.js
new file mode 100644
index 0000000000000000000000000000000000000000..e548f3326698b2fa1b2d4029cab08a92de9eaf8f
--- /dev/null
+++ b/src/components/Blocnote/PreliminaryFinance/SavingsScheduleChart.js
@@ -0,0 +1,76 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import {
+ BarChart,
+ Bar,
+ CartesianGrid,
+ XAxis,
+ YAxis,
+ Tooltip,
+ Legend,
+ ResponsiveContainer,
+} from 'recharts';
+
+
+class SavingsScheduleChart extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ successMessages: [],
+ error: false,
+ loading: false,
+ };
+ }
+
+ render() {
+ const data = [];
+ const chartData = this.props.chartData;
+ chartData.year_list.forEach((year, index) => {
+ data.push({
+ year_label: year,
+ net_savings_list: chartData.net_savings_list[index],
+ total_loan_list: chartData.total_loan_list[index],
+ energy_expense_list: chartData.energy_expense_list[index],
+ });
+ });
+
+ const renderBarChart = (
+
+
+ Energy Expense Savings Projection
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+
+ return renderBarChart;
+ }
+}
+
+SavingsScheduleChart.propTypes = {
+ blockStyle: PropTypes.string,
+ headerStyle: PropTypes.string,
+ chartData: PropTypes.objectOf,
+};
+
+export default SavingsScheduleChart;
diff --git a/src/components/Blocnote/PreliminaryFinance/SelectScenario.js b/src/components/Blocnote/PreliminaryFinance/SelectScenario.js
new file mode 100644
index 0000000000000000000000000000000000000000..44ac0af7ada2861b72a005a55bddd3595c1c892e
--- /dev/null
+++ b/src/components/Blocnote/PreliminaryFinance/SelectScenario.js
@@ -0,0 +1,66 @@
+import React, { Component } from 'react';
+import {
+ Dropdown,
+ DropdownToggle,
+ DropdownMenu,
+ DropdownItem,
+} from 'reactstrap';
+
+
+class SelectScenario extends Component {
+ constructor(props) {
+ super(props);
+ this.toggleScenario = this.toggleScenario.bind(this);
+ this.changeScenario = this.changeScenario.bind(this);
+ this.state = {
+ successMessages: [],
+ error: false,
+ loading: false,
+ scenarioDropdownOpen: false,
+ scenarioDropDownValue: 'Select Scenario',
+ scenarioOptions: [
+ { id: 'Scenario1', key: 'Scenario1', name: 'Scenario 1' },
+ { id: 'Scenario2', key: 'Scenario2', name: 'Scenario 2' },
+ ],
+ };
+ }
+
+ toggleScenario() {
+ this.setState({
+ scenarioDropdownOpen: !this.state.scenarioDropdownOpen,
+ });
+ }
+
+ changeScenario(e) {
+ this.setState({ scenarioDropDownValue: e.currentTarget.textContent });
+ }
+
+ render() {
+ const scenarioOptions = this.state.scenarioOptions.map(e => {
+ return (
+
+ {e.name}
+
+ );
+ });
+ return (
+
+
+
+ {this.state.scenarioDropDownValue}
+
+
+ {scenarioOptions}
+
+
+
+
+ );
+ }
+}
+
+export default SelectScenario;
diff --git a/src/components/Blocnote/PreliminaryFinance/TableContent.js b/src/components/Blocnote/PreliminaryFinance/TableContent.js
new file mode 100644
index 0000000000000000000000000000000000000000..8d0c0b918f657cb1a28f0b025108c3c824d0f859
--- /dev/null
+++ b/src/components/Blocnote/PreliminaryFinance/TableContent.js
@@ -0,0 +1,45 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+
+const TableContent = (props) => {
+ let rows = [];
+
+ if (props.rows !== null) {
+ rows = props.rows.map((items) => {
+ const cells = items.map((item) => {
+ let cellValue = item;
+ if (typeof (item) !== 'string') {
+ cellValue = Math.round(item * 100) / 100;
+ cellValue = cellValue.toLocaleString();
+ cellValue = `$${cellValue}`;
+ }
+
+ return (
+
+
+ {cellValue}
+
+ |
+ );
+ });
+
+ return (
+
+ {cells}
+
);
+ });
+ }
+
+ return (
+
+ {rows}
+
+ );
+};
+
+TableContent.propTypes = {
+ rows: PropTypes.arrayOf,
+};
+
+export default TableContent;
diff --git a/src/components/Blocnote/PreliminaryFinance/test.js b/src/components/Blocnote/PreliminaryFinance/test.js
new file mode 100644
index 0000000000000000000000000000000000000000..ba2a8bafb90ff86283e2a7f0cc16afd37a81cac0
--- /dev/null
+++ b/src/components/Blocnote/PreliminaryFinance/test.js
@@ -0,0 +1,53 @@
+import React, { PureComponent } from 'react';
+import {
+ BarChart, Bar, Cell, XAxis, YAxis, CartesianGrid, Tooltip, Legend,
+} from 'recharts';
+
+const data = [
+ {
+ name: 'Page A', uv: 4000, pv: 2400, amt: 2400,
+ },
+ {
+ name: 'Page B', uv: 3000, pv: 1398, amt: 2210,
+ },
+ {
+ name: 'Page C', uv: 2000, pv: 9800, amt: 2290,
+ },
+ {
+ name: 'Page D', uv: 2780, pv: 3908, amt: 2000,
+ },
+ {
+ name: 'Page E', uv: 1890, pv: 4800, amt: 2181,
+ },
+ {
+ name: 'Page F', uv: 2390, pv: 3800, amt: 2500,
+ },
+ {
+ name: 'Page G', uv: 3490, pv: 4300, amt: 2100,
+ },
+];
+
+export default class Example extends PureComponent {
+ static jsfiddleUrl = 'https://jsfiddle.net/alidingling/30763kr7/';
+
+ render() {
+ return (
+
+
+
+
+
+
+
+
+
+ );
+ }
+}
diff --git a/src/components/Blocnote/styles.css b/src/components/Blocnote/styles.css
new file mode 100644
index 0000000000000000000000000000000000000000..e6249044b459f8a87ac5ea47970b50ac1a55735a
--- /dev/null
+++ b/src/components/Blocnote/styles.css
@@ -0,0 +1,14 @@
+.top-notification {
+ position: fixed;
+ z-index: 1060;
+ top: 0;
+ left: 0;
+ right: 0;
+ text-align: center;
+ overflow: hidden;
+}
+
+.top-notification-item {
+ border-radius: 0px !important;
+ line-height: 2;
+}
diff --git a/src/components/SideBarDetail/index.js b/src/components/SideBarDetail/index.js
index bf06ec463dee55120fc4fb00d00088f2b9c0e5ea..d648702f89cab73b7a23fc7594e63f2a4f295a32 100644
--- a/src/components/SideBarDetail/index.js
+++ b/src/components/SideBarDetail/index.js
@@ -210,14 +210,11 @@ export default function SideBarDetail({ building, children, contacts, user }) {
Reports
-
-
+
+
{blocnoteSVG}
Blocnote
-
+
diff --git a/src/containers/BGroup/BGroupBuildingTable.js b/src/containers/BGroup/BGroupBuildingTable.js
index d44d918138daac947a107f3ee8ac1970bb7c5a8d..018de06e0704c4f749dfff6ca443098e6a8bc1e2 100644
--- a/src/containers/BGroup/BGroupBuildingTable.js
+++ b/src/containers/BGroup/BGroupBuildingTable.js
@@ -1,11 +1,11 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
-import { CSVLink } from 'react-csv';
import ReactTable from 'react-table';
import ReactTooltip from 'react-tooltip';
import { Link } from 'react-router';
import { Icon } from 'react-fa';
import ReactGA from 'react-ga';
+import { CSVLink } from 'react-csv';
import {
Input, Collapse, UncontrolledDropdown,
DropdownToggle, DropdownMenu, DropdownItem,
diff --git a/src/containers/Blocnote/BudgetSimulator/actions.js b/src/containers/Blocnote/BudgetSimulator/actions.js
new file mode 100644
index 0000000000000000000000000000000000000000..157a250fd5448e30c94dab5e3a9bcb30a600c06e
--- /dev/null
+++ b/src/containers/Blocnote/BudgetSimulator/actions.js
@@ -0,0 +1,6 @@
+import * as constants from './constants';
+import { makeActionCreator } from '../../../utils/reduxHelpers';
+
+export const loadBudgetSimulator = makeActionCreator(constants.BUDGET_SIMULATOR_REQUESTED, 'buildingId');
+export const budgetSimulatorLoaded = makeActionCreator(constants.BUDGET_SIMULATOR_SUCCEEDED, 'instance');
+export const budgetSimulatorFailed = makeActionCreator(constants.BUDGET_SIMULATOR_FAILED, 'error');
diff --git a/src/containers/Blocnote/BudgetSimulator/constants.js b/src/containers/Blocnote/BudgetSimulator/constants.js
new file mode 100644
index 0000000000000000000000000000000000000000..c0dbcb69bd2310d6314085618801271d4274bd10
--- /dev/null
+++ b/src/containers/Blocnote/BudgetSimulator/constants.js
@@ -0,0 +1,3 @@
+export const BUDGET_SIMULATOR_REQUESTED = 'BUDGET_SIMULATOR_REQUESTED';
+export const BUDGET_SIMULATOR_SUCCEEDED = 'BUDGET_SIMULATOR_SUCCEEDED';
+export const BUDGET_SIMULATOR_FAILED = 'BUDGET_SIMULATOR_FAILED';
diff --git a/src/containers/Blocnote/BudgetSimulator/index.js b/src/containers/Blocnote/BudgetSimulator/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..00b40c5aa2aec6d03cac1a6b5a27466f1bc52c83
--- /dev/null
+++ b/src/containers/Blocnote/BudgetSimulator/index.js
@@ -0,0 +1,118 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
+import LinkBarDetail from '../../../components/LinkBarDetail';
+import buildingDetailPropTypes from '../../Building/propTypes';
+import './../styles.css';
+import Loading from '../../../components/Loading';
+import BugetTable from '../../../components/Blocnote/BudgetSimulator/BugetTable';
+import BudgetChart from '../../../components/Blocnote/BudgetSimulator/BudgetChart';
+import { loadBudgetSimulator } from './actions';
+import blocnoteProps from './../propTypes';
+
+
+class BudgetSimulator extends Component {
+ componentDidMount() {
+ this.props.loadBudgetSimulator(this.props.building.building_id);
+ }
+
+ processData = (data) => {
+ console.log(data); // eslint-disable-line
+ const tables = data.instance.tables;
+ return {
+ savingPotentialList: data.instance.saving_potential_list,
+ budgetLoanFirst: data.instance.tables.budget_loan_first,
+ budgetLoanOnly: data.instance.tables.budget_loan_only,
+ budgetSfFirst: data.instance.tables.budget_sf_first,
+ budgetSfMax: data.instance.tables.budget_sf_max,
+ budgets: Object.keys(tables).map(tableName => tables[tableName][0].slice(1)),
+ };
+ }
+
+ render() {
+ let mainContent = null;
+ let bugetTables = [];
+ const blockStyle = { marginBottom: '40px' };
+ const tableKeys = [
+ 'budgetLoanFirst',
+ 'budgetLoanOnly',
+ 'budgetSfFirst',
+ 'budgetSfMax',
+ ];
+ const tableNames = {
+ budgetLoanFirst: 'Budget with Loan only',
+ budgetLoanOnly: 'Budget with Loan first',
+ budgetSfFirst: 'Budget with SF first',
+ budgetSfMax: 'Budget with SF maximum',
+ };
+
+ const { blocnote } = this.props;
+ const { budgetSimulator } = blocnote;
+ const { data } = budgetSimulator;
+
+ if (data === null) {
+ mainContent = ;
+ } else {
+ const dataDic = this.processData(data);
+ bugetTables = tableKeys.map((tableKey) => {
+ return (
+
+
+
+ );
+ });
+
+ mainContent = (
+
+ );
+ }
+
+ return (
+
+
+ {mainContent}
+
+ );
+ }
+}
+
+BudgetSimulator.propTypes = {
+ building: buildingDetailPropTypes,
+ blocnote: blocnoteProps,
+ loadBudgetSimulator: PropTypes.func,
+ buildingId: PropTypes.string,
+};
+
+const mapDispatchToProps = dispatch => (
+ bindActionCreators({
+ loadBudgetSimulator,
+ }, dispatch)
+);
+
+const mapStateToProps = state => ({
+ blocnote: state.blocnote,
+});
+
+export default connect(mapStateToProps, mapDispatchToProps)(BudgetSimulator);
diff --git "a/src/containers/Blocnote/FinancialInputs/\bIncomeStatements.js" "b/src/containers/Blocnote/FinancialInputs/\bIncomeStatements.js"
new file mode 100644
index 0000000000000000000000000000000000000000..e8db590725766d50e245303c520eeace7b26ae79
--- /dev/null
+++ "b/src/containers/Blocnote/FinancialInputs/\bIncomeStatements.js"
@@ -0,0 +1,605 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import {
+ Dropdown,
+ DropdownToggle,
+ DropdownMenu,
+ DropdownItem,
+ Button,
+ Input,
+ InputGroup,
+ InputGroupAddon,
+ Table,
+} from 'reactstrap';
+import ResultMessage from './../../../components/Blocnote/FinancialInputs/ResultMessage';
+
+
+class IncomeStatements extends Component {
+ constructor(props) {
+ super(props);
+ this.toggleGrowthRate = this.toggleGrowthRate.bind(this);
+ this.changeGrowthRate = this.changeGrowthRate.bind(this);
+ this.handleOnChange = this.handleOnChange.bind(this);
+ // this.handleOnChangeNew = this.handleOnChangeNew.bind(this);
+
+ const obj = {
+ GRDropdownOpen: false,
+ GRDropdownValue: 'Select Growth Rate',
+ selectedDropdownId: 0,
+ growthRateOptions: [
+ { id: '-2', key: '-2', name: 'CAGR=1.58%' },
+ { id: '-1', key: '-1', name: 'Average' },
+ { id: '0', key: '0', name: '0%' },
+ { id: '1', key: '1', name: '1%' },
+ { id: '2', key: '2', name: '2%' },
+ { id: '3', key: '3', name: '3%' },
+ { id: '4', key: '4', name: '4%' },
+ { id: '5', key: '5', name: '5%' },
+ { id: '6', key: '6', name: '6%' },
+ { id: '7', key: '7', name: '7%' },
+ { id: '8', key: '8', name: '8%' },
+ { id: '9', key: '9', name: '9%' },
+ { id: '10', key: '10', name: '10%' },
+ { id: '11', key: '11', name: '11%' },
+ { id: '12', key: '12', name: '12%' },
+ { id: '13', key: '13', name: '13%' },
+ { id: '14', key: '14', name: '14%' },
+ { id: '15', key: '15', name: '15%' },
+ ],
+ incomeStatements: props.data,
+ incomeStatementsNew: null,
+ error: false,
+ loading: false,
+ action: null,
+ };
+
+ const histYears = {};
+ const incomeStatementsNew = { incomeStatementsNew: [] };
+ if (props.data.hist !== null) {
+ Object.keys(props.data.hist).forEach((year, id) => {
+ const histYear = `Year-${id + 1}`;
+ histYears[histYear] = parseInt(year, 10);
+ });
+ } else {
+ [0, 1, 2].forEach(id => {
+ const histYear = `Year-${id + 1}`;
+ histYears[histYear] = null;
+ });
+
+ const growthRate = {};
+ growthRate['growth-rate'] = props.data.cagr;
+ incomeStatementsNew.incomeStatementsNew.push(this.initIncomeStatement());
+ incomeStatementsNew.incomeStatementsNew.push(this.initIncomeStatement());
+ incomeStatementsNew.incomeStatementsNew.push(this.initIncomeStatement());
+ incomeStatementsNew.incomeStatementsNew.push(growthRate);
+ }
+
+ this.state = Object.assign(obj, histYears, incomeStatementsNew);
+ console.log(this.state); // eslint-disable-line
+ }
+
+ initIncomeStatement = () => {
+ const statement = {
+ year: null,
+ revenue: null,
+ };
+ statement['utility-expense'] = null;
+ statement['non-utility-operating-expense'] = null;
+ return statement;
+ }
+
+ handleOnChange = (event) => {
+ const year = event.target.id;
+ const targetName = event.target.name;
+ const copyIS = this.state.incomeStatements;
+ Object.entries(copyIS.hist).forEach((incomeStatement) => {
+ if (incomeStatement[0] === year) {
+ copyIS.hist[year][targetName] = parseFloat(event.target.value);
+ }
+ });
+
+ this.setState({ incomeStatements: copyIS }, () => {
+ console.log(this.state.incomeStatements); // eslint-disable-line
+ });
+ }
+
+ handleOnChangeNew = (event) => {
+ const id = event.target.id;
+ const targetName = event.target.name.includes('Year') ? 'year' : event.target.name;
+ const targetValue = event.target.value;
+ const copyISNew = this.state.incomeStatementsNew.map((item, key) => {
+ if (parseInt(key, 10) === parseInt(id, 10)) {
+ const tmp = item;
+ tmp[targetName] = targetValue;
+ return tmp;
+ }
+ return item;
+ });
+ this.setState({ incomeStatementsNew: copyISNew }, () => {
+ console.log(this.state.incomeStatementsNew); // eslint-disable-line
+ });
+ }
+
+ toggleGrowthRate() {
+ this.setState({
+ GRDropdownOpen: !this.state.GRDropdownOpen,
+ });
+ }
+
+ changeGrowthRate(e) {
+ this.setState({ GRDropdownValue: e.currentTarget.textContent });
+ this.setState({ selectedDropdownId: e.currentTarget.id });
+ }
+
+ buildHeader = () => {
+ const headers = [];
+ const year = 'year';
+ headers.push(
+
+ Year
+ |
+ );
+
+ Object.entries(this.state).forEach((entry, key) => {
+ if (entry[0].includes('Year')) {
+ headers.push(
+
+
+ |
+ );
+ }
+ });
+ const futureYear = this.state.incomeStatements.future.year;
+ headers.push(
+
+ {futureYear}
+ |
+ );
+ const average = 'average';
+ headers.push(
+
+ Average
+ |
+ );
+ return headers;
+ }
+
+ buildEmptyHeader = () => {
+ const headers = [];
+ const year = 'year';
+ headers.push(
+
+ Year
+ |
+ );
+ let id = 0;
+ Object.entries(this.state).forEach((entry, key) => {
+ if (entry[0].includes('Year')) {
+ headers.push(
+
+
+ |
+ );
+ id += 1;
+ }
+ });
+ headers.push(
+
+ {' '}Next Year{' '}
+ |
+ );
+ headers.push(
+
+ {' '}Average{' '}
+ |
+ );
+ return headers;
+ }
+
+ handleUpdateIncomeStatements = () => {
+ this.setState({ loading: true });
+ const hist = [];
+ Object.entries(this.state.incomeStatements.hist).forEach(incomeStatement => {
+ const obj = {
+ year: String(incomeStatement[0]),
+ revenue: String(incomeStatement[1].revenue),
+ };
+ obj['non-utility-operating-expense'] = String(incomeStatement[1].non_utility_expense);
+ obj['utility-expense'] = String(incomeStatement[1].utility_expense);
+ hist.push(obj);
+ });
+ const growthRate = {};
+ growthRate['growth-rate'] = String(this.state.selectedDropdownId);
+ hist.push(growthRate);
+ this.props.updateIncomeStatements(
+ this.props.buildingId,
+ hist,
+ );
+ this.setState({
+ loading: false,
+ action: 'updated',
+ });
+ }
+
+ handleCreateIncomeStatements = () => {
+ const emptyMessages = [];
+ const incomeStatementsNew = Object.values(this.state.incomeStatementsNew.slice(0, 3))
+ .map(statement => {
+ if (statement.year === null &&
+ !emptyMessages.includes('Year')) {
+ emptyMessages.push('Year');
+ }
+ if (statement.revenue === null &&
+ !emptyMessages.includes('Revenue')) {
+ emptyMessages.push('Revenue');
+ }
+ if (statement['utility-expense'] === null &&
+ !emptyMessages.includes('Utility Expense')) {
+ emptyMessages.push('Utility Expense');
+ }
+ if (statement['non-utility-operating-expense'] === null &&
+ !emptyMessages.includes('Non-Utility Operating Expense')) {
+ emptyMessages.push('Non-Utility Operating Expense');
+ }
+
+ const newStatement = {};
+ newStatement.year = String(statement.year);
+ newStatement.revenue = String(statement.revenue);
+ newStatement['utility-expense'] = String(statement['utility-expense']);
+ newStatement['non-utility-operating-expense'] = String(statement['non-utility-operating-expense']);
+ return newStatement;
+ });
+
+ if (emptyMessages.length !== 0) {
+ const msg = `Please fill in ${emptyMessages.join(', ')} fields.`;
+ alert(msg);
+ } else {
+ const growthRate = {};
+ growthRate['growth-rate'] = String(this.state.incomeStatementsNew[3]['growth-rate']);
+ incomeStatementsNew.push(growthRate);
+ this.setState({ loading: true });
+ this.props.updateIncomeStatements(
+ this.props.buildingId,
+ incomeStatementsNew,
+ );
+ this.setState({
+ loading: false,
+ action: 'updated',
+ });
+ }
+ }
+
+ render() {
+ let header = [];
+ let rows = [];
+ let calculateSaveButton = null;
+
+ const columnKeys = [
+ 'revenue',
+ 'utility_expense',
+ 'energy_opex',
+ 'electric_opex',
+ 'gas_opex',
+ 'oil_opex',
+ 'water_opex',
+ 'other_utility',
+ 'non_utility_expense',
+ 'net_non_energy_opex',
+ 'total_opex',
+ 'noi',
+ ];
+
+ const columnNames = {
+ revenue: 'Revenue',
+ utility_expense: 'Utility Expense',
+ energy_opex: 'Energy Expense',
+ electric_opex: 'Electric Bill',
+ gas_opex: 'Gas Bill',
+ oil_opex: 'Oil Bill',
+ water_opex: 'Water Bill',
+ other_utility: 'Other Utility Expense',
+ non_utility_expense: 'Non-Utility Operating Expense',
+ net_non_energy_opex: 'Net Non-Energy Expense',
+ total_opex: 'Total Expense',
+ noi: 'Net Operating Income',
+ };
+
+ const growthRateOptions = this.state.growthRateOptions.map(e => {
+ return (
+
+ {e.name}
+
+ );
+ });
+
+ if (this.state.incomeStatements.hist !== null &&
+ this.state.incomeStatements.future !== null) {
+ header = this.buildHeader();
+ const histYears = Object.keys(this.state.incomeStatements.hist).sort();
+ rows = columnKeys.map((columnKey, id) => {
+ const cells = [
+ ...[columnNames[columnKey]],
+ ...histYears.map((histYear) => {
+ let cellValue = this.state.incomeStatements.hist[histYear][columnKey];
+ cellValue = Math.round(cellValue * 100) / 100;
+ if (['utility_expense', 'revenue', 'non_utility_expense'].includes(columnKey)) {
+ return (
+
+
+ $
+
+
+
+ );
+ }
+ cellValue = cellValue.toLocaleString();
+ cellValue = `$${cellValue}`;
+ return cellValue;
+ }),
+ ...[this.state.incomeStatements.future[columnKey]].map((amount) => {
+ let cellValue = amount;
+ cellValue = Math.round(cellValue * 100) / 100;
+ cellValue = cellValue.toLocaleString();
+ cellValue = `$${cellValue}`;
+ return cellValue;
+ }),
+ ...Object.values([this.state.incomeStatements.average[columnKey]]).map((amount) => {
+ let cellValue = amount;
+ cellValue = Math.round(cellValue * 100) / 100;
+ cellValue = cellValue.toLocaleString();
+ cellValue = `$${cellValue}`;
+ return cellValue;
+ }),
+ ];
+
+ const cellsData = Object.values(cells).map((celldata, key) => {
+ return (
+
+
+ {celldata}
+
+ |
+ );
+ });
+
+ return (
+
+ {cellsData}
+
+ );
+ });
+
+ calculateSaveButton = (
+
+ );
+ } else {
+ header = this.buildEmptyHeader();
+ const ids = Object.keys(this.state.incomeStatementsNew).slice(0, 3).sort();
+ console.log(this.state.incomeStatementsNew); // eslint-disable-line
+ rows = columnKeys.map((columnKey, id) => {
+ const cells = [
+ ...[columnNames[columnKey]],
+ ...ids.map((index) => {
+ const keyMapping = {
+ revenue: 'revenue',
+ utility_expense: 'utility-expense',
+ non_utility_expense: 'non-utility-operating-expense',
+ };
+
+ if (['revenue', 'utility_expense', 'non_utility_expense'].includes(columnKey)) {
+ const newColumnKey = keyMapping[columnKey];
+ return (
+
+
+ $
+
+
+
+ );
+ }
+ return null;
+ }),
+ ...['', ''],
+ ];
+
+ const cellsData = Object.values(cells).map((celldata, key) => {
+ return (
+
+
+ {celldata}
+
+ |
+ );
+ });
+
+ return (
+
+ {cellsData}
+
+ );
+ });
+
+ calculateSaveButton = (
+
+ );
+ }
+
+ let messageStyle = {};
+ let messageContent = null;
+
+ if (this.state.loading) {
+ messageContent = 'Processing ...';
+ messageStyle = this.props.defaultMessageStyle;
+ }
+
+ if (this.state.error && typeof this.state.error === 'object') {
+ messageContent = this.state.error.response.statusText;
+ messageStyle = this.props.errorMessageStyle;
+ }
+
+ if (!this.state.error && !this.state.loading
+ && this.state.incomeStatements !== null
+ && this.state.action !== null) {
+ messageContent = this.state.action.charAt(0).toUpperCase() + this.state.action.slice(1);
+ messageStyle = this.props.successMessageStyle;
+ }
+
+ return (
+
+
+ Income Statements (in $, End of Year)
+
+
+
+
+
+ {this.state.GRDropdownValue}
+
+
+ {growthRateOptions}
+
+
+
+
+
+ {calculateSaveButton}
+
+
+
+
+
+
+ {header}
+
+
+ {rows}
+
+
+
+
+
+ );
+ }
+}
+
+IncomeStatements.propTypes = {
+ blockStyle: PropTypes.shape({
+ marginBottom: PropTypes.string,
+ }),
+ headerStyle: PropTypes.shape({
+ textAlign: PropTypes.string,
+ marginBottom: PropTypes.string,
+ }),
+ buildingId: PropTypes.number,
+ data: PropTypes.shape({
+ average: PropTypes.shape({
+ electric_opex: PropTypes.number,
+ energy_opex: PropTypes.number,
+ gas_opex: PropTypes.number,
+ net_non_energy_opex: PropTypes.number,
+ noi: PropTypes.number,
+ non_utility_expense: PropTypes.number,
+ oil_opex: PropTypes.number,
+ other_utility: PropTypes.number,
+ revenue: PropTypes.number,
+ total_opex: PropTypes.number,
+ utility_expense: PropTypes.number,
+ water_opex: PropTypes.number,
+ year: null,
+ }),
+ cagr: PropTypes.number,
+ future: PropTypes.shape({
+ electric_opex: PropTypes.number,
+ energy_opex: PropTypes.number,
+ gas_opex: PropTypes.number,
+ net_non_energy_opex: PropTypes.number,
+ noi: PropTypes.number,
+ non_utility_expense: PropTypes.number,
+ oil_opex: PropTypes.number,
+ other_utility: PropTypes.number,
+ revenue: PropTypes.number,
+ total_opex: PropTypes.number,
+ utility_expense: PropTypes.number,
+ water_opex: PropTypes.number,
+ year: null,
+ }),
+ growth_rate: PropTypes.number,
+ hist: PropTypes.objectOf,
+ result: PropTypes.arrayOf(PropTypes.shape({
+ year: PropTypes.string,
+ revenue: PropTypes.string,
+ utility_expense: PropTypes.string,
+ non_utility_operating_expense: PropTypes.string,
+ })),
+ }),
+ successMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ errorMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ defaultMessageStyle: PropTypes.shape({
+ color: PropTypes.string,
+ paddingLeft: PropTypes.string,
+ fontWeight: PropTypes.string,
+ }),
+ updateIncomeStatements: PropTypes.func,
+};
+
+export default IncomeStatements;
diff --git a/src/containers/Blocnote/FinancialInputs/actions.js b/src/containers/Blocnote/FinancialInputs/actions.js
new file mode 100644
index 0000000000000000000000000000000000000000..f33d0c046c7a6530cbf94d005f60542e293fe169
--- /dev/null
+++ b/src/containers/Blocnote/FinancialInputs/actions.js
@@ -0,0 +1,68 @@
+import * as constants from './constants';
+import { makeActionCreator } from '../../../utils/reduxHelpers';
+
+export const loadFinanceOverview = makeActionCreator(constants.FINANCE_OVERVIEW_REQUESTED, 'buildingId');
+export const financeOverviewLoaded = makeActionCreator(constants.FINANCE_OVERVIEW_SUCCEEDED, 'instance');
+export const financeOverviewFailed = makeActionCreator(constants.FINANCE_OVERVIEW_FAILED, 'error');
+export const loadBills = makeActionCreator(constants.BILLS_REQUESTED, 'buildingId');
+export const billsLoaded = makeActionCreator(constants.BILLS_SUCCEEDED, 'instance');
+export const billsFailed = makeActionCreator(constants.BILLS_FAILED, 'error');
+export const loadBillsSummary = makeActionCreator(constants.BILLS_SUMMARY_REQUESTED, 'buildingId');
+export const billsSummaryLoaded = makeActionCreator(constants.BILLS_SUMMARY_SUCCEEDED, 'instance');
+export const billsSummaryFailed = makeActionCreator(constants.BILLS_SUMMARY_FAILED, 'error');
+export const loadBillsOverview = makeActionCreator(constants.BILLS_OVERVIEW_REQUESTED, 'buildingId');
+export const billsOverviewLoaded = makeActionCreator(constants.BILLS_OVERVIEW_SUCCEEDED, 'instance');
+export const billsOverviewFailed = makeActionCreator(constants.BILLS_OVERVIEW_FAILED, 'error');
+export const loadCashBalance = makeActionCreator(constants.CASH_BALANCE_REQUESTED, 'buildingId');
+export const cashBalanceLoaded = makeActionCreator(constants.CASH_BALANCE_SUCCEEDED, 'instance');
+export const cashBalanceFailed = makeActionCreator(constants.CASH_BALANCE_FAILED, 'error');
+export const loadLoanOptions = makeActionCreator(constants.LOAN_OPTIONS_REQUESTED, 'buildingId');
+export const loanOptionsLoaded = makeActionCreator(constants.LOAN_OPTIONS_SUCCEEDED, 'instance');
+export const loanOptionsFailed = makeActionCreator(constants.LOAN_OPTIONS_FAILED, 'error');
+export const loadCustomerPreference = makeActionCreator(constants.CUSTOMER_PREFERENCE_REQUESTED, 'buildingId');
+export const customerPreferenceLoaded = makeActionCreator(constants.CUSTOMER_PREFERENCE_SUCCEEDED, 'instance');
+export const customerPreferenceFailed = makeActionCreator(constants.CUSTOMER_PREFERENCE_FAILED, 'error');
+export const loadIncomeStatement = makeActionCreator(constants.INCOME_STATEMENT_REQUESTED, 'buildingId');
+export const incomeStatementLoaded = makeActionCreator(constants.INCOME_STATEMENT_SUCCEEDED, 'instance');
+export const incomeStatementFailed = makeActionCreator(constants.INCOME_STATEMENT_FAILED, 'error');
+export const loadLiabilities = makeActionCreator(constants.LIABILITIES_REQUESTED, 'buildingId');
+export const liabilitiesLoaded = makeActionCreator(constants.LIABILITIES_SUCCEEDED, 'instance');
+export const liabilitiesFailed = makeActionCreator(constants.LIABILITIES_FAILED, 'error');
+
+export const createBillsSummary = makeActionCreator(constants.CREATE_BILLS_SUMMARY_REQUESTED, 'buildingId', 'payload');
+export const createBillsSummarySucceeded = makeActionCreator(constants.CREATE_BILLS_SUMMARY_SUCCEEDED, 'instance', 'result');
+export const createBillsSummaryFailed = makeActionCreator(constants.CREATE_BILLS_SUMMARY_FAILED, 'error');
+export const updateBillsSummary = makeActionCreator(constants.UPDATE_BILLS_SUMMARY_REQUESTED, 'buildingId', 'payload');
+export const updateBillsSummarySucceeded = makeActionCreator(constants.UPDATE_BILLS_SUMMARY_SUCCEEDED, 'instance');
+export const updateBillsSummaryFailed = makeActionCreator(constants.UPDATE_BILLS_SUMMARY_FAILED, 'error');
+export const deleteBillsSummary = makeActionCreator(constants.DELETE_BILLS_SUMMARY_REQUESTED, 'buildingId', 'payload');
+export const deleteBillsSummarySucceeded = makeActionCreator(constants.DELETE_BILLS_SUMMARY_SUCCEEDED, 'instance');
+export const deleteBillsSummaryFailed = makeActionCreator(constants.DELETE_BILLS_SUMMARY_FAILED, 'error');
+
+export const createBillsOverview = makeActionCreator(constants.CREATE_BILLS_OVERVIEW_REQUESTED, 'buildingId', 'payload');
+export const createBillsOverviewSucceeded = makeActionCreator(constants.CREATE_BILLS_OVERVIEW_SUCCEEDED, 'instance');
+export const createBillsOverviewFailed = makeActionCreator(constants.CREATE_BILLS_OVERVIEW_FAILED, 'error');
+export const updateBillsOverview = makeActionCreator(constants.UPDATE_BILLS_OVERVIEW_REQUESTED, 'buildingId', 'payload');
+export const updateBillsOverviewSucceeded = makeActionCreator(constants.UPDATE_BILLS_OVERVIEW_SUCCEEDED, 'instance');
+export const updateBillsOverviewFailed = makeActionCreator(constants.UPDATE_BILLS_OVERVIEW_FAILED, 'error');
+
+export const updateIncomeStatements = makeActionCreator(constants.UPDATE_INCOME_STATEMENTS_REQUESTED, 'buildingId', 'payload');
+export const updateIncomeStatementsSucceeded = makeActionCreator(constants.UPDATE_INCOME_STATEMENTS_SUCCEEDED, 'instance');
+export const updateIncomeStatementsFailed = makeActionCreator(constants.UPDATE_INCOME_STATEMENTS_FAILED, 'error');
+
+export const updateCashBalance = makeActionCreator(constants.UPDATE_CASH_BALANCE_REQUESTED, 'buildingId', 'payload');
+export const updateCashBalanceSucceeded = makeActionCreator(constants.UPDATE_CASH_BALANCE_SUCCEEDED, 'instance');
+export const updateCashBalanceFailed = makeActionCreator(constants.UPDATE_CASH_BALANCE_FAILED, 'error');
+
+export const updateLiabilities = makeActionCreator(constants.UPDATE_LIABILITIES_REQUESTED, 'buildingId', 'payload');
+export const updateLiabilitiesSucceeded = makeActionCreator(constants.UPDATE_LIABILITIES_SUCCEEDED, 'instance');
+export const updateLiabilitiesFailed = makeActionCreator(constants.UPDATE_LIABILITIES_FAILED, 'error');
+
+export const updateLoanOptions = makeActionCreator(constants.UPDATE_LOAN_OPTIONS_REQUESTED, 'buildingId', 'payload');
+export const updateLoanOptionsSucceeded = makeActionCreator(constants.UPDATE_LOAN_OPTIONS_SUCCEEDED, 'instance');
+export const updateLoanOptionsFailed = makeActionCreator(constants.UPDATE_LOAN_OPTIONS_FAILED, 'error');
+
+export const updateCustomerPreference = makeActionCreator(constants.UPDATE_CUSTOMER_PREFERENCE_REQUESTED, 'buildingId', 'payload');
+export const updateCustomerPreferenceSucceeded = makeActionCreator(constants.UPDATE_CUSTOMER_PREFERENCE_SUCCEEDED, 'instance');
+export const updateCustomerPreferenceFailed = makeActionCreator(constants.UPDATE_CUSTOMER_PREFERENCE_FAILED, 'error');
+
diff --git a/src/containers/Blocnote/FinancialInputs/constants.js b/src/containers/Blocnote/FinancialInputs/constants.js
new file mode 100644
index 0000000000000000000000000000000000000000..de4a0ad4f73da6db65ba8ffb30e02099e936bf31
--- /dev/null
+++ b/src/containers/Blocnote/FinancialInputs/constants.js
@@ -0,0 +1,64 @@
+export const FINANCE_OVERVIEW_REQUESTED = 'FINANCE_OVERIVEW_REQUESTED';
+export const FINANCE_OVERVIEW_SUCCEEDED = 'FINANCE_OVERIVEW_SUCCEEDED';
+export const FINANCE_OVERVIEW_FAILED = 'FINANCE_OVERIVEW_FAILED';
+export const BILLS_REQUESTED = 'BILLS_REQUESTED';
+export const BILLS_SUCCEEDED = 'BILLS_SUCCEEDED';
+export const BILLS_FAILED = 'BILLS_FAILED';
+export const BILLS_OVERVIEW_REQUESTED = 'BILLS_OVERVIEW_REQUESTED';
+export const BILLS_OVERVIEW_SUCCEEDED = 'BILLS_OVERVIEW_SUCCEEDED';
+export const BILLS_OVERVIEW_FAILED = 'BILLS_OVERVIEW_FAILED';
+export const BILLS_SUMMARY_REQUESTED = 'BILLS_SUMMARY_REQUESTED';
+export const BILLS_SUMMARY_SUCCEEDED = 'BILLS_SUMMARY_SUCCEEDED';
+export const BILLS_SUMMARY_FAILED = 'BILLS_SUMMARY_FAILED';
+export const CASH_BALANCE_REQUESTED = 'CASH_BALANCE_REQUESTED';
+export const CASH_BALANCE_SUCCEEDED = 'CASH_BALANCE_SUCCEEDED';
+export const CASH_BALANCE_FAILED = 'CASH_BALANCE_FAILED';
+export const CUSTOMER_PREFERENCE_REQUESTED = 'CUSTOMER_PREFERENCE_REQUESTED';
+export const CUSTOMER_PREFERENCE_SUCCEEDED = 'CUSTOMER_PREFERENCE_SUCCEEDED';
+export const CUSTOMER_PREFERENCE_FAILED = 'CUSTOMER_PREFERENCE_FAILED';
+export const INCOME_STATEMENT_REQUESTED = 'INCOME_STATEMENT_REQUESTED';
+export const INCOME_STATEMENT_SUCCEEDED = 'INCOME_STATEMENT_SUCCEEDED';
+export const INCOME_STATEMENT_FAILED = 'INCOME_STATEMENT_FAILED';
+export const LOAN_OPTIONS_REQUESTED = 'LOAN_OPTIONS_REQUESTED';
+export const LOAN_OPTIONS_SUCCEEDED = 'LOAN_OPTIONS_SUCCEEDED';
+export const LOAN_OPTIONS_FAILED = 'LOAN_OPTIONS_FAILED';
+export const LIABILITIES_REQUESTED = 'LIABILITIES_REQUESTED';
+export const LIABILITIES_SUCCEEDED = 'LIABILITIES_SUCCEEDED';
+export const LIABILITIES_FAILED = 'LIABILITIES_FAILED';
+
+export const CREATE_BILLS_SUMMARY_REQUESTED = 'CREATE_BILLS_SUMMARY_REQUESTED';
+export const CREATE_BILLS_SUMMARY_SUCCEEDED = 'CREATE_BILLS_SUMMARY_SUCCEEDED';
+export const CREATE_BILLS_SUMMARY_FAILED = 'CREATE_BILLS_SUMMARY_FAILED';
+export const UPDATE_BILLS_SUMMARY_REQUESTED = 'UPDATE_BILLS_SUMMARY_REQUESTED';
+export const UPDATE_BILLS_SUMMARY_SUCCEEDED = 'UPDATE_BILLS_SUMMARY_SUCCEEDED';
+export const UPDATE_BILLS_SUMMARY_FAILED = 'UPDATE_BILLS_SUMMARY_FAILED';
+export const DELETE_BILLS_SUMMARY_REQUESTED = 'DELETE_BILLS_SUMMARY_REQUESTED';
+export const DELETE_BILLS_SUMMARY_SUCCEEDED = 'DELETE_BILLS_SUMMARY_SUCCEEDED';
+export const DELETE_BILLS_SUMMARY_FAILED = 'DELETE_BILLS_SUMMARY_FAILED';
+
+export const CREATE_BILLS_OVERVIEW_REQUESTED = 'CREATE_BILLS_OVERVIEW_REQUESTED';
+export const CREATE_BILLS_OVERVIEW_SUCCEEDED = 'CREATE_BILLS_OVERVIEW_SUCCEEDED';
+export const CREATE_BILLS_OVERVIEW_FAILED = 'CREATE_BILLS_OVERVIEW_FAILED';
+export const UPDATE_BILLS_OVERVIEW_REQUESTED = 'UPDATE_BILLS_OVERVIEW_REQUESTED';
+export const UPDATE_BILLS_OVERVIEW_SUCCEEDED = 'UPDATE_BILLS_OVERVIEW_SUCCEEDED';
+export const UPDATE_BILLS_OVERVIEW_FAILED = 'UPDATE_BILLS_OVERVIEW_FAILED';
+
+export const UPDATE_INCOME_STATEMENTS_REQUESTED = 'UPDATE_INCOME_STATEMENTS_REQUESTED';
+export const UPDATE_INCOME_STATEMENTS_SUCCEEDED = 'UPDATE_INCOME_STATEMENTS_SUCCEEDED';
+export const UPDATE_INCOME_STATEMENTS_FAILED = 'UPDATE_INCOME_STATEMENTS_FAILED';
+
+export const UPDATE_CASH_BALANCE_REQUESTED = 'UPDATE_CASH_BALANCE_REQUESTED';
+export const UPDATE_CASH_BALANCE_SUCCEEDED = 'UPDATE_CASH_BALANCE_SUCCEEDED';
+export const UPDATE_CASH_BALANCE_FAILED = 'UPDATE_CASH_BALANCE_FAILED';
+
+export const UPDATE_LIABILITIES_REQUESTED = 'UPDATE_LIABILITIES_REQUESTED';
+export const UPDATE_LIABILITIES_SUCCEEDED = 'UPDATE_LIABILITIES_SUCCEEDED';
+export const UPDATE_LIABILITIES_FAILED = 'UPDATE_LIABILITIES_FAILED';
+
+export const UPDATE_LOAN_OPTIONS_REQUESTED = 'UPDATE_LOAN_OPTIONS_REQUESTED';
+export const UPDATE_LOAN_OPTIONS_SUCCEEDED = 'UPDATE_LOAN_OPTIONS_SUCCEEDED';
+export const UPDATE_LOAN_OPTIONS_FAILED = 'UPDATE_LOAN_OPTIONS_FAILED';
+
+export const UPDATE_CUSTOMER_PREFERENCE_REQUESTED = 'UPDATE_CUSTOMER_PREFERENCE_REQUESTED';
+export const UPDATE_CUSTOMER_PREFERENCE_SUCCEEDED = 'UPDATE_CUSTOMER_PREFERENCE_SUCCEEDED';
+export const UPDATE_CUSTOMER_PREFERENCE_FAILED = 'UPDATE_CUSTOMER_PREFERENCE_FAILED';
diff --git a/src/containers/Blocnote/FinancialInputs/index.js b/src/containers/Blocnote/FinancialInputs/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..5b526be1446b6af7de6669261f5598bc717c88a7
--- /dev/null
+++ b/src/containers/Blocnote/FinancialInputs/index.js
@@ -0,0 +1,357 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
+import LinkBarDetail from '../../../components/LinkBarDetail';
+import buildingDetailPropTypes from '../../Building/propTypes';
+import './../styles.css';
+import Loading from '../../../components/Loading';
+import {
+ loadFinanceOverview, loadBills, loadBillsOverview,
+ loadBillsSummary, loadCashBalance, loadLoanOptions,
+ loadCustomerPreference, loadIncomeStatement, loadLiabilities,
+ createBillsSummary, updateBillsSummary, deleteBillsSummary,
+ createBillsOverview, updateBillsOverview, updateIncomeStatements, updateCashBalance,
+ updateLiabilities, updateLoanOptions, updateCustomerPreference,
+} from './actions';
+import blocnoteProps from './../propTypes';
+import FinanceOverview from './../../../components/Blocnote/FinancialInputs/FinanceOverview';
+import Bills from '../../../components/Blocnote/FinancialInputs/Bills';
+import BillsSummary from '../../../components/Blocnote/FinancialInputs/BillsSummary';
+import BillsOverview from '../../../components/Blocnote/FinancialInputs/BillsOverview';
+import IncomeStatements from '../../../components/Blocnote/FinancialInputs/IncomeStatements';
+import CashBalance from '../../../components/Blocnote/FinancialInputs/CashBalance';
+import MortgageLiabilities from '../../../components/Blocnote/FinancialInputs/MortgageLiabilities';
+import LoanOptions from '../../../components/Blocnote/FinancialInputs/LoanOptions';
+import CustomerPreference from '../../../components/Blocnote/FinancialInputs/CustomerPreference';
+import { blocnoteURL } from '../../../utils/restServices';
+
+
+class FinancialInputs extends Component {
+ componentDidMount() {
+ this.props.loadFinanceOverview(this.props.buildingId);
+ this.props.loadBills(this.props.buildingId);
+ this.props.loadBillsSummary(this.props.buildingId);
+ this.props.loadBillsOverview(this.props.buildingId);
+ this.props.loadIncomeStatement(this.props.buildingId);
+ this.props.loadCashBalance(this.props.buildingId);
+ this.props.loadLiabilities(this.props.buildingId);
+ this.props.loadLoanOptions(this.props.buildingId);
+ this.props.loadCustomerPreference(this.props.buildingId);
+ }
+
+ processFinanceOverview = (data) => {
+ const funds = [];
+ data.instance.funds.forEach(fund => {
+ funds.push({
+ fund_id: fund[0],
+ fund_name: fund[1],
+ });
+ });
+
+ const financeData = {
+ fundOptions: funds,
+ fundDropDownId: null,
+ fundDropDownValue: 'No Fund',
+ proFormaStartDate: null,
+ proFormaDuration: null,
+ analysisDate: null,
+ anticipatedConstructionStartDate: null,
+ anticipatedCommissioningDate: null,
+ anticipatedConstructionPeriod: null,
+ };
+
+ if (data.instance.financing_overview_data !== undefined) {
+ const fData = data.instance.financing_overview_data;
+ data.instance.funds.forEach(fund => {
+ if (fund[0] === fData.fund_id) {
+ financeData.fundDropDownValue = fund[1];
+ }
+ });
+ financeData.fundDropDownId = fData.fund_id;
+ financeData.proFormaStartDate = fData.pro_forma_start_date;
+ financeData.proFormaDuration = fData.pro_forma_duration;
+ financeData.analysisDate = fData.analysis_date;
+ financeData.anticipatedConstructionStartDate = fData.anticipated_construction_start_date;
+ financeData.anticipatedCommissioningDate = fData.anticipated_commissioning_date;
+ financeData.anticipatedConstructionPeriod = parseInt(
+ fData.anticipated_construction_period, 10
+ );
+ }
+
+ return financeData;
+ }
+
+ render() {
+ let mainContent = null;
+ const baseURL = `${blocnoteURL}buildings/${this.props.buildingId}/financial-inputs`;
+ const blockStyle = { marginBottom: '40px' };
+ const headerStyle = {
+ textAlign: 'left',
+ marginBottom: '25px',
+ paddingLeft: '10px',
+ };
+ const successMessageStyle = {
+ color: 'green',
+ paddingLeft: '25px',
+ fontWeight: 'bold',
+ };
+ const errorMessageStyle = {
+ color: 'red',
+ paddingLeft: '25px',
+ fontWeight: 'bold',
+ };
+ const defaultMessageStyle = {
+ color: 'black',
+ paddingLeft: '25px',
+ fontWeight: 'bold',
+ };
+
+ console.log(this.props); // eslint-disable-line
+ const { blocnote } = this.props;
+ const {
+ fianceOverview, bills, billsOverview, billsSummary, cashBalance,
+ loanOptions, incomeStatement, liabilities, customerPreference,
+ } = blocnote;
+
+ mainContent = ;
+ console.log(blocnote); // eslint-disable-line
+
+ if (fianceOverview.data !== null &&
+ bills.data !== null &&
+ billsOverview.data !== null &&
+ billsSummary.data !== null &&
+ cashBalance.data !== null &&
+ loanOptions.data !== null &&
+ incomeStatement.data !== null &&
+ liabilities.data !== null &&
+ customerPreference.data !== null) {
+ console.log(fianceOverview); // eslint-disable-line
+ console.log(bills.data); // eslint-disable-line
+ console.log(billsOverview.data); // eslint-disable-line
+ console.log(billsSummary.data); // eslint-disable-line
+ console.log(cashBalance.data); // eslint-disable-line
+ console.log(loanOptions.data); // eslint-disable-line
+ console.log(incomeStatement.data); // eslint-disable-line
+ console.log(liabilities.data); // eslint-disable-line
+ console.log(customerPreference.data); // eslint-disable-line
+ const foData = this.processFinanceOverview(fianceOverview.data);
+
+ const financeOverviewExist =
+ fianceOverview.data.instance.financing_overview_data !== undefined;
+ let cashBalanceData = [];
+ let loanOptionsData = [];
+ let billsSummaryData = {
+ gas: [],
+ oil: [],
+ water: [],
+ electric: [],
+ };
+ let customerPreferenceData = {};
+ if (Object.keys(cashBalance.data).length !== 0) {
+ cashBalanceData = cashBalance.data.instance.result;
+ }
+ if (loanOptions.data.load === true) {
+ loanOptionsData = loanOptions.data.status;
+ }
+ if (Object.keys(billsSummary.data.result.user_bill).length === 0) {
+ Object.entries(billsSummary.data.result).forEach((billSummary, id) => {
+ if (billSummary[0] !== 'user_bill') {
+ billsSummaryData[billSummary[0]] = [{
+ year: String(Object.keys(billSummary[1])[0]),
+ charge: String(Object.values(billSummary[1])[0]),
+ id,
+ }];
+ }
+ });
+ } else {
+ billsSummaryData = billsSummary.data.result.user_bill;
+ }
+ if (Object.keys(customerPreference.data).length !== 0) {
+ customerPreferenceData = customerPreference.data.instance;
+ }
+ console.log(billsSummaryData); // eslint-disable-line
+
+ mainContent = (
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+
+ return (
+
+
+ {mainContent}
+
+ );
+ }
+}
+
+FinancialInputs.propTypes = {
+ buildingId: PropTypes.string,
+ building: buildingDetailPropTypes,
+ blocnote: blocnoteProps,
+ loadFinanceOverview: PropTypes.func,
+ loadBills: PropTypes.func,
+ loadBillsSummary: PropTypes.func,
+ loadBillsOverview: PropTypes.func,
+ loadIncomeStatement: PropTypes.func,
+ loadCashBalance: PropTypes.func,
+ loadLiabilities: PropTypes.func,
+ loadLoanOptions: PropTypes.func,
+ loadCustomerPreference: PropTypes.func,
+ createBillsSummary: PropTypes.func,
+ updateBillsSummary: PropTypes.func,
+ deleteBillsSummary: PropTypes.func,
+ createBillsOverview: PropTypes.func,
+ updateBillsOverview: PropTypes.func,
+ updateIncomeStatements: PropTypes.func,
+ updateCashBalance: PropTypes.func,
+ updateLiabilities: PropTypes.func,
+ updateLoanOptions: PropTypes.func,
+ updateCustomerPreference: PropTypes.func,
+};
+
+const mapDispatchToProps = dispatch => {
+ return bindActionCreators({
+ loadFinanceOverview,
+ loadBills,
+ loadBillsSummary,
+ loadBillsOverview,
+ loadIncomeStatement,
+ loadCashBalance,
+ loadLiabilities,
+ loadLoanOptions,
+ loadCustomerPreference,
+ createBillsSummary,
+ updateBillsSummary,
+ deleteBillsSummary,
+ createBillsOverview,
+ updateBillsOverview,
+ updateIncomeStatements,
+ updateCashBalance,
+ updateLiabilities,
+ updateLoanOptions,
+ updateCustomerPreference,
+ }, dispatch);
+};
+
+const mapStateToProps = state => ({
+ blocnote: state.blocnote,
+});
+
+export default connect(mapStateToProps, mapDispatchToProps)(FinancialInputs);
diff --git a/src/containers/Blocnote/PreliminaryFinance/actions.js b/src/containers/Blocnote/PreliminaryFinance/actions.js
new file mode 100644
index 0000000000000000000000000000000000000000..0fd3725efb0b29883329c2affad9b2654fc48433
--- /dev/null
+++ b/src/containers/Blocnote/PreliminaryFinance/actions.js
@@ -0,0 +1,10 @@
+import * as constants from './constants';
+import { makeActionCreator } from '../../../utils/reduxHelpers';
+
+export const loadScenario = makeActionCreator(constants.SCENARIO_REQUESTED, 'buildingId');
+export const scenarioLoaded = makeActionCreator(constants.SCENARIO_SUCCEEDED, 'instance');
+export const scenarioFailed = makeActionCreator(constants.SCENARIO_FAILED, 'error');
+
+export const updateScenario = makeActionCreator(constants.UPDATE_SCENARIO_REQUESTED, 'buildingId', 'payload');
+export const updateScenarioSucceeded = makeActionCreator(constants.UPDATE_SCENARIO_SUCCEEDED, 'instance');
+export const updateScenarioFailed = makeActionCreator(constants.UPDATE_SCENARIO_FAILED, 'error');
diff --git a/src/containers/Blocnote/PreliminaryFinance/constants.js b/src/containers/Blocnote/PreliminaryFinance/constants.js
new file mode 100644
index 0000000000000000000000000000000000000000..ba79846104e8659d0769dc4a94a80791d46e285f
--- /dev/null
+++ b/src/containers/Blocnote/PreliminaryFinance/constants.js
@@ -0,0 +1,7 @@
+export const SCENARIO_REQUESTED = 'SCENARIO_REQUESTED';
+export const SCENARIO_SUCCEEDED = 'SCENARIO_SUCCEEDED';
+export const SCENARIO_FAILED = 'SCENARIO_FAILED';
+
+export const UPDATE_SCENARIO_REQUESTED = 'UPDATE_SCENARIO_REQUESTED';
+export const UPDATE_SCENARIO_SUCCEEDED = 'UPDATE_SCENARIO_SUCCEEDED';
+export const UPDATE_SCENARIO_FAILED = 'UPDATE_SCENARIO_FAILED';
diff --git a/src/containers/Blocnote/PreliminaryFinance/index.js b/src/containers/Blocnote/PreliminaryFinance/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..720090a88ecaf3128c4a103d742c027bf31e26b5
--- /dev/null
+++ b/src/containers/Blocnote/PreliminaryFinance/index.js
@@ -0,0 +1,166 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
+import LinkBarDetail from '../../../components/LinkBarDetail';
+import './../styles.css';
+import blocnoteProps from './../propTypes';
+import Loading from '../../../components/Loading';
+import {
+ loadScenario, updateScenario,
+} from './actions';
+import BudgetChart from './../../../components/Blocnote/PreliminaryFinance/BudgetChart';
+import LoanSummary from './../../../components/Blocnote/PreliminaryFinance/LoanSummary';
+import ProjectEconomics from './../../../components/Blocnote/PreliminaryFinance/ProjectEconomics';
+import SavingsScheduleChart from './../../../components/Blocnote/PreliminaryFinance/SavingsScheduleChart';
+import PriorRetrofitIncomeStatement from './../../../components/Blocnote/PreliminaryFinance/PriorRetrofitIncomeStatement';
+import PostRetrofitIncomeStatement from './../../../components/Blocnote/PreliminaryFinance/PostRetrofitIncomeStatement';
+import PriorRetrofitBalanceSheet from './../../../components/Blocnote/PreliminaryFinance/PriorRetrofitBalanceSheet';
+import PostRetrofitBalanceSheet from './../../../components/Blocnote/PreliminaryFinance/PostRetrofitBalanceSheet';
+import DownPayment from './../../../components/Blocnote/PreliminaryFinance/DownPayment';
+import SelectScenario from './../../../components/Blocnote/PreliminaryFinance/SelectScenario';
+import InputScenario from './../../../components/Blocnote/PreliminaryFinance/InputScenario';
+import { blocnoteURL } from '../../../utils/restServices';
+
+
+class PreliminaryFinance extends Component {
+ componentDidMount() {
+ this.props.loadScenario(this.props.buildingId);
+ }
+
+ render() {
+ let mainContent = null;
+ const baseURL = `${blocnoteURL}buildings/${this.props.buildingId}/financial-inputs`;
+ const blockStyle = { marginBottom: '40px' };
+ const headerStyle = { textAlign: 'left', marginBottom: '25px' };
+ const successMessageStyle = {
+ color: 'green',
+ paddingLeft: '25px',
+ fontWeight: 'bold',
+ };
+ const errorMessageStyle = {
+ color: 'red',
+ paddingLeft: '25px',
+ fontWeight: 'bold',
+ };
+ const defaultMessageStyle = {
+ color: 'black',
+ paddingLeft: '25px',
+ fontWeight: 'bold',
+ };
+
+ console.log(this.props); // eslint-disable-line
+ const { blocnote } = this.props;
+ const { scenario } = blocnote;
+
+ mainContent = ;
+
+ if (scenario.data !== null) {
+ const tables = scenario.data.instance.instance.tables;
+ const budgets = Object.keys(tables).map(tableName => tables[tableName][0].slice(1));
+
+ const projectEconomicsContent = [[]];
+ Object.keys(scenario.data.instance.economics_overview).forEach((key) => {
+ const temp = [];
+ temp.push(key);
+ temp.push(scenario.data.instance.economics_overview[key]);
+ projectEconomicsContent.push(temp);
+ });
+ mainContent = (
+
+ );
+ }
+
+ return (
+
+
+ {mainContent}
+
+ );
+ }
+}
+
+PreliminaryFinance.propTypes = {
+ buildingId: PropTypes.string,
+ blocnote: blocnoteProps,
+ loadScenario: PropTypes.func,
+ updateScenario: PropTypes.func,
+};
+
+const mapDispatchToProps = dispatch => {
+ return bindActionCreators({
+ loadScenario,
+ updateScenario,
+ }, dispatch);
+};
+
+const mapStateToProps = state => ({
+ blocnote: state.blocnote,
+});
+
+export default connect(mapStateToProps, mapDispatchToProps)(PreliminaryFinance);
diff --git a/src/containers/Blocnote/actions.js b/src/containers/Blocnote/actions.js
new file mode 100644
index 0000000000000000000000000000000000000000..2a43545fb4da65241a73d29b9e5d037b4151cabe
--- /dev/null
+++ b/src/containers/Blocnote/actions.js
@@ -0,0 +1,6 @@
+import * as constants from './constants';
+import { makeActionCreator } from '../../utils/reduxHelpers';
+
+export const loadLandingData = makeActionCreator(constants.LANDING_DATA_REQUESTED, 'buildingId');
+export const landingDataLoaded = makeActionCreator(constants.LANDING_DATA_SUCCEEDED, 'instance');
+export const landingDataFailed = makeActionCreator(constants.LANDING_DATA_FAILED, 'error');
diff --git a/src/containers/Blocnote/constants.js b/src/containers/Blocnote/constants.js
new file mode 100644
index 0000000000000000000000000000000000000000..ae65e1bd050af7321693226b0f1125e4052508e4
--- /dev/null
+++ b/src/containers/Blocnote/constants.js
@@ -0,0 +1,3 @@
+export const LANDING_DATA_REQUESTED = 'LANDING_DATA_REQUESTED';
+export const LANDING_DATA_SUCCEEDED = 'LANDING_DATA_SUCCEEDED';
+export const LANDING_DATA_FAILED = 'LANDING_DATA_FAILED';
diff --git a/src/containers/Blocnote/index.js b/src/containers/Blocnote/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..f5d13fbdbfba352c3ee909cebec9568367940e5b
--- /dev/null
+++ b/src/containers/Blocnote/index.js
@@ -0,0 +1,172 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
+import { Table } from 'reactstrap';
+import { Link } from 'react-router';
+import LinkBarDetail from '../../components/LinkBarDetail';
+import buildingDetailPropTypes from '../Building/propTypes';
+import { loadLandingData } from './actions';
+import './styles.css';
+import Loading from '../../components/Loading';
+import blocnoteProps from './propTypes';
+
+
+class Blocnote extends Component {
+ componentDidMount() {
+ this.props.loadLandingData(this.props.building.building_id);
+ }
+
+ processData = (data) => {
+ const rootURL = `/buildings/${this.props.building.building_id}`;
+ const dataDic = {
+ financialInputs: {
+ name: null,
+ status: null,
+ },
+ preliminaryFinance: {
+ name: null,
+ status: null,
+ },
+ budgetSimilator: {
+ name: null,
+ status: null,
+ },
+ };
+
+ if (data.instance.if_completed) {
+ dataDic.name = (
+ Financial Inputs
+ );
+ dataDic.status = (Complete);
+ dataDic.preliminaryFinance.name = (
+ Preliminary Finance
+ );
+ dataDic.preliminaryFinance.status = (OK);
+ dataDic.budgetSimilator.name = (
+ Budget Simulator
+ );
+ dataDic.budgetSimilator.status = (OK);
+ } else {
+ dataDic.name = (
+ Financial Inputs
+ );
+ if (data.instance.if_started) {
+ dataDic.status = (Started but not complete.);
+ } else {
+ dataDic.status = (Not Started.);
+ }
+ dataDic.preliminaryFinance.name = (Preliminary Finance);
+ const prelimItems = data.instance.not_saved_list_for_prelim.map((item) => {
+ return (Please fill {item});
+ });
+ dataDic.preliminaryFinance.status = (
+
+ );
+
+ if (data.instance.if_completed_for_budget) {
+ dataDic.budgetSimilator.name = (
+ Budget Simulator
+ );
+ dataDic.budgetSimilator.status = (OK);
+ } else {
+ dataDic.budgetSimilator.name = (Budget Simulator);
+ const budgetItems = data.instance.not_saved_list_for_budget.map((item) => {
+ return (Please fill {item});
+ });
+ dataDic.budgetSimilator.status = ();
+ }
+ }
+
+ return dataDic;
+ }
+
+ render() {
+ let mainContent = null;
+ const { blocnote } = this.props;
+ const { landingData } = blocnote;
+ const { data } = landingData;
+
+ if (data === null) {
+ mainContent = ;
+ } else {
+ const dataDic = this.processData(data);
+ mainContent = (
+
+
+
+
+
+
+ | OPTIONS |
+ STATUS |
+
+
+
+
+ |
+ {dataDic.name}
+ |
+
+ {dataDic.status}
+ |
+
+
+ |
+ {dataDic.preliminaryFinance.name}
+ |
+
+ {dataDic.preliminaryFinance.status}
+ |
+
+
+ |
+ {dataDic.budgetSimilator.name}
+ |
+
+ {dataDic.budgetSimilator.status}
+ |
+
+
+
+
+
+
+ );
+ }
+
+ return (
+
+
+ {mainContent}
+
+ );
+ }
+}
+
+Blocnote.propTypes = {
+ building: buildingDetailPropTypes,
+ loadLandingData: PropTypes.func,
+ blocnote: blocnoteProps,
+};
+
+const mapDispatchToProps = dispatch => (
+ bindActionCreators({
+ loadLandingData,
+ }, dispatch)
+);
+
+const mapStateToProps = state => ({
+ blocnote: state.blocnote,
+});
+
+export default connect(mapStateToProps, mapDispatchToProps)(Blocnote);
diff --git a/src/containers/Blocnote/propTypes.js b/src/containers/Blocnote/propTypes.js
new file mode 100644
index 0000000000000000000000000000000000000000..546be1a012c935b94b8ee4748af73e1c42a099e0
--- /dev/null
+++ b/src/containers/Blocnote/propTypes.js
@@ -0,0 +1,39 @@
+import PropTypes from 'prop-types';
+
+const { shape, arrayOf, number, string, bool, oneOfType, instanceOf } = PropTypes;
+
+export const loadErrorPropTypes = {
+ loading: bool,
+ error: oneOfType([
+ bool,
+ instanceOf(Error),
+ ]),
+};
+
+export const buildingProps = shape({
+ building_id: number,
+ lot_id: number,
+ bbl: number,
+ bin: number,
+ street_address: string,
+ borough: string,
+ zipcode: string,
+ state: string,
+ targeting_score: number,
+});
+
+export const dataProps = shape({
+ if_started: bool,
+ if_completed: bool,
+ if_completed_for_budget: bool,
+ if_started_for_budget: bool,
+ not_saved_list_for_prelim: arrayOf(string),
+ not_saved_list_for_budget: arrayOf(string),
+ building: buildingProps,
+});
+
+export default shape({
+ ...loadErrorPropTypes,
+ data: dataProps,
+});
+
diff --git a/src/containers/Blocnote/reducer.js b/src/containers/Blocnote/reducer.js
new file mode 100644
index 0000000000000000000000000000000000000000..28a07d32cb97899a1f95fa82cf5f79362b8484b9
--- /dev/null
+++ b/src/containers/Blocnote/reducer.js
@@ -0,0 +1,778 @@
+import * as LandingPage from './constants';
+import * as FinancialInputs from './FinancialInputs/constants';
+import * as PreliminaryFinance from './PreliminaryFinance/constants';
+import * as BudgetSimulator from './BudgetSimulator/constants';
+
+const blocnoteInitialState = {
+ landingData: {
+ loading: false,
+ error: false,
+ data: null,
+ },
+ fianceOverview: {
+ loading: false,
+ error: false,
+ data: null,
+ },
+ billsSummary: {
+ loading: false,
+ error: false,
+ data: null,
+ },
+ cashBalance: {
+ loading: false,
+ error: false,
+ data: null,
+ },
+ customerPreference: {
+ loading: false,
+ error: false,
+ data: null,
+ },
+ bills: {
+ loading: false,
+ error: false,
+ data: null,
+ },
+ incomeStatement: {
+ loading: false,
+ error: false,
+ data: null,
+ },
+ loanOptions: {
+ loading: false,
+ error: false,
+ data: null,
+ },
+ liabilities: {
+ loading: false,
+ error: false,
+ data: null,
+ },
+ scenario: {
+ loading: false,
+ error: false,
+ data: null,
+ },
+ budgetSimulator: {
+ loading: false,
+ error: false,
+ data: null,
+ },
+};
+
+export default function (state = blocnoteInitialState, action) {
+ console.log(state); // eslint-disable-line
+ switch (action.type) {
+ case LandingPage.LANDING_DATA_REQUESTED:
+ return {
+ ...state,
+ landingData: {
+ ...state.landingData,
+ loading: true,
+ error: false,
+ },
+ };
+
+ case LandingPage.LANDING_DATA_SUCCEEDED:
+ return {
+ ...state,
+ landingData: {
+ data: action.instance,
+ loading: false,
+ error: false,
+ },
+ };
+
+ case LandingPage.LANDING_DATA_FAILED:
+ return {
+ ...state,
+ landingData: {
+ loading: false,
+ error: action.error,
+ },
+ };
+
+ case FinancialInputs.FINANCE_OVERVIEW_REQUESTED:
+ return {
+ ...state,
+ fianceOverview: {
+ ...state.fianceOverview,
+ loading: true,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.FINANCE_OVERVIEW_SUCCEEDED:
+ return {
+ ...state,
+ fianceOverview: {
+ data: action.instance,
+ loading: false,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.FINANCE_OVERVIEW_FAILED:
+ return {
+ ...state,
+ fianceOverview: {
+ loading: false,
+ error: action.error,
+ },
+ };
+
+ case FinancialInputs.BILLS_REQUESTED:
+ return {
+ ...state,
+ bills: {
+ ...state.bills,
+ loading: true,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.BILLS_SUCCEEDED:
+ return {
+ ...state,
+ bills: {
+ data: action.instance,
+ loading: false,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.BILLS_FAILED:
+ return {
+ ...state,
+ bills: {
+ loading: false,
+ error: action.error,
+ },
+ };
+
+ case FinancialInputs.BILLS_OVERVIEW_REQUESTED:
+ return {
+ ...state,
+ billsOverview: {
+ ...state.billsOverview,
+ loading: true,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.BILLS_OVERVIEW_SUCCEEDED:
+ return {
+ ...state,
+ billsOverview: {
+ data: action.instance,
+ loading: false,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.BILLS_OVERVIEW_FAILED:
+ return {
+ ...state,
+ billsOverview: {
+ loading: false,
+ error: action.error,
+ },
+ };
+
+ case FinancialInputs.BILLS_SUMMARY_REQUESTED:
+ return {
+ ...state,
+ billsSummary: {
+ ...state.billsSummary,
+ loading: true,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.BILLS_SUMMARY_SUCCEEDED:
+ return {
+ ...state,
+ billsSummary: {
+ data: action.instance,
+ loading: false,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.BILLS_SUMMARY_FAILED:
+ return {
+ ...state,
+ billsSummary: {
+ loading: false,
+ error: action.error,
+ },
+ };
+
+ case FinancialInputs.CREATE_BILLS_SUMMARY_REQUESTED:
+ return {
+ ...state,
+ billsSummary: {
+ ...state.billsSummary,
+ loading: true,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.CREATE_BILLS_SUMMARY_SUCCEEDED:
+ // const utilityType = action.instance.utility_type;
+ console.log(state.billsSummary.data); // eslint-disable-line
+ // console.log([
+ // ...state.billsSummary.data,
+ // {
+ // id: action.result.id,
+ // utility_type: action.instance.utility_type,
+ // year: action.instance.year,
+ // charge: action.instance.charge,
+ // },
+ // ]); // eslint-disable-line
+
+ return {
+ ...state,
+ billsSummary: {
+ data: {
+ result:
+ [
+ ...state.billsSummary.data,
+ {
+ id: action.result.id,
+ utility_type: action.instance.utility_type,
+ year: action.instance.year,
+ charge: action.instance.charge,
+ },
+ ],
+
+ },
+ loading: false,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.CREATE_BILLS_SUMMARY_FAILED:
+ return {
+ ...state,
+ billsSummary: {
+ loading: false,
+ error: action.error,
+ },
+ };
+
+ case FinancialInputs.UPDATE_BILLS_SUMMARY_REQUESTED:
+ return {
+ ...state,
+ billsSummary: {
+ ...state.billsSummary,
+ loading: true,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.UPDATE_BILLS_SUMMARY_SUCCEEDED:
+ return {
+ ...state,
+ billsSummary: {
+ ...state.billsSummary,
+ loading: false,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.UPDATE_BILLS_SUMMARY_FAILED:
+ return {
+ ...state,
+ billsSummary: {
+ loading: false,
+ error: action.error,
+ },
+ };
+
+ case FinancialInputs.DELETE_BILLS_SUMMARY_REQUESTED:
+ return {
+ ...state,
+ billsSummary: {
+ ...state.billsSummary,
+ loading: true,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.DELETE_BILLS_SUMMARY_SUCCEEDED:
+ return {
+ ...state,
+ billsSummary: {
+ ...state.billsSummary,
+ loading: false,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.DELETE_BILLS_SUMMARY_FAILED:
+ return {
+ ...state,
+ billsSummary: {
+ loading: false,
+ error: action.error,
+ },
+ };
+
+ case FinancialInputs.LOAN_OPTIONS_REQUESTED:
+ return {
+ ...state,
+ loanOptions: {
+ ...state.loanOptions,
+ loading: true,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.LOAN_OPTIONS_SUCCEEDED:
+ return {
+ ...state,
+ loanOptions: {
+ data: action.instance,
+ loading: false,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.LOAN_OPTIONS_FAILED:
+ console.log(action); // eslint-disable-line
+ return {
+ ...state,
+ loanOptions: {
+ loading: false,
+ error: action.error,
+ },
+ };
+
+ case FinancialInputs.CASH_BALANCE_REQUESTED:
+ return {
+ ...state,
+ cashBalance: {
+ ...state.cashBalance,
+ loading: true,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.CASH_BALANCE_SUCCEEDED:
+ return {
+ ...state,
+ cashBalance: {
+ data: action.instance,
+ loading: false,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.CASH_BALANCE_FAILED:
+ return {
+ ...state,
+ cashBalance: {
+ loading: false,
+ error: action.error,
+ },
+ };
+
+ case FinancialInputs.INCOME_STATEMENT_REQUESTED:
+ return {
+ ...state,
+ incomeStatement: {
+ ...state.incomeStatement,
+ loading: true,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.INCOME_STATEMENT_SUCCEEDED:
+ return {
+ ...state,
+ incomeStatement: {
+ data: action.instance,
+ loading: false,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.INCOME_STATEMENT_FAILED:
+ return {
+ ...state,
+ incomeStatement: {
+ loading: false,
+ error: action.error,
+ },
+ };
+
+ case FinancialInputs.LIABILITIES_REQUESTED:
+ return {
+ ...state,
+ liabilities: {
+ ...state.liabilities,
+ loading: true,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.LIABILITIES_SUCCEEDED:
+ return {
+ ...state,
+ liabilities: {
+ data: action.instance,
+ loading: false,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.LIABILITIES_FAILED:
+ return {
+ ...state,
+ liabilities: {
+ loading: false,
+ error: action.error,
+ },
+ };
+
+ case FinancialInputs.CUSTOMER_PREFERENCE_REQUESTED:
+ return {
+ ...state,
+ customerPreference: {
+ ...state.customerPreference,
+ loading: true,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.CUSTOMER_PREFERENCE_SUCCEEDED:
+ return {
+ ...state,
+ customerPreference: {
+ data: action.instance,
+ loading: false,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.CUSTOMER_PREFERENCE_FAILED:
+ return {
+ ...state,
+ customerPreference: {
+ loading: false,
+ error: action.error,
+ },
+ };
+
+ case FinancialInputs.CREATE_BILLS_OVERVIEW_REQUESTED:
+ return {
+ ...state,
+ billsOverview: {
+ ...state.billsOverview,
+ loading: true,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.CREATE_BILLS_OVERVIEW_SUCCEEDED:
+ return {
+ ...state,
+ billsOverview: {
+ ...state.billsOverview,
+ loading: false,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.CREATE_BILLS_OVERVIEW_FAILED:
+ return {
+ ...state,
+ billsOverview: {
+ loading: false,
+ error: action.error,
+ },
+ };
+
+ case FinancialInputs.UPDATE_BILLS_OVERVIEW_REQUESTED:
+ return {
+ ...state,
+ billsOverview: {
+ ...state.billsOverview,
+ loading: true,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.UPDATE_BILLS_OVERVIEW_SUCCEEDED:
+ console.log(action); // eslint-disable-line
+ console.log(state); // eslint-disable-line
+ return {
+ ...state,
+ billsOverview: {
+ ...state.billsOverview,
+ loading: false,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.UPDATE_BILLS_OVERVIEW_FAILED:
+ return { ...state,
+ billsOverview: {
+ ...state.billsOverview,
+ loading: false,
+ error: action.error,
+ },
+ };
+
+ case FinancialInputs.UPDATE_INCOME_STATEMENTS_REQUESTED:
+ return {
+ ...state,
+ incomeStatement: {
+ ...state.incomeStatement,
+ loading: true,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.UPDATE_INCOME_STATEMENTS_SUCCEEDED:
+ console.log(action); // eslint-disable-line
+ console.log(state); // eslint-disable-line
+ return {
+ ...state,
+ incomeStatement: {
+ data: { instance: action.instance },
+ loading: false,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.UPDATE_INCOME_STATEMENTS_FAILED:
+ return { ...state,
+ incomeStatement: {
+ ...state.incomeStatement,
+ loading: false,
+ error: action.error,
+ },
+ };
+
+ case FinancialInputs.UPDATE_CASH_BALANCE_REQUESTED:
+ return {
+ ...state,
+ cashBalance: {
+ ...state.cashBalance,
+ loading: true,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.UPDATE_CASH_BALANCE_SUCCEEDED:
+ console.log(action); // eslint-disable-line
+ console.log(state); // eslint-disable-line
+ return {
+ ...state,
+ cashBalance: {
+ data: { instance: action.instance },
+ loading: false,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.UPDATE_CASH_BALANCE_FAILED:
+ return { ...state,
+ cashBalance: {
+ ...state.cashBalance,
+ loading: false,
+ error: action.error,
+ },
+ };
+
+ case FinancialInputs.UPDATE_LIABILITIES_REQUESTED:
+ return {
+ ...state,
+ liabilities: {
+ ...state.liabilities,
+ loading: true,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.UPDATE_LIABILITIES_SUCCEEDED:
+ console.log(action); // eslint-disable-line
+ console.log(state); // eslint-disable-line
+ return {
+ ...state,
+ liabilities: {
+ data: { instance: action.instance },
+ loading: false,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.UPDATE_LIABILITIES_FAILED:
+ return { ...state,
+ liabilities: {
+ ...state.liabilities,
+ loading: false,
+ error: action.error,
+ },
+ };
+
+ case FinancialInputs.UPDATE_LOAN_OPTIONS_REQUESTED:
+ return {
+ ...state,
+ loanOptions: {
+ ...state.loanOptions,
+ loading: true,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.UPDATE_LOAN_OPTIONS_SUCCEEDED:
+ console.log(action); // eslint-disable-line
+ console.log(state); // eslint-disable-line
+ return {
+ ...state,
+ loanOptions: {
+ data: { instance: action.instance },
+ loading: false,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.UPDATE_LOAN_OPTIONS_FAILED:
+ return { ...state,
+ loanOptions: {
+ ...state.loanOptions,
+ loading: false,
+ error: action.error,
+ },
+ };
+
+ case FinancialInputs.UPDATE_CUSTOMER_PREFERENCE_REQUESTED:
+ return {
+ ...state,
+ customerPreference: {
+ ...state.customerPreference,
+ loading: true,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.UPDATE_CUSTOMER_PREFERENCE_SUCCEEDED:
+ console.log(action); // eslint-disable-line
+ console.log(state); // eslint-disable-line
+ return {
+ ...state,
+ customerPreference: {
+ data: { instance: action.instance },
+ loading: false,
+ error: false,
+ },
+ };
+
+ case FinancialInputs.UPDATE_CUSTOMER_PREFERENCE_FAILED:
+ return { ...state,
+ customerPreference: {
+ ...state.customerPreference,
+ loading: false,
+ error: action.error,
+ },
+ };
+
+ case PreliminaryFinance.SCENARIO_REQUESTED:
+ return {
+ ...state,
+ scenario: {
+ ...state.scenario,
+ loading: true,
+ error: false,
+ },
+ };
+
+ case PreliminaryFinance.SCENARIO_SUCCEEDED:
+ console.log(action); // eslint-disable-line
+ console.log(state); // eslint-disable-line
+ return {
+ ...state,
+ scenario: {
+ data: { instance: action.instance },
+ loading: false,
+ error: false,
+ },
+ };
+
+ case PreliminaryFinance.SCENARIO_FAILED:
+ return { ...state,
+ scenario: {
+ ...state.scenario,
+ loading: false,
+ error: action.error,
+ },
+ };
+
+ case PreliminaryFinance.UPDATE_SCENARIO_REQUESTED:
+ return {
+ ...state,
+ scenario: {
+ ...state.scenario,
+ loading: true,
+ error: false,
+ },
+ };
+
+ case PreliminaryFinance.UPDATE_SCENARIO_SUCCEEDED:
+ console.log(action); // eslint-disable-line
+ console.log(state); // eslint-disable-line
+ return {
+ ...state,
+ scenario: {
+ data: { instance: action.instance },
+ loading: false,
+ error: false,
+ },
+ };
+
+ case PreliminaryFinance.UPDATE_SCENARIO_FAILED:
+ return { ...state,
+ scenario: {
+ ...state.scenario,
+ loading: false,
+ error: action.error,
+ },
+ };
+
+ case BudgetSimulator.BUDGET_SIMULATOR_REQUESTED:
+ return {
+ ...state,
+ budgetSimulator: {
+ ...state.budgetSimulator,
+ loading: true,
+ error: false,
+ },
+ };
+
+ case BudgetSimulator.BUDGET_SIMULATOR_SUCCEEDED:
+ return {
+ ...state,
+ budgetSimulator: {
+ data: action.instance,
+ loading: false,
+ error: false,
+ },
+ };
+
+ case BudgetSimulator.BUDGET_SIMULATOR_FAILED:
+ return {
+ ...state,
+ budgetSimulator: {
+ loading: false,
+ error: action.error,
+ },
+ };
+
+ default:
+ return state;
+ }
+}
diff --git a/src/containers/Blocnote/sagas.js b/src/containers/Blocnote/sagas.js
new file mode 100644
index 0000000000000000000000000000000000000000..b07e51ad3d5efa016171da9bc95c7d9ca49c3f26
--- /dev/null
+++ b/src/containers/Blocnote/sagas.js
@@ -0,0 +1,361 @@
+import { call, put, takeEvery } from 'redux-saga/effects';
+import SagaRequests from '../../utils/sagaRequests';
+import request from '../../utils/request';
+import { getHeaders } from '../../utils/restServices';
+import * as LandingPage from './constants';
+import * as FinancialInputs from './FinancialInputs/constants';
+import * as PreliminaryFinance from './PreliminaryFinance/constants';
+import * as BudgetSimulator from './BudgetSimulator/constants';
+
+import {
+ landingDataLoaded, landingDataFailed,
+} from './actions';
+
+import {
+ financeOverviewLoaded, financeOverviewFailed,
+ billsLoaded, billsFailed,
+ billsOverviewLoaded, billsOverviewFailed,
+ billsSummaryLoaded, billsSummaryFailed,
+ incomeStatementLoaded, incomeStatementFailed,
+ loanOptionsLoaded, loanOptionsFailed,
+ cashBalanceLoaded, cashBalanceFailed,
+ liabilitiesLoaded, liabilitiesFailed,
+ customerPreferenceLoaded, customerPreferenceFailed,
+ createBillsSummarySucceeded, createBillsSummaryFailed,
+ updateBillsSummarySucceeded, updateBillsSummaryFailed,
+ deleteBillsSummarySucceeded, deleteBillsSummaryFailed,
+ createBillsOverviewSucceeded, createBillsOverviewFailed,
+ updateBillsOverviewSucceeded, updateBillsOverviewFailed,
+ updateIncomeStatementsSucceeded, updateIncomeStatementsFailed,
+ updateCashBalanceSucceeded, updateCashBalanceFailed,
+ updateLiabilitiesSucceeded, updateLiabilitiesFailed,
+ updateLoanOptionsSucceeded, updateLoanOptionsFailed,
+ updateCustomerPreferenceSucceeded, updateCustomerPreferenceFailed,
+} from './FinancialInputs/actions';
+
+import {
+ scenarioLoaded, scenarioFailed,
+ updateScenarioSucceeded, updateScenarioFailed,
+} from './PreliminaryFinance/actions';
+
+import {
+ budgetSimulatorLoaded, budgetSimulatorFailed,
+} from './BudgetSimulator/actions';
+
+function* loadLandingData(action) {
+ const url = `${process.env.REACT_APP_BLOCNOTE_URL}/buildings/${action.buildingId}/data/`;
+ yield SagaRequests.get(action, url, landingDataLoaded, landingDataFailed);
+}
+
+function* loadFinanceOverview(action) {
+ const url = `${process.env.REACT_APP_BLOCNOTE_URL}/buildings/${action.buildingId}/financial-inputs/finance-overview/`;
+ yield SagaRequests.get(action, url, financeOverviewLoaded, financeOverviewFailed);
+}
+
+function* loadBills(action) {
+ const url = `${process.env.REACT_APP_BLOCNOTE_URL}/buildings/${action.buildingId}/financial-inputs/bills/`;
+ yield SagaRequests.get(action, url, billsLoaded, billsFailed);
+}
+
+function* loadBillsOverview(action) {
+ const url = `${process.env.REACT_APP_BLOCNOTE_URL}/buildings/${action.buildingId}/financial-inputs/bills-overview/`;
+ yield SagaRequests.get(action, url, billsOverviewLoaded, billsOverviewFailed);
+}
+
+function* loadBillsSummary(action) {
+ const url = `${process.env.REACT_APP_BLOCNOTE_URL}/buildings/${action.buildingId}/financial-inputs/bills-summary/`;
+ yield SagaRequests.get(action, url, billsSummaryLoaded, billsSummaryFailed);
+}
+
+function* loadLoanOptions(action) {
+ const url = `${process.env.REACT_APP_BLOCNOTE_URL}/buildings/${action.buildingId}/financial-inputs/loan-options/?loans=all-loans`;
+ yield SagaRequests.get(action, url, loanOptionsLoaded, loanOptionsFailed);
+}
+
+function* loadCashBalance(action) {
+ const url = `${process.env.REACT_APP_BLOCNOTE_URL}/buildings/${action.buildingId}/financial-inputs/cash-balance/`;
+ yield SagaRequests.get(action, url, cashBalanceLoaded, cashBalanceFailed);
+}
+
+function* loadIncomeStatement(action) {
+ const url = `${process.env.REACT_APP_BLOCNOTE_URL}/buildings/${action.buildingId}/financial-inputs/income-statement/`;
+ yield SagaRequests.get(action, url, incomeStatementLoaded, incomeStatementFailed);
+}
+
+function* loadCustomerPreference(action) {
+ const url = `${process.env.REACT_APP_BLOCNOTE_URL}/buildings/${action.buildingId}/financial-inputs/customer-preference/`;
+ yield SagaRequests.get(action, url, customerPreferenceLoaded, customerPreferenceFailed);
+}
+
+function* loadLiabilities(action) {
+ const url = `${process.env.REACT_APP_BLOCNOTE_URL}/buildings/${action.buildingId}/financial-inputs/liabilities/`;
+ yield SagaRequests.get(action, url, liabilitiesLoaded, liabilitiesFailed);
+}
+
+function* loadBudgetSimulator(action) {
+ const url = `${process.env.REACT_APP_BLOCNOTE_URL}/buildings/${action.buildingId}/budget/budget-data/`;
+ yield SagaRequests.get(action, url, budgetSimulatorLoaded, budgetSimulatorFailed);
+ const res = yield call(request, url, {
+ method: 'GET',
+ headers: getHeaders(),
+ });
+
+ if (!res.err) {
+ yield put(budgetSimulatorLoaded(res));
+ } else {
+ yield put(budgetSimulatorFailed(res.err));
+ }
+}
+
+function* createBillsSummary(action) {
+ console.log(action); // eslint-disable-line
+ const url = `${process.env.REACT_APP_BLOCNOTE_URL}/buildings/${action.buildingId}/financial-inputs/bills-summary/`;
+ const res = yield call(
+ request,
+ SagaRequests.generateURL(url, action),
+ {
+ method: 'POST',
+ headers: getHeaders(),
+ body: JSON.stringify(action.payload),
+ }
+ );
+
+ if (!res.err) {
+ console.log(res); // eslint-disable-line
+ yield put(createBillsSummarySucceeded(action.payload, res));
+ } else {
+ yield put(createBillsSummaryFailed(res.err));
+ }
+}
+
+function* updateBillsSummary(action) {
+ console.log(action); // eslint-disable-line
+ const url = `${process.env.REACT_APP_BLOCNOTE_URL}/buildings/${action.buildingId}/financial-inputs/bills-summary/`;
+ const res = yield call(
+ request,
+ SagaRequests.generateURL(url, action),
+ {
+ method: 'PUT',
+ headers: getHeaders(),
+ body: JSON.stringify(action.payload),
+ }
+ );
+
+ if (!res.err) {
+ yield put(updateBillsSummarySucceeded(action.payload));
+ } else {
+ yield put(updateBillsSummaryFailed(res.err));
+ }
+}
+
+function* deleteBillsSummary(action) {
+ console.log(action); // eslint-disable-line
+ const url = `${process.env.REACT_APP_BLOCNOTE_URL}/buildings/${action.buildingId}/financial-inputs/bills-summary/`;
+ const res = yield call(
+ request,
+ SagaRequests.generateURL(url, action),
+ {
+ method: 'DELETE',
+ headers: getHeaders(),
+ body: JSON.stringify(action.payload),
+ }
+ );
+
+ if (!res.err) {
+ yield put(deleteBillsSummarySucceeded(action.payload));
+ } else {
+ yield put(deleteBillsSummaryFailed(res.err));
+ }
+}
+
+function* createBillsOverview(action) {
+ console.log(action); // eslint-disable-line
+ const url = `${process.env.REACT_APP_BLOCNOTE_URL}/buildings/${action.buildingId}/financial-inputs/bills-overview/`;
+ const res = yield call(
+ request,
+ SagaRequests.generateURL(url, action),
+ {
+ method: 'POST',
+ headers: getHeaders(),
+ body: JSON.stringify(action.payload),
+ }
+ );
+
+ if (!res.err) {
+ console.log(res); // eslint-disable-line
+ yield put(createBillsOverviewSucceeded(action.payload, res));
+ } else {
+ yield put(createBillsOverviewFailed(res.err));
+ }
+}
+
+function* updateBillsOverview(action) {
+ const url = `${process.env.REACT_APP_BLOCNOTE_URL}/buildings/${action.buildingId}/financial-inputs/bills-overview/`;
+ const res = yield call(
+ request,
+ SagaRequests.generateURL(url, action),
+ {
+ method: 'PUT',
+ headers: getHeaders(),
+ body: JSON.stringify(action.payload),
+ }
+ );
+
+ if (!res.err) {
+ yield put(updateBillsOverviewSucceeded(action.payload));
+ } else {
+ yield put(updateBillsOverviewFailed(res.err));
+ }
+}
+
+function* updateIncomeStatements(action) {
+ const url = `${process.env.REACT_APP_BLOCNOTE_URL}/buildings/${action.buildingId}/financial-inputs/income-statement/`;
+ const res = yield call(
+ request,
+ SagaRequests.generateURL(url, action),
+ {
+ method: 'PUT',
+ headers: getHeaders(),
+ body: JSON.stringify(action.payload),
+ }
+ );
+
+ if (!res.err) {
+ yield put(updateIncomeStatementsSucceeded(action.payload));
+ } else {
+ yield put(updateIncomeStatementsFailed(res.err));
+ }
+}
+
+function* updateCashBalance(action) {
+ const url = `${process.env.REACT_APP_BLOCNOTE_URL}/buildings/${action.buildingId}/financial-inputs/cash-balance/`;
+ const res = yield call(
+ request,
+ SagaRequests.generateURL(url, action),
+ {
+ method: 'PUT',
+ headers: getHeaders(),
+ body: JSON.stringify(action.payload),
+ }
+ );
+
+ if (!res.err) {
+ yield put(updateCashBalanceSucceeded(action.payload));
+ } else {
+ yield put(updateCashBalanceFailed(res.err));
+ }
+}
+
+function* updateLiabilities(action) {
+ const url = `${process.env.REACT_APP_BLOCNOTE_URL}/buildings/${action.buildingId}/financial-inputs/liabilities/`;
+ const res = yield call(
+ request,
+ SagaRequests.generateURL(url, action),
+ {
+ method: 'PUT',
+ headers: getHeaders(),
+ body: JSON.stringify(action.payload),
+ }
+ );
+
+ if (!res.err) {
+ yield put(updateLiabilitiesSucceeded(action.payload));
+ } else {
+ yield put(updateLiabilitiesFailed(res.err));
+ }
+}
+
+function* updateLoanOptions(action) {
+ const url = `${process.env.REACT_APP_BLOCNOTE_URL}/buildings/${action.buildingId}/financial-inputs/loan-options/`;
+ const res = yield call(
+ request,
+ SagaRequests.generateURL(url, action),
+ {
+ method: 'PUT',
+ headers: getHeaders(),
+ body: JSON.stringify(action.payload),
+ }
+ );
+
+ if (!res.err) {
+ yield put(updateLoanOptionsSucceeded(action.payload));
+ } else {
+ yield put(updateLoanOptionsFailed(res.err));
+ }
+}
+
+function* updateCustomerPreference(action) {
+ console.log(action); // eslint-disable-line
+ const url = `${process.env.REACT_APP_BLOCNOTE_URL}/buildings/${action.buildingId}/financial-inputs/customer-preference/`;
+ const res = yield call(
+ request,
+ SagaRequests.generateURL(url, action),
+ {
+ method: 'PUT',
+ headers: getHeaders(),
+ body: JSON.stringify(action.payload),
+ }
+ );
+
+ if (!res.err) {
+ yield put(updateCustomerPreferenceSucceeded(action.payload));
+ } else {
+ yield put(updateCustomerPreferenceFailed(res.err));
+ }
+}
+
+function* loadScenario(action) {
+ console.log(action); // eslint-disable-line
+ console.log(`${process.env.REACT_APP_BLOCNOTE_URL}/buildings/${action.buildingId}/preliminary-finance/scenario/`); // eslint-disable-line
+ const url = `${process.env.REACT_APP_BLOCNOTE_URL}/buildings/${action.buildingId}/preliminary-finance/scenario/`;
+ yield SagaRequests.get(action, url, scenarioLoaded, scenarioFailed);
+}
+
+function* updateScenario(action) {
+ console.log(action); // eslint-disable-line
+ const url = `${process.env.REACT_APP_BLOCNOTE_URL}/buildings/${action.buildingId}/preliminary-finance/scenario/`;
+ const res = yield call(
+ request,
+ SagaRequests.generateURL(url, action),
+ {
+ method: 'PUT',
+ headers: getHeaders(),
+ body: JSON.stringify(action.payload),
+ }
+ );
+
+ console.log(res); // eslint-disable-line
+ if (!res.err) {
+ yield put(updateScenarioSucceeded(action.payload));
+ } else {
+ yield put(updateScenarioFailed(res.err));
+ }
+}
+
+function* blocnoteWatcher() {
+ yield takeEvery(LandingPage.LANDING_DATA_REQUESTED, loadLandingData);
+ yield takeEvery(FinancialInputs.FINANCE_OVERVIEW_REQUESTED, loadFinanceOverview);
+ yield takeEvery(FinancialInputs.BILLS_REQUESTED, loadBills);
+ yield takeEvery(FinancialInputs.BILLS_OVERVIEW_REQUESTED, loadBillsOverview);
+ yield takeEvery(FinancialInputs.BILLS_SUMMARY_REQUESTED, loadBillsSummary);
+ yield takeEvery(FinancialInputs.CASH_BALANCE_REQUESTED, loadCashBalance);
+ yield takeEvery(FinancialInputs.LOAN_OPTIONS_REQUESTED, loadLoanOptions);
+ yield takeEvery(FinancialInputs.INCOME_STATEMENT_REQUESTED, loadIncomeStatement);
+ yield takeEvery(FinancialInputs.CUSTOMER_PREFERENCE_REQUESTED, loadCustomerPreference);
+ yield takeEvery(FinancialInputs.LIABILITIES_REQUESTED, loadLiabilities);
+ yield takeEvery(FinancialInputs.CREATE_BILLS_SUMMARY_REQUESTED, createBillsSummary);
+ yield takeEvery(FinancialInputs.UPDATE_BILLS_SUMMARY_REQUESTED, updateBillsSummary);
+ yield takeEvery(FinancialInputs.DELETE_BILLS_SUMMARY_REQUESTED, deleteBillsSummary);
+ yield takeEvery(FinancialInputs.CREATE_BILLS_OVERVIEW_REQUESTED, createBillsOverview);
+ yield takeEvery(FinancialInputs.UPDATE_BILLS_OVERVIEW_REQUESTED, updateBillsOverview);
+ yield takeEvery(FinancialInputs.UPDATE_INCOME_STATEMENTS_REQUESTED, updateIncomeStatements);
+ yield takeEvery(FinancialInputs.UPDATE_CASH_BALANCE_REQUESTED, updateCashBalance);
+ yield takeEvery(FinancialInputs.UPDATE_LIABILITIES_REQUESTED, updateLiabilities);
+ yield takeEvery(FinancialInputs.UPDATE_LOAN_OPTIONS_REQUESTED, updateLoanOptions);
+ yield takeEvery(FinancialInputs.UPDATE_CUSTOMER_PREFERENCE_REQUESTED, updateCustomerPreference);
+ yield takeEvery(PreliminaryFinance.SCENARIO_REQUESTED, loadScenario);
+ yield takeEvery(PreliminaryFinance.UPDATE_SCENARIO_REQUESTED, updateScenario);
+ yield takeEvery(BudgetSimulator.BUDGET_SIMULATOR_REQUESTED, loadBudgetSimulator);
+}
+
+export default blocnoteWatcher;
diff --git a/src/containers/Blocnote/styles.css b/src/containers/Blocnote/styles.css
new file mode 100644
index 0000000000000000000000000000000000000000..b849a45a13feb51f31e5b5af8676647fe8be624b
--- /dev/null
+++ b/src/containers/Blocnote/styles.css
@@ -0,0 +1,10 @@
+.leaflet-container {
+ height: 475px;
+}
+
+#run-sim-btn {
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ margin-bottom: 17px;
+}
diff --git a/src/reducers.js b/src/reducers.js
index a6b710cfccb473f998eb3378f70b6372d23a1d55..5bf5ae9a1062f43b94532462678242010e5bacc5 100644
--- a/src/reducers.js
+++ b/src/reducers.js
@@ -16,6 +16,7 @@ import sensors from './containers/Sensors/reducer';
import buildingArea from './containers/BuildingArea/reducer';
import weather from './containers/Weather/reducer';
import events from './containers/Event/reducer';
+import blocnote from './containers/Blocnote/reducer';
export default combineReducers({
@@ -35,4 +36,5 @@ export default combineReducers({
buildingArea,
weather,
events,
+ blocnote,
});
diff --git a/src/routes.js b/src/routes.js
index 381b8699d32f795b53981ae64b23c82a131b7e24..9ef9c9b8d062331206808339af5334025ece1a6f 100644
--- a/src/routes.js
+++ b/src/routes.js
@@ -23,6 +23,10 @@ import Sensors from './containers/Sensors/Sensors';
import SensorInstall from './containers/Sensors/SensorInstall';
import GatewayList from './components/SensorInstall/GatewayList';
import BuildingReports from './containers/BuildingReports';
+import Blocnote from './containers/Blocnote';
+import FinancialInputs from './containers/Blocnote/FinancialInputs/';
+import PreliminaryFinance from './containers/Blocnote/PreliminaryFinance/';
+import BudgetSimulator from './containers/Blocnote/BudgetSimulator/';
import Wrapper from './containers/Wrapper';
import { BGroupOverview, BGroup } from './containers/BGroup';
import NavOnly from './screens/NavOnly/NavOnly';
@@ -57,6 +61,18 @@ export default (
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/sagas.js b/src/sagas.js
index 7f33bf76b92293a53360514ddf6728f329287a39..d880c23e59846c7ff9383acd9af729ae3ff7124e 100644
--- a/src/sagas.js
+++ b/src/sagas.js
@@ -13,6 +13,7 @@ import sensorsSaga from './containers/Sensors/sagas';
import buildingAreaSaga from './containers/BuildingArea/sagas';
import weatherSaga from './containers/Weather/sagas';
import eventsSaga from './containers/Event/sagas';
+import blocnoteSaga from './containers/Blocnote/sagas';
export default function* rootSaga() {
@@ -32,5 +33,6 @@ export default function* rootSaga() {
buildingAreaSaga(),
weatherSaga(),
eventsSaga(),
+ blocnoteSaga(),
];
}
diff --git a/src/utils/restServices.js b/src/utils/restServices.js
index 5bc0b01049e4e9f54cc98fd9d2f22648bd911614..cc696f2996036a593dec234ade8b7d6b7848a3f2 100644
--- a/src/utils/restServices.js
+++ b/src/utils/restServices.js
@@ -13,6 +13,7 @@ const reportService = process.env.REACT_APP_REPORT_SERVICE;
const iotService = process.env.REACT_APP_IOT_SERVICE;
const userService = process.env.REACT_APP_USER_SERVICE;
const weatherService = process.env.REACT_APP_WEATHER_SERVICE;
+const blocnoteService = process.env.REACT_APP_BLOCNOTE_URL;
export const buildingsURL = `${buildingService}/building/`;
export const apartmentsURL = `${buildingService}/apartment/`;
@@ -56,3 +57,5 @@ export const userURL = `${userService}/user/`;
export const userGroupsURL = `${userService}/usergroup/`;
export const weatherURL = `${weatherService}/weather/`;
+
+export const blocnoteURL = `${blocnoteService}/`;