diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index daddd39..66e0666 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -31,7 +31,8 @@ sonar-scanner: - dev script: - cd smart-hut - - yarn sonar-scanner -Dsonar.host.url=$SONAR_URL -Dsonar.login=$SONAR_LOGIN -Dsonar.projectName=$CI_PROJECT_PATH_SLUG -Dsonar.projectKey=$CI_PROJECT_PATH_SLUG -Dsonar.exclusion=cypress -Dsonar.sources=src -Dsonar.javascript.file.suffixes=.js,.jsx -Dsonar.sourceEncoding=UTF-8 -Dsonar.scm.disabled=True + - yarn eslint:report || true + - yarn sonar-scanner -Dsonar.host.url=$SONAR_URL -Dsonar.login=$SONAR_LOGIN -Dsonar.projectName=$CI_PROJECT_PATH_SLUG -Dsonar.projectKey=$CI_PROJECT_PATH_SLUG -Dsonar.exclusion=cypress -Dsonar.sources=src -Dsonar.javascript.file.suffixes=.js,.jsx -Dsonar.sourceEncoding=UTF-8 -Dsonar.scm.disabled=True -Dsonar.eslint.reportPaths=eslint-report.json smartHut_deploy: stage: deploy diff --git a/hooks/pre-commit.sh b/hooks/pre-commit.sh index 2b233cc..6b0c5cd 100755 --- a/hooks/pre-commit.sh +++ b/hooks/pre-commit.sh @@ -1,10 +1,11 @@ #!/bin/sh -FILES=$(git diff --cached --name-only --diff-filter=ACMR "*.js" "*.jsx" | sed 's| |\\ |g') -[ -z "$FILES" ] && exit 0 +FILES=$(git diff --cached --name-only --diff-filter=ACMR | sed 's| |\\ |g') # Prettify all selected files -echo "$FILES" | xargs ./smart-hut/node_modules/.bin/prettier --write +cd $(git rev-parse --show-toplevel)/smart-hut +npm run eslint-fix +cd .. # Add back the modified/prettified files to staging echo "$FILES" | xargs git add diff --git a/smart-hut/.eslintrc b/smart-hut/.eslintrc new file mode 100644 index 0000000..ed73165 --- /dev/null +++ b/smart-hut/.eslintrc @@ -0,0 +1,54 @@ +{ + "parser": "babel-eslint", + "parserOptions": { + "ecmaVersion": 2020, + "sourceType": "module", + "ecmaFeatures": { + "jsx": true + } + }, + "rules": { + "semi": "error", + "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], + "react/jsx-no-bind": [ + "error", + { + "allowArrowFunctions": true, + "allowBind": false, + "ignoreRefs": true + } + ], + "react/no-did-update-set-state": "error", + "react/no-unknown-property": "error", + "react/no-unused-prop-types": "error", + "react/prop-types": "error", + "react/react-in-jsx-scope": "error", + "no-unused-expressions": 0, + "chai-friendly/no-unused-expressions": 2, + "indent": [0, 4] + }, + "extends": [ + "eslint:recommended", + "plugin:react/recommended", + "airbnb" + ], + "env": { + "node": true, + "browser": true, + "jest": true + }, + + "globals": { + "Atomics": "readonly", + "SharedArrayBuffer": "readonly" + }, + + "settings": { + "react": { + "version": "detect" + } + }, + + "plugins": ["react", "chai-friendly"] +} + diff --git a/smart-hut/package-lock.json b/smart-hut/package-lock.json index f1c109d..188d272 100644 --- a/smart-hut/package-lock.json +++ b/smart-hut/package-lock.json @@ -1397,6 +1397,12 @@ "resolved": "https://registry.npmjs.org/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.2.tgz", "integrity": "sha512-vTCdPp/T/Q3oSqwHmZ5Kpa9oI7iLtGl3RQaA/NyLHikvcrPxACkkKVr/XzkSPJWXHRhKGzVvb0urJsbMlRxi1Q==" }, + "@sindresorhus/is": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", + "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==", + "dev": true + }, "@stardust-ui/react-component-event-listener": { "version": "0.38.0", "resolved": "https://registry.npmjs.org/@stardust-ui/react-component-event-listener/-/react-component-event-listener-0.38.0.tgz", @@ -2101,6 +2107,15 @@ "type-fest": "^0.8.1" } }, + "ansi-gray": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", + "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, "ansi-html": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", @@ -2119,6 +2134,12 @@ "color-convert": "^1.9.0" } }, + "ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", + "dev": true + }, "anymatch": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", @@ -2133,6 +2154,23 @@ "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" }, + "archive-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/archive-type/-/archive-type-4.0.0.tgz", + "integrity": "sha1-+S5yIzBW38aWlHJ0nCZ72wRrHXA=", + "dev": true, + "requires": { + "file-type": "^4.2.0" + }, + "dependencies": { + "file-type": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz", + "integrity": "sha1-G2AOX8ofvcboDApwxxyNul95BsU=", + "dev": true + } + } + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -2739,6 +2777,48 @@ "file-uri-to-path": "1.0.0" } }, + "bl": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", + "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", + "dev": true, + "requires": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -2970,6 +3050,34 @@ } } }, + "buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "dev": true, + "requires": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "dev": true + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "dev": true + }, + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", + "dev": true + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -3046,6 +3154,72 @@ "unset-value": "^1.0.0" } }, + "cacheable-request": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz", + "integrity": "sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=", + "dev": true, + "requires": { + "clone-response": "1.0.2", + "get-stream": "3.0.0", + "http-cache-semantics": "3.8.1", + "keyv": "3.0.0", + "lowercase-keys": "1.0.0", + "normalize-url": "2.0.1", + "responselike": "1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "lowercase-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", + "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=", + "dev": true + }, + "normalize-url": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", + "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", + "dev": true, + "requires": { + "prepend-http": "^2.0.0", + "query-string": "^5.0.1", + "sort-keys": "^2.0.0" + } + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + }, + "query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "dev": true, + "requires": { + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "sort-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", + "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", + "dev": true, + "requires": { + "is-plain-obj": "^1.0.0" + } + } + } + }, "call-me-maybe": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", @@ -3125,6 +3299,18 @@ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, + "caw": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/caw/-/caw-2.0.1.tgz", + "integrity": "sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==", + "dev": true, + "requires": { + "get-proxy": "^2.0.0", + "isurl": "^1.0.0-alpha5", + "tunnel-agent": "^0.6.0", + "url-to-options": "^1.0.1" + } + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -3323,6 +3509,15 @@ "shallow-clone": "^0.1.2" } }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, "clsx": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.0.tgz", @@ -3388,6 +3583,12 @@ "simple-swizzle": "^0.2.2" } }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true + }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -3506,6 +3707,16 @@ } } }, + "config-chain": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", + "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", + "dev": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, "confusing-browser-globals": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz", @@ -4023,6 +4234,151 @@ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" }, + "decompress": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.1.tgz", + "integrity": "sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ==", + "dev": true, + "requires": { + "decompress-tar": "^4.0.0", + "decompress-tarbz2": "^4.0.0", + "decompress-targz": "^4.0.0", + "decompress-unzip": "^4.0.1", + "graceful-fs": "^4.1.10", + "make-dir": "^1.0.0", + "pify": "^2.3.0", + "strip-dirs": "^2.0.0" + }, + "dependencies": { + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "decompress-tar": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", + "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", + "dev": true, + "requires": { + "file-type": "^5.2.0", + "is-stream": "^1.1.0", + "tar-stream": "^1.5.2" + }, + "dependencies": { + "file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=", + "dev": true + } + } + }, + "decompress-tarbz2": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", + "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", + "dev": true, + "requires": { + "decompress-tar": "^4.1.0", + "file-type": "^6.1.0", + "is-stream": "^1.1.0", + "seek-bzip": "^1.0.5", + "unbzip2-stream": "^1.0.9" + }, + "dependencies": { + "file-type": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", + "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==", + "dev": true + } + } + }, + "decompress-targz": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", + "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", + "dev": true, + "requires": { + "decompress-tar": "^4.1.1", + "file-type": "^5.2.0", + "is-stream": "^1.1.0" + }, + "dependencies": { + "file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=", + "dev": true + } + } + }, + "decompress-unzip": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", + "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=", + "dev": true, + "requires": { + "file-type": "^3.8.0", + "get-stream": "^2.2.0", + "pify": "^2.3.0", + "yauzl": "^2.4.2" + }, + "dependencies": { + "file-type": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=", + "dev": true + }, + "get-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", + "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", + "dev": true, + "requires": { + "object-assign": "^4.0.1", + "pinkie-promise": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, "deep-equal": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", @@ -4357,11 +4713,54 @@ "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" }, + "download": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/download/-/download-7.1.0.tgz", + "integrity": "sha512-xqnBTVd/E+GxJVrX5/eUJiLYjCGPwMpdL+jGhGU57BvtcA7wwhtHVbXBeUk51kOpW3S7Jn3BQbN9Q1R1Km2qDQ==", + "dev": true, + "requires": { + "archive-type": "^4.0.0", + "caw": "^2.0.1", + "content-disposition": "^0.5.2", + "decompress": "^4.2.0", + "ext-name": "^5.0.0", + "file-type": "^8.1.0", + "filenamify": "^2.0.0", + "get-stream": "^3.0.0", + "got": "^8.3.1", + "make-dir": "^1.2.0", + "p-event": "^2.1.0", + "pify": "^3.0.0" + }, + "dependencies": { + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + } + } + }, "duplexer": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=" }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, "duplexify": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", @@ -4687,6 +5086,28 @@ } } }, + "eslint-config-airbnb": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-18.1.0.tgz", + "integrity": "sha512-kZFuQC/MPnH7KJp6v95xsLBf63G/w7YqdPfQ0MUanxQ7zcKUNG8j+sSY860g3NwCBOa62apw16J6pRN+AOgXzw==", + "dev": true, + "requires": { + "eslint-config-airbnb-base": "^14.1.0", + "object.assign": "^4.1.0", + "object.entries": "^1.1.1" + } + }, + "eslint-config-airbnb-base": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.1.0.tgz", + "integrity": "sha512-+XCcfGyCnbzOnktDVhwsCAx+9DmrzEmuwxyHUJpw+kqBVT744OUBrB09khgFKlK1lshVww6qXGsYPZpavoNjJw==", + "dev": true, + "requires": { + "confusing-browser-globals": "^1.0.9", + "object.assign": "^4.1.0", + "object.entries": "^1.1.1" + } + }, "eslint-config-react-app": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-5.2.0.tgz", @@ -4801,6 +5222,12 @@ } } }, + "eslint-plugin-chai-friendly": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-chai-friendly/-/eslint-plugin-chai-friendly-0.6.0.tgz", + "integrity": "sha512-Uvvv1gkbRGp/qfN15B0kQyQWg+oFA8buDSqrwmW3egNSk/FpqH2MjQqKOuKwmEL6w4QIQrIjDp+gg6kGGmD3oQ==", + "dev": true + }, "eslint-plugin-flowtype": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-4.6.0.tgz", @@ -5264,6 +5691,25 @@ } } }, + "ext-list": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", + "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", + "dev": true, + "requires": { + "mime-db": "^1.28.0" + } + }, + "ext-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", + "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", + "dev": true, + "requires": { + "ext-list": "^2.0.0", + "sort-keys-length": "^1.0.0" + } + }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -5367,6 +5813,18 @@ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, + "fancy-log": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", + "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", + "dev": true, + "requires": { + "ansi-gray": "^0.1.1", + "color-support": "^1.1.3", + "parse-node-version": "^1.0.0", + "time-stamp": "^1.0.0" + } + }, "fast-deep-equal": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", @@ -5461,6 +5919,15 @@ } } }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, "figgy-pudding": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", @@ -5491,12 +5958,35 @@ "schema-utils": "^2.5.0" } }, + "file-type": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-8.1.0.tgz", + "integrity": "sha512-qyQ0pzAy78gVoJsmYeNgl8uH8yKhr1lVhW7JbzJmnlRi0I4R2eEDEJZVKG8agpDnLpacwNbDhLNG/LMdxHD2YQ==", + "dev": true + }, "file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", "optional": true }, + "filename-reserved-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", + "integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik=", + "dev": true + }, + "filenamify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-2.1.0.tgz", + "integrity": "sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA==", + "dev": true, + "requires": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.0", + "trim-repeated": "^1.0.0" + } + }, "filesize": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.0.1.tgz", @@ -5752,6 +6242,12 @@ } } }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, "fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -5846,6 +6342,15 @@ "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" }, + "get-proxy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-2.1.0.tgz", + "integrity": "sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw==", + "dev": true, + "requires": { + "npm-conf": "^1.1.0" + } + }, "get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -5949,11 +6454,50 @@ } } }, + "got": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/got/-/got-8.3.2.tgz", + "integrity": "sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw==", + "dev": true, + "requires": { + "@sindresorhus/is": "^0.7.0", + "cacheable-request": "^2.1.1", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "into-stream": "^3.1.0", + "is-retry-allowed": "^1.1.0", + "isurl": "^1.0.0-alpha5", + "lowercase-keys": "^1.0.0", + "mimic-response": "^1.0.0", + "p-cancelable": "^0.4.0", + "p-timeout": "^2.0.1", + "pify": "^3.0.0", + "safe-buffer": "^5.1.1", + "timed-out": "^4.0.1", + "url-parse-lax": "^3.0.0", + "url-to-options": "^1.0.1" + }, + "dependencies": { + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + } + } + }, "graceful-fs": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true + }, "growly": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", @@ -6032,11 +6576,26 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, + "has-symbol-support-x": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", + "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", + "dev": true + }, "has-symbols": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" }, + "has-to-string-tag-x": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", + "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", + "dev": true, + "requires": { + "has-symbol-support-x": "^1.4.1" + } + }, "has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", @@ -6268,6 +6827,12 @@ } } }, + "http-cache-semantics": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", + "dev": true + }, "http-deceiver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", @@ -6492,6 +7057,24 @@ "ipaddr.js": "^1.9.0" } }, + "into-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", + "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=", + "dev": true, + "requires": { + "from2": "^2.1.1", + "p-is-promise": "^1.1.0" + }, + "dependencies": { + "p-is-promise": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", + "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=", + "dev": true + } + } + }, "invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -6655,6 +7238,12 @@ "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=" }, + "is-natural-number": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", + "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=", + "dev": true + }, "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", @@ -6668,6 +7257,12 @@ "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" }, + "is-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", + "dev": true + }, "is-path-cwd": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", @@ -6725,6 +7320,12 @@ "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==" }, + "is-retry-allowed": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", + "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", + "dev": true + }, "is-root": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", @@ -6859,6 +7460,16 @@ "html-escaper": "^2.0.0" } }, + "isurl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", + "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", + "dev": true, + "requires": { + "has-to-string-tag-x": "^1.2.0", + "is-object": "^1.0.1" + } + }, "jest": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/jest/-/jest-24.9.0.tgz", @@ -7924,6 +8535,12 @@ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", @@ -8085,6 +8702,15 @@ "resolved": "https://registry.npmjs.org/keyboard-key/-/keyboard-key-1.1.0.tgz", "integrity": "sha512-qkBzPTi3rlAKvX7k0/ub44sqOfXeLc/jcnGGmj5c7BJpU8eDrEVPyhCvNYAaoubbsLm9uGWwQJO1ytQK1a9/dQ==" }, + "keyv": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz", + "integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, "killable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", @@ -8258,6 +8884,12 @@ "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=" }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true + }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -8311,6 +8943,12 @@ "tslib": "^1.10.0" } }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, "lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -8551,6 +9189,12 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, "min-indent": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.0.tgz", @@ -8987,6 +9631,16 @@ "sort-keys": "^1.0.0" } }, + "npm-conf": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", + "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", + "dev": true, + "requires": { + "config-chain": "^1.1.11", + "pify": "^3.0.0" + } + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -9250,6 +9904,12 @@ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" }, + "p-cancelable": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", + "integrity": "sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==", + "dev": true + }, "p-defer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", @@ -9263,6 +9923,15 @@ "p-reduce": "^1.0.0" } }, + "p-event": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-2.3.1.tgz", + "integrity": "sha512-NQCqOFhbpVTMX4qMe8PF8lbGtzZ+LCiN7pcNrb/413Na7+TRoe1xkKUzuWa/YEJdGQ0FvKtj35EEbDoVPO2kbA==", + "dev": true, + "requires": { + "p-timeout": "^2.0.1" + } + }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -9310,6 +9979,15 @@ "retry": "^0.12.0" } }, + "p-timeout": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", + "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", + "dev": true, + "requires": { + "p-finally": "^1.0.0" + } + }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -9405,6 +10083,12 @@ "json-parse-better-errors": "^1.0.1" } }, + "parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true + }, "parse5": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", @@ -9492,6 +10176,12 @@ "sha.js": "^2.4.8" } }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -10600,6 +11290,12 @@ "react-is": "^16.8.1" } }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "dev": true + }, "proxy-addr": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", @@ -11624,6 +12320,15 @@ } } }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0" + } + }, "restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -11827,6 +12532,26 @@ "ajv-keywords": "^3.4.1" } }, + "seek-bzip": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz", + "integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=", + "dev": true, + "requires": { + "commander": "~2.8.1" + }, + "dependencies": { + "commander": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", + "dev": true, + "requires": { + "graceful-readlink": ">= 1.0.0" + } + } + } + }, "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -12122,6 +12847,12 @@ } } }, + "slugify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.4.0.tgz", + "integrity": "sha512-FtLNsMGBSRB/0JOE2A0fxlqjI6fJsgHGS13iTuVT28kViI4JjUiNqp/vyis0ZXYcMnpR3fzGNkv+6vRlI2GwdQ==", + "dev": true + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -12272,6 +13003,78 @@ } } }, + "sonarqube-scanner": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/sonarqube-scanner/-/sonarqube-scanner-2.6.0.tgz", + "integrity": "sha512-H6DKMW2WBjFAZ81ubscwE803aiaTQCBeOIu+STrACRdNtrw6WmRmUvw5JY5eGxs/Q+ysyEvz4hInWn0h+7YAlQ==", + "dev": true, + "requires": { + "download": "^7.1.0", + "extend": "3.0.2", + "fancy-log": "^1.3.3", + "lodash.get": "^4.4.2", + "lodash.uniq": "^4.5.0", + "mkdirp": "^1.0.3", + "progress": "^2.0.3", + "read-pkg": "2.0.0", + "slugify": "^1.4.0" + }, + "dependencies": { + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + } + } + }, "sort-keys": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", @@ -12280,6 +13083,15 @@ "is-plain-obj": "^1.0.0" } }, + "sort-keys-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", + "integrity": "sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=", + "dev": true, + "requires": { + "sort-keys": "^1.0.0" + } + }, "source-list-map": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", @@ -12665,6 +13477,15 @@ "babel-plugin-transform-object-rest-spread": "^6.26.0" } }, + "strip-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", + "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", + "dev": true, + "requires": { + "is-natural-number": "^4.0.1" + } + }, "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", @@ -12683,6 +13504,15 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==" }, + "strip-outer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", + "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.2" + } + }, "style-loader": { "version": "0.23.1", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz", @@ -12824,6 +13654,53 @@ "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" }, + "tar-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", + "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "dev": true, + "requires": { + "bl": "^1.0.0", + "buffer-alloc": "^1.2.0", + "end-of-stream": "^1.0.0", + "fs-constants": "^1.0.0", + "readable-stream": "^2.3.0", + "to-buffer": "^1.1.1", + "xtend": "^4.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "terser": { "version": "4.6.4", "resolved": "https://registry.npmjs.org/terser/-/terser-4.6.4.tgz", @@ -12999,6 +13876,18 @@ "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" }, + "time-stamp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", + "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", + "dev": true + }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "dev": true + }, "timers-browserify": { "version": "2.0.11", "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz", @@ -13040,6 +13929,12 @@ "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=" }, + "to-buffer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", + "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", + "dev": true + }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -13095,6 +13990,15 @@ "punycode": "^2.1.0" } }, + "trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", + "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.2" + } + }, "ts-pnp": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.1.5.tgz", @@ -13173,6 +14077,28 @@ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.21.tgz", "integrity": "sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ==" }, + "unbzip2-stream": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.2.tgz", + "integrity": "sha512-pZMVAofMrrHX6Ik39hCk470kulCbmZ2SWfQLPmTWqfJV/oUm0gn1CblvHdUu4+54Je6Jq34x8kY6XjTy6dMkOg==", + "dev": true, + "requires": { + "buffer": "^5.2.1", + "through": "^2.3.8" + }, + "dependencies": { + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + } + } + }, "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", @@ -13343,6 +14269,29 @@ "requires-port": "^1.0.0" } }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "requires": { + "prepend-http": "^2.0.0" + }, + "dependencies": { + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + } + } + }, + "url-to-options": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", + "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", + "dev": true + }, "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", @@ -15411,6 +16360,16 @@ "camelcase": "^5.0.0", "decamelize": "^1.2.0" } + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } } } } diff --git a/smart-hut/package.json b/smart-hut/package.json index a0225fc..d6010d7 100644 --- a/smart-hut/package.json +++ b/smart-hut/package.json @@ -37,6 +37,9 @@ "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", + "eslint": "eslint src", + "eslint-fix": "eslint --fix src", + "eslint:report": "eslint src -f json -o eslint-report.json", "eject": "react-scripts eject" }, "eslintConfig": { @@ -56,6 +59,8 @@ }, "devDependencies": { "prettier": "2.0.1", - "sonarqube-scanner": "^2.6.0" + "sonarqube-scanner": "^2.6.0", + "eslint-config-airbnb": "^18.1.0", + "eslint-plugin-chai-friendly": "^0.6.0" } } diff --git a/smart-hut/src/App.js b/smart-hut/src/App.js index 602e77f..fa6403d 100644 --- a/smart-hut/src/App.js +++ b/smart-hut/src/App.js @@ -1,28 +1,29 @@ -import React, { Component } from "react"; -import { BrowserRouter, Switch, Route, Redirect } from "react-router-dom"; -import Home from "./views/Home"; -import Dashboard from "./views/Dashboard"; -import Signup from "./views/Signup"; -import Login from "./views/Login"; -import FourOhFour from "./views/FourOhFour"; -import ForgotPass from "./views/Forgot-password"; -import ChangePass from "./views/Forgot-pass-reset"; -import ConfirmForgotPasswrod from "./views/ConfirmForgotPassword"; -import ConfirmRegistration from "./views/ConfirmRegistration"; -import ConfirmResetPassword from "./views/ConfirmResetPassword"; -import Instruction from "./views/Instruction"; -import Videocam from "./views/Videocam"; -import queryString from "query-string"; -import { RemoteService } from "./remote"; -import { connect } from "react-redux"; +import React, { Component } from 'react'; +import { + BrowserRouter, Switch, Route, Redirect, +} from 'react-router-dom'; +import queryString from 'query-string'; +import { connect } from 'react-redux'; +import Home from './views/Home'; +import Dashboard from './views/Dashboard'; +import Signup from './views/Signup'; +import Login from './views/Login'; +import FourOhFour from './views/FourOhFour'; +import ForgotPass from './views/Forgot-password'; +import ConfirmForgotPasswrod from './views/ConfirmForgotPassword'; +import ConfirmRegistration from './views/ConfirmRegistration'; +import ConfirmResetPassword from './views/ConfirmResetPassword'; +import Instruction from './views/Instruction'; +import Videocam from './views/Videocam'; +import { RemoteService } from './remote'; class App extends Component { constructor(props, context) { super(props, context); this.state = { - query: "", - info: "", + query: '', + info: '', }; } @@ -36,7 +37,7 @@ class App extends Component { } render() { - console.log("rendering root", this.props.loggedIn, this.state.query); + console.log('rendering root', this.props.loggedIn, this.state.query); return ( @@ -49,7 +50,7 @@ class App extends Component { {this.props.loggedIn ? : } - + @@ -60,9 +61,11 @@ class App extends Component { - + + + - + diff --git a/smart-hut/src/App.test.js b/smart-hut/src/App.test.js index 135fe7a..3ff4d37 100644 --- a/smart-hut/src/App.test.js +++ b/smart-hut/src/App.test.js @@ -1,19 +1,19 @@ -import React from "react"; -import { render } from "@testing-library/react"; -import { Router } from "react-router"; -import { createMemoryHistory } from "history"; -import App from "./App"; -import { Provider } from "react-redux"; -import smartHutStore from "./store"; +import React from 'react'; +import { render } from '@testing-library/react'; +import { Router } from 'react-router'; +import { createMemoryHistory } from 'history'; +import { Provider } from 'react-redux'; +import App from './App'; +import smartHutStore from './store'; -test("redirects to homepage", () => { +test('redirects to homepage', () => { const history = createMemoryHistory(); render( - + , ); - expect(history.location.pathname).toBe("/"); + expect(history.location.pathname).toBe('/'); }); diff --git a/smart-hut/src/components/Banner.js b/smart-hut/src/components/Banner.js index 5ff1efd..0cd88bb 100644 --- a/smart-hut/src/components/Banner.js +++ b/smart-hut/src/components/Banner.js @@ -1,34 +1,34 @@ -import React from "react"; -import PropTypes from "prop-types"; -import { makeStyles } from "@material-ui/core/styles"; -import Paper from "@material-ui/core/Paper"; -import Typography from "@material-ui/core/Typography"; -import Grid from "@material-ui/core/Grid"; -import Link from "@material-ui/core/Link"; +import React from 'react'; +import PropTypes from 'prop-types'; +import { makeStyles } from '@material-ui/core/styles'; +import Paper from '@material-ui/core/Paper'; +import Typography from '@material-ui/core/Typography'; +import Grid from '@material-ui/core/Grid'; +import Link from '@material-ui/core/Link'; const useStyles = makeStyles((theme) => ({ mainFeaturedPost: { - position: "relative", + position: 'relative', backgroundColor: theme.palette.grey[800], color: theme.palette.common.white, marginBottom: theme.spacing(4), - backgroundImage: "img/banner.jpg", - backgroundSize: "cover", - backgroundRepeat: "no-repeat", - backgroundPosition: "center", + backgroundImage: 'img/banner.jpg', + backgroundSize: 'cover', + backgroundRepeat: 'no-repeat', + backgroundPosition: 'center', }, overlay: { - position: "absolute", + position: 'absolute', top: 0, bottom: 0, right: 0, left: 0, - backgroundColor: "rgba(0,0,0,.3)", + backgroundColor: 'rgba(0,0,0,.3)', }, mainFeaturedPostContent: { - position: "relative", + position: 'relative', padding: theme.spacing(3), - [theme.breakpoints.up("md")]: { + [theme.breakpoints.up('md')]: { padding: theme.spacing(6), paddingRight: 0, }, @@ -47,7 +47,7 @@ export default function Banner(props) { {/* Increase the priority of the hero background image */} { {post.imageText} diff --git a/smart-hut/src/components/FilterDevices.js b/smart-hut/src/components/FilterDevices.js deleted file mode 100644 index bc241b1..0000000 --- a/smart-hut/src/components/FilterDevices.js +++ /dev/null @@ -1,82 +0,0 @@ -import { Dropdown } from "semantic-ui-react"; -import React, { Component } from "react"; - -export default class FilterDevices extends Component { - render() { - const tagOptions = [ - { - key: "regularLight", - text: "regularLight", - value: "regularLight", - label: { color: "red", empty: true, circular: true }, - }, - { - key: "dimmableLight", - text: "dimmableLight", - value: "dimmableLight", - label: { color: "blue", empty: true, circular: true }, - }, - { - key: "buttonDimmer", - text: "buttonDimmer", - value: "buttonDimmer", - label: { color: "black", empty: true, circular: true }, - }, - { - key: "knobDimmer", - text: "knobDimmer", - value: "knobDimmer", - label: { color: "purple", empty: true, circular: true }, - }, - { - key: "motionSensor", - text: "motionSensor", - value: "motionSensor", - label: { color: "orange", empty: true, circular: true }, - }, - { - key: "sensor", - text: "sensor", - value: "sensor", - label: { empty: true, circular: true }, - }, - { - key: "smartPlug", - text: "smartPlug", - value: "smartPlug", - label: { color: "pink", empty: true, circular: true }, - }, - { - key: "switch", - text: "switch", - value: "switch", - label: { color: "green", empty: true, circular: true }, - }, - ]; - - return ( - - - - - - {tagOptions.map((option) => ( - - ))} - - - - ); - } -} diff --git a/smart-hut/src/components/Footer.js b/smart-hut/src/components/Footer.js index acf9ebb..e0a34fc 100644 --- a/smart-hut/src/components/Footer.js +++ b/smart-hut/src/components/Footer.js @@ -1,4 +1,4 @@ -import React from "react"; +import React from 'react'; export default function Footer() { return ( diff --git a/smart-hut/src/components/Header.js b/smart-hut/src/components/Header.js index b9bde06..0b789ed 100644 --- a/smart-hut/src/components/Header.js +++ b/smart-hut/src/components/Header.js @@ -1,12 +1,12 @@ -import React from "react"; -import PropTypes from "prop-types"; -import { makeStyles } from "@material-ui/core/styles"; -import Toolbar from "@material-ui/core/Toolbar"; -import Button from "@material-ui/core/Button"; -import IconButton from "@material-ui/core/IconButton"; -import SearchIcon from "@material-ui/icons/Search"; -import Typography from "@material-ui/core/Typography"; -import Link from "@material-ui/core/Link"; +import React from 'react'; +import PropTypes from 'prop-types'; +import { makeStyles } from '@material-ui/core/styles'; +import Toolbar from '@material-ui/core/Toolbar'; +import Button from '@material-ui/core/Button'; +import IconButton from '@material-ui/core/IconButton'; +import SearchIcon from '@material-ui/icons/Search'; +import Typography from '@material-ui/core/Typography'; +import Link from '@material-ui/core/Link'; const useStyles = makeStyles((theme) => ({ toolbar: { @@ -16,8 +16,8 @@ const useStyles = makeStyles((theme) => ({ flex: 1, }, toolbarSecondary: { - justifyContent: "space-between", - overflowX: "auto", + justifyContent: 'space-between', + overflowX: 'auto', }, toolbarLink: { padding: theme.spacing(1), @@ -30,7 +30,7 @@ export default function Header(props) { const { sections, title } = props; return ( - + <> ))} - @@ -68,7 +68,7 @@ export default function Header(props) { Sign up - + ); } diff --git a/smart-hut/src/components/HeaderController.js b/smart-hut/src/components/HeaderController.js index 13c9f16..7912173 100644 --- a/smart-hut/src/components/HeaderController.js +++ b/smart-hut/src/components/HeaderController.js @@ -1,4 +1,4 @@ -import React from "react"; +import React from 'react'; import { Grid, Divider, @@ -6,17 +6,18 @@ import { Label, Responsive, Checkbox, -} from "semantic-ui-react"; -import { Segment, Image } from "semantic-ui-react"; -import { RemoteService } from "../remote"; -import { withRouter } from "react-router-dom"; -import { connect } from "react-redux"; -import SimulationPanel from "./SimulationPanel"; + Segment, Image, +} from 'semantic-ui-react'; + +import { withRouter } from 'react-router-dom'; +import { connect } from 'react-redux'; +import { RemoteService } from '../remote'; +import SimulationPanel from './SimulationPanel'; const IconHomeImage = () => ( this.props.history.push("/")); + this.props.logout().then(() => this.props.history.push('/')); } getInfo() { this.props .fetchUserInfo() - .catch((err) => console.error("MyHeader fetch user info error", err)); + .catch((err) => console.error('MyHeader fetch user info error', err)); } setCameraEnabled(val) { - let enabled = { + const enabled = { cameraEnabled: val, }; this.props .userPermissions(enabled) .then(() => this.getInfo()) - .catch((err) => console.error("Camera enabled", err)); + .catch((err) => console.error('Camera enabled', err)); } openSimulationPanel = () => { - this.setState((state) => { - return { simulationPanel: true }; - }); + this.setState((state) => ({ simulationPanel: true })); }; closeSimulationPanel = () => { - this.setState((state) => { - return { simulationPanel: undefined }; - }); + this.setState((state) => ({ simulationPanel: undefined })); }; render() { return (
- @@ -77,17 +74,17 @@ export class MyHeader extends React.Component { - - - - - - - -
- -
-
+ + + + + + + +
+ +
+
@@ -107,9 +104,9 @@ export class MyHeader extends React.Component { -
- -
-
+
+ +
+
- - - - - - + + - Share cameras} - checked={this.props.cameraEnabled} - onChange={(e, val) => this.setCameraEnabled(val.checked)} - /> - - + > + Share cameras} + checked={this.props.cameraEnabled} + onChange={(e, val) => this.setCameraEnabled(val.checked)} + /> + +
@@ -179,11 +176,11 @@ export class MyHeader extends React.Component { const mapStateToProps = (state, _) => ({ username: - state.userInfo && state.userInfo.username ? state.userInfo.username : "", + state.userInfo && state.userInfo.username ? state.userInfo.username : '', cameraEnabled: state.userInfo ? state.userInfo.cameraEnabled : false, }); const LoginContainer = connect( mapStateToProps, - RemoteService + RemoteService, )(withRouter(MyHeader)); export default LoginContainer; diff --git a/smart-hut/src/components/HomeNavbar.js b/smart-hut/src/components/HomeNavbar.js index 401cf72..8aa4cd4 100644 --- a/smart-hut/src/components/HomeNavbar.js +++ b/smart-hut/src/components/HomeNavbar.js @@ -1,5 +1,5 @@ -import _ from "lodash"; -import React, { Component } from "react"; +import _ from 'lodash'; +import React, { Component } from 'react'; import { Container, Icon, @@ -7,7 +7,7 @@ import { Menu, Sidebar, Responsive, -} from "semantic-ui-react"; +} from 'semantic-ui-react'; const NavBarMobile = ({ children, @@ -30,7 +30,7 @@ const NavBarMobile = ({ @@ -67,7 +67,7 @@ const NavBarDesktop = ({ leftItems, rightItems }) => ( ); const NavBarChildren = ({ children }) => ( - {children} + {children} ); class HomeNavabarApp extends Component { @@ -75,10 +75,11 @@ class HomeNavabarApp extends Component { super(props); this.state = { logged: true, - email: "", - password: "", + email: '', + password: '', }; } + state = { visible: false, }; @@ -117,17 +118,23 @@ class HomeNavabarApp extends Component { } } -const leftItems = [{ as: "a", content: "Home", key: "home", href: "/" }]; +const leftItems = [{ + as: 'a', content: 'Home', key: 'home', href: '/', +}]; const rightItems = [ - { as: "a", content: "Login", key: "login", href: "/login" }, - { as: "a", content: "Sign up", key: "register", href: "/signup" }, + { + as: 'a', content: 'Login', key: 'login', href: '/login', +}, + { + as: 'a', content: 'Sign up', key: 'register', href: '/signup', +}, ]; const HomeNavbarApp = () => ( + /> ); export default HomeNavbarApp; diff --git a/smart-hut/src/components/HostModal.js b/smart-hut/src/components/HostModal.js index cd03809..5d890a3 100644 --- a/smart-hut/src/components/HostModal.js +++ b/smart-hut/src/components/HostModal.js @@ -1,4 +1,4 @@ -import React, { Component } from "react"; +import React, { Component } from 'react'; import { Button, Header, @@ -7,10 +7,10 @@ import { Form, Responsive, Dropdown, -} from "semantic-ui-react"; -import { connect } from "react-redux"; -import { RemoteService, Forms } from "../remote"; -import { appActions } from "../storeActions"; +} from 'semantic-ui-react'; +import { connect } from 'react-redux'; +import { RemoteService, Forms } from '../remote'; +import { appActions } from '../storeActions'; class HostModal extends Component { constructor(props) { @@ -28,8 +28,7 @@ class HostModal extends Component { .catch(console.error); Forms.fetchAllUsers() - .then((users) => - this.setState({ + .then((users) => this.setState({ ...this.state, users: users .filter((u) => u.id !== this.props.currentUserId) @@ -38,8 +37,7 @@ class HostModal extends Component { text: `@${u.username} (${u.name})`, value: u.id, })), - }) - ) + })) .catch(console.error); this.saveGuestSettings = this.saveGuestSettings.bind(this); @@ -70,7 +68,7 @@ class HostModal extends Component { render() { return ( - + <> - + ); } } -const setActiveHost = (activeHost) => { - return (dispatch) => dispatch(appActions.setActiveHost(activeHost)); -}; +const setActiveHost = (activeHost) => (dispatch) => dispatch(appActions.setActiveHost(activeHost)); const mapStateToProps = (state) => ({ guests: state.guests, @@ -129,6 +129,6 @@ const HostModalContainer = connect( mapStateToProps, { ...RemoteService, setActiveHost }, null, - { forwardRef: true } + { forwardRef: true }, )(HostModal); export default HostModalContainer; diff --git a/smart-hut/src/components/RoomModal.js b/smart-hut/src/components/RoomModal.js index d6dae1e..e8e60f0 100644 --- a/smart-hut/src/components/RoomModal.js +++ b/smart-hut/src/components/RoomModal.js @@ -1,4 +1,4 @@ -import React, { Component } from "react"; +import React, { Component } from 'react'; import { Button, Header, @@ -9,13 +9,13 @@ import { Responsive, Image, Confirm, -} from "semantic-ui-react"; -import SelectIcons from "./SelectIcons"; -import { connect } from "react-redux"; -import { RemoteService } from "../remote"; -import { appActions } from "../storeActions"; +} from 'semantic-ui-react'; +import { connect } from 'react-redux'; +import SelectIcons from './SelectIcons'; +import { RemoteService } from '../remote'; +import { appActions } from '../storeActions'; -const NO_IMAGE = "https://react.semantic-ui.com/images/wireframe/image.png"; +const NO_IMAGE = 'https://react.semantic-ui.com/images/wireframe/image.png'; class RoomModal extends Component { constructor(props) { @@ -31,9 +31,9 @@ class RoomModal extends Component { get initialState() { return { - selectedIcon: this.type === "new" ? "home" : this.props.room.icon, - name: this.type === "new" ? "New Room" : this.props.room.name, - img: this.type === "new" ? null : this.props.room.image, + selectedIcon: this.type === 'new' ? 'home' : this.props.room.icon, + name: this.type === 'new' ? 'New Room' : this.props.room.name, + img: this.type === 'new' ? null : this.props.room.image, openModal: false, sure: false, }; @@ -41,7 +41,7 @@ class RoomModal extends Component { unsetImage = (e) => { e.preventDefault(); - this.setState({ ...this.state, img: "" }); + this.setState({ ...this.state, img: '' }); }; setInitialState() { @@ -49,11 +49,11 @@ class RoomModal extends Component { } get type() { - return !this.props.id ? "new" : "modify"; + return !this.props.id ? 'new' : 'modify'; } addRoomModal = (e) => { - let data = { + const data = { icon: this.state.selectedIcon, name: this.state.name, image: this.state.img, @@ -65,17 +65,17 @@ class RoomModal extends Component { this.setInitialState(); this.closeModal(); }) - .catch((err) => console.error("error in creating room", err)); + .catch((err) => console.error('error in creating room', err)); }; modifyRoomModal = (e) => { - let data = { + const data = { icon: this.state.selectedIcon, name: this.state.name, image: this.state.img, }; - console.log("data", data); + console.log('data', data); this.props .saveRoom(data, this.props.id) @@ -83,14 +83,14 @@ class RoomModal extends Component { this.setInitialState(); this.closeModal(); }) - .catch((err) => console.error("error in updating room", err)); + .catch((err) => console.error('error in updating room', err)); }; deleteRoom = (e) => { this.props .deleteRoom(this.props.id) .then(() => this.closeModal()) - .catch((err) => console.error("error in deleting room", err)); + .catch((err) => console.error('error in deleting room', err)); }; setSureTrue = () => { @@ -102,8 +102,8 @@ class RoomModal extends Component { }; changeSomething = (event) => { - let nam = event.target.name; - let val = event.target.value; + const nam = event.target.name; + const val = event.target.value; this.setState({ [nam]: val }); }; @@ -120,7 +120,7 @@ class RoomModal extends Component { } getBase64(file, callback) { - let reader = new FileReader(); + const reader = new FileReader(); reader.readAsDataURL(file.target.files[0]); reader.onload = () => { this.setState(Object.assign(this.state, { img: reader.result })); @@ -130,16 +130,16 @@ class RoomModal extends Component { render() { const spaceDiv = { - background: "#f4f4f4", - padding: "10px 10px", - margin: "10px 0px", + background: '#f4f4f4', + padding: '10px 10px', + margin: '10px 0px', }; return (
{!this.props.nicolaStop ? (
- {this.type === "new" ? ( + {this.type === 'new' ? (
- {this.type === "modify" ? ( + {this.type === 'modify' ? (
@@ -271,9 +274,7 @@ class RoomModal extends Component { } } -const setActiveRoom = (activeRoom) => { - return (dispatch) => dispatch(appActions.setActiveRoom(activeRoom)); -}; +const setActiveRoom = (activeRoom) => (dispatch) => dispatch(appActions.setActiveRoom(activeRoom)); const mapStateToProps = (state, ownProps) => ({ room: ownProps.id ? state.rooms[ownProps.id] : null, @@ -282,6 +283,6 @@ const RoomModalContainer = connect( mapStateToProps, { ...RemoteService, setActiveRoom }, null, - { forwardRef: true } + { forwardRef: true }, )(RoomModal); export default RoomModalContainer; diff --git a/smart-hut/src/components/SceneModal.js b/smart-hut/src/components/SceneModal.js index d9cce65..f4a4d9e 100644 --- a/smart-hut/src/components/SceneModal.js +++ b/smart-hut/src/components/SceneModal.js @@ -1,4 +1,4 @@ -import React, { Component } from "react"; +import React, { Component } from 'react'; import { Button, Header, @@ -10,12 +10,12 @@ import { Dropdown, Checkbox, Segment, -} from "semantic-ui-react"; -import SelectIcons from "./SelectIcons"; -import { connect } from "react-redux"; -import { RemoteService } from "../remote"; -import { appActions } from "../storeActions"; -//import { update } from "immutability-helper"; +} from 'semantic-ui-react'; +import { connect } from 'react-redux'; +import SelectIcons from './SelectIcons'; +import { RemoteService } from '../remote'; +import { appActions } from '../storeActions'; +// import { update } from "immutability-helper"; class SceneModal extends Component { constructor(props) { @@ -39,13 +39,13 @@ class SceneModal extends Component { get initialState() { return { - name: this.type === "new" ? "New Scene" : this.props.scene.name, + name: this.type === 'new' ? 'New Scene' : this.props.scene.name, openModal: false, - selectedIcon: "home", + selectedIcon: 'home', scenes: this.scenes, copyFrom: null, guestAccessEnabled: - this.type === "new" ? null : this.props.scene.guestAccessEnabled, + this.type === 'new' ? null : this.props.scene.guestAccessEnabled, }; } @@ -62,11 +62,11 @@ class SceneModal extends Component { } get type() { - return !this.props.id ? "new" : "modify"; + return !this.props.id ? 'new' : 'modify'; } addSceneModal = (e) => { - let data = { + const data = { name: this.state.name, icon: this.state.selectedIcon, }; @@ -77,11 +77,11 @@ class SceneModal extends Component { this.setInitialState(); this.closeModal(); }) - .catch((err) => console.error("error in creating room", err)); + .catch((err) => console.error('error in creating room', err)); }; modifySceneModal = (e) => { - let data = { + const data = { name: this.state.name, icon: this.state.selectedIcon, guestAccessEnabled: this.state.guestAccessEnabled, @@ -94,19 +94,19 @@ class SceneModal extends Component { this.setInitialState(); this.closeModal(); }) - .catch((err) => console.error("error in updating room", err)); + .catch((err) => console.error('error in updating room', err)); }; deleteScene = (e) => { this.props .deleteScene(this.props.id) .then(() => this.closeModal()) - .catch((err) => console.error("error in deleting room", err)); + .catch((err) => console.error('error in deleting room', err)); }; changeSomething = (event) => { - let nam = event.target.name; - let val = event.target.value; + const nam = event.target.name; + const val = event.target.value; this.setState({ [nam]: val }); }; @@ -133,16 +133,16 @@ class SceneModal extends Component { render() { const spaceDiv = { - background: "#f4f4f4", - padding: "10px 10px", - margin: "10px 0px", + background: '#f4f4f4', + padding: '10px 10px', + margin: '10px 0px', }; return (
{!this.props.nicolaStop ? (
- {this.type === "new" ? ( + {this.type === 'new' ? (
- {this.type === "new" && ( + {this.type === 'new' && ( )} - {this.type === "modify" ? ( + {this.type === 'modify' ? ( - + - this.setGuestAccessEnabled(val.checked) - } + onChange={(e, val) => this.setGuestAccessEnabled(val.checked)} /> ) : null} - {this.type === "modify" ? ( + {this.type === 'modify' ? ( @@ -273,9 +273,7 @@ class SceneModal extends Component { } } -const setActiveScene = (activeScene) => { - return (dispatch) => dispatch(appActions.setActiveScene(activeScene)); -}; +const setActiveScene = (activeScene) => (dispatch) => dispatch(appActions.setActiveScene(activeScene)); const mapStateToProps = (state, ownProps) => ({ scene: ownProps.id ? state.scenes[ownProps.id] : null, @@ -285,6 +283,6 @@ const SceneModalContainer = connect( mapStateToProps, { ...RemoteService, setActiveScene }, null, - { forwardRef: true } + { forwardRef: true }, )(SceneModal); export default SceneModalContainer; diff --git a/smart-hut/src/components/SelectIcons.js b/smart-hut/src/components/SelectIcons.js index 3722168..fa6cce6 100644 --- a/smart-hut/src/components/SelectIcons.js +++ b/smart-hut/src/components/SelectIcons.js @@ -1,5 +1,5 @@ -import React, { Component } from "react"; -import { Button, Grid } from "semantic-ui-react"; +import React, { Component } from 'react'; +import { Button, Grid } from 'semantic-ui-react'; export default class SelectIcons extends Component { constructor(props) { @@ -11,7 +11,7 @@ export default class SelectIcons extends Component { selectIcon = (e) => { let el = e.target.name; - if (e.target.tagName === "I") { + if (e.target.tagName === 'I') { el = e.target.parentNode.name; } this.props.updateIcon(el); @@ -20,36 +20,32 @@ export default class SelectIcons extends Component { render() { const myicons = [ - ["home", "coffee", "beer", "glass martini", "film", "video"], - ["music", "headphones", "fax", "phone", "laptop", "bath"], - ["shower", "bed", "child", "warehouse", "car", "bicycle"], - ["motorcycle", "archive", "boxes", "cubes", "chess", "gamepad"], - ["futbol", "table tennis", "server", "tv", "heart", "camera"], - ["trophy", "wrench", "image", "book", "university", "medkit"], - ["paw", "tree", "utensils", "male", "female", "life ring outline"], + ['home', 'coffee', 'beer', 'glass martini', 'film', 'video'], + ['music', 'headphones', 'fax', 'phone', 'laptop', 'bath'], + ['shower', 'bed', 'child', 'warehouse', 'car', 'bicycle'], + ['motorcycle', 'archive', 'boxes', 'cubes', 'chess', 'gamepad'], + ['futbol', 'table tennis', 'server', 'tv', 'heart', 'camera'], + ['trophy', 'wrench', 'image', 'book', 'university', 'medkit'], + ['paw', 'tree', 'utensils', 'male', 'female', 'life ring outline'], ]; return ( - {myicons.map((e, i) => { - return ( - - {e.map((e, i) => { - return ( - - - ); - } - - render() { + const position = props.order.indexOf(props.scene.id); return ( - - -
- {this.state.editName ? ( - - ) : ( - this.state.automationName - )} -
- - - - )} -
-
-
- - + + + - - + + props.orderScenes(props.scene.id, val.checked)} + checked={position + 1 > 0} + /> + + +

{props.scene.name}

+
+ +

{position !== -1 ? `# ${position + 1}` : ''}

- - +
+
); - } +}; + +const Trigger = ({ + deviceName, trigger, onRemove, index, + }) => { + const { + operand, value, on, mode, +} = trigger; + let symbol; + if (operand) { + symbol = operands.filter((opt) => opt.key === operand)[0].text; + } + return ( + + + {deviceName} + {operand ? {symbol} : ''} + {mode || (operand ? value : on ? 'on' : 'off')} + + onRemove(index)} + className="remove-icon" + name="remove" + /> + + ); +}; + +class AutomationSaveModal extends Component { + constructor(props) { + super(props); + this.state = { + triggerList: [], + conditionsList: [], + order: [], + automationName: 'New Automation', + editName: false, + newTrigger: {}, + newCondition: {}, + scenesFilter: null, + openModal: false, + }; + + if (this.props.automation) { + this.state.automationName = this.props.automation.name; + for (const scenePriority of this.props.automation.scenes) { + this.state.order[scenePriority.priority] = scenePriority.sceneId; + } + for (const trigger of this.props.automation.triggers) { + this.state.triggerList.push( + { + device: trigger.deviceId, + kind: trigger.kind, + ...(trigger.kind === 'booleanTrigger' + ? { on: trigger.on } + : { + operand: trigger.operator, + value: trigger.value, + }), + }, + ); + } + } + + this.setTrigger = this._setter('triggerList'); + this.setOrder = this._setter('order'); + this.setautomationName = this._setter('automationName'); + this.setEditName = this._setter('editName'); + this.setNewTrigger = this._setter('newTrigger'); + this.addTrigger = this.addTrigger.bind(this); + this.removeTrigger = this.removeTrigger.bind(this); + this.onInputChange = this.onInputChange.bind(this); + this.searchScenes = this.searchScenes.bind(this); + this.orderScenes = this.orderScenes.bind(this); + this.onChangeName = this.onChangeName.bind(this); + + // Conditions + this.setNewCondition = this._setter('newCondition'); + this.addCondition = this.addCondition.bind(this); + this.removeCondition = this.removeCondition.bind(this); + } + + openModal = (e) => { + this.setState({ openModal: true }); + }; + + closeModal = (e) => { + this.setState({ openModal: false }); + }; + + get deviceList() { + return Object.values(this.props.devices); + } + + _setter(property) { + return (value) => this.setState(update(this.state, { [property]: { $set: value } })); + } + + triggerKind(trigger) { + if ('operand' in trigger && 'value' in trigger) { + return 'rangeTrigger'; + } + if ('on' in trigger) { + return 'booleanTrigger'; + } + return false; + // throw new Error("Trigger kind not handled"); + } + + conditionKind(condition) { + if ('operand' in condition && 'value' in condition) { + return 'rangeTrigger'; + } + if ('on' in condition) { + return 'booleanTrigger'; + } + + if ('operand' in condition && 'mode' in condition) { + return 'thermostatCondition'; + } + return false; + } + + checkRange(deviceKind, devicesWithPercentage, trigger, error, device) { + if (!trigger.device || !trigger.operand || !trigger.value) { + return error; + } + if (trigger.value < 0) { + error.message = 'Values cannot be negative'; + return error; + } + // If the device's range is a percentage, values cannot exceed 100 + if ( + devicesWithPercentage.includes(deviceKind) + && trigger.value > 100 + ) { + error.message = "The value can't exceed 100, as it's a percentage"; + return error; + } + if ( + deviceKind === 'sensor' + && device.sensor === 'HUMIDITY' + && trigger.value > 100 + ) { + error.message = "The value can't exceed 100, as it's a percentage"; + return error; + } + return false; + } + + checkBool(trigger, error) { + if (!trigger.device || trigger.on === null || trigger.on === undefined) return error; + return false; + } + + _checkNewTrigger(trigger, isCondition = false) { + const error = { + result: false, + message: 'There are missing fields!', + }; + const device = Object.values(this.props.devices).filter( + (d) => d.id === trigger.device, + )[0]; + + const triggerKind = this.triggerKind(trigger); + const conditionKind = this.conditionKind(trigger); + if (!isCondition && (!device || !triggerKind)) { + error.message = 'There are missing fields'; + return error; + } + + if (isCondition && !conditionKind) { + error.message = 'There are missing fields'; + return error; + } + const deviceKind = device.kind; + const devicesWithPercentage = ['dimmableLight', 'curtains', 'knobDimmer']; + + switch (isCondition ? conditionKind : triggerKind) { + case 'booleanTrigger': + const checkBoolTrigger = this.checkBool(trigger, error); + if (checkBoolTrigger) { + return checkBoolTrigger; + } + break; + case 'booleanCondition': + const checkBoolCond = this.checkBool(trigger, error); + if (checkBoolCond) { + return checkBoolCond; + } + break; + case 'rangeTrigger': + const checkRangeTrigger = this.checkRange(deviceKind, devicesWithPercentage, trigger, error, device); + if (checkRangeTrigger) { + return checkRangeTrigger; + } + break; + case 'rangeCondition': + const checkRangeCond = this.checkRange(deviceKind, devicesWithPercentage, trigger, error, device); + if (checkRangeCond) { + return checkRangeCond; + } + break; + case 'thermostatCondition': + if (!trigger.device || trigger.mode === null || trigger.mode === undefined || !trigger.operand) return error; + break; + default: + throw new Error('theoretically unreachable statement'); + } + + let isNotDuplicate = null; + + if (isCondition === true) { + isNotDuplicate = !this.state.conditionsList.some( + (t) => t.device === trigger.device && t.operand === trigger.operand, + ); + } else { + isNotDuplicate = !this.state.triggerList.some( + (t) => t.device === trigger.device && t.operand === trigger.operand, + ); + } + const type = isCondition ? 'condition' : 'trigger'; + const duplicationMessage = `You have already created a ${type} for this device with the same conditions`; + return { + result: isNotDuplicate, + message: isNotDuplicate + ? null + : duplicationMessage, + }; + } + + addTrigger() { + const { result, message } = this._checkNewTrigger(this.state.newTrigger); + if (result) { + this.setState( + update(this.state, { + triggerList: { $push: [this.state.newTrigger] }, + }), + ); + } else { + alert(message); + } + } + + removeTrigger(index) { + this.setState( + update(this.state, { triggerList: { $splice: [[index, 1]] } }), + ); + } + + // This gets triggered when the devices dropdown changes the value. + onInputChange(val) { + if (val.name === 'device') { + this.setNewTrigger({ [val.name]: val.value }); + } else { + this.setNewTrigger({ + ...this.state.newTrigger, + [val.name]: val.value, + }); + } + } + + onChangeName(_, val) { + this.setautomationName(val.value); + } + + orderScenes = (id, checked) => { + if (checked) { + this.setState(update(this.state, { order: { $push: [id] } })); + } else { + this.setState( + update(this.state, { + order: (prevList) => prevList.filter((e) => e !== id), + }), + ); + } + }; + + searchScenes(_, { value }) { + this.setState(update(this.state, { scenesFilter: { $set: value } })); + this.forceUpdate(); + } + + get sceneList() { + if (!this.scenesFilter) { + return this.props.scenes; + } + return this.props.scenes.filter((e) => e.name.includes(this.scenesFilter)); + } + + generateBoolKey(trigger) { + return `${trigger.device}${trigger.on}`; + } + + generateRangeKey(trigger) { + return `${trigger.device}${trigger.operand}${trigger.value}`; + } + + _generateKey = (trigger, isCondition = false) => { + switch (isCondition ? this.conditionKind(trigger) : this.triggerKind(trigger)) { + case 'booleanTrigger': + return this.generateBoolKey(trigger); + case 'booleanCondition': + return this.generateBoolKey(trigger); + case 'rangeTrigger': + return this.generateRangeKey(trigger); + case 'rangeCondition': + return this.generateRangeKey(trigger); + case 'thermostatCondition': + return `${trigger.device}${trigger.operand}${trigger.mode}`; + default: + throw new Error('theoretically unreachable statement'); + } + }; + + checkBeforeSave = () => { + if (!this.state.automationName) { + alert('Give a name to the automation'); + return false; + } + if (this.state.triggerList.length <= 0) { + alert('You have to create a trigger'); + return false; + } + if (this.state.order.length <= 0) { + alert('You need at least one active scene'); + return false; + } + return true; + }; + + saveAutomation = () => { + if (this.checkBeforeSave()) { + const automation = { + name: this.state.automationName, + }; + + if (this.props.id) { + automation.id = this.props.id; + automation.triggers = []; + automation.scenes = []; + automation.conditions = []; + for (let i = 0; i < this.state.order.length; i++) { + automation.scenes.push({ + priority: i, + sceneId: this.state.order[i], + }); + } + + for (const trigger of this.state.triggerList) { + const kind = trigger.kind || this.triggerKind(trigger); + automation.triggers.push( + { + deviceId: trigger.device, + kind, + ...(kind === 'booleanTrigger' + ? { on: trigger.on } + : { + operator: trigger.operand, + range: parseInt(trigger.value), + }), + }, + ); + } + + for (const condition of this.state.conditionsList) { + const kind = condition.kind || this.conditionKind(condition); + const loSpagnolo = (kind === 'thermostatCondition' ? { operator: condition.operand, mode: condition.mode } + : { + operator: condition.operand, + range: parseInt(condition.value), + }); + automation.conditions.push( + { + deviceId: condition.device, + kind, + ...(kind === 'booleanTrigger' + ? { on: condition.on } + : loSpagnolo + ), + }, + ); + } + + this.props + .fastUpdateAutomation(automation) + .then(this.closeModal) + .catch(console.error); + } else { + this.props + .saveAutomation({ + automation, + triggerList: this.state.triggerList, + order: this.state.order, + conditionList: this.state.conditionsList, + }) + .then(this.closeModal) + .catch(console.error); + } + } + }; + + get trigger() { + return this.props.id ? ( + + ); + } + + // CONDITIONS + + addCondition() { + // Same method used to check triggers and conditions, not a mistake + const { result, message } = this._checkNewTrigger(this.state.newCondition, true); + if (result) { + this.setState( + update(this.state, { + conditionsList: { $push: [this.state.newCondition] }, + }), + ); + } else { + alert(message); + } + } + + removeCondition(index) { + this.setState( + update(this.state, { conditionsList: { $splice: [[index, 1]] } }), + ); + } + + onInputChangeCondition = (val) => { + if (val.name === 'device') { + this.setNewCondition({ [val.name]: val.value }); + } else { + this.setNewCondition({ + ...this.state.newCondition, + [val.name]: val.value, + }); + } + } + + render() { + return ( + + +
+ {this.state.editName ? ( + + ) : ( + this.state.automationName + )} +
+ + + )} + + +
+ + + + +
Add Conditions
+ + {this.state.conditionsList.length > 0 + && this.state.conditionsList.map((condition, i) => { + const deviceName = this.deviceList.filter( + (d) => d.id === condition.device, + )[0].name; + const key = this._generateKey(condition, true); + return ( + + ); + })} + + + +
+
+
+ + + ); + } } const mapStateToProps = (state, ownProps) => ({ - scenes: Object.values(state.scenes), - devices: state.devices, - automation: ownProps.id ? state.automations[ownProps.id] : null, + scenes: Object.values(state.scenes), + devices: state.devices, + automation: ownProps.id ? state.automations[ownProps.id] : null, }); const AutomationSaveModalContainer = connect( - mapStateToProps, - RemoteService + mapStateToProps, + RemoteService, )(AutomationSaveModal); export default AutomationSaveModalContainer; diff --git a/smart-hut/src/components/dashboard/AutomationsPanel.js b/smart-hut/src/components/dashboard/AutomationsPanel.js index 8530213..69c6035 100644 --- a/smart-hut/src/components/dashboard/AutomationsPanel.js +++ b/smart-hut/src/components/dashboard/AutomationsPanel.js @@ -1,7 +1,7 @@ -import React, { Component } from "react"; -import { connect } from "react-redux"; -import { RemoteService } from "../../remote"; -import "./Automations.css"; +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import { RemoteService } from '../../remote'; +import './Automations.css'; import { Segment, @@ -11,52 +11,54 @@ import { List, Divider, Menu, -} from "semantic-ui-react"; -import CreateAutomation, { operands } from "./AutomationCreationModal"; +} from 'semantic-ui-react'; +import CreateAutomation, { operands } from './AutomationCreationModal'; -const Automation = ({ automation, devices, scenes, removeAutomation }) => { - const { triggers } = automation; +const Automation = ({ + automation, devices, scenes, removeAutomation, +}) => { + const { triggers, conditions } = automation; const scenePriorities = automation.scenes; - const getOperator = (operand) => - operands.filter((o) => o.key === operand)[0].text; + const getOperator = (operand) => operands.filter((o) => o.key === operand)[0].text; return ( - -
+ <> +
{automation.name}
- {this.props.stateOrDevice.kind === "smartPlug" ? ( + {this.props.stateOrDevice.kind === 'smartPlug' ? ( - } + )} closeIcon >
@@ -31,7 +37,7 @@ const SettingsForm = (props) => { setValues({ ...values, [name]: value }); }; - const [values, setValues] = useState({ name: "" }); + const [values, setValues] = useState({ name: '' }); return (
@@ -69,7 +75,7 @@ class DeviceSettingsModal extends Component { this.updateDevice = this.updateDevice.bind(this); this.deleteDevice = this.deleteDevice.bind(this); - //this.useExternalTempSensor = this.useExternalTempSensor.bind(this); + // this.useExternalTempSensor = this.useExternalTempSensor.bind(this); } closeModal = (e) => { @@ -82,18 +88,18 @@ class DeviceSettingsModal extends Component { updateDevice(values) { console.log(values, this.external); - let name = values.name; + let { name } = values; if (values.name.length === 0) { name = this.props.device.name; } - let data = { + const data = { ...this.props.device, - name: name, + name, }; - if (this.props.device.kind === "thermostat") { - let external = values.external + if (this.props.device.kind === 'thermostat') { + const external = values.external ? values.external : this.props.device.useExternalSensors; console.log(external); @@ -103,27 +109,24 @@ class DeviceSettingsModal extends Component { this.props .saveDevice(data) .then(() => this.setState({ openModal: false })) - .catch((err) => - console.error( + .catch((err) => console.error( `settings modal for device ${this.props.id} deletion error`, - err - ) - ); + err, + )); } deleteDevice() { this.props .deleteDevice(this.props.device) .then(() => this.setState({ openModal: false })) - .catch((err) => - console.error( + .catch((err) => console.error( `settings modal for device ${this.props.id} deletion error`, - err - ) - ); + err, + )); } _editForm = null; + get editForm() { this._editForm = this._editForm || ( - Settings of {this.props.device.name} + +Settings of + {this.props.device.name} + {this.editForm} ); @@ -153,6 +159,6 @@ const DeviceSettingsModalContainer = connect( mapStateToProps, RemoteService, null, - { forwardRef: true } + { forwardRef: true }, )(DeviceSettingsModal); export default DeviceSettingsModalContainer; diff --git a/smart-hut/src/components/dashboard/devices/Dimmer.js b/smart-hut/src/components/dashboard/devices/Dimmer.js index 60fdc32..f8652db 100644 --- a/smart-hut/src/components/dashboard/devices/Dimmer.js +++ b/smart-hut/src/components/dashboard/devices/Dimmer.js @@ -5,20 +5,21 @@ • A dimmer without state can just increase or decrease the intensity of a light. <-- DefualtDimmer The user can change the state of a dimmer through an intuitive UI in SmartHut . - **/ + * */ -import React, { Component } from "react"; +import React, { Component } from 'react'; import { CircularInput, CircularProgress, CircularThumb, -} from "react-circular-input"; +} from 'react-circular-input'; +import { connect } from 'react-redux'; import { ButtonDimmerContainer, MinusPanel, PlusPanel, ThumbText, -} from "./styleComponents"; +} from './styleComponents'; import { CircularThumbStyle, KnobDimmerStyle, @@ -26,22 +27,21 @@ import { textStyle, knobIcon, knobContainer, -} from "./DimmerStyle"; -import { RemoteService } from "../../../remote"; -import { connect } from "react-redux"; -import mapStateToProps from "../../../deviceProps"; +} from './DimmerStyle'; +import { RemoteService } from '../../../remote'; +import mapStateToProps from '../../../deviceProps'; export class ButtonDimmerComponent extends Component { increaseIntensity = () => { this.props - .buttonDimmerDim(this.props.id, "UP") - .catch((err) => console.error("button dimmer increase error", err)); + .buttonDimmerDim(this.props.id, 'UP') + .catch((err) => console.error('button dimmer increase error', err)); }; decreaseIntensity = () => { this.props - .buttonDimmerDim(this.props.id, "DOWN") - .catch((err) => console.error("button dimmer decrease error", err)); + .buttonDimmerDim(this.props.id, 'DOWN') + .catch((err) => console.error('button dimmer decrease error', err)); }; render() { @@ -96,7 +96,7 @@ export class KnobDimmerComponent extends Component { const val = Math.round(this.state.intensity); this.props .knobDimmerDimTo(this.props.id, val) - .catch((err) => console.error("knob dimmer set intensity error", err)); + .catch((err) => console.error('knob dimmer set intensity error', err)); } render() { @@ -104,7 +104,7 @@ export class KnobDimmerComponent extends Component {
- + Knob Icon
diff --git a/smart-hut/src/components/dashboard/devices/DimmerStyle.js b/smart-hut/src/components/dashboard/devices/DimmerStyle.js index a8b3260..25e8f2b 100644 --- a/smart-hut/src/components/dashboard/devices/DimmerStyle.js +++ b/smart-hut/src/components/dashboard/devices/DimmerStyle.js @@ -1,72 +1,72 @@ export const KnobDimmerStyle = { - cursor: "pointer", - marginTop: "1rem", - width: "9rem", - height: "9rem", - fill: "#1a2849", + cursor: 'pointer', + marginTop: '1rem', + width: '9rem', + height: '9rem', + fill: '#1a2849', }; export const KnobHolder = { - marginTop: "1rem", - cursor: "pointer", - padding: "3rem", - backgroundColor: "white", - width: "10rem", - height: "10rem", + marginTop: '1rem', + cursor: 'pointer', + padding: '3rem', + backgroundColor: 'white', + width: '10rem', + height: '10rem', }; export const KnobCircularTrack = { - fill: "white", - stroke: "#1a2849", + fill: 'white', + stroke: '#1a2849', }; export const KnobIcon = { - fill: "#1a2849", + fill: '#1a2849', }; export const KnobProgress = { - stroke: "#1a2849", - strokeWidth: "3rem", + stroke: '#1a2849', + strokeWidth: '3rem', }; export const ValueStyle = { - pointerEvents: "none", - fill: "#1a2849", - fontSize: "1.3rem", - fontFamily: "Lato", - textAnchor: "middle", - userSelect: "none", + pointerEvents: 'none', + fill: '#1a2849', + fontSize: '1.3rem', + fontFamily: 'Lato', + textAnchor: 'middle', + userSelect: 'none', }; export const CircularThumbStyle = { - fill: "white", - stroke: "#1a2849", - strokeWidth: ".2rem", - r: "1.4rem", + fill: 'white', + stroke: '#1a2849', + strokeWidth: '.2rem', + r: '1.4rem', }; export const textStyle = { - position: "absolute", - fill: "#1a2849", - fontSize: "1.5rem", - fontFamily: "Lato", - overflow: "hidden", - whiteSpace: "nowrap", - textOverflow: "ellipsis", - userSelect: "none", + position: 'absolute', + fill: '#1a2849', + fontSize: '1.5rem', + fontFamily: 'Lato', + overflow: 'hidden', + whiteSpace: 'nowrap', + textOverflow: 'ellipsis', + userSelect: 'none', }; export const knobIcon = { - position: "absolute", - left: "50%", - top: "30%", - transform: "translateX(-50%)", - width: "2rem", - height: "2rem", + position: 'absolute', + left: '50%', + top: '30%', + transform: 'translateX(-50%)', + width: '2rem', + height: '2rem', }; export const knobContainer = { - position: "relative", - width: "9rem", - height: "9rem", + position: 'relative', + width: '9rem', + height: '9rem', }; diff --git a/smart-hut/src/components/dashboard/devices/Light.js b/smart-hut/src/components/dashboard/devices/Light.js index 911f155..919b167 100644 --- a/smart-hut/src/components/dashboard/devices/Light.js +++ b/smart-hut/src/components/dashboard/devices/Light.js @@ -7,19 +7,20 @@ * Lights have an internal state that can be changed and it must * be shown accordingly in the SmartHut views (house view and room views). */ -import React, { Component } from "react"; +import React, { Component } from 'react'; +import { Image } from 'semantic-ui-react'; +import { + CircularInput, + CircularProgress, + CircularThumb, +} from 'react-circular-input'; +import { connect } from 'react-redux'; import { iconStyle, StyledDiv, BottomPanel, ThumbText, -} from "./styleComponents"; -import { Image } from "semantic-ui-react"; -import { - CircularInput, - CircularProgress, - CircularThumb, -} from "react-circular-input"; +} from './styleComponents'; import { LightDimmerContainer, LightDimmerStyle, @@ -28,10 +29,9 @@ import { KnobProgress, CircularThumbStyle, knobIcon, -} from "./LightStyle"; -import { RemoteService } from "../../../remote"; -import { connect } from "react-redux"; -import mapStateToProps from "../../../deviceProps"; +} from './LightStyle'; +import { RemoteService } from '../../../remote'; +import mapStateToProps from '../../../deviceProps'; class Light extends Component { constructor(props) { @@ -41,8 +41,8 @@ class Light extends Component { timeout: null, }; - this.iconOn = "/img/lightOn.svg"; - this.iconOff = "/img/lightOff.svg"; + this.iconOn = '/img/lightOn.svg'; + this.iconOff = '/img/lightOff.svg'; this.setIntensity = this.setIntensity.bind(this); } @@ -68,34 +68,30 @@ class Light extends Component { onClickDevice = () => { const on = !this.turnedOn; - if (this.props.tab !== "Scenes") { + if (this.props.tab !== 'Scenes') { this.props .saveDevice( { ...this.props.stateOrDevice, on }, - this.props.tab === "Hosts" ? this.props.activeHost : null + this.props.tab === 'Hosts' ? this.props.activeHost : null, ) - .catch((err) => console.error("regular light update error", err)); - } else { - if (this.props.device.kind === "regularLight") { + .catch((err) => console.error('regular light update error', err)); + } else if (this.props.device.kind === 'regularLight') { this.props .updateState( { id: this.props.stateOrDevice.id, - on: on, + on, sceneId: this.props.stateOrDevice.sceneId, }, - this.props.stateOrDevice.kind + this.props.stateOrDevice.kind, ) .then((res) => { console.log(res); }); } - } }; - getIcon = () => { - return this.turnedOn ? this.iconOn : this.iconOff; - }; + getIcon = () => (this.turnedOn ? this.iconOn : this.iconOff); setIntensity(intensity) { intensity *= 100; @@ -118,18 +114,18 @@ class Light extends Component { saveIntensity = () => { const intensity = Math.round(this.state.intensity); - if (this.props.tab !== "Scenes") { + if (this.props.tab !== 'Scenes') { this.props .saveDevice( { ...this.props.stateOrDevice, intensity }, - this.props.tab === "Hosts" ? this.props.activeHost : null + this.props.tab === 'Hosts' ? this.props.activeHost : null, ) - .catch((err) => console.error("dimmable light update error", err)); + .catch((err) => console.error('dimmable light update error', err)); } else { this.props .updateState( - { id: this.props.stateOrDevice.id, intensity: intensity }, - this.props.stateOrDevice.kind + { id: this.props.stateOrDevice.id, intensity }, + this.props.stateOrDevice.kind, ) .then((res) => { console.log(res, this.props.stateOrDevice.kind); @@ -142,7 +138,7 @@ class Light extends Component {
@@ -163,7 +159,7 @@ class Light extends Component { }} /> - +
@@ -173,7 +169,7 @@ class Light extends Component {
- +
Light
@@ -182,7 +178,7 @@ class Light extends Component { return (
- {this.props.device.kind === "dimmableLight" + {this.props.device.kind === 'dimmableLight' ? intensityLightView : normalLightView}
diff --git a/smart-hut/src/components/dashboard/devices/LightStyle.js b/smart-hut/src/components/dashboard/devices/LightStyle.js index 54ebc5d..d6b33d6 100644 --- a/smart-hut/src/components/dashboard/devices/LightStyle.js +++ b/smart-hut/src/components/dashboard/devices/LightStyle.js @@ -1,69 +1,69 @@ export const valueStyle = { - fill: "#3e99ff", - fontSize: "2.5rem", - fontFamily: "Lato", - textShadow: "1px 1px 0.5px rgba(0, 0, 0, .2)", + fill: '#3e99ff', + fontSize: '2.5rem', + fontFamily: 'Lato', + textShadow: '1px 1px 0.5px rgba(0, 0, 0, .2)', }; export const intensityLightStyle = { - fill: "#ffd31d", - fontSize: "1.2rem", - fontFamily: "Lato", - textShadow: "1px 1px 0.5px rgba(0, 0, 0, .2)", + fill: '#ffd31d', + fontSize: '1.2rem', + fontFamily: 'Lato', + textShadow: '1px 1px 0.5px rgba(0, 0, 0, .2)', }; export const textStyle = { - position: "absolute", - fill: "#ffd31d", - fontSize: "1.5rem", - fontFamily: "Lato", - overflow: "hidden", - whiteSpace: "nowrap", - textOverflow: "ellipsis", - userSelect: "none", + position: 'absolute', + fill: '#ffd31d', + fontSize: '1.5rem', + fontFamily: 'Lato', + overflow: 'hidden', + whiteSpace: 'nowrap', + textOverflow: 'ellipsis', + userSelect: 'none', }; export const nameStyle = { - fontSize: "1rem", - position: "absolute", - top: "30%", - left: "50%", - transform: "translateX(-50%)", - color: "white", - userSelect: "none", + fontSize: '1rem', + position: 'absolute', + top: '30%', + left: '50%', + transform: 'translateX(-50%)', + color: 'white', + userSelect: 'none', }; export const LightDimmerStyle = { - cursor: "pointer", - marginTop: "1rem", - width: "9rem", - height: "9rem", - fill: "#ffd31d", + cursor: 'pointer', + marginTop: '1rem', + width: '9rem', + height: '9rem', + fill: '#ffd31d', }; export const LightDimmerContainer = { - position: "relative", - width: "9rem", - height: "9rem", + position: 'relative', + width: '9rem', + height: '9rem', }; export const CircularThumbStyle = { - fill: "white", - stroke: "#ffd31d", - strokeWidth: ".2rem", - r: "1.4rem", + fill: 'white', + stroke: '#ffd31d', + strokeWidth: '.2rem', + r: '1.4rem', }; export const KnobProgress = { - stroke: "#ffd31d", - strokeWidth: "3rem", + stroke: '#ffd31d', + strokeWidth: '3rem', }; export const knobIcon = { - position: "absolute", - left: "50%", - top: "30%", - transform: "translateX(-50%)", - width: "2rem", - height: "2rem", + position: 'absolute', + left: '50%', + top: '30%', + transform: 'translateX(-50%)', + width: '2rem', + height: '2rem', }; diff --git a/smart-hut/src/components/dashboard/devices/NewDevice.js b/smart-hut/src/components/dashboard/devices/NewDevice.js index c384282..2002750 100644 --- a/smart-hut/src/components/dashboard/devices/NewDevice.js +++ b/smart-hut/src/components/dashboard/devices/NewDevice.js @@ -1,5 +1,5 @@ -import React, { Component } from "react"; -import styled from "styled-components"; +import React, { Component } from 'react'; +import styled from 'styled-components'; import { Button, Dropdown, @@ -8,9 +8,9 @@ import { Image, Input, Modal, -} from "semantic-ui-react"; -import { RemoteService } from "../../../remote"; -import { connect } from "react-redux"; +} from 'semantic-ui-react'; +import { connect } from 'react-redux'; +import { RemoteService } from '../../../remote'; const StyledDiv = styled.div` background-color: #505bda; @@ -38,7 +38,7 @@ class NewDevice extends Component { step: 1, openModal: false, motion: false, - deviceName: "", + deviceName: '', }; this.baseState = this.state; this.createDevice = this.createDevice.bind(this); @@ -47,6 +47,7 @@ class NewDevice extends Component { handleOpen = () => { this.setState({ openModal: true }); }; + handleClose = () => { this.setState({ openModal: false }); }; @@ -59,12 +60,13 @@ class NewDevice extends Component { nextStep = () => { this.setState((prevState) => ({ step: prevState.step + 1 })); }; + previousStep = () => { this.setState((prevState) => ({ step: prevState.step - 1 })); }; setTypeOfDevice = (e, d) => { - if (d.value === "dimmableLight") { + if (d.value === 'dimmableLight') { this.setState({ typeOfDevice: d.value, intensity: 0 }); } else { this.setState({ typeOfDevice: d.value }); @@ -77,7 +79,7 @@ class NewDevice extends Component { setTypeOfSensor = (e, d) => { console.log(d.value); - if (d.value === "motionSensor") { + if (d.value === 'motionSensor') { this.setState({ typeOfSensor: d.value, motion: true }); } else { this.setState({ typeOfSensor: d.value }); @@ -94,59 +96,59 @@ class NewDevice extends Component { id: null, roomId: this.props.activeRoom, name: this.state.deviceName, - kind: this.state.motion ? "motionSensor" : this.state.typeOfDevice, + kind: this.state.motion ? 'motionSensor' : this.state.typeOfDevice, }; let outputs = null; const defaultNames = { - regularLight: "New regular light", - dimmableLight: "New intensity light", - smartPlug: "New smart Plug", - sensor: "New sensor", - switch: "New switch", - buttonDimmer: "New button dimmer", - knobDimmer: "New knob dimmer", - securityCamera: "New security camera", - thermostat: "New thermostat", - curtains: "New curtains", + regularLight: 'New regular light', + dimmableLight: 'New intensity light', + smartPlug: 'New smart Plug', + sensor: 'New sensor', + switch: 'New switch', + buttonDimmer: 'New button dimmer', + knobDimmer: 'New knob dimmer', + securityCamera: 'New security camera', + thermostat: 'New thermostat', + curtains: 'New curtains', }; - if (this.state.deviceName === "") { + if (this.state.deviceName === '') { data.name = defaultNames[this.state.typeOfDevice]; } - console.log("-------------------------"); + console.log('-------------------------'); console.log(this.state.typeOfDevice); switch (this.state.typeOfDevice) { - //trying to make securityCamera work - //case "securityCamera": + // trying to make securityCamera work + // case "securityCamera": // data.path="/security_camera_videos/security_camera_1.mp4"; // data.on=false; - //break; - //trying to make thermostat work - case "thermostat": + // break; + // trying to make thermostat work + case 'thermostat': data.targetTemperature = 0; data.measuredTemperature = 0; break; - case "dimmableLight": + case 'dimmableLight': data.intensity = 0; break; - case "sensor": + case 'sensor': if (!this.state.motion) { data.sensor = this.state.typeOfSensor; data.value = 0; } break; - case "switch": - case "buttonDimmer": - case "knobDimmer": + case 'switch': + case 'buttonDimmer': + case 'knobDimmer': outputs = this.state.lightsAttached; if ( - this.state.lightsAttached === undefined || - this.state.lightsAttached.length === 0 + this.state.lightsAttached === undefined + || this.state.lightsAttached.length === 0 ) { alert( - "No lights attached to this switch! Please, add a light a first." + 'No lights attached to this switch! Please, add a light a first.', ); return; } @@ -156,114 +158,114 @@ class NewDevice extends Component { } try { - let newDevice = await this.props.saveDevice(data); + const newDevice = await this.props.saveDevice(data); if (outputs) { await this.props.connectOutputs(newDevice, outputs); } this.resetState(); } catch (e) { - console.error("device creation error: ", e); + console.error('device creation error: ', e); } } render() { const deviceOptions = [ - //stuff + // stuff { - key: "thermostat", - text: "Thermostat", - value: "thermostat", - image: { avatar: true, src: "/img/thermostat-icon.png" }, + key: 'thermostat', + text: 'Thermostat', + value: 'thermostat', + image: { avatar: true, src: '/img/thermostat-icon.png' }, }, { - key: "curtains", - text: "Curtain", - value: "curtains", - image: { avatar: true, src: "/img/curtains-icon.png" }, + key: 'curtains', + text: 'Curtain', + value: 'curtains', + image: { avatar: true, src: '/img/curtains-icon.png' }, }, - //stuff ends + // stuff ends { - key: "light", - text: "Normal Light", - value: "regularLight", - image: { avatar: true, src: "/img/lightOn.svg" }, + key: 'light', + text: 'Normal Light', + value: 'regularLight', + image: { avatar: true, src: '/img/lightOn.svg' }, }, { - key: "intensity-light", - text: "Intensity Light", - value: "dimmableLight", - image: { avatar: true, src: "/img/intensity-light.svg" }, + key: 'intensity-light', + text: 'Intensity Light', + value: 'dimmableLight', + image: { avatar: true, src: '/img/intensity-light.svg' }, }, { - key: "smart-plug", - text: "Smart Plug", - value: "smartPlug", - image: { avatar: true, src: "/img/smart-plug.svg" }, + key: 'smart-plug', + text: 'Smart Plug', + value: 'smartPlug', + image: { avatar: true, src: '/img/smart-plug.svg' }, }, { - key: "sensor", - text: "Sensor", - value: "sensor", - image: { avatar: true, src: "/img/sensorOn.svg" }, + key: 'sensor', + text: 'Sensor', + value: 'sensor', + image: { avatar: true, src: '/img/sensorOn.svg' }, }, { - key: "switch", - text: "Switch", - value: "switch", - image: { avatar: true, src: "/img/switchOn.svg" }, + key: 'switch', + text: 'Switch', + value: 'switch', + image: { avatar: true, src: '/img/switchOn.svg' }, }, { - key: "knobDimmer", - text: "Knob Dimmer", - value: "knobDimmer", - image: { avatar: true, src: "/img/knob.svg" }, + key: 'knobDimmer', + text: 'Knob Dimmer', + value: 'knobDimmer', + image: { avatar: true, src: '/img/knob.svg' }, }, { - key: "buttonDimmer", - text: "Button Dimmer", - value: "buttonDimmer", - image: { avatar: true, src: "/img/plusMinus.svg" }, + key: 'buttonDimmer', + text: 'Button Dimmer', + value: 'buttonDimmer', + image: { avatar: true, src: '/img/plusMinus.svg' }, }, { - key: "securityCamera", - text: "Security Camera", - value: "securityCamera", - image: { avatar: true, src: "/img/security-icon.png" }, + key: 'securityCamera', + text: 'Security Camera', + value: 'securityCamera', + image: { avatar: true, src: '/img/security-icon.png' }, }, ]; const sensorOptions = [ { - key: "temperature", - text: "Temperature Sensor", - value: "TEMPERATURE", - image: { avatar: true, src: "/img/temperature-sensor.svg" }, + key: 'temperature', + text: 'Temperature Sensor', + value: 'TEMPERATURE', + image: { avatar: true, src: '/img/temperature-sensor.svg' }, }, { - key: "humidity", - text: "Humidity Sensor", - value: "HUMIDITY", - image: { avatar: true, src: "/img/humidity-sensor.svg" }, + key: 'humidity', + text: 'Humidity Sensor', + value: 'HUMIDITY', + image: { avatar: true, src: '/img/humidity-sensor.svg' }, }, { - key: "light", - text: "Light Sensor", - value: "LIGHT", - image: { avatar: true, src: "/img/light-sensor.svg" }, + key: 'light', + text: 'Light Sensor', + value: 'LIGHT', + image: { avatar: true, src: '/img/light-sensor.svg' }, }, { - key: "motion", - text: "Motion Sensor", - value: "motionSensor", - image: { avatar: true, src: "/img/sensorOn.svg" }, + key: 'motion', + text: 'Motion Sensor', + value: 'motionSensor', + image: { avatar: true, src: '/img/sensorOn.svg' }, }, ]; const availableSwitchDevices = []; const availableDimmerDevices = []; this.props.devices.forEach((d) => { if ( - d.kind === "regularLight" || - d.kind === "dimmableLight" || - d.kind === "smartPlug" + d.kind === 'regularLight' + || d.kind === 'dimmableLight' + || d.kind === 'smartPlug' ) { availableSwitchDevices.push({ key: d.id, @@ -271,7 +273,7 @@ class NewDevice extends Component { value: d.id, }); } - if (d.kind === "dimmableLight") { + if (d.kind === 'dimmableLight') { availableDimmerDevices.push({ key: d.id, text: d.name, @@ -296,7 +298,7 @@ class NewDevice extends Component { ); const sensorForm = ( - + ); const switchOptions = ( - + ); const dimmerOptions = ( - + {deviceName} - {this.state.typeOfDevice === "sensor" ? sensorForm : ""} - {this.state.typeOfDevice === "switch" ? switchOptions : ""} - {this.state.typeOfDevice === "buttonDimmer" || - this.state.typeOfDevice === "knobDimmer" + {this.state.typeOfDevice === 'sensor' ? sensorForm : ''} + {this.state.typeOfDevice === 'switch' ? switchOptions : ''} + {this.state.typeOfDevice === 'buttonDimmer' + || this.state.typeOfDevice === 'knobDimmer' ? dimmerOptions - : ""} + : ''} ); }; @@ -361,19 +363,19 @@ class NewDevice extends Component { closeIcon open={this.state.openModal} onClose={this.resetState} - trigger={ + trigger={( - + - } - centered={true} + )} + centered > Add a New Device {steps[this.state.step - 1]} @@ -389,7 +391,7 @@ class NewDevice extends Component { Back ) : ( - "" + '' )} {this.state.step < steps.length ? ( ) : ( - "" + '' )} {this.state.step === steps.length ? (
@@ -164,13 +171,13 @@ class Thermostats extends Component { const mapStateToProps2 = (state, ownProps) => ({ ...mapStateToProps(state, ownProps), get tempSensorsInRoom() { - if (state.active.activeTab !== "Devices") return false; + if (state.active.activeTab !== 'Devices') return false; const room = state.rooms[state.devices[ownProps.id].roomId]; if (!room) return false; const deviceIds = room.devices; const devices = [...deviceIds].map((id) => state.devices[id]); const sensors = devices.filter( - (d) => d.kind === "sensor" && d.sensor === "TEMPERATURE" + (d) => d.kind === 'sensor' && d.sensor === 'TEMPERATURE', ); return sensors.length > 0; }, @@ -178,6 +185,6 @@ const mapStateToProps2 = (state, ownProps) => ({ const ThermostatContainer = connect( mapStateToProps2, - RemoteService + RemoteService, )(Thermostats); export default ThermostatContainer; diff --git a/smart-hut/src/components/dashboard/devices/TypesOfDevices.js b/smart-hut/src/components/dashboard/devices/TypesOfDevices.js index 6f3e2ba..1882afc 100644 --- a/smart-hut/src/components/dashboard/devices/TypesOfDevices.js +++ b/smart-hut/src/components/dashboard/devices/TypesOfDevices.js @@ -1,24 +1,24 @@ export const LightDevice = { - img: "/img/lightOff.svg", - imgClick: "/img/lightOn.svg", + img: '/img/lightOff.svg', + imgClick: '/img/lightOn.svg', }; export const SmartPlugDevice = { - img: "/img/smart-plug.svg", - imgClick: "/img/smart-plug-off.svg", + img: '/img/smart-plug.svg', + imgClick: '/img/smart-plug-off.svg', }; export const TemperatureSensor = { - type: "temperature_sensor", - img: "", - imgClick: "", - units: "ºC", + type: 'temperature_sensor', + img: '', + imgClick: '', + units: 'ºC', }; export const deviceList = [ - "Light", - "Dimmer", - "Switcher", - "Smart Plug", - "Sensor", + 'Light', + 'Dimmer', + 'Switcher', + 'Smart Plug', + 'Sensor', ]; diff --git a/smart-hut/src/components/dashboard/devices/Videocam.js b/smart-hut/src/components/dashboard/devices/Videocam.js index 75dee30..736fd9a 100644 --- a/smart-hut/src/components/dashboard/devices/Videocam.js +++ b/smart-hut/src/components/dashboard/devices/Videocam.js @@ -1,13 +1,13 @@ // vim: set ts=2 sw=2 et tw=80: -import React, { Component } from "react"; -import { StyledDivCamera } from "./styleComponents"; -import { Grid, Checkbox } from "semantic-ui-react"; -import { RemoteService } from "../../../remote"; -import { endpointURL } from "../../../endpoint"; -import { connect } from "react-redux"; -import VideocamModal from "./VideocamModal"; -import mapStateToProps from "../../../deviceProps"; +import React, { Component } from 'react'; +import { Grid, Checkbox } from 'semantic-ui-react'; +import { connect } from 'react-redux'; +import { StyledDivCamera } from './styleComponents'; +import { RemoteService } from '../../../remote'; +import { endpointURL } from '../../../endpoint'; +import VideocamModal from './VideocamModal'; +import mapStateToProps from '../../../deviceProps'; class Videocam extends Component { constructor(props) { @@ -18,30 +18,24 @@ class Videocam extends Component { } openModal = () => { - this.setState((state) => { - return { selectedVideo: true }; - }); + this.setState((state) => ({ selectedVideo: true })); }; closeModal = () => { - this.setState((state) => { - return { selectedVideo: undefined }; - }); + this.setState((state) => ({ selectedVideo: undefined })); }; setOnOff(onOff) { const turn = onOff; - if (this.props.tab === "Devices" || this.props.tab === "Hosts") { + if (this.props.tab === 'Devices' || this.props.tab === 'Hosts') { this.props .saveDevice({ ...this.props.device, on: turn }) - .then((res) => - turn ? this.refs.vidRef.play() : this.refs.vidRef.pause() - ) - .catch((err) => console.error("videocamera update error", err)); + .then((res) => (turn ? this.refs.vidRef.play() : this.refs.vidRef.pause())) + .catch((err) => console.error('videocamera update error', err)); } else { this.props.updateState( { id: this.props.stateOrDevice.id, on: turn }, - this.props.stateOrDevice.kind + this.props.stateOrDevice.kind, ); } } diff --git a/smart-hut/src/components/dashboard/devices/VideocamModal.js b/smart-hut/src/components/dashboard/devices/VideocamModal.js index ccefe1e..539551b 100644 --- a/smart-hut/src/components/dashboard/devices/VideocamModal.js +++ b/smart-hut/src/components/dashboard/devices/VideocamModal.js @@ -1,5 +1,21 @@ -import React from "react"; -import Modal from "react-modal"; +import React from 'react'; +import Modal from 'react-modal'; +import { Button } from 'semantic-ui-react'; + +const modal = { + opacity: 0, + alignItems: 'center', + display: 'flex', + justifyContent: 'center', + transition: 'opacity 200ms ease-in-out', + background: 'grey', + color: 'white', + maxWidth: '2rem', + outline: 'none', + padding: '2rem', + textAlign: 'center', + maxHeight: '50vh', +}; const VideocamModal = (props) => ( ( left: 0, right: 0, bottom: 0, - backgroundColor: 'rgba(0,0,0,0.5)' + backgroundColor: 'rgba(0,0,0,0.5)', }, content: { position: 'absolute', @@ -28,8 +44,8 @@ const VideocamModal = (props) => ( borderRadius: '4px', outline: 'none', padding: '20px', - backgroundColor: 'black' - } + backgroundColor: 'black', + }, }} > {props.selectedVideo && ( diff --git a/smart-hut/src/components/dashboard/devices/styleComponents.js b/smart-hut/src/components/dashboard/devices/styleComponents.js index 9750404..f388f83 100644 --- a/smart-hut/src/components/dashboard/devices/styleComponents.js +++ b/smart-hut/src/components/dashboard/devices/styleComponents.js @@ -1,105 +1,105 @@ -import styled from "styled-components"; -import { useCircularInputContext } from "react-circular-input"; -import { ValueStyle } from "./DimmerStyle"; -import React from "react"; +import styled from 'styled-components'; +import { useCircularInputContext } from 'react-circular-input'; +import React from 'react'; +import { ValueStyle } from './DimmerStyle'; export const editButtonStyle = { - position: "absolute", - top: "0", - right: "0", - backgroundColor: "#505bda", - borderRadius: "0 0 0 20px", - border: "none", - padding: ".4rem 1.2rem", - outline: "none", - color: "white", - fontFamily: "Lato", - textTransform: "uppercase", + position: 'absolute', + top: '0', + right: '0', + backgroundColor: '#505bda', + borderRadius: '0 0 0 20px', + border: 'none', + padding: '.4rem 1.2rem', + outline: 'none', + color: 'white', + fontFamily: 'Lato', + textTransform: 'uppercase', }; export const panelStyle = { - backgroundColor: "#fafafa", - height: "85vh", - padding: "0rem 3rem", - color: "#000000", - overflow: "auto", - maxHeight: "75vh", + backgroundColor: '#fafafa', + height: '85vh', + padding: '0rem 3rem', + color: '#000000', + overflow: 'auto', + maxHeight: '75vh', }; export const mobilePanelStyle = { - backgroundColor: "#fafafa", - minHeight: "100vh", - padding: "0rem 3rem", - color: "#000000", + backgroundColor: '#fafafa', + minHeight: '100vh', + padding: '0rem 3rem', + color: '#000000', }; export const editModeStyle = { - position: "absolute", - top: "15%", - right: "0", - width: "1.5rem", - height: "1.5rem", - backgroundColor: "black", - borderRadius: "100%", - zIndex: "1000", - cursor: "pointer", + position: 'absolute', + top: '15%', + right: '0', + width: '1.5rem', + height: '1.5rem', + backgroundColor: 'black', + borderRadius: '100%', + zIndex: '1000', + cursor: 'pointer', }; export const editModeStyleLeft = { - position: "absolute", - top: "15%", - left: "0", - width: "1.5rem", - height: "1.5rem", - backgroundColor: "white", - borderRadius: "100%", - zIndex: "1000", - cursor: "pointer", + position: 'absolute', + top: '15%', + left: '0', + width: '1.5rem', + height: '1.5rem', + backgroundColor: 'white', + borderRadius: '100%', + zIndex: '1000', + cursor: 'pointer', }; export const editModeIconStyle = { - position: "absolute", - top: "50%", - left: "50%", - transform: "translate(-50%, -50%)", - width: "0.75rem", - height: "0.75rem", - borderRadius: "20%", - zIndex: "101", + position: 'absolute', + top: '50%', + left: '50%', + transform: 'translate(-50%, -50%)', + width: '0.75rem', + height: '0.75rem', + borderRadius: '20%', + zIndex: '101', }; export const iconStyle = { - width: "3.5rem", - height: "auto", - position: "absolute", - top: "10%", - left: "50%", - transform: "translateX(-50%)", - userSelect: "none", + width: '3.5rem', + height: 'auto', + position: 'absolute', + top: '10%', + left: '50%', + transform: 'translateX(-50%)', + userSelect: 'none', }; export const nameStyle = { - position: "absolute", - top: "50%", - left: "50%", - transform: "translateX(-50%)", + position: 'absolute', + top: '50%', + left: '50%', + transform: 'translateX(-50%)', }; export const formStyle = { - position: "absolute", - zIndex: "1000", - width: "80rem", - height: "10rem", - padding: "1rem", - margin: "1rem", - borderRadius: "10%", - boxShadow: "1px 1px 5px 2px #5d5d5d", - backgroundColor: "#3e99ff", + position: 'absolute', + zIndex: '1000', + width: '80rem', + height: '10rem', + padding: '1rem', + margin: '1rem', + borderRadius: '10%', + boxShadow: '1px 1px 5px 2px #5d5d5d', + backgroundColor: '#3e99ff', }; export const addDeviceFormStyle = { - maxWidth: "400px", - background: "#3e99ff", - paddingRight: "5rem", + maxWidth: '400px', + background: '#3e99ff', + paddingRight: '5rem', }; export const StyledDiv = styled.div` diff --git a/smart-hut/src/deviceProps.js b/smart-hut/src/deviceProps.js index 352e017..f79de98 100644 --- a/smart-hut/src/deviceProps.js +++ b/smart-hut/src/deviceProps.js @@ -1,24 +1,24 @@ function getStateOrDevice(state, ownProps) { switch (state.active.activeTab) { - case "Devices": + case 'Devices': return state.devices[ownProps.id]; - case "Scenes": + case 'Scenes': return state.sceneStates[ownProps.id]; - case "Hosts": + case 'Hosts': return state.hostDevices[ownProps.hostId][ownProps.id]; default: throw new Error( - `stateOrDevice has no value in tab "${state.active.activeTab}"` + `stateOrDevice has no value in tab "${state.active.activeTab}"`, ); } } function getDevice(state, ownProps) { switch (state.active.activeTab) { - case "Scenes": + case 'Scenes': return state.devices[getStateOrDevice(state, ownProps).deviceId]; - case "Devices": - case "Hosts": + case 'Devices': + case 'Hosts': return getStateOrDevice(state, ownProps); default: throw new Error(`device has no value in tab "${state.active.activeTab}"`); @@ -27,18 +27,18 @@ function getDevice(state, ownProps) { function getRoomName(state, ownProps) { switch (state.active.activeTab) { - case "Scenes": - case "Devices": + case 'Scenes': + case 'Devices': return (state.rooms[getDevice(state, ownProps).roomId] || {}).name; - case "Hosts": + case 'Hosts': const hostRooms = state.hostRooms[ownProps.hostId]; - if (!hostRooms) return ""; + if (!hostRooms) return ''; const room = hostRooms[getDevice(state, ownProps).roomId]; - if (!room) return ""; + if (!room) return ''; return room.name; default: throw new Error( - `room name has no value in tab "${state.active.activeTab}"` + `room name has no value in tab "${state.active.activeTab}"`, ); } } @@ -60,9 +60,9 @@ export default function mapStateToProps(state, ownProps) { }, get disabled() { return ( - ownProps.tab === "Hosts" && - ["dimmableLight", "light"].indexOf(getDevice(state, ownProps).kind) === - -1 + ownProps.tab === 'Hosts' + && ['dimmableLight', 'light'].indexOf(getDevice(state, ownProps).kind) + === -1 ); }, }; diff --git a/smart-hut/src/endpoint.js b/smart-hut/src/endpoint.js index 6dbc3b0..32a15e7 100644 --- a/smart-hut/src/endpoint.js +++ b/smart-hut/src/endpoint.js @@ -3,17 +3,17 @@ * @returns {String} endpoint URL */ export function endpointURL() { - return window.BACKEND_URL !== "__BACKEND_URL__" + return window.BACKEND_URL !== '__BACKEND_URL__' ? window.BACKEND_URL - : "http://localhost:8080"; + : 'http://localhost:8080'; } export function socketURL(token) { const httpURL = new URL(endpointURL()); - const isSecure = httpURL.protocol === "https:"; - const protocol = isSecure ? "wss:" : "ws:"; + const isSecure = httpURL.protocol === 'https:'; + const protocol = isSecure ? 'wss:' : 'ws:'; const port = httpURL.port || (isSecure ? 443 : 80); const url = `${protocol}//${httpURL.hostname}:${port}/sensor-socket?token=${token}`; - console.log("socket url: ", url); + console.log('socket url: ', url); return url; } diff --git a/smart-hut/src/index.js b/smart-hut/src/index.js index 111847a..2aa57e9 100644 --- a/smart-hut/src/index.js +++ b/smart-hut/src/index.js @@ -1,9 +1,9 @@ -import React from "react"; -import ReactDOM from "react-dom"; -import App from "./App"; -import * as serviceWorker from "./serviceWorker"; -import { Provider } from "react-redux"; -import smartHutStore from "./store"; +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Provider } from 'react-redux'; +import App from './App'; +import * as serviceWorker from './serviceWorker'; +import smartHutStore from './store'; const index = ( @@ -11,5 +11,5 @@ const index = ( ); -ReactDOM.render(index, document.getElementById("root")); +ReactDOM.render(index, document.getElementById('root')); serviceWorker.unregister(); diff --git a/smart-hut/src/remote.js b/smart-hut/src/remote.js index 42a5841..b648c77 100644 --- a/smart-hut/src/remote.js +++ b/smart-hut/src/remote.js @@ -1,8 +1,8 @@ -import smartHutStore from "./store"; -import actions from "./storeActions"; -import axios from "axios"; -import { endpointURL, socketURL } from "./endpoint"; -import { connect, disconnect } from "@giantmachines/redux-websocket"; +import axios from 'axios'; +import { connect, disconnect } from '@giantmachines/redux-websocket'; +import smartHutStore from './store'; +import actions from './storeActions'; +import { endpointURL, socketURL } from './endpoint'; /** * An object returned by promise rejections in remoteservice @@ -15,8 +15,8 @@ class RemoteError extends Error { constructor(messages) { super( messages && Array.isArray(messages) - ? messages.join(" - ") - : JSON.stringify(messages, null, 2) + ? messages.join(' - ') + : JSON.stringify(messages, null, 2), ); this.messages = messages; } @@ -45,23 +45,22 @@ const Endpoint = { */ send: (method, route, query = {}, body = null) => { if (!Endpoint.token) { - throw new Error("No token while performing authenticated request"); + throw new Error('No token while performing authenticated request'); } return Endpoint.axiosInstance(route, { - method: method, + method, params: query, - data: ["put", "post"].indexOf(method) !== -1 ? body : null, + data: ['put', 'post'].indexOf(method) !== -1 ? body : null, headers: { Authorization: `Bearer ${Endpoint.token}`, }, }).then((res) => { - if (!res.data && method !== "delete") { - console.error("Response body is empty"); + if (!res.data && method !== 'delete') { + console.error('Response body is empty'); return null; - } else { - return res; } + return res; }); }, @@ -72,20 +71,17 @@ const Endpoint = { * @param {[String]String} query query ('?') parameters (no params by default) * @param {any} body the JSON request body */ - sendNA: (method, route, query = {}, body = null) => { - return Endpoint.axiosInstance(route, { - method: method, + sendNA: (method, route, query = {}, body = null) => Endpoint.axiosInstance(route, { + method, params: query, - data: ["put", "post"].indexOf(method) !== -1 ? body : null, + data: ['put', 'post'].indexOf(method) !== -1 ? body : null, }).then((res) => { if (!res.data) { - console.error("Response body is empty"); + console.error('Response body is empty'); return null; - } else { - return res; } - }); - }, + return res; + }), /** * Performs login @@ -94,26 +90,24 @@ const Endpoint = { * @returns {Promise} promise that resolves to the token string * and rejects to the axios error. */ - login: (usernameOrEmail, password) => { - return Endpoint.axiosInstance - .post(`/auth/login`, { + login: (usernameOrEmail, password) => Endpoint.axiosInstance + .post('/auth/login', { usernameOrEmail, password, }) .then((res) => { - localStorage.setItem("token", res.data.jwttoken); - localStorage.setItem("exp", new Date().getTime() + 5 * 60 * 60 * 1000); + localStorage.setItem('token', res.data.jwttoken); + localStorage.setItem('exp', new Date().getTime() + 5 * 60 * 60 * 1000); return res.data.jwttoken; - }); - }, + }), /** * Returns an immediately resolved promise for the socket logouts * @return {Promise} An always-resolved promise */ logout: () => { - localStorage.removeItem("token"); - localStorage.removeItem("exp"); + localStorage.removeItem('token'); + localStorage.removeItem('exp'); return Promise.resolve(void 0); }, @@ -124,7 +118,7 @@ const Endpoint = { * @returns {Promise<*, *>} The Axios-generated promise */ get(route, query = {}) { - return this.send("get", route, query); + return this.send('get', route, query); }, /** @@ -135,7 +129,7 @@ const Endpoint = { * @returns {Promise<*, *>} The Axios-generated promise */ post(route, query, body) { - return this.send("post", route, query, body); + return this.send('post', route, query, body); }, /** @@ -146,7 +140,7 @@ const Endpoint = { * @returns {Promise<*, *>} The Axios-generated promise */ postNA(route, query, body) { - return this.sendNA("post", route, query, body); + return this.sendNA('post', route, query, body); }, /** @@ -157,7 +151,7 @@ const Endpoint = { * @returns {Promise<*, *>} The Axios-generated promise */ put(route, query = {}, body = {}) { - return this.send("put", route, query, body); + return this.send('put', route, query, body); }, /** @@ -168,7 +162,7 @@ const Endpoint = { * @returns {Promise<*, *>} The Axios-generated promise */ putNA(route, query = {}, body = {}) { - return this.sendNA("put", route, query, body); + return this.sendNA('put', route, query, body); }, /** @@ -179,7 +173,7 @@ const Endpoint = { * @returns {Promise<*, *>} The Axios-generated promise */ delete(route, query = {}) { - return this.send("delete", route, query); + return this.send('delete', route, query); }, }; @@ -191,17 +185,17 @@ const Endpoint = { */ function parseValidationErrors(err) { if ( - err.response && - err.response.status === 400 && - err.response.data && - Array.isArray(err.response.data.errors) + err.response + && err.response.status === 400 + && err.response.data + && Array.isArray(err.response.data.errors) ) { throw new RemoteError([ ...new Set(err.response.data.errors.map((e) => e.defaultMessage)), ]); } else { - console.warn("Non validation error", err); - throw new RemoteError(["Network error"]); + console.warn('Non validation error', err); + throw new RemoteError(['Network error']); } } @@ -213,64 +207,49 @@ export const RemoteService = { * @returns {Promise} promise that resolves to void and rejects * with user-fiendly errors as a RemoteError */ - login: (usernameOrEmail, password) => { - return (dispatch) => { - return Endpoint.login(usernameOrEmail, password) + login: (usernameOrEmail, password) => (dispatch) => Endpoint.login(usernameOrEmail, password) .then((token) => { dispatch(actions.loginSuccess(token)); dispatch(connect(socketURL(token))); }) .catch((err) => { - console.warn("login error", err); + console.warn('login error', err); throw new RemoteError([ err.response && err.response.status === 401 - ? "Wrong credentials" - : "An error occurred while logging in", + ? 'Wrong credentials' + : 'An error occurred while logging in', ]); - }); - }; - }, + }), /** * Performs logout */ - logout: () => { - return (dispatch) => - Endpoint.logout().then(() => { + logout: () => (dispatch) => Endpoint.logout().then(() => { dispatch(disconnect()); dispatch(actions.logout()); - }); - }, + }), /** * Fetches user information via REST calls, if it is logged in * @returns {Promise} promise that resolves to void and rejects * with user-fiendly errors as a RemoteError */ - userPermissions: (data) => { - return (dispatch) => { - return Endpoint.put("/user/permissions", {}, data).catch((err) => { - console.warn("Fetch user info error", err); - throw new RemoteError(["Network error"]); - }); - }; - }, + userPermissions: (data) => (dispatch) => Endpoint.put('/user/permissions', {}, data).catch((err) => { + console.warn('Fetch user info error', err); + throw new RemoteError(['Network error']); + }), /** * Fetches user information via REST calls, if it is logged in * @returns {Promise} promise that resolves to void and rejects * with user-fiendly errors as a RemoteError */ - fetchUserInfo: () => { - return (dispatch) => { - return Endpoint.get("/auth/profile") + fetchUserInfo: () => (dispatch) => Endpoint.get('/auth/profile') .then((res) => void dispatch(actions.userInfoUpdate(res.data))) .catch((err) => { - console.warn("Fetch user info error", err); - throw new RemoteError(["Network error"]); - }); - }; - }, + console.warn('Fetch user info error', err); + throw new RemoteError(['Network error']); + }), /** * Fetches all rooms that belong to this user. This call does not @@ -280,23 +259,18 @@ export const RemoteService = { * @returns {Promise} promise that resolves to void and rejects * with user-fiendly errors as a RemoteError */ - fetchAllRooms: (hostId = null) => { - return (dispatch) => { - return Endpoint.get("/room", hostId ? { hostId } : null) + fetchAllRooms: (hostId = null) => (dispatch) => Endpoint.get('/room', hostId ? { hostId } : null) .then( - (res) => - void dispatch( + (res) => void dispatch( hostId ? actions.hostRoomsUpdate(hostId, res.data) - : actions.roomsUpdate(res.data) - ) + : actions.roomsUpdate(res.data), + ), ) .catch((err) => { - console.error("Fetch all rooms error", err); - throw new RemoteError(["Network error"]); - }); - }; - }, + console.error('Fetch all rooms error', err); + throw new RemoteError(['Network error']); + }), /** * Fetches all scenes that belong to this user. This call does not @@ -304,23 +278,18 @@ export const RemoteService = { * @returns {Promise} promise that resolves to void and rejects * with user-fiendly errors as a RemoteError */ - fetchAllScenes: (hostId = null) => { - return (dispatch) => { - return Endpoint.get("/scene", hostId ? { hostId } : {}) + fetchAllScenes: (hostId = null) => (dispatch) => Endpoint.get('/scene', hostId ? { hostId } : {}) .then( - (res) => - void dispatch( + (res) => void dispatch( !hostId ? actions.scenesUpdate(res.data) - : actions.hostScenesUpdate(hostId, res.data) - ) + : actions.hostScenesUpdate(hostId, res.data), + ), ) .catch((err) => { - console.error("Fetch all scenes error", err); - throw new RemoteError(["Network error"]); - }); - }; - }, + console.error('Fetch all scenes error', err); + throw new RemoteError(['Network error']); + }), /** * Fetches all devices in a particular room, or fetches all devices. @@ -332,42 +301,33 @@ export const RemoteService = { * @returns {Promise} promise that resolves to void and rejects * with user-fiendly errors as a RemoteError */ - fetchDevices: (roomId = null, hostId = null) => { - return (dispatch) => { - return Endpoint.get( - roomId ? `/room/${roomId}/device` : "/device", - hostId ? { hostId } : null + fetchDevices: (roomId = null, hostId = null) => (dispatch) => Endpoint.get( + roomId ? `/room/${roomId}/device` : '/device', + hostId ? { hostId } : null, ) .then( - (res) => - void dispatch( + (res) => void dispatch( !hostId ? actions.devicesUpdate(roomId, res.data, hostId) - : actions.hostDevicesUpdate(hostId, res.data) - ) + : actions.hostDevicesUpdate(hostId, res.data), + ), ) .catch((err) => { console.error(`Fetch devices roomId=${roomId} error`, err); - throw new RemoteError(["Network error"]); - }); - }; - }, + throw new RemoteError(['Network error']); + }), /** * Fetches all the automations * @returns {Promise} promise that resolves to void and rejects * with user-fiendly errors as a RemoteError */ - fetchAutomations: () => { - return (dispatch) => { - return Endpoint.get("/automation/") + fetchAutomations: () => (dispatch) => Endpoint.get('/automation/') .then((res) => void dispatch(actions.automationsUpdate(res.data))) .catch((err) => { - console.error(`Fetch automations error`, err); - throw new RemoteError(["Network error"]); - }); - }; - }, + console.error('Fetch automations error', err); + throw new RemoteError(['Network error']); + }), /** * Fetches all devices in a particular scene, or fetches all devices. @@ -377,48 +337,36 @@ export const RemoteService = { * @returns {Promise} promise that resolves to void and rejects * with user-fiendly errors as a RemoteError */ - fetchStates: (sceneId) => { - return (dispatch) => { - return Endpoint.get(`/scene/${sceneId}/states`) + fetchStates: (sceneId) => (dispatch) => Endpoint.get(`/scene/${sceneId}/states`) .then((res) => void dispatch(actions.statesUpdate(sceneId, res.data))) .catch((err) => { console.error(`Fetch devices sceneId=${sceneId} error`, err); - throw new RemoteError(["Network error"]); - }); - }; - }, + throw new RemoteError(['Network error']); + }), /** * Fetches all hosts of a particular user. * @returns {Promise} promise that resolves to void and rejects * with user-fiendly errors as a RemoteError */ - fetchHosts: () => { - return (dispatch) => { - return Endpoint.get(`/user/hosts`) + fetchHosts: () => (dispatch) => Endpoint.get('/user/hosts') .then((res) => void dispatch(actions.hostsUpdate(res.data))) .catch((err) => { - console.error(`Fetch hosts error`, err); - throw new RemoteError(["Network error"]); - }); - }; - }, + console.error('Fetch hosts error', err); + throw new RemoteError(['Network error']); + }), /** * Fetches all guests of a particular user. * @returns {Promise} promise that resolves to void and rejects * with user-fiendly errors as a RemoteError */ - fetchGuests: () => { - return (dispatch) => { - return Endpoint.get(`/user/guests`) + fetchGuests: () => (dispatch) => Endpoint.get('/user/guests') .then((res) => void dispatch(actions.guestsUpdate(res.data))) .catch((err) => { - console.error(`Fetch guests error`, err); - throw new RemoteError(["Network error"]); - }); - }; - }, + console.error('Fetch guests error', err); + throw new RemoteError(['Network error']); + }), /** * Adds the current user as a guest to another user @@ -427,16 +375,12 @@ export const RemoteService = { * @returns {Promise} promise that resolves to void and rejects * with user-fiendly errors as a RemoteError */ - updateGuests: (userIds) => { - return (dispatch) => { - return Endpoint.put(`/user/guests`, {}, { ids: userIds }) + updateGuests: (userIds) => (dispatch) => Endpoint.put('/user/guests', {}, { ids: userIds }) .then((res) => void dispatch(actions.guestsUpdate(res.data))) .catch((err) => { - console.error(`Guest save error`, err); - throw new RemoteError(["Network Error"]); - }); - }; - }, + console.error('Guest save error', err); + throw new RemoteError(['Network Error']); + }), /** * Creates/Updates a room with the given data @@ -447,8 +391,7 @@ export const RemoteService = { * @returns {Promise} promise that resolves to void and rejects * with user-fiendly errors as a RemoteError */ - saveRoom: (data, roomId = null) => { - return (dispatch) => { + saveRoom: (data, roomId = null) => (dispatch) => { data = { name: data.name, icon: data.icon, @@ -457,12 +400,11 @@ export const RemoteService = { return (roomId ? Endpoint.put(`/room/${roomId}`, {}, data) - : Endpoint.post(`/room`, {}, data) + : Endpoint.post('/room', {}, data) ) .then((res) => void dispatch(actions.roomSave(res.data))) .catch(parseValidationErrors); - }; - }, + }, /** * Creates/Updates a scene with the given data @@ -473,8 +415,7 @@ export const RemoteService = { * @returns {Promise} promise that resolves to void and rejects * with user-fiendly errors as a RemoteError */ - saveScene: (data, sceneId = null, copyFrom = null) => { - return (dispatch) => { + saveScene: (data, sceneId = null, copyFrom = null) => (dispatch) => { copyFrom = sceneId === null ? copyFrom : null; data = { name: data.name, @@ -484,7 +425,7 @@ export const RemoteService = { return (sceneId ? Endpoint.put(`/scene/${sceneId}`, {}, data) - : Endpoint.post(`/scene`, {}, data) + : Endpoint.post('/scene', {}, data) ) .then(async (res) => { let states = []; @@ -493,12 +434,12 @@ export const RemoteService = { const sceneId = res.data.id; try { const res = await Endpoint.post( - `/scene/${sceneId}/copyFrom/${copyFrom}` + `/scene/${sceneId}/copyFrom/${copyFrom}`, ); states = res.data; } catch (e) { - console.warn("Error in state cloning from scene " + copyFrom, e); - throw new RemoteError(["Network error"]); + console.warn(`Error in state cloning from scene ${copyFrom}`, e); + throw new RemoteError(['Network error']); } } @@ -508,16 +449,14 @@ export const RemoteService = { } }) .catch(parseValidationErrors); - }; - }, + }, - updateState: (data, type) => { - return (dispatch) => { + updateState: (data, type) => (dispatch) => { let url; if (data.on !== undefined) { - url = "/switchableState"; + url = '/switchableState'; } else { - url = "/dimmableState"; + url = '/dimmableState'; } return Endpoint.put(url, {}, data) @@ -526,50 +465,43 @@ export const RemoteService = { return res.data; }) .catch((err) => { - console.warn("Update device: ", data, "error: ", err); - throw new RemoteError(["Network error"]); + console.warn('Update device: ', data, 'error: ', err); + throw new RemoteError(['Network error']); }); - }; - }, + }, - deleteState: (id, type) => { - return (dispatch) => { + deleteState: (id, type) => (dispatch) => { let url; - if (type === "dimmableState") { - url = "/dimmableState"; + if (type === 'dimmableState') { + url = '/dimmableState'; } else { - url = "/switchableState"; + url = '/switchableState'; } - return Endpoint.delete(url + `/${id}`) + return Endpoint.delete(`${url}/${id}`) .then((_) => dispatch(actions.stateDelete(id))) .catch((err) => { - console.warn("state delete error", err); - throw new RemoteError(["Network error"]); + console.warn('state delete error', err); + throw new RemoteError(['Network error']); }); - }; - }, + }, - sceneApply: (id, hostId = null) => { - return (dispatch) => { + sceneApply: (id, hostId = null) => (dispatch) => { let url = `/scene/${id}/apply`; if (hostId) { - url = url + "?hostId=" + hostId; + url = `${url}?hostId=${hostId}`; } return Endpoint.post(url) - .then((res) => - dispatch( + .then((res) => dispatch( hostId ? actions.hostDevicesUpdate(hostId, res.data, true) - : actions.deviceOperationUpdate(res.data) - ) - ) + : actions.deviceOperationUpdate(res.data), + )) .catch((err) => { - console.warn("scene apply error", err); - throw new RemoteError(["Network error"]); + console.warn('scene apply error', err); + throw new RemoteError(['Network error']); }); - }; - }, + }, /** * Creates/Updates a device with the given data. If @@ -583,43 +515,37 @@ export const RemoteService = { * @returns {Promise} promise that resolves to the saved device and rejects * with user-fiendly errors as a RemoteError */ - saveDevice: (data, hostId = null) => { - return (dispatch) => { - let url = "/device"; - if ((data.id && data.flowType === "OUTPUT") || !data.id) { - url = "/" + data.kind; + saveDevice: (data, hostId = null) => (dispatch) => { + let url = '/device'; + if ((data.id && data.flowType === 'OUTPUT') || !data.id) { + url = `/${data.kind}`; } - return Endpoint[data.id ? "put" : "post"]( + return Endpoint[data.id ? 'put' : 'post']( url, hostId ? { hostId } : {}, - data + data, ) .then((res) => { dispatch( hostId ? actions.hostDeviceSave(hostId, res.data) - : actions.deviceSave(res.data) + : actions.deviceSave(res.data), ); return res.data; }) .catch((err) => { - console.warn("Update device: ", data, "error: ", err); - throw new RemoteError(["Network error"]); + console.warn('Update device: ', data, 'error: ', err); + throw new RemoteError(['Network error']); }); - }; - }, + }, - fastUpdateAutomation: (automation) => { - return (dispatch) => { - return Endpoint.put("/automation/fast", {}, automation) + fastUpdateAutomation: (automation) => (dispatch) => Endpoint.put('/automation/fast', {}, automation) .then((res) => dispatch(actions.automationSave(res.data))) .catch((err) => { - console.warn("Update automation: ", automation, "error: ", err); - throw new RemoteError(["Network error"]); - }); - }; - }, + console.warn('Update automation: ', automation, 'error: ', err); + throw new RemoteError(['Network error']); + }), /** * Creates/Updates an automation with the given data. If @@ -630,69 +556,123 @@ export const RemoteService = { * with user-fiendly errors as a RemoteError */ saveAutomation: (data) => { - const { automation, triggerList, order } = data; - console.log("automation: ", automation, triggerList, order); + const { + automation, triggerList, order, conditionList, +} = data; automation.triggers = []; automation.scenes = []; + automation.condition = []; return (dispatch) => { - let urlAutomation = "/automation"; - let urlBooleanTrigger = "/booleanTrigger"; - let urlRangeTrigger = "/rangeTrigger"; - let urlScenePriority = "/scenePriority"; + const urlAutomation = '/automation'; + const urlBooleanTrigger = '/booleanTrigger'; + const urlRangeTrigger = '/rangeTrigger'; + const urlScenePriority = '/scenePriority'; + // conditions + const urlRangeCondition = '/rangeCondition'; + const urlBooleanCondition = '/booleanCondition'; + const urlThermostatCondition = '/thermostatCondition'; - let rangeTriggerList = triggerList.filter((trigger) => - trigger.hasOwnProperty("operand") - ); - let booleanTriggerList = triggerList.filter( - (trigger) => !trigger.hasOwnProperty("operand") + const rangeTriggerList = triggerList.filter((trigger) => 'operand' in trigger); + const booleanTriggerList = triggerList.filter( + (trigger) => !('operand' in trigger), ); + const rangeConditionList = conditionList.filter((condition) => 'operand' in condition && 'value' in condition); + const booleanConditionList = conditionList.filter((condition) => 'on' in condition); + const thermostatConditionList = conditionList.filter((condition) => 'operand' in condition && 'mode' in condition); - return Endpoint["post"](urlAutomation, {}, automation).then( + + return Endpoint.post(urlAutomation, {}, automation).then( async (automationRes) => { const { id } = automationRes.data; // Introduce the range triggers in the automation - for (let t of rangeTriggerList) { + const resRangeTriggers = []; + for (const t of rangeTriggerList) { const trigger = { automationId: id, deviceId: t.device, operator: t.operand, range: t.value, }; - let resRange = await Endpoint.post(urlRangeTrigger, {}, trigger); - automation.triggers.push(resRange.data); + resRangeTriggers.push(Endpoint.post(urlRangeTrigger, {}, trigger)); } + automation.triggers = (await Promise.all(resRangeTriggers)).map((v) => v.data); - for (let t of booleanTriggerList) { + const resBoolTriggers = []; + for (const t of booleanTriggerList) { const trigger = { automationId: id, deviceId: t.device, - on: t.value, + on: t.on, }; - let resBoolean = await Endpoint.post( + resBoolTriggers.push(Endpoint.post( urlBooleanTrigger, {}, - trigger - ); - automation.triggers.push(resBoolean.data); - console.log("TRIGGERS: ", automation); + trigger, + )); } + automation.triggers.push(...((await Promise.all(resBoolTriggers)).map((v) => v.data))); - for (let [priority, sceneId] of order.entries()) { + // Conditions + const resRangeConditions = []; + for (const t of rangeConditionList) { + const condition = { + automationId: id, + deviceId: t.device, + operator: t.operand, + range: t.value, + }; + resRangeConditions.push(Endpoint.post(urlRangeCondition, {}, condition)); + } + automation.conditions = (await Promise.all(resRangeConditions)).map((v) => v.data); + + const resBoolConditions = []; + for (const t of booleanConditionList) { + const condition = { + automationId: id, + deviceId: t.device, + on: t.on, + }; + resBoolConditions.push(Endpoint.post( + urlBooleanCondition, + {}, + condition, + )); + } + automation.conditions.push(...((await Promise.all(resBoolConditions)).map((v) => v.data))); + + const resThermoConditions = []; + for (const t of thermostatConditionList) { + const condition = { + automationId: id, + deviceId: t.device, + mode: t.mode, + operator: t.operand, + }; + resThermoConditions.push(Endpoint.post( + urlThermostatCondition, + {}, + condition, + )); + } + automation.conditions.push(...((await Promise.all(resThermoConditions)).map((v) => v.data))); + + const resScenePriorities = []; + for (const [priority, sceneId] of order.entries()) { const scenePriority = { automationId: id, priority, sceneId, }; - let resScenes = await Endpoint["post"]( + resScenePriorities.push(Endpoint.post( urlScenePriority, {}, - scenePriority - ); - automation.scenes.push(resScenes.data); + scenePriority, + )); } + automation.scenes = (await Promise.all(resScenePriorities)).map((v) => v.data); automation.id = id; dispatch(actions.automationSave(automation)); - } + }, ); }; }, @@ -709,22 +689,19 @@ export const RemoteService = { * @returns {Promise} promise that resolves to the saved device and rejects * with user-fiendly errors as a RemoteError */ - saveState: (data) => { - return (dispatch) => { - let url = - "/" + data.kind + "/" + data.id + "/state?sceneId=" + data.sceneId; + saveState: (data) => (dispatch) => { + const url = `/${data.kind}/${data.id}/state?sceneId=${data.sceneId}`; - return Endpoint["post"](url, {}, data) + return Endpoint.post(url, {}, data) .then((res) => { dispatch(actions.stateSave(res.data)); return res.data; }) .catch((err) => { - console.warn("Update device: ", data, "error: ", err); - throw new RemoteError(["Network error"]); + console.warn('Update device: ', data, 'error: ', err); + throw new RemoteError(['Network error']); }); - }; - }, + }, /** * Connetcs a series of output devices to an input device. @@ -739,9 +716,8 @@ export const RemoteService = { * @returns {Promise} promise that resolves to void and rejects * with user-fiendly errors as a RemoteError */ - connectOutputs: (newDevice, outputs) => { - return (dispatch) => { - let url = `/${newDevice.kind}/${newDevice.id}/lights`; + connectOutputs: (newDevice, outputs) => (dispatch) => { + const url = `/${newDevice.kind}/${newDevice.id}/lights`; return Endpoint.post(url, {}, outputs) .then((res) => { @@ -750,34 +726,29 @@ export const RemoteService = { }) .catch((err) => { console.warn( - "ConnectOutputs of ", + 'ConnectOutputs of ', newDevice.id, - " with outputs: ", + ' with outputs: ', outputs, - "error: ", - err + 'error: ', + err, ); - throw new RemoteError(["Network error"]); + throw new RemoteError(['Network error']); }); - }; - }, + }, - _operateInput: (url, getUrl, action) => { - return (dispatch) => { - return Endpoint.put(url, {}, action) + _operateInput: (url, getUrl, action) => (dispatch) => Endpoint.put(url, {}, action) .then(async (res) => { const inputDevice = await Endpoint.get(getUrl); delete inputDevice.outputs; dispatch( - actions.deviceOperationUpdate([...res.data, inputDevice.data]) + actions.deviceOperationUpdate([...res.data, inputDevice.data]), ); }) .catch((err) => { console.warn(`${url} error`, err); - throw new RemoteError(["Network error"]); - }); - }; - }, + throw new RemoteError(['Network error']); + }), /** * Changes the state of a switch, by turning it on, off or toggling it. @@ -789,16 +760,14 @@ export const RemoteService = { * @returns {Promise} promise that resolves to void and rejects * with user-fiendly errors as a RemoteError */ - switchOperate: (switchId, type) => { - return RemoteService._operateInput( - "/switch/operate", + switchOperate: (switchId, type) => RemoteService._operateInput( + '/switch/operate', `/switch/${switchId}`, { type: type.toUpperCase(), id: switchId, - } - ); - }, + }, + ), /** * Turns a knob dimmer to a specific amount @@ -808,16 +777,14 @@ export const RemoteService = { * @returns {Promise} promise that resolves to void and rejects * with user-fiendly errors as a RemoteError */ - knobDimmerDimTo: (dimmerId, intensity) => { - return RemoteService._operateInput( - "/knobDimmer/dimTo", + knobDimmerDimTo: (dimmerId, intensity) => RemoteService._operateInput( + '/knobDimmer/dimTo', `/knobDimmer/${dimmerId}`, { intensity, id: dimmerId, - } - ); - }, + }, + ), /** * Turns a button dimmer up or down @@ -829,16 +796,14 @@ export const RemoteService = { * @returns {Promise} promise that resolves to void and rejects * with user-fiendly errors as a RemoteError */ - buttonDimmerDim: (dimmerId, dimType) => { - return RemoteService._operateInput( - "/buttonDimmer/dim", + buttonDimmerDim: (dimmerId, dimType) => RemoteService._operateInput( + '/buttonDimmer/dim', `/buttonDimmer/${dimmerId}`, { dimType, id: dimmerId, - } - ); - }, + }, + ), /** * Resets the meter on a smart plug @@ -848,14 +813,12 @@ export const RemoteService = { * with user-fiendly errors as a RemoteError */ smartPlugReset(smartPlugId) { - return (dispatch) => { - return Endpoint.delete(`/smartPlug/${smartPlugId}/meter`) + return (dispatch) => Endpoint.delete(`/smartPlug/${smartPlugId}/meter`) .then((res) => dispatch(actions.deviceOperationUpdate([res.data]))) .catch((err) => { - console.warn(`Smartplug reset error`, err); - throw new RemoteError(["Network error"]); + console.warn('Smartplug reset error', err); + throw new RemoteError(['Network error']); }); - }; }, /** * Deletes a room @@ -863,27 +826,21 @@ export const RemoteService = { * @returns {Promise} promise that resolves to void and rejects * with user-fiendly errors as a RemoteError */ - deleteRoom: (roomId) => { - return (dispatch) => { - return Endpoint.delete(`/room/${roomId}`) + deleteRoom: (roomId) => (dispatch) => Endpoint.delete(`/room/${roomId}`) .then((_) => dispatch(actions.roomDelete(roomId))) .catch((err) => { - console.warn("Room deletion error", err); - throw new RemoteError(["Network error"]); - }); - }; - }, + console.warn('Room deletion error', err); + throw new RemoteError(['Network error']); + }), deleteAutomation: (id) => { - console.log("ID OF AUTO ", id); - return (dispatch) => { - return Endpoint.delete(`/automation/${id}`) + console.log('ID OF AUTO ', id); + return (dispatch) => Endpoint.delete(`/automation/${id}`) .then((_) => dispatch(actions.automationDelete(id))) .catch((err) => { - console.warn("Automation deletion error", err); - throw new RemoteError(["Network error"]); + console.warn('Automation deletion error', err); + throw new RemoteError(['Network error']); }); - }; }, /** @@ -892,16 +849,12 @@ export const RemoteService = { * @returns {Promise} promise that resolves to void and rejects * with user-fiendly errors as a RemoteError */ - deleteScene: (sceneId) => { - return (dispatch) => { - return Endpoint.delete(`/scene/${sceneId}`) + deleteScene: (sceneId) => (dispatch) => Endpoint.delete(`/scene/${sceneId}`) .then((_) => dispatch(actions.sceneDelete(sceneId))) .catch((err) => { - console.warn("Scene deletion error", err); - throw new RemoteError(["Network error"]); - }); - }; - }, + console.warn('Scene deletion error', err); + throw new RemoteError(['Network error']); + }), /** * Deletes a device @@ -909,16 +862,12 @@ export const RemoteService = { * @returns {Promise} promise that resolves to void and rejects * with user-fiendly errors as a RemoteError */ - deleteDevice: (device) => { - return (dispatch) => { - return Endpoint.delete(`/${device.kind}/${device.id}`) + deleteDevice: (device) => (dispatch) => Endpoint.delete(`/${device.kind}/${device.id}`) .then((_) => dispatch(actions.deviceDelete(device.id))) .catch((err) => { - console.warn("Device deletion error", err); - throw new RemoteError(["Network error"]); - }); - }; - }, + console.warn('Device deletion error', err); + throw new RemoteError(['Network error']); + }), }; for (const key in RemoteService) { @@ -927,11 +876,11 @@ for (const key in RemoteService) { export class Forms { static fetchAllUsers() { - return Endpoint.get(`/user`) + return Endpoint.get('/user') .then((res) => res.data) .catch((err) => { - console.error(`Fetch users error`, err); - throw new RemoteError(["Network error"]); + console.error('Fetch users error', err); + throw new RemoteError(['Network error']); }); } @@ -948,14 +897,14 @@ export class Forms { */ static submitRegistration(data) { return Endpoint.postNA( - "/register", + '/register', {}, { username: data.username, password: data.password, name: data.name, email: data.email, - } + }, ) .then((_) => void 0) .catch(parseValidationErrors); @@ -971,16 +920,16 @@ export class Forms { */ static submitInitResetPassword(email) { return Endpoint.postNA( - "/register/init-reset-password", + '/register/init-reset-password', {}, { - email: email, - } + email, + }, ) .then((_) => void 0) .catch((err) => { - console.warn("Init reset password failed", err); - throw new RemoteError(["Network error"]); + console.warn('Init reset password failed', err); + throw new RemoteError(['Network error']); }); } @@ -996,12 +945,12 @@ export class Forms { */ static submitResetPassword(confirmationToken, password) { return Endpoint.putNA( - "/register/reset-password", + '/register/reset-password', {}, { confirmationToken, password, - } + }, ) .then((_) => void 0) .catch(parseValidationErrors); diff --git a/smart-hut/src/serviceWorker.js b/smart-hut/src/serviceWorker.js index c7cd666..a034430 100644 --- a/smart-hut/src/serviceWorker.js +++ b/smart-hut/src/serviceWorker.js @@ -11,17 +11,17 @@ // opt-in, read https://bit.ly/CRA-PWA const isLocalhost = Boolean( - window.location.hostname === "localhost" || + window.location.hostname === 'localhost' // [::1] is the IPv6 localhost address. - window.location.hostname === "[::1]" || + || window.location.hostname === '[::1]' // 127.0.0.0/8 are considered localhost for IPv4. - window.location.hostname.match( - /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ - ) + || window.location.hostname.match( + /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/, + ), ); export function register(config) { - if (process.env.NODE_ENV === "production" && "serviceWorker" in navigator) { + if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { // The URL constructor is available in all browsers that support SW. const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); if (publicUrl.origin !== window.location.origin) { @@ -31,7 +31,7 @@ export function register(config) { return; } - window.addEventListener("load", () => { + window.addEventListener('load', () => { const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; if (isLocalhost) { @@ -42,8 +42,8 @@ export function register(config) { // service worker/PWA documentation. navigator.serviceWorker.ready.then(() => { console.log( - "This web app is being served cache-first by a service " + - "worker. To learn more, visit https://bit.ly/CRA-PWA" + 'This web app is being served cache-first by a service ' + + 'worker. To learn more, visit https://bit.ly/CRA-PWA', ); }); } else { @@ -64,14 +64,14 @@ function registerValidSW(swUrl, config) { return; } installingWorker.onstatechange = () => { - if (installingWorker.state === "installed") { + if (installingWorker.state === 'installed') { if (navigator.serviceWorker.controller) { // At this point, the updated precached content has been fetched, // but the previous service worker will still serve the older // content until all client tabs are closed. console.log( - "New content is available and will be used when all " + - "tabs for this page are closed. See https://bit.ly/CRA-PWA." + 'New content is available and will be used when all ' + + 'tabs for this page are closed. See https://bit.ly/CRA-PWA.', ); // Execute callback @@ -82,7 +82,7 @@ function registerValidSW(swUrl, config) { // At this point, everything has been precached. // It's the perfect time to display a // "Content is cached for offline use." message. - console.log("Content is cached for offline use."); + console.log('Content is cached for offline use.'); // Execute callback if (config && config.onSuccess) { @@ -94,21 +94,21 @@ function registerValidSW(swUrl, config) { }; }) .catch((error) => { - console.error("Error during service worker registration:", error); + console.error('Error during service worker registration:', error); }); } function checkValidServiceWorker(swUrl, config) { // Check if the service worker can be found. If it can't reload the page. fetch(swUrl, { - headers: { "Service-Worker": "script" }, + headers: { 'Service-Worker': 'script' }, }) .then((response) => { // Ensure service worker exists, and that we really are getting a JS file. - const contentType = response.headers.get("content-type"); + const contentType = response.headers.get('content-type'); if ( - response.status === 404 || - (contentType != null && contentType.indexOf("javascript") === -1) + response.status === 404 + || (contentType != null && contentType.indexOf('javascript') === -1) ) { // No service worker found. Probably a different app. Reload the page. navigator.serviceWorker.ready.then((registration) => { @@ -123,13 +123,13 @@ function checkValidServiceWorker(swUrl, config) { }) .catch(() => { console.log( - "No internet connection found. App is running in offline mode." + 'No internet connection found. App is running in offline mode.', ); }); } export function unregister() { - if ("serviceWorker" in navigator) { + if ('serviceWorker' in navigator) { navigator.serviceWorker.ready .then((registration) => { registration.unregister(); diff --git a/smart-hut/src/setupTests.js b/smart-hut/src/setupTests.js index 5fdf001..74b1a27 100644 --- a/smart-hut/src/setupTests.js +++ b/smart-hut/src/setupTests.js @@ -2,4 +2,4 @@ // allows you to do things like: // expect(element).toHaveTextContent(/react/i) // learn more: https://github.com/testing-library/jest-dom -import "@testing-library/jest-dom/extend-expect"; +import '@testing-library/jest-dom/extend-expect'; diff --git a/smart-hut/src/store.js b/smart-hut/src/store.js index ecfa94a..60b9e9f 100644 --- a/smart-hut/src/store.js +++ b/smart-hut/src/store.js @@ -1,11 +1,12 @@ -import { createStore, applyMiddleware, compose } from "redux"; -import thunk from "redux-thunk"; -import update from "immutability-helper"; -import reduxWebSocket, { connect } from "@giantmachines/redux-websocket"; -import { socketURL } from "./endpoint"; +import { createStore, applyMiddleware, compose } from 'redux'; +import thunk from 'redux-thunk'; +import update from 'immutability-helper'; +import reduxWebSocket, { connect } from '@giantmachines/redux-websocket'; +import { socketURL } from './endpoint'; function reducer(previousState, action) { - let newState, change; + let newState; let +change; const createOrUpdateRoom = (room) => { if (!newState.rooms[room.id]) { @@ -89,21 +90,21 @@ function reducer(previousState, action) { }; switch (action.type) { - case "LOGIN_UPDATE": + case 'LOGIN_UPDATE': newState = update(previousState, { login: { $set: action.login } }); break; - case "USER_INFO_UPDATE": + case 'USER_INFO_UPDATE': newState = update(previousState, { userInfo: { $set: action.userInfo }, }); break; - case "ROOMS_UPDATE": + case 'ROOMS_UPDATE': newState = previousState; for (const room of action.rooms) { createOrUpdateRoom(room); } break; - case "HOST_ROOMS_UPDATE": + case 'HOST_ROOMS_UPDATE': change = { hostRooms: { [action.hostId]: { $set: {} }, @@ -117,13 +118,13 @@ function reducer(previousState, action) { newState = update(previousState, change); break; - case "SCENES_UPDATE": + case 'SCENES_UPDATE': newState = previousState; for (const scene of action.scenes) { createOrUpdateScene(scene); } break; - case "HOST_SCENES_UPDATE": + case 'HOST_SCENES_UPDATE': change = { hostScenes: { [action.hostId]: { $set: action.scenes }, // stored as array @@ -132,8 +133,8 @@ function reducer(previousState, action) { newState = update(previousState, change); break; - case "STATES_UPDATE": - //console.log(action.sceneStates); + case 'STATES_UPDATE': + // console.log(action.sceneStates); change = null; // if scene is given, delete all sceneStates in that scene @@ -169,11 +170,9 @@ function reducer(previousState, action) { } if (sceneState.sceneId in newState.scenes) { - change.scenes[sceneState.sceneId] = - change.scenes[sceneState.sceneId] || {}; - change.scenes[sceneState.sceneId].sceneStates = - change.scenes[sceneState.sceneId].sceneStates || {}; - const sceneStates = change.scenes[sceneState.sceneId].sceneStates; + change.scenes[sceneState.sceneId] = change.scenes[sceneState.sceneId] || {}; + change.scenes[sceneState.sceneId].sceneStates = change.scenes[sceneState.sceneId].sceneStates || {}; + const { sceneStates } = change.scenes[sceneState.sceneId]; sceneStates.$add = sceneStates.$add || []; sceneStates.$add.push(sceneState.id); } else { @@ -186,7 +185,7 @@ function reducer(previousState, action) { }; } else { change.pendingJoins.scenes[sceneState.sceneId].$set.add( - sceneState.id + sceneState.id, ); } } @@ -195,7 +194,7 @@ function reducer(previousState, action) { newState = update(newState, change); break; - case "DEVICES_UPDATE": + case 'DEVICES_UPDATE': change = null; // if room is given, delete all devices in that room @@ -225,7 +224,7 @@ function reducer(previousState, action) { for (const device of action.devices) { if (!previousState.devices[device.id]) continue; change.devices.$unset.push(device.id); - const roomId = previousState.devices[device.id].roomId; + const { roomId } = previousState.devices[device.id]; if (roomId in previousState.rooms) { change.rooms[roomId] = change.rooms[roomId] || { @@ -265,9 +264,8 @@ function reducer(previousState, action) { if (device.roomId in newState.rooms) { change.rooms[device.roomId] = change.rooms[device.roomId] || {}; - change.rooms[device.roomId].devices = - change.rooms[device.roomId].devices || {}; - const devices = change.rooms[device.roomId].devices; + change.rooms[device.roomId].devices = change.rooms[device.roomId].devices || {}; + const { devices } = change.rooms[device.roomId]; devices.$add = devices.$add || []; devices.$add.push(device.id); } else { @@ -286,14 +284,13 @@ function reducer(previousState, action) { newState = update(newState, change); break; - case "HOST_DEVICES_UPDATE": + case 'HOST_DEVICES_UPDATE': newState = action.partial ? previousState : update(previousState, { hostDevices: { [action.hostId]: { $set: {} } }, }); - newState.hostDevices[action.hostId] = - newState.hostDevices[action.hostId] || {}; + newState.hostDevices[action.hostId] = newState.hostDevices[action.hostId] || {}; change = { hostDevices: { [action.hostId]: {}, @@ -307,7 +304,7 @@ function reducer(previousState, action) { newState = update(newState, change); break; - case "AUTOMATION_UPDATE": + case 'AUTOMATION_UPDATE': const automations = {}; for (const automation of action.automations) { automations[automation.id] = automation; @@ -318,15 +315,15 @@ function reducer(previousState, action) { }; newState = update(previousState, change); break; - case "ROOM_SAVE": + case 'ROOM_SAVE': newState = previousState; createOrUpdateRoom(action.room); break; - case "SCENE_SAVE": + case 'SCENE_SAVE': newState = previousState; createOrUpdateScene(action.scene); break; - case "DEVICE_SAVE": + case 'DEVICE_SAVE': change = { devices: { [action.device.id]: { $set: action.device } }, }; @@ -350,7 +347,7 @@ function reducer(previousState, action) { } newState = update(previousState, change); break; - case "HOST_DEVICE_SAVE": + case 'HOST_DEVICE_SAVE': change = { hostDevices: { [action.hostId]: { @@ -362,7 +359,7 @@ function reducer(previousState, action) { }; newState = update(previousState, change); break; - case "HOST_DEVICES_DELETE": + case 'HOST_DEVICES_DELETE': change = { hostDevices: { [action.hostId]: { @@ -373,7 +370,7 @@ function reducer(previousState, action) { newState = update(previousState, change); break; - case "AUTOMATION_SAVE": + case 'AUTOMATION_SAVE': change = { automations: { [action.automation.id]: { $set: action.automation }, @@ -384,7 +381,7 @@ function reducer(previousState, action) { break; - case "STATE_SAVE": + case 'STATE_SAVE': change = { sceneStates: { [action.sceneState.id]: { $set: action.sceneState }, @@ -410,7 +407,7 @@ function reducer(previousState, action) { } newState = update(previousState, change); break; - case "ROOM_DELETE": + case 'ROOM_DELETE': if (!(action.roomId in previousState.rooms)) { console.warn(`Room to delete ${action.roomId} does not exist`); break; @@ -434,14 +431,14 @@ function reducer(previousState, action) { newState = update(previousState, change); break; - case "AUTOMATION_DELETE": + case 'AUTOMATION_DELETE': change = { automations: { $unset: [action.id] }, }; newState = update(previousState, change); break; - case "SCENE_DELETE": + case 'SCENE_DELETE': if (!(action.sceneId in previousState.scenes)) { console.warn(`Scene to delete ${action.sceneId} does not exist`); break; @@ -464,7 +461,7 @@ function reducer(previousState, action) { newState = update(previousState, change); break; - case "STATE_DELETE": + case 'STATE_DELETE': if (!(action.stateId in previousState.sceneStates)) { console.warn(`State to delete ${action.stateId} does not exist`); break; @@ -487,7 +484,7 @@ function reducer(previousState, action) { newState = update(previousState, change); break; - case "DEVICE_DELETE": + case 'DEVICE_DELETE': if (!(action.deviceId in previousState.devices)) { console.warn(`Device to delete ${action.deviceId} does not exist`); break; @@ -507,10 +504,10 @@ function reducer(previousState, action) { newState = update(previousState, change); break; - case "LOGOUT": + case 'LOGOUT': newState = update(initState, {}); break; - case "SET_ACTIVE": + case 'SET_ACTIVE': newState = update(previousState, { active: { [action.key]: { @@ -519,17 +516,16 @@ function reducer(previousState, action) { }, }); break; - case "REDUX_WEBSOCKET::MESSAGE": + case 'REDUX_WEBSOCKET::MESSAGE': const allDevices = JSON.parse(action.payload.message); const devices = allDevices.filter( - (d) => - (d.fromHostId === null || d.fromHostId === undefined) && !d.deleted + (d) => (d.fromHostId === null || d.fromHostId === undefined) && !d.deleted, ); const hostDevicesMapByHostId = allDevices .filter((d) => d.fromHostId) .reduce((a, e) => { const hostId = e.fromHostId; - //delete e.fromHostId; + // delete e.fromHostId; a[hostId] = a[hostId] || { updated: [], deletedIds: [] }; if (e.deleted) { a[hostId].deletedIds.push(e.id); @@ -539,21 +535,22 @@ function reducer(previousState, action) { return a; }, {}); newState = reducer(previousState, { - type: "DEVICES_UPDATE", + type: 'DEVICES_UPDATE', partial: true, devices, }); for (const hostId in hostDevicesMapByHostId) { - if (hostDevicesMapByHostId[hostId].updated.length > 0) - newState = reducer(newState, { - type: "HOST_DEVICES_UPDATE", + if (hostDevicesMapByHostId[hostId].updated.length > 0) { + newState = reducer(newState, { + type: 'HOST_DEVICES_UPDATE', devices: hostDevicesMapByHostId[hostId].updated, partial: true, hostId, }); +} if (hostDevicesMapByHostId[hostId].deletedIds.length > 0) { newState = reducer(newState, { - type: "HOST_DEVICES_DELETE", + type: 'HOST_DEVICES_DELETE', deviceIds: hostDevicesMapByHostId[hostId].deletedIds, partial: true, hostId, @@ -561,7 +558,7 @@ function reducer(previousState, action) { } } break; - case "HG_UPDATE": + case 'HG_UPDATE': newState = update(previousState, { [action.key]: { $set: action.value }, }); @@ -581,7 +578,7 @@ const initState = { }, active: { activeRoom: -1, - activeTab: "Devices", + activeTab: 'Devices', activeScene: -1, activeAutomation: -1, activeHost: -1, @@ -613,8 +610,8 @@ const initState = { }; function createSmartHutStore() { - const token = localStorage.getItem("token"); - const exp = localStorage.getItem("exp"); + const token = localStorage.getItem('token'); + const exp = localStorage.getItem('exp'); const initialState = update(initState, { login: { @@ -624,15 +621,15 @@ function createSmartHutStore() { }); if (!initialState.login.loggedIn) { - localStorage.removeItem("token"); - localStorage.removeItem("exp"); + localStorage.removeItem('token'); + localStorage.removeItem('exp'); initialState.login.token = null; } const store = createStore( reducer, initialState, - compose(applyMiddleware(thunk), applyMiddleware(reduxWebSocket())) + compose(applyMiddleware(thunk), applyMiddleware(reduxWebSocket())), ); if (initialState.login.loggedIn) { store.dispatch(connect(socketURL(token))); diff --git a/smart-hut/src/storeActions.js b/smart-hut/src/storeActions.js index 6a4e4e4..77ca199 100644 --- a/smart-hut/src/storeActions.js +++ b/smart-hut/src/storeActions.js @@ -1,134 +1,134 @@ const actions = { loginSuccess: (token) => ({ - type: "LOGIN_UPDATE", + type: 'LOGIN_UPDATE', login: { loggedIn: true, token, }, }), logout: () => ({ - type: "LOGOUT", + type: 'LOGOUT', }), userInfoUpdate: (userInfo) => ({ - type: "USER_INFO_UPDATE", + type: 'USER_INFO_UPDATE', userInfo, }), roomSave: (room) => ({ - type: "ROOM_SAVE", + type: 'ROOM_SAVE', room, }), sceneSave: (scene) => ({ - type: "SCENE_SAVE", + type: 'SCENE_SAVE', scene, }), deviceSave: (device) => ({ - type: "DEVICE_SAVE", + type: 'DEVICE_SAVE', device, }), hostDeviceSave: (hostId, device) => ({ - type: "HOST_DEVICE_SAVE", + type: 'HOST_DEVICE_SAVE', hostId, device, }), triggerSave: (automation) => ({ - type: "TRIGGER_SAVE", + type: 'TRIGGER_SAVE', automation, }), scenePrioritySave: (automation) => ({ - type: "SCENE_PRIORITY_SAVE", + type: 'SCENE_PRIORITY_SAVE', automation, }), automationSave: (automation) => ({ - type: "AUTOMATION_SAVE", + type: 'AUTOMATION_SAVE', automation, }), automationsUpdate: (automations) => ({ - type: "AUTOMATION_UPDATE", + type: 'AUTOMATION_UPDATE', automations, }), stateSave: (sceneState) => ({ - type: "STATE_SAVE", + type: 'STATE_SAVE', sceneState, }), statesUpdate: (sceneId, sceneStates) => ({ - type: "STATES_UPDATE", + type: 'STATES_UPDATE', sceneId, sceneStates, }), devicesUpdate: (roomId, devices, partial = false) => ({ - type: "DEVICES_UPDATE", + type: 'DEVICES_UPDATE', roomId, devices, partial, }), hostDevicesUpdate: (hostId, devices, partial = false) => ({ - type: "HOST_DEVICES_UPDATE", + type: 'HOST_DEVICES_UPDATE', hostId, partial, devices, }), stateDelete: (stateId) => ({ - type: "STATE_DELETE", + type: 'STATE_DELETE', stateId, }), deviceOperationUpdate: (devices) => ({ - type: "DEVICES_UPDATE", + type: 'DEVICES_UPDATE', devices, partial: true, }), roomsUpdate: (rooms) => ({ - type: "ROOMS_UPDATE", + type: 'ROOMS_UPDATE', rooms, }), hostRoomsUpdate: (hostId, rooms) => ({ - type: "HOST_ROOMS_UPDATE", + type: 'HOST_ROOMS_UPDATE', hostId, rooms, }), roomDelete: (roomId) => ({ - type: "ROOM_DELETE", + type: 'ROOM_DELETE', roomId, }), automationDelete: (id) => ({ - type: "AUTOMATION_DELETE", + type: 'AUTOMATION_DELETE', id, }), sceneDelete: (sceneId) => ({ - type: "SCENE_DELETE", + type: 'SCENE_DELETE', sceneId, }), scenesUpdate: (scenes) => ({ - type: "SCENES_UPDATE", + type: 'SCENES_UPDATE', scenes, }), hostScenesUpdate: (hostId, scenes) => ({ - type: "HOST_SCENES_UPDATE", + type: 'HOST_SCENES_UPDATE', hostId, scenes, }), deviceDelete: (deviceId) => ({ - type: "DEVICE_DELETE", + type: 'DEVICE_DELETE', deviceId, }), hostsUpdate: (hosts) => ({ - type: "HG_UPDATE", - key: "hosts", + type: 'HG_UPDATE', + key: 'hosts', value: hosts, }), guestsUpdate: (hosts) => ({ - type: "HG_UPDATE", - key: "guests", + type: 'HG_UPDATE', + key: 'guests', value: hosts, }), getHostDevices: (host) => ({ - type: "GET_HOST_DEVICES", + type: 'GET_HOST_DEVICES', host, }), guestUpdate: (guests) => ({ - type: "HG_UPDATE", - key: "guests", + type: 'HG_UPDATE', + key: 'guests', value: guests, }), }; @@ -136,23 +136,23 @@ const actions = { export const appActions = { // -1 for home view setActiveRoom: (activeRoom = -1) => ({ - type: "SET_ACTIVE", - key: "activeRoom", + type: 'SET_ACTIVE', + key: 'activeRoom', value: activeRoom, }), setActiveTab: (activeTab) => ({ - type: "SET_ACTIVE", - key: "activeTab", + type: 'SET_ACTIVE', + key: 'activeTab', value: activeTab, }), setActiveScene: (activeScene = -1) => ({ - type: "SET_ACTIVE", - key: "activeScene", + type: 'SET_ACTIVE', + key: 'activeScene', value: activeScene, }), setActiveHost: (activeHost = -1) => ({ - type: "SET_ACTIVE", - key: "activeHost", + type: 'SET_ACTIVE', + key: 'activeHost', value: activeHost, }), }; diff --git a/smart-hut/src/views/Confirm.js b/smart-hut/src/views/Confirm.js new file mode 100644 index 0000000..2003fdf --- /dev/null +++ b/smart-hut/src/views/Confirm.js @@ -0,0 +1,39 @@ +import React, { Component } from 'react'; +import { + Image, + Grid, + Button, + Icon, + Header, + Container, +} from 'semantic-ui-react'; + +export default class Confirm extends Component { + render() { + return ( + <> + + + +
+ + {' '} +Congratulation! +
+ +

{this.props.msg}

+
+
+
+ + ); + } +} diff --git a/smart-hut/src/views/ConfirmForgotPassword.js b/smart-hut/src/views/ConfirmForgotPassword.js index 1f4d0ec..7459df7 100644 --- a/smart-hut/src/views/ConfirmForgotPassword.js +++ b/smart-hut/src/views/ConfirmForgotPassword.js @@ -1,40 +1,9 @@ -import React, { Component } from "react"; -import { - Image, - Grid, - Button, - Icon, - Header, - Container, -} from "semantic-ui-react"; +import React, { Component } from 'react'; +import Confirm from './Confirm'; +const msg = "An E-mail has been sent to your address, confirm your registration by following the enclosed link. If you don't find the E-mail please check also the spam folder."; export default class ConfirmForgotPasswrod extends Component { render() { - return ( - - - - -
- Link has been sent! -
- -

- An E-mail has been sent to your address, please follow the - instructions to create a new password. If you don't find the - E-mail please check also the spam folder. -

-
-
-
-
- ); + return ; } } diff --git a/smart-hut/src/views/ConfirmRegistration.js b/smart-hut/src/views/ConfirmRegistration.js index 05adedd..8c13b3a 100644 --- a/smart-hut/src/views/ConfirmRegistration.js +++ b/smart-hut/src/views/ConfirmRegistration.js @@ -1,40 +1,9 @@ -import React, { Component } from "react"; -import { - Image, - Grid, - Button, - Icon, - Header, - Container, -} from "semantic-ui-react"; +import React, { Component } from 'react'; +import Confirm from './Confirm'; +const msg = "An E-mail has been sent to your address, confirm your registration by following the enclosed link. If you don't find the E-mail please check also the spam folder."; export default class ConfirmRegistration extends Component { render() { - return ( - - - - -
- Congratulation! -
- -

- An E-mail has been sent to your address, confirm your - registration by following the enclosed link. If you don't find - the E-mail please check also the spam folder. -

-
-
-
-
- ); + return ; } } diff --git a/smart-hut/src/views/ConfirmResetPassword.js b/smart-hut/src/views/ConfirmResetPassword.js index 75c0bdc..798e9af 100644 --- a/smart-hut/src/views/ConfirmResetPassword.js +++ b/smart-hut/src/views/ConfirmResetPassword.js @@ -1,36 +1,10 @@ -import React, { Component } from "react"; -import { - Image, - Grid, - Button, - Icon, - Header, - Container, -} from "semantic-ui-react"; +import React, { Component } from 'react'; +import Confirm from './Confirm'; + +const msg = 'Your password has been successfully reset.'; export default class ConfirmResetPassword extends Component { render() { - return ( - - - - -
- Congratulation! -
- -

Your password has been successfully reset.

-
-
-
-
- ); + return ; } } diff --git a/smart-hut/src/views/Dashboard.js b/smart-hut/src/views/Dashboard.js index cac1298..4cb70b9 100644 --- a/smart-hut/src/views/Dashboard.js +++ b/smart-hut/src/views/Dashboard.js @@ -1,24 +1,26 @@ -import React, { Component } from "react"; -import DevicePanel from "../components/dashboard/DevicePanel"; -import ScenesPanel from "../components/dashboard/ScenesPanel"; -import AutomationsPanel from "../components/dashboard/AutomationsPanel"; -import HostsPanel from "../components/dashboard/HostsPanel"; -import Navbar from "./Navbar"; -import ScenesNavbar from "./ScenesNavbar"; -import HostsNavbar from "./HostsNavbar"; -import MyHeader from "../components/HeaderController"; -import { Grid, Responsive, Button, Menu } from "semantic-ui-react"; -import { mobilePanelStyle } from "../components/dashboard/devices/styleComponents"; +import React, { Component } from 'react'; +import { + Grid, Responsive, Button, Menu, +} from 'semantic-ui-react'; +import { connect } from 'react-redux'; +import DevicePanel from '../components/dashboard/DevicePanel'; +import ScenesPanel from '../components/dashboard/ScenesPanel'; +import AutomationsPanel from '../components/dashboard/AutomationsPanel'; +import HostsPanel from '../components/dashboard/HostsPanel'; +import Navbar from './Navbar'; +import ScenesNavbar from './ScenesNavbar'; +import HostsNavbar from './HostsNavbar'; +import MyHeader from '../components/HeaderController'; +import { mobilePanelStyle } from '../components/dashboard/devices/styleComponents'; -import { RemoteService } from "../remote"; -import { connect } from "react-redux"; -import { appActions } from "../storeActions"; +import { RemoteService } from '../remote'; +import { appActions } from '../storeActions'; class Dashboard extends Component { constructor(props) { super(props); this.state = this.initialState; - this.activeTab = "Devices"; + this.activeTab = 'Devices'; this.selectTab = this.selectTab.bind(this); } @@ -47,13 +49,13 @@ class Dashboard extends Component { renderTab(tab) { switch (tab) { - case "Devices": + case 'Devices': return ; - case "Scenes": + case 'Scenes': return ; - case "Automations": + case 'Automations': return ; - case "Hosts": + case 'Hosts': return ; default: return

ERROR

; @@ -62,11 +64,11 @@ class Dashboard extends Component { renderNavbar(tab) { switch (tab) { - case "Devices": + case 'Devices': return ; - case "Scenes": + case 'Scenes': return ; - case "Hosts": + case 'Hosts': return ; default: return

ERROR

; @@ -74,21 +76,21 @@ class Dashboard extends Component { } get hasNavbar() { - return this.state.activeTab !== "Automations"; + return this.state.activeTab !== 'Automations'; } render() { // needed to correctly assign the background image - //in case a room has one. + // in case a room has one. let backgroundImageHelper; - if (this.activeTab === "Devices") { + if (this.activeTab === 'Devices') { backgroundImageHelper = this.props.backgroundImage; } else { backgroundImageHelper = null; } - //console.log("helper is",helper) + // console.log("helper is",helper) return ( -
+
@@ -102,25 +104,25 @@ class Dashboard extends Component {
@@ -134,13 +136,13 @@ class Dashboard extends Component {
{this.renderTab(this.activeTab)} @@ -162,33 +164,33 @@ class Dashboard extends Component { basic name="Devices" content="Devices" - active={this.activeTab === "Devices"} - color={this.activeTab === "Devices" ? "yellow" : "grey"} + active={this.activeTab === 'Devices'} + color={this.activeTab === 'Devices' ? 'yellow' : 'grey'} onClick={this.selectTab} /> ); } diff --git a/smart-hut/src/views/Forgot-pass-reset.js b/smart-hut/src/views/Forgot-pass-reset.js deleted file mode 100644 index 24ed9e6..0000000 --- a/smart-hut/src/views/Forgot-pass-reset.js +++ /dev/null @@ -1,114 +0,0 @@ -import React, { Component } from "react"; -import { - Button, - Form, - Grid, - Header, - Image, - Icon, - Message, -} from "semantic-ui-react"; -import { Redirect } from "react-router-dom"; -import { Forms } from "../remote"; - -export default class ChangePass extends Component { - constructor(props) { - super(props); - this.state = { - password: "", - error: { - state: false, - message: "", - }, - success: false, - }; - this.handleChangePassword = this.handleChangePassword.bind(this); - } - - onChangeHandler = (event) => { - let nam = event.target.name; - let val = event.target.value; - this.setState({ [nam]: val }); - }; - - handleChangePassword = (e) => { - if (this.state.confirmPassword !== this.state.password) { - this.setState({ - error: { - state: true, - message: "Passwords do not match.", - }, - }); - } - - Forms.submitResetPassword(this.props.query.token, this.state.password) - .then(() => this.setState({ success: true })) - .catch((err) => - this.setState({ - error: { state: true, message: err.messages.join(" - ") }, - }) - ); - }; - - render() { - if (this.state.success) { - return ; - } - return ( - - - - -
- Reset Password -
-
- - - - - -
-
-
- ); - } -} diff --git a/smart-hut/src/views/Forgot-password.js b/smart-hut/src/views/Forgot-password.js index 6ebc2a5..47797c4 100644 --- a/smart-hut/src/views/Forgot-password.js +++ b/smart-hut/src/views/Forgot-password.js @@ -1,4 +1,4 @@ -import React, { Component } from "react"; +import React, { Component } from 'react'; import { Button, Form, @@ -7,26 +7,28 @@ import { Image, Icon, Message, -} from "semantic-ui-react"; -import { Redirect } from "react-router-dom"; -import { Forms } from "../remote"; +} from 'semantic-ui-react'; +import { Redirect } from 'react-router-dom'; +import { Forms } from '../remote'; export default class ForgotPass extends Component { constructor(props) { super(props); this.state = { - user: "", + user: '', error: { state: false, message: [], }, success: false, }; + + this.handleChangePassword = this.handleChangePassword.bind(this); } onChangeHandler = (event) => { - let nam = event.target.name; - let val = event.target.value; + const nam = event.target.name; + const val = event.target.value; this.setState({ [nam]: val }); }; @@ -35,33 +37,52 @@ export default class ForgotPass extends Component { Forms.submitInitResetPassword(this.state.user) .then(() => this.setState({ success: true })) - .catch((err) => - this.setState({ error: { state: true, message: err.messages } }) - ); + .catch((err) => this.setState({ error: { state: true, message: err.messages } })); + }; + + handleChangePassword = (e) => { + if (this.state.confirmPassword !== this.state.password) { + this.setState({ + error: { + state: true, + message: 'Passwords do not match.', + }, + }); + } + + Forms.submitResetPassword(this.props.query.token, this.state.password) + .then(() => this.setState({ success: true })) + .catch((err) => this.setState({ + error: { state: true, message: err.messages.join(' - ') }, + })); }; render() { + console.log(this.props); if (this.state.success) { return ; } return ( - -
- Reset Password + + {' '} +Reset Password
@@ -74,27 +95,60 @@ export default class ForgotPass extends Component { ))} - - + {this.props.type === 'FPassword1' ? ( + <> + + + + ) : ( + <> + + + + + )}
-
+ ); } } diff --git a/smart-hut/src/views/ForgotPassword.js b/smart-hut/src/views/ForgotPassword.js deleted file mode 100644 index b6ade3f..0000000 --- a/smart-hut/src/views/ForgotPassword.js +++ /dev/null @@ -1,91 +0,0 @@ -import React, { Component } from "react"; -import { render } from "react-dom"; -import HomeNavbar from "./../components/HomeNavbar"; -import { - Container, - Icon, - Image, - Menu, - Sidebar, - Responsive, - Header, - Divider, - Message, - Grid, -} from "semantic-ui-react"; - -class Paragraph extends Component { - state = { visible: true }; - - handleDismiss = () => { - this.setState({ visible: false }); - - setTimeout(() => { - this.setState({ visible: true }); - }, 2000); - }; - - render() { - if (this.state.visible) { - return ( - - ); - } - - return ( -

-
- The message will return in 2s -
-
-

- ); - } -} - -const MessageReg = () => ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -); - -export default class ForgotPasswrod extends React.Component { - render() { - return ; - } -} diff --git a/smart-hut/src/views/FourOhFour.js b/smart-hut/src/views/FourOhFour.js index 14ae7af..f6f52e8 100644 --- a/smart-hut/src/views/FourOhFour.js +++ b/smart-hut/src/views/FourOhFour.js @@ -1,35 +1,37 @@ -import React, { Component } from "react"; -import { Grid, Button, Segment, Responsive, Image } from "semantic-ui-react"; -import { Link } from "react-router-dom"; -import MyHeader from "../components/HeaderController"; +import React, { Component } from 'react'; +import { + Grid, Button, Segment, Responsive, Image, +} from 'semantic-ui-react'; +import { Link } from 'react-router-dom'; +import MyHeader from '../components/HeaderController'; export default class FourOhFour extends Component { constructor(props) { super(props); const meme = [ - "1.jpeg", - "2.jpeg", - "3.png", - "4.jpeg", - "5.jpeg", - "6.jpg", - "7.jpg", - "8.jpg", - "9.jpeg", - "10.jpg", - "11.jpeg", - "12.gif", - "13.gif", - "14.gif", + '1.jpeg', + '2.jpeg', + '3.png', + '4.jpeg', + '5.jpeg', + '6.jpg', + '7.jpg', + '8.jpg', + '9.jpeg', + '10.jpg', + '11.jpeg', + '12.gif', + '13.gif', + '14.gif', ]; - var arrayNum = Math.floor(Math.random() * 13) + 1; - var path = "img/room_404_meme/" + meme[arrayNum]; + const arrayNum = Math.floor(Math.random() * 13) + 1; + const path = `img/room_404_meme/${meme[arrayNum]}`; this.state = { meme: path }; } render() { return ( -
+
@@ -59,7 +61,7 @@ export default class FourOhFour extends Component { our main room! ...or refresh this page some times...

@@ -103,7 +105,7 @@ export default class FourOhFour extends Component { our main room! ...or refresh this page some times...

diff --git a/smart-hut/src/views/Home.js b/smart-hut/src/views/Home.js index 1347c0a..a846d9b 100644 --- a/smart-hut/src/views/Home.js +++ b/smart-hut/src/views/Home.js @@ -1,6 +1,5 @@ -import PropTypes from "prop-types"; -import React, { Component } from "react"; -import HomeNavbar from "./../components/HomeNavbar"; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; import { Button, Container, @@ -14,13 +13,14 @@ import { Segment, Sidebar, Visibility, -} from "semantic-ui-react"; +} from 'semantic-ui-react'; +import HomeNavbar from '../components/HomeNavbar'; // Heads up! // We using React Static to prerender our docs with server side rendering, this is a quite simple solution. // For more advanced usage please check Responsive docs under the "Usage" section. const getWidth = () => { - const isSSR = typeof window === "undefined"; + const isSSR = typeof window === 'undefined'; return isSSR ? Responsive.onlyTablet.minWidth : window.innerWidth; }; @@ -35,10 +35,10 @@ const HomepageHeading = ({ mobile }) => ( content="SmartHut" inverted style={{ - fontSize: mobile ? "2em" : "4em", - fontWeight: "normal", + fontSize: mobile ? '2em' : '4em', + fontWeight: 'normal', marginBottom: 0, - marginTop: mobile ? "1.5em" : "3em", + marginTop: mobile ? '1.5em' : '3em', }} />
( content="Keep your Home fully Connected" inverted style={{ - fontSize: mobile ? "1.5em" : "1.7em", - fontWeight: "normal", - marginTop: mobile ? "0.5em" : "1.5em", + fontSize: mobile ? '1.5em' : '1.7em', + fontWeight: 'normal', + marginTop: mobile ? '0.5em' : '1.5em', }} /> - @@ -184,20 +186,20 @@ ResponsiveContainer.propTypes = { const Home = () => ( - + -
+
We help you keep your home connected
-

+

In a few steps your home will be fully connected with SmartHut.

-
+
Choose between a wide range of devices
-

+

SmartHut is a leading worldwide company in technology innovation. Explore our website to find the best devices for each room of your home! @@ -210,12 +212,12 @@ const Home = () => ( - + -

+
Have you ever dreamt about a smart home?
-

+

Let us carrying you into the future. With SmartHut, being at home will be a refreshing experience. With just a few clicks, you will be able the set the illumination of your entire place. Follow the intelligent @@ -224,7 +226,7 @@ const Home = () => ( - + diff --git a/smart-hut/src/views/HostsNavbar.js b/smart-hut/src/views/HostsNavbar.js index 0158346..a5d5e52 100644 --- a/smart-hut/src/views/HostsNavbar.js +++ b/smart-hut/src/views/HostsNavbar.js @@ -1,9 +1,11 @@ -import React, { Component } from "react"; -import { Menu, Grid, Responsive, Dropdown } from "semantic-ui-react"; -import HostModal from "../components/HostModal"; -import { RemoteService } from "../remote"; -import { connect } from "react-redux"; -import { appActions } from "../storeActions"; +import React, { Component } from 'react'; +import { + Menu, Grid, Responsive, Dropdown, +} from 'semantic-ui-react'; +import { connect } from 'react-redux'; +import HostModal from '../components/HostModal'; +import { RemoteService } from '../remote'; +import { appActions } from '../storeActions'; class HostsNavbar extends Component { constructor(props) { @@ -29,7 +31,7 @@ class HostsNavbar extends Component { } get activeItemHostsName() { - if (this.props.activeItem === -1) return "Home"; + if (this.props.activeItem === -1) return 'Home'; return this.props.hosts[this.props.activeHost].name; } @@ -37,7 +39,7 @@ class HostsNavbar extends Component { return (

- + Hosts - {Object.values(this.props.hosts).map((e, i) => { - return ( - - {e.name} - - ); - })} + {Object.values(this.props.hosts).map((e, i) => ( + + {e.name} + + ))} @@ -84,19 +84,17 @@ class HostsNavbar extends Component { Hosts - {Object.values(this.props.hosts).map((e, i) => { - return ( - - {e.name} - - ); - })} + {Object.values(this.props.hosts).map((e, i) => ( + + {e.name} + + ))} @@ -106,9 +104,7 @@ class HostsNavbar extends Component { } } -const setActiveHost = (activeHost) => { - return (dispatch) => dispatch(appActions.setActiveHost(activeHost)); -}; +const setActiveHost = (activeHost) => (dispatch) => dispatch(appActions.setActiveHost(activeHost)); const mapStateToProps = (state, _) => ({ hosts: state.hosts, diff --git a/smart-hut/src/views/Instruction.js b/smart-hut/src/views/Instruction.js index 5dd4923..2da364f 100644 --- a/smart-hut/src/views/Instruction.js +++ b/smart-hut/src/views/Instruction.js @@ -1,6 +1,8 @@ -import React, { Component } from "react"; -import HomeNavbar from "./../components/HomeNavbar"; -import { Container, Header, Divider, Grid } from "semantic-ui-react"; +import React, { Component } from 'react'; +import { + Container, Header, Divider, Grid, +} from 'semantic-ui-react'; +import HomeNavbar from '../components/HomeNavbar'; const ContainerExampleAlignment = () => (
diff --git a/smart-hut/src/views/Login.js b/smart-hut/src/views/Login.js index 3a0bf71..a68d499 100644 --- a/smart-hut/src/views/Login.js +++ b/smart-hut/src/views/Login.js @@ -1,4 +1,4 @@ -import React, { Component } from "react"; +import React, { Component } from 'react'; import { Button, Form, @@ -8,19 +8,19 @@ import { Message, Icon, Input, -} from "semantic-ui-react"; -import { RemoteService } from "../remote"; -import { withRouter } from "react-router-dom"; -import { connect } from "react-redux"; +} from 'semantic-ui-react'; +import { withRouter } from 'react-router-dom'; +import { connect } from 'react-redux'; +import { RemoteService } from '../remote'; class Login extends Component { constructor(props) { super(props); this.state = { - user: "", - password: "", + user: '', + password: '', fireRedirect: false, - error: { state: false, message: "" }, + error: { state: false, message: '' }, }; } @@ -29,42 +29,43 @@ class Login extends Component { this.props .login(this.state.user, this.state.password) - .then(() => this.props.history.push("/dashboard")) + .then(() => this.props.history.push('/dashboard')) .catch((err) => { this.setState({ - error: { state: true, message: err.messages.join(" - ") }, + error: { state: true, message: err.messages.join(' - ') }, }); }); }; onChangeHandler = (event) => { - let nam = event.target.name; - let val = event.target.value; + const nam = event.target.name; + const val = event.target.value; this.setState({ [nam]: val }); }; - toggle = () => - this.setState((prevState) => ({ rememberme: !prevState.rememberme })); + toggle = () => this.setState((prevState) => ({ rememberme: !prevState.rememberme })); render() { return ( - -
- Log-in to SmartHut + + {' '} +Log-in to SmartHut
Forgot Password?

- New to us? Sign Up + New to us? + {' '} + Sign Up

- + ); } } @@ -117,6 +120,6 @@ class Login extends Component { const mapStateToProps = (state, _) => ({ loggedIn: state.login.loggedIn }); const LoginContainer = connect( mapStateToProps, - RemoteService + RemoteService, )(withRouter(Login)); export default LoginContainer; diff --git a/smart-hut/src/views/Navbar.js b/smart-hut/src/views/Navbar.js index 3132aca..6927b91 100644 --- a/smart-hut/src/views/Navbar.js +++ b/smart-hut/src/views/Navbar.js @@ -1,4 +1,4 @@ -import React, { Component } from "react"; +import React, { Component } from 'react'; import { Menu, Button, @@ -6,12 +6,12 @@ import { Icon, Responsive, Dropdown, -} from "semantic-ui-react"; -import { editButtonStyle } from "../components/dashboard/devices/styleComponents"; -import RoomModal from "../components/RoomModal"; -import { RemoteService } from "../remote"; -import { connect } from "react-redux"; -import { appActions } from "../storeActions"; +} from 'semantic-ui-react'; +import { connect } from 'react-redux'; +import { editButtonStyle } from '../components/dashboard/devices/styleComponents'; +import RoomModal from '../components/RoomModal'; +import { RemoteService } from '../remote'; +import { appActions } from '../storeActions'; class Navbar extends Component { constructor(props) { @@ -40,7 +40,7 @@ class Navbar extends Component { } get activeItemName() { - if (this.props.activeRoom === -1) return "Home"; + if (this.props.activeRoom === -1) return 'Home'; return this.props.rooms[this.props.activeRoom].name; } @@ -62,7 +62,7 @@ class Navbar extends Component { return (
- +
- Sign-up to SmartHut + + {' '} +Sign-up to SmartHut
@@ -107,10 +108,10 @@ export default class Signup extends Component { iconPosition="left" placeholder="E-mail" onChange={this.onChangeHandler} - /*error={{ + /* error={{ content: 'Please enter a valid email address', pointing: 'below', - }}*/ + }} */ required />
- + ); } } diff --git a/smart-hut/src/views/TestHeaderController.js b/smart-hut/src/views/TestHeaderController.js index 3c8f681..181f65a 100644 --- a/smart-hut/src/views/TestHeaderController.js +++ b/smart-hut/src/views/TestHeaderController.js @@ -1,6 +1,6 @@ -import _ from "lodash"; -import React from "react"; -import HeaderController from "./../components/HeaderController"; +import _ from 'lodash'; +import React from 'react'; +import HeaderController from '../components/HeaderController'; export default class TestHeaderController extends React.Component { render() { diff --git a/smart-hut/src/views/Videocam.js b/smart-hut/src/views/Videocam.js index 45905ec..a294a7c 100644 --- a/smart-hut/src/views/Videocam.js +++ b/smart-hut/src/views/Videocam.js @@ -1,11 +1,12 @@ -import React from "react"; -import VideoTest from "../components/VideoTest"; +import React from 'react'; +import VideoTest from '../components/VideoTest'; export default class TestHeaderController extends React.Component { render() { return (
- ; + +;
); } diff --git a/smart-hut/yarn.lock b/smart-hut/yarn.lock index 583d399..be190fa 100644 --- a/smart-hut/yarn.lock +++ b/smart-hut/yarn.lock @@ -1009,7 +1009,11 @@ dependencies: regenerator-runtime "^0.13.4" +<<<<<<< HEAD "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.4", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +======= +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.4", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 version "7.9.6" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.6.tgz#a9102eb5cadedf3f31d08a9ecf294af7827ea29f" integrity sha512-64AF1xY3OAkFHqOb9s4jpgk1Mm5vDZ4L3acHvAml+53nO1XbXLuDodsVpO4OIUsmemlUHMxNdYMNJmsvOwLrvQ== @@ -1292,6 +1296,7 @@ chalk "^3.0.0" "@material-ui/core@^4.9.4": +<<<<<<< HEAD version "4.9.13" resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-4.9.13.tgz#024962bcdda05139e1bad17a1815bf4088702b15" integrity sha512-GEXNwUr+laZ0N+F1efmHB64Fyg+uQIRXLqbSejg3ebSXgLYNpIjnMOPRfWdu4rICq0dAIgvvNXGkKDMcf3AMpA== @@ -1301,6 +1306,16 @@ "@material-ui/styles" "^4.9.13" "@material-ui/system" "^4.9.13" "@material-ui/types" "^5.0.1" +======= + version "4.9.14" + resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-4.9.14.tgz#4388f82cf94554cd3a935774fc12820f3c607a8a" + integrity sha512-71oYrOpInx5honJ9GzZlygPjmsFhn7Bui61/SWLJsPTkMnfvuZfU3qVqlEHjXyDsnZ+uKmLAIdsrOYnphJxxXw== + dependencies: + "@babel/runtime" "^7.4.4" + "@material-ui/styles" "^4.9.14" + "@material-ui/system" "^4.9.14" + "@material-ui/types" "^5.1.0" +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 "@material-ui/utils" "^4.9.12" "@types/react-transition-group" "^4.2.0" clsx "^1.0.4" @@ -1308,7 +1323,11 @@ popper.js "^1.16.1-lts" prop-types "^15.7.2" react-is "^16.8.0" +<<<<<<< HEAD react-transition-group "^4.3.0" +======= + react-transition-group "^4.4.0" +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 "@material-ui/icons@^4.9.1": version "4.9.1" @@ -1317,6 +1336,7 @@ dependencies: "@babel/runtime" "^7.4.4" +<<<<<<< HEAD "@material-ui/react-transition-group@^4.3.0": version "4.3.0" resolved "https://registry.yarnpkg.com/@material-ui/react-transition-group/-/react-transition-group-4.3.0.tgz#92529142addb5cc179dbf42d246c7e3fe4d6104b" @@ -1335,6 +1355,16 @@ "@babel/runtime" "^7.4.4" "@emotion/hash" "^0.8.0" "@material-ui/types" "^5.0.1" +======= +"@material-ui/styles@^4.9.14": + version "4.9.14" + resolved "https://registry.yarnpkg.com/@material-ui/styles/-/styles-4.9.14.tgz#0a9e93a2bf24e8daa0811411a6f3dabdafbe9a07" + integrity sha512-zecwWKgRU2VzdmutNovPB4s5LKI0TWyZKc/AHfPu9iY8tg4UoLjpa4Rn9roYrRfuTbBZHI6b0BXcQ8zkis0nzQ== + dependencies: + "@babel/runtime" "^7.4.4" + "@emotion/hash" "^0.8.0" + "@material-ui/types" "^5.1.0" +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 "@material-ui/utils" "^4.9.6" clsx "^1.0.4" csstype "^2.5.2" @@ -1349,6 +1379,7 @@ jss-plugin-vendor-prefixer "^10.0.3" prop-types "^15.7.2" +<<<<<<< HEAD "@material-ui/system@^4.9.13": version "4.9.13" resolved "https://registry.yarnpkg.com/@material-ui/system/-/system-4.9.13.tgz#adefb3b6a5ddf0b00fe4e82ac63bb48276e9749d" @@ -1362,6 +1393,22 @@ version "5.0.1" resolved "https://registry.yarnpkg.com/@material-ui/types/-/types-5.0.1.tgz#c4954063cdc196eb327ee62c041368b1aebb6d61" integrity sha512-wURPSY7/3+MAtng3i26g+WKwwNE3HEeqa/trDBR5+zWKmcjO+u9t7Npu/J1r+3dmIa/OeziN9D/18IrBKvKffw== +======= +"@material-ui/system@^4.9.14": + version "4.9.14" + resolved "https://registry.yarnpkg.com/@material-ui/system/-/system-4.9.14.tgz#4b00c48b569340cefb2036d0596b93ac6c587a5f" + integrity sha512-oQbaqfSnNlEkXEziDcJDDIy8pbvwUmZXWNqlmIwDqr/ZdCK8FuV3f4nxikUh7hvClKV2gnQ9djh5CZFTHkZj3w== + dependencies: + "@babel/runtime" "^7.4.4" + "@material-ui/utils" "^4.9.6" + csstype "^2.5.2" + prop-types "^15.7.2" + +"@material-ui/types@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@material-ui/types/-/types-5.1.0.tgz#efa1c7a0b0eaa4c7c87ac0390445f0f88b0d88f2" + integrity sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A== +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 "@material-ui/utils@^4.9.12", "@material-ui/utils@^4.9.6": version "4.9.12" @@ -1623,9 +1670,15 @@ "@types/node" "*" "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": +<<<<<<< HEAD version "2.0.1" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff" integrity sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg== +======= + version "2.0.2" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.2.tgz#79d7a78bad4219f4c03d6557a1c72d9ca6ba62d5" + integrity sha512-rsZg7eL+Xcxsxk2XlBt9KcG8nOp9iYdKCOikY9x2RFJCyOdNj4MKPQty0e8oZr29vVAzKXr1BmR+kZauti3o1w== +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 "@types/istanbul-lib-report@*": version "3.0.0" @@ -1635,9 +1688,15 @@ "@types/istanbul-lib-coverage" "*" "@types/istanbul-reports@^1.1.1": +<<<<<<< HEAD version "1.1.1" resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz#7a8cbf6a406f36c8add871625b278eaf0b0d255a" integrity sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA== +======= + version "1.1.2" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz#e875cc689e47bce549ec81f3df5e6f6f11cfaeb2" + integrity sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw== +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 dependencies: "@types/istanbul-lib-coverage" "*" "@types/istanbul-lib-report" "*" @@ -1653,9 +1712,15 @@ integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== "@types/node@*": +<<<<<<< HEAD version "13.13.5" resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.5.tgz#96ec3b0afafd64a4ccea9107b75bf8489f0e5765" integrity sha512-3ySmiBYJPqgjiHA7oEaIo2Rzz0HrOZ7yrNO5HWyaE5q0lQ3BppDZ3N53Miz8bw2I7gh1/zir2MGVZBvpb1zq9g== +======= + version "14.0.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.1.tgz#5d93e0a099cd0acd5ef3d5bde3c086e1f49ff68c" + integrity sha512-FAYBGwC+W6F9+huFIDtn43cpy7+SzG+atzRiTfdp3inUKL2hXnd4rG8hylJLIh4+hqrQy1P17kvJByE/z825hA== +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 "@types/parse-json@^4.0.0": version "4.0.0" @@ -1673,9 +1738,15 @@ integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw== "@types/react-dom@*": +<<<<<<< HEAD version "16.9.7" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.7.tgz#60844d48ce252d7b2dccf0c7bb937130e27c0cd2" integrity sha512-GHTYhM8/OwUCf254WO5xqR/aqD3gC9kSTLpopWGpQLpnw23jk44RvMHsyUSEplvRJZdHxhJGMMLF0kCPYHPhQA== +======= + version "16.9.8" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.8.tgz#fe4c1e11dfc67155733dfa6aa65108b4971cb423" + integrity sha512-ykkPQ+5nFknnlU6lDd947WbQ6TE3NNzbQAkInC2EKY1qeYdTKp7onFusmYZb+ityzx2YviqT6BXSu+LyWWJwcA== +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 dependencies: "@types/react" "*" @@ -1687,9 +1758,15 @@ "@types/react" "*" "@types/react@*": +<<<<<<< HEAD version "16.9.34" resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.34.tgz#f7d5e331c468f53affed17a8a4d488cd44ea9349" integrity sha512-8AJlYMOfPe1KGLKyHpflCg5z46n0b5DbRfqDksxBLBTUpB75ypDBAO9eCUcjNwE6LCUslwTz00yyG/X9gaVtow== +======= + version "16.9.35" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.35.tgz#a0830d172e8aadd9bd41709ba2281a3124bbd368" + integrity sha512-q0n0SsWcGc8nDqH2GJfWQWUOmZSJhXV64CjVN5SvcNti3TdEaA3AH0D8DwNmMdzjMAC/78tB8nAZIlV8yTz+zQ== +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 dependencies: "@types/prop-types" "*" csstype "^2.2.0" @@ -1728,29 +1805,50 @@ integrity sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw== "@types/yargs@^13.0.0": +<<<<<<< HEAD version "13.0.8" resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-13.0.8.tgz#a38c22def2f1c2068f8971acb3ea734eb3c64a99" integrity sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA== +======= + version "13.0.9" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-13.0.9.tgz#44028e974343c7afcf3960f1a2b1099c39a7b5e1" + integrity sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg== +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 dependencies: "@types/yargs-parser" "*" "@types/yargs@^15.0.0": +<<<<<<< HEAD version "15.0.4" resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.4.tgz#7e5d0f8ca25e9d5849f2ea443cf7c402decd8299" integrity sha512-9T1auFmbPZoxHz0enUFlUuKRy3it01R+hlggyVUMtnCTQRunsQYifnSGb8hET4Xo8yiC0o0r1paW3ud5+rbURg== +======= + version "15.0.5" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.5.tgz#947e9a6561483bdee9adffc983e91a6902af8b79" + integrity sha512-Dk/IDOPtOgubt/IaevIUbTgV7doaKkoorvOyYM2CMwuDyP89bekI7H4xLIwunNYiK9jhCkmc6pUrJk3cj2AB9w== +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 dependencies: "@types/yargs-parser" "*" "@typescript-eslint/eslint-plugin@^2.10.0": +<<<<<<< HEAD version "2.31.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.31.0.tgz#942c921fec5e200b79593c71fafb1e3f57aa2e36" integrity sha512-iIC0Pb8qDaoit+m80Ln/aaeu9zKQdOLF4SHcGLarSeY1gurW6aU4JsOPMjKQwXlw70MvWKZQc6S2NamA8SJ/gg== dependencies: "@typescript-eslint/experimental-utils" "2.31.0" +======= + version "2.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.33.0.tgz#d6c8319d5011b4783bb3d2dadf105d8bdd499bd5" + integrity sha512-QV6P32Btu1sCI/kTqjTNI/8OpCYyvlGjW5vD8MpTIg+HGE5S88HtT1G+880M4bXlvXj/NjsJJG0aGcVh0DdbeQ== + dependencies: + "@typescript-eslint/experimental-utils" "2.33.0" +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 functional-red-black-tree "^1.0.1" regexpp "^3.0.0" tsutils "^3.17.1" +<<<<<<< HEAD "@typescript-eslint/experimental-utils@2.31.0": version "2.31.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.31.0.tgz#a9ec514bf7fd5e5e82bc10dcb6a86d58baae9508" @@ -1758,10 +1856,20 @@ dependencies: "@types/json-schema" "^7.0.3" "@typescript-eslint/typescript-estree" "2.31.0" +======= +"@typescript-eslint/experimental-utils@2.33.0": + version "2.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.33.0.tgz#000f1e5f344fbea1323dc91cc174805d75f99a03" + integrity sha512-qzPM2AuxtMrRq78LwyZa8Qn6gcY8obkIrBs1ehqmQADwkYzTE1Pb4y2W+U3rE/iFkSWcWHG2LS6MJfj6SmHApg== + dependencies: + "@types/json-schema" "^7.0.3" + "@typescript-eslint/typescript-estree" "2.33.0" +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 eslint-scope "^5.0.0" eslint-utils "^2.0.0" "@typescript-eslint/parser@^2.10.0": +<<<<<<< HEAD version "2.31.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.31.0.tgz#beddd4e8efe64995108b229b2862cd5752d40d6f" integrity sha512-uph+w6xUOlyV2DLSC6o+fBDzZ5i7+3/TxAsH4h3eC64tlga57oMb96vVlXoMwjR/nN+xyWlsnxtbDkB46M2EPQ== @@ -1775,13 +1883,32 @@ version "2.31.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.31.0.tgz#ac536c2d46672aa1f27ba0ec2140d53670635cfd" integrity sha512-vxW149bXFXXuBrAak0eKHOzbcu9cvi6iNcJDzEtOkRwGHxJG15chiAQAwhLOsk+86p9GTr/TziYvw+H9kMaIgA== +======= + version "2.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.33.0.tgz#395c0ef229ebef883608f8632a34f0acf02b9bdd" + integrity sha512-AUtmwUUhJoH6yrtxZMHbRUEMsC2G6z5NSxg9KsROOGqNXasM71I8P2NihtumlWTUCRld70vqIZ6Pm4E5PAziEA== + dependencies: + "@types/eslint-visitor-keys" "^1.0.0" + "@typescript-eslint/experimental-utils" "2.33.0" + "@typescript-eslint/typescript-estree" "2.33.0" + eslint-visitor-keys "^1.1.0" + +"@typescript-eslint/typescript-estree@2.33.0": + version "2.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.33.0.tgz#33504c050ccafd38f397a645d4e9534d2eccbb5c" + integrity sha512-d8rY6/yUxb0+mEwTShCQF2zYQdLlqihukNfG9IUlLYz5y1CH6G/9XYbrxQLq3Z14RNvkCC6oe+OcFlyUpwUbkg== +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 dependencies: debug "^4.1.1" eslint-visitor-keys "^1.1.0" glob "^7.1.6" is-glob "^4.0.1" lodash "^4.17.15" +<<<<<<< HEAD semver "^6.3.0" +======= + semver "^7.3.2" +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 tsutils "^3.17.1" "@webassemblyjs/ast@1.8.5": @@ -1982,9 +2109,15 @@ acorn@^6.0.1, acorn@^6.0.4, acorn@^6.2.1: integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== acorn@^7.1.1: +<<<<<<< HEAD version "7.1.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf" integrity sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg== +======= + version "7.2.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.2.0.tgz#17ea7e40d7c8640ff54a694c889c26f31704effe" + integrity sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ== +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 address@1.1.2, address@^1.0.1: version "1.1.2" @@ -2970,9 +3103,15 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001035, caniuse-lite@^1.0.30001039, caniuse-lite@^1.0.30001043: +<<<<<<< HEAD version "1.0.30001054" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001054.tgz#7e82fc42d927980b0ce1426c4813df12381e1a75" integrity sha512-jiKlTI6Ur8Kjfj8z0muGrV6FscpRvefcQVPSuMuXnvRCfExU7zlVLNjmOz1TnurWgUrAY7MMmjyy+uTgIl1XHw== +======= + version "1.0.30001059" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001059.tgz#7bff0613d94b6ea41cb5c864c966d340f8ae6d34" + integrity sha512-oOrc+jPJWooKIA0IrNZ5sYlsXc7NP7KLhNWrSGEJhnfSzDvDJ0zd3i6HXsslExY9bbu+x0FQ5C61LcqmPt7bOQ== +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 capture-exit@^2.0.0: version "2.0.0" @@ -4251,9 +4390,15 @@ ee-first@1.1.1: integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= electron-to-chromium@^1.3.378, electron-to-chromium@^1.3.413: +<<<<<<< HEAD version "1.3.432" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.432.tgz#3bf7b191978ff2e8bc3caf811bb52b1e9f9eab25" integrity sha512-/GdNhXyLP5Yl2322CUX/+Xi8NhdHBqL6lD9VJVKjH6CjoPGakvwZ5CpKgj/oOlbzuWWjOvMjDw1bBuAIRCNTlw== +======= + version "1.3.438" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.438.tgz#56051a9b148842fec813b113e8070ae892a85920" + integrity sha512-QKMcpfA/fCOnqFHsZvKr2haQQb3eXkDI17zT+4hHxJJThyN5nShcG6q1VR8vRiE/2GCJM+0p3PzinYknkdsBYg== +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 elliptic@^6.0.0, elliptic@^6.5.2: version "6.5.2" @@ -4322,9 +4467,15 @@ entities@^1.1.1: integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== entities@^2.0.0: +<<<<<<< HEAD version "2.0.0" resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4" integrity sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw== +======= + version "2.0.2" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.2.tgz#ac74db0bba8d33808bbf36809c3a5c3683531436" + integrity sha512-dmD3AvJQBUjKpcNkoqr+x+IF0SdRtPz9Vk0uTy4yWqga9ibB6s4v++QFWNohjiUGoMlF552ZvNyXDxz5iW0qmw== +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 errno@^0.1.3, errno@~0.1.7: version "0.1.7" @@ -4419,6 +4570,27 @@ escodegen@^1.11.0, escodegen@^1.9.1: optionalDependencies: source-map "~0.6.1" +<<<<<<< HEAD +======= +eslint-config-airbnb-base@^14.1.0: + version "14.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.1.0.tgz#2ba4592dd6843258221d9bff2b6831bd77c874e4" + integrity sha512-+XCcfGyCnbzOnktDVhwsCAx+9DmrzEmuwxyHUJpw+kqBVT744OUBrB09khgFKlK1lshVww6qXGsYPZpavoNjJw== + dependencies: + confusing-browser-globals "^1.0.9" + object.assign "^4.1.0" + object.entries "^1.1.1" + +eslint-config-airbnb@^18.1.0: + version "18.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-18.1.0.tgz#724d7e93dadd2169492ff5363c5aaa779e01257d" + integrity sha512-kZFuQC/MPnH7KJp6v95xsLBf63G/w7YqdPfQ0MUanxQ7zcKUNG8j+sSY860g3NwCBOa62apw16J6pRN+AOgXzw== + dependencies: + eslint-config-airbnb-base "^14.1.0" + object.assign "^4.1.0" + object.entries "^1.1.1" + +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 eslint-config-react-app@^5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/eslint-config-react-app/-/eslint-config-react-app-5.2.1.tgz#698bf7aeee27f0cea0139eaef261c7bf7dd623df" @@ -4453,6 +4625,14 @@ eslint-module-utils@^2.4.1: debug "^2.6.9" pkg-dir "^2.0.0" +<<<<<<< HEAD +======= +eslint-plugin-chai-friendly@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-chai-friendly/-/eslint-plugin-chai-friendly-0.6.0.tgz#54052fab79302ed0cea76ab997351ea4809bfb77" + integrity sha512-Uvvv1gkbRGp/qfN15B0kQyQWg+oFA8buDSqrwmW3egNSk/FpqH2MjQqKOuKwmEL6w4QIQrIjDp+gg6kGGmD3oQ== + +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 eslint-plugin-flowtype@4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-4.6.0.tgz#82b2bd6f21770e0e5deede0228e456cb35308451" @@ -4640,9 +4820,15 @@ etag@~1.8.1: integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= eventemitter3@^4.0.0: +<<<<<<< HEAD version "4.0.0" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb" integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg== +======= + version "4.0.4" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384" + integrity sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ== +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 events@^3.0.0: version "3.1.0" @@ -5654,9 +5840,15 @@ html-escaper@^2.0.0: integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== html-minifier-terser@^5.0.1: +<<<<<<< HEAD version "5.1.0" resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-5.1.0.tgz#95d3df037f04835e9d1a09d1767c0e361a7de916" integrity sha512-tiYE76O1zunboByeB/nFGwUEb263Z3nkNv6Lz2oLC1s6M36bLKfTrjQ+7ssVfaucVllE+N7hh/FbpbxvnIA+LQ== +======= + version "5.1.1" + resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz#922e96f1f3bb60832c2634b79884096389b1f054" + integrity sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg== +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 dependencies: camel-case "^4.1.1" clean-css "^4.2.3" @@ -7520,6 +7712,7 @@ min-indent@^1.0.0: resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.0.tgz#cfc45c37e9ec0d8f0a0ec3dd4ef7f7c3abe39256" integrity sha1-z8RcN+nsDY8KDsPdTvf3w6vjklY= +<<<<<<< HEAD mini-create-react-context@^0.3.0: version "0.3.2" resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.3.2.tgz#79fc598f283dd623da8e088b05db8cddab250189" @@ -7528,6 +7721,15 @@ mini-create-react-context@^0.3.0: "@babel/runtime" "^7.4.0" gud "^1.0.0" tiny-warning "^1.0.2" +======= +mini-create-react-context@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.4.0.tgz#df60501c83151db69e28eac0ef08b4002efab040" + integrity sha512-b0TytUgFSbgFJGzJqXPKCFCBWigAjpjo+Fl7Vf7ZbKRDptszpppKxXH6DRXEABZ/gcEQczeb0iZ7JvL8e8jjCA== + dependencies: + "@babel/runtime" "^7.5.5" + tiny-warning "^1.0.3" +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 mini-css-extract-plugin@0.9.0: version "0.9.0" @@ -7576,16 +7778,28 @@ minipass-flush@^1.0.5: minipass "^3.0.0" minipass-pipeline@^1.2.2: +<<<<<<< HEAD version "1.2.2" resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.2.tgz#3dcb6bb4a546e32969c7ad710f2c79a86abba93a" integrity sha512-3JS5A2DKhD2g0Gg8x3yamO0pj7YeKGwVlDS90pF++kxptwx/F+B//roxf9SqYil5tQo65bijy+dAuAFZmYOouA== +======= + version "1.2.3" + resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.3.tgz#55f7839307d74859d6e8ada9c3ebe72cec216a34" + integrity sha512-cFOknTvng5vqnwOpDsZTWhNll6Jf8o2x+/diplafmxpuIymAjzoOolZG0VvQf3V2HgqzJNhnuKHYp2BqDgz8IQ== +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 dependencies: minipass "^3.0.0" minipass@^3.0.0, minipass@^3.1.1: +<<<<<<< HEAD version "3.1.1" resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.1.tgz#7607ce778472a185ad6d89082aa2070f79cedcd5" integrity sha512-UFqVihv6PQgwj8/yTGvl9kPz7xIAY+R5z6XYjRInD3Gk3qx6QGSD6zEcpeG4Dy/lQnv1J6zv8ejV90hyYIKf3w== +======= + version "3.1.3" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.3.tgz#7d42ff1f39635482e15f9cdb53184deebd5815fd" + integrity sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg== +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 dependencies: yallist "^4.0.0" @@ -9173,9 +9387,15 @@ postcss@7.0.21: supports-color "^6.1.0" postcss@^7, postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.23, postcss@^7.0.27, postcss@^7.0.5, postcss@^7.0.6: +<<<<<<< HEAD version "7.0.29" resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.29.tgz#d3a903872bd52280b83bce38cdc83ce55c06129e" integrity sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw== +======= + version "7.0.30" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.30.tgz#cc9378beffe46a02cbc4506a0477d05fcea9a8e2" + integrity sha512-nu/0m+NtIzoubO+xdAlwZl/u5S5vi/y6BCsoL8D+8IxsD3XvBS8X4YEADNIVXKVuQvduiucnRv+vPIqj56EGMQ== +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 dependencies: chalk "^2.4.2" source-map "^0.6.1" @@ -9595,14 +9815,21 @@ react-round-slider@^1.0.1: react "16.4.2" react-router-dom@^5.1.2: +<<<<<<< HEAD version "5.1.2" resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.1.2.tgz#06701b834352f44d37fbb6311f870f84c76b9c18" integrity sha512-7BPHAaIwWpZS074UKaw1FjVdZBSVWEk8IuDXdB+OkLb8vd/WRQIpA4ag9WQk61aEfQs47wHyjWUoUGGZxpQXew== +======= + version "5.2.0" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.2.0.tgz#9e65a4d0c45e13289e66c7b17c7e175d0ea15662" + integrity sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA== +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 dependencies: "@babel/runtime" "^7.1.2" history "^4.9.0" loose-envify "^1.3.1" prop-types "^15.6.2" +<<<<<<< HEAD react-router "5.1.2" tiny-invariant "^1.0.2" tiny-warning "^1.0.0" @@ -9611,12 +9838,26 @@ react-router@5.1.2, react-router@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.1.2.tgz#6ea51d789cb36a6be1ba5f7c0d48dd9e817d3418" integrity sha512-yjEuMFy1ONK246B+rsa0cUam5OeAQ8pyclRDgpxuSCrAlJ1qN9uZ5IgyKC7gQg0w8OM50NXHEegPh/ks9YuR2A== +======= + react-router "5.2.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + +react-router@5.2.0, react-router@^5.1.2: + version "5.2.0" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.2.0.tgz#424e75641ca8747fbf76e5ecca69781aa37ea293" + integrity sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw== +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 dependencies: "@babel/runtime" "^7.1.2" history "^4.9.0" hoist-non-react-statics "^3.1.0" loose-envify "^1.3.1" +<<<<<<< HEAD mini-create-react-context "^0.3.0" +======= + mini-create-react-context "^0.4.0" +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 path-to-regexp "^1.7.0" prop-types "^15.6.2" react-is "^16.6.0" @@ -9683,7 +9924,11 @@ react-scripts@3.4.0: optionalDependencies: fsevents "2.1.2" +<<<<<<< HEAD react-transition-group@^4.3.0: +======= +react-transition-group@^4.4.0: +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 version "4.4.1" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9" integrity sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw== @@ -10164,9 +10409,15 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: +<<<<<<< HEAD version "5.2.0" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== +======= + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 safe-regex@^1.1.0: version "1.1.0" @@ -10299,6 +10550,14 @@ semver@7.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== +<<<<<<< HEAD +======= +semver@^7.3.2: + version "7.3.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" + integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== + +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 send@0.17.1: version "0.17.1" resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" @@ -10625,9 +10884,15 @@ spdx-exceptions@^2.1.0: integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== spdx-expression-parse@^3.0.0: +<<<<<<< HEAD version "3.0.0" resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== +======= + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 dependencies: spdx-exceptions "^2.1.0" spdx-license-ids "^3.0.0" @@ -11172,7 +11437,11 @@ tiny-invariant@^1.0.2: resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw== +<<<<<<< HEAD tiny-warning@^1.0.0, tiny-warning@^1.0.2: +======= +tiny-warning@^1.0.0, tiny-warning@^1.0.2, tiny-warning@^1.0.3: +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 version "1.0.3" resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== @@ -11274,9 +11543,15 @@ ts-pnp@^1.1.2: integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw== tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0: +<<<<<<< HEAD version "1.11.2" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.2.tgz#9c79d83272c9a7aaf166f73915c9667ecdde3cc9" integrity sha512-tTSkux6IGPnUGUd1XAZHcpu85MOkIl5zX49pO+jfsie3eP0B6pyhOlLXm3cAC6T7s+euSDDUUV+Acop5WmtkVg== +======= + version "1.13.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" + integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q== +>>>>>>> c583c0e73e2d0b08fae52a663ee1bc68247430e7 tsutils@^3.17.1: version "3.17.1"