diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 0000000..862af33
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,94 @@
+{
+ "extends": [
+ "plugin:@typescript-eslint/recommended",
+ "prettier",
+ "plugin:prettier/recommended",
+ "plugin:react/recommended"
+ ],
+ "env": {
+ "browser": true,
+ "commonjs": true,
+ "es6": true,
+ "jest": true,
+ "node": true
+ },
+ "parserOptions": {
+ "sourceType": "module",
+ "ecmaVersion": 2018
+ },
+ "plugins": ["jest"],
+ "rules": {
+ "array-bracket-newline": ["error", "consistent"],
+ "strict": ["error", "safe"],
+ "block-scoped-var": "error",
+ "complexity": "warn",
+ "default-case": "error",
+ "dot-notation": "warn",
+ "eqeqeq": "error",
+ "guard-for-in": "warn",
+ "linebreak-style": ["warn", "unix"],
+ "no-alert": "error",
+ "no-case-declarations": "error",
+ "no-console": "error",
+ "no-constant-condition": "error",
+ "no-continue": "warn",
+ "no-div-regex": "error",
+ "no-empty": "warn",
+ "no-empty-pattern": "error",
+ "no-implicit-coercion": "error",
+ "prefer-arrow-callback": "warn",
+ "no-labels": "error",
+ "no-loop-func": "error",
+ "no-nested-ternary": "warn",
+ "no-script-url": "error",
+ "quote-props": ["error", "as-needed"],
+ "require-yield": "error",
+ "max-nested-callbacks": ["error", 4],
+ "max-depth": ["error", 4],
+ "require-await": "error",
+ "space-before-function-paren": [
+ "error",
+ {
+ "anonymous": "never",
+ "named": "never",
+ "asyncArrow": "always"
+ }
+ ],
+ "padding-line-between-statements": [
+ "error",
+ { "blankLine": "always", "prev": "*", "next": "if" },
+ { "blankLine": "always", "prev": "*", "next": "function" },
+ { "blankLine": "always", "prev": "*", "next": "return" }
+ ],
+ "no-useless-constructor": "off",
+ "no-dupe-class-members": "off",
+ "no-unused-expressions": "off",
+ "curly": ["error", "multi-line"],
+ "object-curly-spacing": ["error", "always"],
+ "comma-dangle": ["error", "always-multiline"],
+ "@typescript-eslint/no-useless-constructor": "error",
+ "@typescript-eslint/no-unused-expressions": "error",
+ "@typescript-eslint/member-delimiter-style": [
+ "error",
+ {
+ "multiline": {
+ "delimiter": "none",
+ "requireLast": true
+ },
+ "singleline": {
+ "delimiter": "semi",
+ "requireLast": false
+ }
+ }
+ ],
+ "react/react-in-jsx-scope": "off" // React v17+ does not need React in scope for JSX elements
+ },
+ "overrides": [
+ {
+ "files": ["*.spec.ts", "*.spec.tsx", "*.test.ts", "*.test.tsx"],
+ "rules": {
+ "max-nested-callbacks": ["error", 10] // allow describe/it/test nesting
+ }
+ }
+ ]
+}
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..5dfd3c7
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,13 @@
+{
+ "printWidth": 120,
+ "tabWidth": 2,
+ "useTabs": false,
+ "bracketSpacing": true,
+ "semi": false,
+ "singleQuote": true,
+ "quoteProps": "as-needed",
+ "trailingComma": "all",
+ "endOfLine": "lf",
+ "arrowParens": "avoid",
+ "proseWrap": "always"
+}
diff --git a/package-lock.json b/package-lock.json
index 3f6722f..0c0e53c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -37,6 +37,12 @@
"@types/react-copy-to-clipboard": "^5.0.0",
"@types/react-dom": "^17.0.3",
"@types/react-syntax-highlighter": "^13.5.0",
+ "eslint": "^7.23.0",
+ "eslint-config-prettier": "^8.1.0",
+ "eslint-plugin-jest": "^24.3.2",
+ "eslint-plugin-prettier": "^3.3.1",
+ "eslint-plugin-react": "^7.23.1",
+ "prettier": "^2.2.1",
"react-scripts": "4.0.3",
"typescript": "^4.2.3",
"web-vitals": "^1.1.1"
@@ -1393,9 +1399,9 @@
"integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow=="
},
"node_modules/@eslint/eslintrc": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz",
- "integrity": "sha512-1JTKgrOKAHVivSvOYw+sJOunkBjUOvjqWk1DPja7ZFhIS2mX/4EgTT8M7eTK9jrKhL/FvXXEbQwIs3pg1xp3dg==",
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz",
+ "integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==",
"dev": true,
"dependencies": {
"ajv": "^6.12.4",
@@ -1405,7 +1411,6 @@
"ignore": "^4.0.6",
"import-fresh": "^3.2.1",
"js-yaml": "^3.13.1",
- "lodash": "^4.17.20",
"minimatch": "^3.0.4",
"strip-json-comments": "^3.1.1"
},
@@ -1423,6 +1428,9 @@
},
"engines": {
"node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@eslint/eslintrc/node_modules/ignore": {
@@ -3174,7 +3182,10 @@
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz",
"integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==",
- "dev": true
+ "dev": true,
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
},
"node_modules/acorn-walk": {
"version": "7.2.0",
@@ -6868,13 +6879,13 @@
}
},
"node_modules/eslint": {
- "version": "7.20.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.20.0.tgz",
- "integrity": "sha512-qGi0CTcOGP2OtCQBgWZlQjcTuP0XkIpYFj25XtRTQSHC+umNnp7UMshr2G8SLsRFYDdAPFeHOsiteadmMH02Yw==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.23.0.tgz",
+ "integrity": "sha512-kqvNVbdkjzpFy0XOszNwjkKzZ+6TcwCQ/h+ozlcIWwaimBBuhlQ4nN6kbiM2L+OjDcznkTJxzYfRFH92sx4a0Q==",
"dev": true,
"dependencies": {
"@babel/code-frame": "7.12.11",
- "@eslint/eslintrc": "^0.3.0",
+ "@eslint/eslintrc": "^0.4.0",
"ajv": "^6.10.0",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.2",
@@ -6887,10 +6898,10 @@
"espree": "^7.3.1",
"esquery": "^1.4.0",
"esutils": "^2.0.2",
- "file-entry-cache": "^6.0.0",
+ "file-entry-cache": "^6.0.1",
"functional-red-black-tree": "^1.0.1",
"glob-parent": "^5.0.0",
- "globals": "^12.1.0",
+ "globals": "^13.6.0",
"ignore": "^4.0.6",
"import-fresh": "^3.0.0",
"imurmurhash": "^0.1.4",
@@ -6898,7 +6909,7 @@
"js-yaml": "^3.13.1",
"json-stable-stringify-without-jsonify": "^1.0.1",
"levn": "^0.4.1",
- "lodash": "^4.17.20",
+ "lodash": "^4.17.21",
"minimatch": "^3.0.4",
"natural-compare": "^1.4.0",
"optionator": "^0.9.1",
@@ -6916,6 +6927,21 @@
},
"engines": {
"node": "^10.12.0 || >=12.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-config-prettier": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.1.0.tgz",
+ "integrity": "sha512-oKMhGv3ihGbCIimCAjqkdzx2Q+jthoqnXSP+d86M9tptwugycmTFdVR4IpLgq2c4SHifbwO90z2fQ8/Aio73yw==",
+ "dev": true,
+ "bin": {
+ "eslint-config-prettier": "bin/cli.js"
+ },
+ "peerDependencies": {
+ "eslint": ">=7.0.0"
}
},
"node_modules/eslint-config-react-app": {
@@ -7128,15 +7154,24 @@
"dev": true
},
"node_modules/eslint-plugin-jest": {
- "version": "24.1.5",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-24.1.5.tgz",
- "integrity": "sha512-FIP3lwC8EzEG+rOs1y96cOJmMVpdFNreoDJv29B5vIupVssRi8zrSY3QadogT0K3h1Y8TMxJ6ZSAzYUmFCp2hg==",
+ "version": "24.3.2",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-24.3.2.tgz",
+ "integrity": "sha512-cicWDr+RvTAOKS3Q/k03+Z3odt3VCiWamNUHWd6QWbVQWcYJyYgUTu8x0mx9GfeDEimawU5kQC+nQ3MFxIM6bw==",
"dev": true,
"dependencies": {
"@typescript-eslint/experimental-utils": "^4.0.1"
},
"engines": {
"node": ">=10"
+ },
+ "peerDependencies": {
+ "@typescript-eslint/eslint-plugin": ">= 4",
+ "eslint": ">=5"
+ },
+ "peerDependenciesMeta": {
+ "@typescript-eslint/eslint-plugin": {
+ "optional": true
+ }
}
},
"node_modules/eslint-plugin-jsx-a11y": {
@@ -7167,26 +7202,51 @@
"integrity": "sha512-117l1H6U4X3Krn+MrzYrL57d5H7siRHWraBs7s+LjRuFK7Fe7hJqnJ0skWlinqsycVLU5YAo6L8CsEYQ0V5prg==",
"dev": true
},
- "node_modules/eslint-plugin-react": {
- "version": "7.22.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.22.0.tgz",
- "integrity": "sha512-p30tuX3VS+NWv9nQot9xIGAHBXR0+xJVaZriEsHoJrASGCJZDJ8JLNM0YqKqI0AKm6Uxaa1VUHoNEibxRCMQHA==",
+ "node_modules/eslint-plugin-prettier": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.1.tgz",
+ "integrity": "sha512-Rq3jkcFY8RYeQLgk2cCwuc0P7SEFwDravPhsJZOQ5N4YI4DSg50NyqJ/9gdZHzQlHf8MvafSesbNJCcP/FF6pQ==",
"dev": true,
"dependencies": {
- "array-includes": "^3.1.1",
- "array.prototype.flatmap": "^1.2.3",
+ "prettier-linter-helpers": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ },
+ "peerDependencies": {
+ "eslint": ">=5.0.0",
+ "prettier": ">=1.13.0"
+ },
+ "peerDependenciesMeta": {
+ "eslint-config-prettier": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-plugin-react": {
+ "version": "7.23.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.23.1.tgz",
+ "integrity": "sha512-MvFGhZjI8Z4HusajmSw0ougGrq3Gs4vT/0WgwksZgf5RrLrRa2oYAw56okU4tZJl8+j7IYNuTM+2RnFEuTSdRQ==",
+ "dev": true,
+ "dependencies": {
+ "array-includes": "^3.1.3",
+ "array.prototype.flatmap": "^1.2.4",
"doctrine": "^2.1.0",
"has": "^1.0.3",
"jsx-ast-utils": "^2.4.1 || ^3.0.0",
- "object.entries": "^1.1.2",
- "object.fromentries": "^2.0.2",
- "object.values": "^1.1.1",
+ "minimatch": "^3.0.4",
+ "object.entries": "^1.1.3",
+ "object.fromentries": "^2.0.4",
+ "object.values": "^1.1.3",
"prop-types": "^15.7.2",
- "resolve": "^1.18.1",
- "string.prototype.matchall": "^4.0.2"
+ "resolve": "^2.0.0-next.3",
+ "string.prototype.matchall": "^4.0.4"
},
"engines": {
"node": ">=4"
+ },
+ "peerDependencies": {
+ "eslint": "^3 || ^4 || ^5 || ^6 || ^7"
}
},
"node_modules/eslint-plugin-react-hooks": {
@@ -7210,6 +7270,19 @@
"node": ">=0.10.0"
}
},
+ "node_modules/eslint-plugin-react/node_modules/resolve": {
+ "version": "2.0.0-next.3",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz",
+ "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==",
+ "dev": true,
+ "dependencies": {
+ "is-core-module": "^2.2.0",
+ "path-parse": "^1.0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/eslint-plugin-testing-library": {
"version": "3.10.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-3.10.1.tgz",
@@ -7398,15 +7471,18 @@
}
},
"node_modules/eslint/node_modules/globals": {
- "version": "12.4.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
- "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==",
+ "version": "13.7.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.7.0.tgz",
+ "integrity": "sha512-Aipsz6ZKRxa/xQkZhNg0qIWXT6x6rD46f6x/PCnBomlttdIyAPak4YD9jTmKpZ72uROSMU87qJtcgpgHaVchiA==",
"dev": true,
"dependencies": {
- "type-fest": "^0.8.1"
+ "type-fest": "^0.20.2"
},
"engines": {
"node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/eslint/node_modules/ignore": {
@@ -7448,6 +7524,18 @@
"node": ">=8"
}
},
+ "node_modules/eslint/node_modules/type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/eslint/node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -7931,6 +8019,12 @@
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
+ "node_modules/fast-diff": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
+ "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
+ "dev": true
+ },
"node_modules/fast-glob": {
"version": "3.2.5",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz",
@@ -12977,18 +13071,21 @@
}
},
"node_modules/object.values": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.2.tgz",
- "integrity": "sha512-MYC0jvJopr8EK6dPBiO8Nb9mvjdypOachO5REGk6MXzujbBrAisKo3HmdEI6kZDL6fC31Mwee/5YbtMebixeag==",
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.3.tgz",
+ "integrity": "sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw==",
"dev": true,
"dependencies": {
- "call-bind": "^1.0.0",
+ "call-bind": "^1.0.2",
"define-properties": "^1.1.3",
- "es-abstract": "^1.18.0-next.1",
+ "es-abstract": "^1.18.0-next.2",
"has": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/obuf": {
@@ -15008,6 +15105,30 @@
"node": ">=0.10.0"
}
},
+ "node_modules/prettier": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz",
+ "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==",
+ "dev": true,
+ "bin": {
+ "prettier": "bin-prettier.js"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/prettier-linter-helpers": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
+ "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
+ "dev": true,
+ "dependencies": {
+ "fast-diff": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
"node_modules/pretty-bytes": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
@@ -18037,6 +18158,9 @@
"dev": true,
"engines": {
"node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/style-loader": {
@@ -22515,9 +22639,9 @@
"integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow=="
},
"@eslint/eslintrc": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz",
- "integrity": "sha512-1JTKgrOKAHVivSvOYw+sJOunkBjUOvjqWk1DPja7ZFhIS2mX/4EgTT8M7eTK9jrKhL/FvXXEbQwIs3pg1xp3dg==",
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz",
+ "integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==",
"dev": true,
"requires": {
"ajv": "^6.12.4",
@@ -22527,7 +22651,6 @@
"ignore": "^4.0.6",
"import-fresh": "^3.2.1",
"js-yaml": "^3.13.1",
- "lodash": "^4.17.20",
"minimatch": "^3.0.4",
"strip-json-comments": "^3.1.1"
},
@@ -24080,7 +24203,8 @@
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz",
"integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"acorn-walk": {
"version": "7.2.0",
@@ -27277,13 +27401,13 @@
}
},
"eslint": {
- "version": "7.20.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.20.0.tgz",
- "integrity": "sha512-qGi0CTcOGP2OtCQBgWZlQjcTuP0XkIpYFj25XtRTQSHC+umNnp7UMshr2G8SLsRFYDdAPFeHOsiteadmMH02Yw==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.23.0.tgz",
+ "integrity": "sha512-kqvNVbdkjzpFy0XOszNwjkKzZ+6TcwCQ/h+ozlcIWwaimBBuhlQ4nN6kbiM2L+OjDcznkTJxzYfRFH92sx4a0Q==",
"dev": true,
"requires": {
"@babel/code-frame": "7.12.11",
- "@eslint/eslintrc": "^0.3.0",
+ "@eslint/eslintrc": "^0.4.0",
"ajv": "^6.10.0",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.2",
@@ -27296,10 +27420,10 @@
"espree": "^7.3.1",
"esquery": "^1.4.0",
"esutils": "^2.0.2",
- "file-entry-cache": "^6.0.0",
+ "file-entry-cache": "^6.0.1",
"functional-red-black-tree": "^1.0.1",
"glob-parent": "^5.0.0",
- "globals": "^12.1.0",
+ "globals": "^13.6.0",
"ignore": "^4.0.6",
"import-fresh": "^3.0.0",
"imurmurhash": "^0.1.4",
@@ -27307,7 +27431,7 @@
"js-yaml": "^3.13.1",
"json-stable-stringify-without-jsonify": "^1.0.1",
"levn": "^0.4.1",
- "lodash": "^4.17.20",
+ "lodash": "^4.17.21",
"minimatch": "^3.0.4",
"natural-compare": "^1.4.0",
"optionator": "^0.9.1",
@@ -27352,12 +27476,12 @@
}
},
"globals": {
- "version": "12.4.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
- "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==",
+ "version": "13.7.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.7.0.tgz",
+ "integrity": "sha512-Aipsz6ZKRxa/xQkZhNg0qIWXT6x6rD46f6x/PCnBomlttdIyAPak4YD9jTmKpZ72uROSMU87qJtcgpgHaVchiA==",
"dev": true,
"requires": {
- "type-fest": "^0.8.1"
+ "type-fest": "^0.20.2"
}
},
"ignore": {
@@ -27387,6 +27511,12 @@
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"dev": true
},
+ "type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "dev": true
+ },
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -27398,6 +27528,13 @@
}
}
},
+ "eslint-config-prettier": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.1.0.tgz",
+ "integrity": "sha512-oKMhGv3ihGbCIimCAjqkdzx2Q+jthoqnXSP+d86M9tptwugycmTFdVR4IpLgq2c4SHifbwO90z2fQ8/Aio73yw==",
+ "dev": true,
+ "requires": {}
+ },
"eslint-config-react-app": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-6.0.0.tgz",
@@ -27578,9 +27715,9 @@
}
},
"eslint-plugin-jest": {
- "version": "24.1.5",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-24.1.5.tgz",
- "integrity": "sha512-FIP3lwC8EzEG+rOs1y96cOJmMVpdFNreoDJv29B5vIupVssRi8zrSY3QadogT0K3h1Y8TMxJ6ZSAzYUmFCp2hg==",
+ "version": "24.3.2",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-24.3.2.tgz",
+ "integrity": "sha512-cicWDr+RvTAOKS3Q/k03+Z3odt3VCiWamNUHWd6QWbVQWcYJyYgUTu8x0mx9GfeDEimawU5kQC+nQ3MFxIM6bw==",
"dev": true,
"requires": {
"@typescript-eslint/experimental-utils": "^4.0.1"
@@ -27613,23 +27750,33 @@
}
}
},
- "eslint-plugin-react": {
- "version": "7.22.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.22.0.tgz",
- "integrity": "sha512-p30tuX3VS+NWv9nQot9xIGAHBXR0+xJVaZriEsHoJrASGCJZDJ8JLNM0YqKqI0AKm6Uxaa1VUHoNEibxRCMQHA==",
+ "eslint-plugin-prettier": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.1.tgz",
+ "integrity": "sha512-Rq3jkcFY8RYeQLgk2cCwuc0P7SEFwDravPhsJZOQ5N4YI4DSg50NyqJ/9gdZHzQlHf8MvafSesbNJCcP/FF6pQ==",
"dev": true,
"requires": {
- "array-includes": "^3.1.1",
- "array.prototype.flatmap": "^1.2.3",
+ "prettier-linter-helpers": "^1.0.0"
+ }
+ },
+ "eslint-plugin-react": {
+ "version": "7.23.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.23.1.tgz",
+ "integrity": "sha512-MvFGhZjI8Z4HusajmSw0ougGrq3Gs4vT/0WgwksZgf5RrLrRa2oYAw56okU4tZJl8+j7IYNuTM+2RnFEuTSdRQ==",
+ "dev": true,
+ "requires": {
+ "array-includes": "^3.1.3",
+ "array.prototype.flatmap": "^1.2.4",
"doctrine": "^2.1.0",
"has": "^1.0.3",
"jsx-ast-utils": "^2.4.1 || ^3.0.0",
- "object.entries": "^1.1.2",
- "object.fromentries": "^2.0.2",
- "object.values": "^1.1.1",
+ "minimatch": "^3.0.4",
+ "object.entries": "^1.1.3",
+ "object.fromentries": "^2.0.4",
+ "object.values": "^1.1.3",
"prop-types": "^15.7.2",
- "resolve": "^1.18.1",
- "string.prototype.matchall": "^4.0.2"
+ "resolve": "^2.0.0-next.3",
+ "string.prototype.matchall": "^4.0.4"
},
"dependencies": {
"doctrine": {
@@ -27640,6 +27787,16 @@
"requires": {
"esutils": "^2.0.2"
}
+ },
+ "resolve": {
+ "version": "2.0.0-next.3",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz",
+ "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==",
+ "dev": true,
+ "requires": {
+ "is-core-module": "^2.2.0",
+ "path-parse": "^1.0.6"
+ }
}
}
},
@@ -28162,6 +28319,12 @@
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
+ "fast-diff": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
+ "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
+ "dev": true
+ },
"fast-glob": {
"version": "3.2.5",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz",
@@ -32413,14 +32576,14 @@
}
},
"object.values": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.2.tgz",
- "integrity": "sha512-MYC0jvJopr8EK6dPBiO8Nb9mvjdypOachO5REGk6MXzujbBrAisKo3HmdEI6kZDL6fC31Mwee/5YbtMebixeag==",
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.3.tgz",
+ "integrity": "sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw==",
"dev": true,
"requires": {
- "call-bind": "^1.0.0",
+ "call-bind": "^1.0.2",
"define-properties": "^1.1.3",
- "es-abstract": "^1.18.0-next.1",
+ "es-abstract": "^1.18.0-next.2",
"has": "^1.0.3"
}
},
@@ -34125,6 +34288,21 @@
"integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=",
"dev": true
},
+ "prettier": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz",
+ "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==",
+ "dev": true
+ },
+ "prettier-linter-helpers": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
+ "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
+ "dev": true,
+ "requires": {
+ "fast-diff": "^1.1.2"
+ }
+ },
"pretty-bytes": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
diff --git a/package.json b/package.json
index ed27904..8c2c70c 100644
--- a/package.json
+++ b/package.json
@@ -50,6 +50,12 @@
"@types/react-copy-to-clipboard": "^5.0.0",
"@types/react-dom": "^17.0.3",
"@types/react-syntax-highlighter": "^13.5.0",
+ "eslint": "^7.23.0",
+ "eslint-config-prettier": "^8.1.0",
+ "eslint-plugin-jest": "^24.3.2",
+ "eslint-plugin-prettier": "^3.3.1",
+ "eslint-plugin-react": "^7.23.1",
+ "prettier": "^2.2.1",
"react-scripts": "4.0.3",
"typescript": "^4.2.3",
"web-vitals": "^1.1.1"
@@ -58,7 +64,9 @@
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
- "eject": "react-scripts eject"
+ "eject": "react-scripts eject",
+ "lint": "eslint --fix \"src/**/*.ts\" \"src/**/*.tsx\" && prettier --write \"src/**/*.ts\" \"src/**/*.tsx\"",
+ "lint:check": "eslint \"src/**/*.ts\" \"src/**/*.tsx\" && prettier --check \"src/**/*.ts\" \"src/**/*.tsx\""
},
"eslintConfig": {
"extends": [
diff --git a/src/@types/react-identicons/index.d.ts b/src/@types/react-identicons/index.d.ts
new file mode 100644
index 0000000..4ee06f6
--- /dev/null
+++ b/src/@types/react-identicons/index.d.ts
@@ -0,0 +1,15 @@
+declare module 'react-identicons' {
+ interface Props {
+ string: string
+ size?: number
+ padding?: number
+ bg?: string
+ fg?: string
+ palette?: string[]
+ count?: number
+ getColor?: () => string
+ }
+
+ const Identicon = (props: Props): JSXElementConstructor => ReactNode
+ export default Identicon
+}
diff --git a/src/App.test.tsx b/src/App.test.tsx
index e6d9874..1485fbb 100644
--- a/src/App.test.tsx
+++ b/src/App.test.tsx
@@ -1,5 +1,5 @@
-import { render } from '@testing-library/react';
-import App from './App';
+import { render } from '@testing-library/react'
+import App from './App'
// Mocks methods that are not implemented in JSDOM
// see https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom
@@ -15,9 +15,9 @@ Object.defineProperty(window, 'matchMedia', {
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
-});
+})
// TODO: this is not a good test and should be removed. Keeping it in to make sure the whole app renders (to be used in CI)
-test('should render the app', async () => {
- render( );
-});
+test('should render the app', () => {
+ render( )
+})
diff --git a/src/App.tsx b/src/App.tsx
index 337ba11..bebdf2c 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,18 +1,18 @@
-import React, { useEffect, useState } from 'react';
-import { BrowserRouter as Router } from 'react-router-dom';
-import './App.css';
+import { ReactElement, useEffect, useState } from 'react'
+import { BrowserRouter as Router } from 'react-router-dom'
+import './App.css'
-import { ThemeProvider } from '@material-ui/styles';
-import CssBaseline from '@material-ui/core/CssBaseline';
+import { ThemeProvider } from '@material-ui/styles'
+import CssBaseline from '@material-ui/core/CssBaseline'
-import BaseRouter from './routes/routes';
-import { lightTheme, darkTheme } from './theme';
+import BaseRouter from './routes/routes'
+import { lightTheme, darkTheme } from './theme'
-function App() {
- const [themeMode, toggleThemeMode] = useState('light');
+const App = (): ReactElement => {
+ const [themeMode, toggleThemeMode] = useState('light')
useEffect(() => {
- let theme = localStorage.getItem('theme')
+ const theme = localStorage.getItem('theme')
if (theme) {
toggleThemeMode(String(localStorage.getItem('theme')))
@@ -21,14 +21,14 @@ function App() {
}
window?.matchMedia('(prefers-color-scheme: dark)')?.addEventListener('change', e => {
- toggleThemeMode(e?.matches ? "dark" : "light")
- });
-
- return () => window?.matchMedia('(prefers-color-scheme: dark)')?.removeEventListener('change', e => {
- toggleThemeMode(e?.matches ? "dark" : "light")
+ toggleThemeMode(e?.matches ? 'dark' : 'light')
})
- }, []);
+ return () =>
+ window?.matchMedia('(prefers-color-scheme: dark)')?.removeEventListener('change', e => {
+ toggleThemeMode(e?.matches ? 'dark' : 'light')
+ })
+ }, [])
return (
@@ -39,7 +39,7 @@ function App() {
- );
+ )
}
-export default App;
+export default App
diff --git a/src/components/CashoutModal.tsx b/src/components/CashoutModal.tsx
index c71758c..0fa5ed5 100644
--- a/src/components/CashoutModal.tsx
+++ b/src/components/CashoutModal.tsx
@@ -1,98 +1,92 @@
-import React from 'react';
-import Button from '@material-ui/core/Button';
-import Input from '@material-ui/core/Input';
-import Dialog from '@material-ui/core/Dialog';
-import DialogActions from '@material-ui/core/DialogActions';
-import DialogContent from '@material-ui/core/DialogContent';
-import DialogContentText from '@material-ui/core/DialogContentText';
-import DialogTitle from '@material-ui/core/DialogTitle';
-import { Snackbar, Container, CircularProgress } from '@material-ui/core';
+import { ReactElement, useState } from 'react'
+import Button from '@material-ui/core/Button'
+import Input from '@material-ui/core/Input'
+import Dialog from '@material-ui/core/Dialog'
+import DialogActions from '@material-ui/core/DialogActions'
+import DialogContent from '@material-ui/core/DialogContent'
+import DialogContentText from '@material-ui/core/DialogContentText'
+import DialogTitle from '@material-ui/core/DialogTitle'
+import { Snackbar, Container, CircularProgress } from '@material-ui/core'
-import { beeDebugApi } from '../services/bee';
+import { beeDebugApi } from '../services/bee'
-import EthereumAddress from './EthereumAddress';
+import EthereumAddress from './EthereumAddress'
-export default function DepositModal() {
- const [open, setOpen] = React.useState(false);
- const [peerId, setPeerId] = React.useState('');
- const [loadingCashout, setLoadingCashout] = React.useState(false);
- const [showToast, setToastVisibility] = React.useState(false);
- const [toastContent, setToastContent] = React.useState(null);
+export default function DepositModal(): ReactElement {
+ const [open, setOpen] = useState(false)
+ const [peerId, setPeerId] = useState('')
+ const [loadingCashout, setLoadingCashout] = useState(false)
+ const [showToast, setToastVisibility] = useState(false)
+ const [toastContent, setToastContent] = useState(null)
const handleClickOpen = () => {
- setOpen(true);
- };
+ setOpen(true)
+ }
const handleClose = () => {
- setOpen(false);
- };
+ setOpen(false)
+ }
const handleCashout = () => {
if (peerId) {
- setLoadingCashout(true)
- beeDebugApi.chequebook.peerCashout(peerId)
+ setLoadingCashout(true)
+ beeDebugApi.chequebook
+ .peerCashout(peerId)
.then(res => {
- setOpen(false);
- handleToast(Successfully cashed out cheque. Transaction
-
- )
+ setOpen(false)
+ handleToast(
+
+ Successfully cashed out cheque. Transaction
+
+ ,
+ )
})
- .catch(error => {
+ .catch(() => {
+ // FIXME: handle errors more gracefully
handleToast(Error with cashout )
})
.finally(() => {
setLoadingCashout(false)
})
} else {
- handleToast(Peer Id invalid )
+ handleToast(Peer Id invalid )
}
- };
+ }
const handleToast = (text: JSX.Element) => {
setToastContent(text)
- setToastVisibility(true);
- setTimeout(
- () => setToastVisibility(false),
- 7000
- );
- };
+ setToastVisibility(true)
+ setTimeout(() => setToastVisibility(false), 7000)
+ }
return (
-
+
Cashout
-
+
Cashout Cheque
- {loadingCashout ?
-
-
+ {loadingCashout ? (
+
+
- :
-
-
- Specify the peer Id of the peer you would like to cashout.
-
- setPeerId(e.target.value)}
- />
- }
+ ) : (
+
+
+ Specify the peer Id of the peer you would like to cashout.
+
+ setPeerId(e.target.value)}
+ />
+
+ )}
Cancel
@@ -103,5 +97,5 @@ export default function DepositModal() {
- );
+ )
}
diff --git a/src/components/ClipboardCopy.tsx b/src/components/ClipboardCopy.tsx
index 2712905..6309e4c 100644
--- a/src/components/ClipboardCopy.tsx
+++ b/src/components/ClipboardCopy.tsx
@@ -1,37 +1,28 @@
-import React from 'react';
-import { IconButton, Snackbar } from '@material-ui/core';
-import {CopyToClipboard} from 'react-copy-to-clipboard';
-import { Clipboard } from 'react-feather';
+import { ReactElement, useState } from 'react'
+import { IconButton, Snackbar } from '@material-ui/core'
+import { CopyToClipboard } from 'react-copy-to-clipboard'
+import { Clipboard } from 'react-feather'
-interface IProps {
- value: string,
+interface Props {
+ value: string
}
-export default function ClipboardCopy(props: IProps) {
- const [copied, setCopied] = React.useState(false);
-
- const handleCopy = () => {
- setCopied(true);
- setTimeout(
- () => setCopied(false),
- 3000
- );
- };
-
-
- return (
-
-
-
-
-
-
-
-
- );
+export default function ClipboardCopy(props: Props): ReactElement {
+ const [copied, setCopied] = useState(false)
+
+ const handleCopy = () => {
+ setCopied(true)
+ setTimeout(() => setCopied(false), 3000)
}
+
+ return (
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/src/components/CodeBlock.tsx b/src/components/CodeBlock.tsx
index 7ca2a62..5f5f0d5 100644
--- a/src/components/CodeBlock.tsx
+++ b/src/components/CodeBlock.tsx
@@ -1,22 +1,20 @@
-import SyntaxHighlighter from 'react-syntax-highlighter';
+import type { ReactElement } from 'react'
+import SyntaxHighlighter from 'react-syntax-highlighter'
-interface IProps {
- code: string,
- language: string,
- showLineNumbers?: boolean,
+interface Props {
+ code: string
+ language: string
+ showLineNumbers?: boolean
}
-const CodeBlock = (props: IProps) => {
+const CodeBlock = (props: Props): ReactElement => {
return (
-
-
+
+
{props.code}
-
+
- );
-};
+ )
+}
-export default CodeBlock;
\ No newline at end of file
+export default CodeBlock
diff --git a/src/components/CodeBlockTabs.tsx b/src/components/CodeBlockTabs.tsx
index cd19d5c..f6010d9 100644
--- a/src/components/CodeBlockTabs.tsx
+++ b/src/components/CodeBlockTabs.tsx
@@ -1,158 +1,147 @@
-import React, { useEffect } from 'react';
-import { withStyles, Theme, createStyles } from '@material-ui/core/styles';
-import { Tabs, Tab, Box, Typography } from '@material-ui/core';
-import CodeBlock from './CodeBlock';
+import React, { ReactElement, useEffect } from 'react'
+import { withStyles, Theme, createStyles } from '@material-ui/core/styles'
+import { Tabs, Tab, Box, Typography } from '@material-ui/core'
+import CodeBlock from './CodeBlock'
interface TabPanelProps {
- children?: React.ReactNode;
- index: any;
- value: any;
+ children?: React.ReactNode
+ index: number
+ value: number
}
-interface IProps {
- linux: string;
- mac: string;
- showLineNumbers?: boolean
+interface Props {
+ linux: string
+ mac: string
+ showLineNumbers?: boolean
}
-function a11yProps(index: any) {
- return {
- id: `simple-tab-${index}`,
- 'aria-controls': `simple-tabpanel-${index}`,
- };
+function a11yProps(index: number) {
+ return {
+ id: `simple-tab-${index}`,
+ 'aria-controls': `simple-tabpanel-${index}`,
+ }
}
function getOS() {
- var userAgent = window.navigator.userAgent,
- platform = window.navigator.platform,
- macosPlatforms = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'],
- windowsPlatforms = ['Win32', 'Win64', 'Windows', 'WinCE'],
- iosPlatforms = ['iPhone', 'iPad', 'iPod'],
- os = null;
+ const userAgent = window.navigator.userAgent
+ const platform = window.navigator.platform
+ const macosPlatforms = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K']
+ const windowsPlatforms = ['Win32', 'Win64', 'Windows', 'WinCE']
+ const iosPlatforms = ['iPhone', 'iPad', 'iPod']
- if (macosPlatforms.indexOf(platform) !== -1) {
- os = 'macOS';
- } else if (iosPlatforms.indexOf(platform) !== -1) {
- os = 'iOS';
- } else if (windowsPlatforms.indexOf(platform) !== -1) {
- os = 'windows';
- } else if (/Android/.test(userAgent)) {
- os = 'android';
- } else if (!os && /Linux/.test(platform)) {
- os = 'linux';
+ if (macosPlatforms.includes(platform)) return 'macOS'
+
+ if (iosPlatforms.includes(platform)) return 'iOS'
+
+ if (windowsPlatforms.includes(platform)) return 'windows'
+
+ if (/Android/.test(userAgent)) return 'android'
+
+ if (/Linux/.test(platform)) return 'linux'
+
+ return null
+}
+
+export default function CodeBlockTabs(props: Props): ReactElement {
+ const [value, setValue] = React.useState(0)
+
+ const handleChange = (event: React.ChangeEvent, newValue: number) => {
+ setValue(newValue)
}
- return os;
-}
+ useEffect(() => {
+ const os = getOS()
-export default function CodeBlockTabs(props: IProps) {
- const [value, setValue] = React.useState(0);
+ if (os === 'windows') {
+ setValue(0)
+ } else if (os === 'linux') {
+ setValue(0)
+ } else if (os === 'macOS') {
+ setValue(1)
+ }
+ }, [])
- const handleChange = (event: React.ChangeEvent<{}>, newValue: number) => {
- setValue(newValue);
- };
-
- useEffect(() => {
- let os = getOS()
- if(os === 'windows') {
- setValue(0)
- } else if (os === 'linux') {
- setValue(0)
- } else if (os === 'macOS') {
- setValue(1)
- }
-
- }, [])
-
- function TabPanel(props: TabPanelProps) {
- const { children, value, index, ...other } = props;
-
- return (
-
- {value === index && (
-
- {children}
-
- )}
-
- );
- }
-
- const AntTabs = withStyles({
- root: {
- borderBottom: '1px solid #e8e8e8',
- },
- indicator: {
- backgroundColor: '#3f51b5',
- },
- })(Tabs);
-
- interface StyledTabProps {
- label: string;
- }
-
- const AntTab = withStyles((theme: Theme) =>
- createStyles({
- root: {
- textTransform: 'none',
- minWidth: 72,
- backgroundColor: 'transparent',
- fontWeight: theme.typography.fontWeightRegular,
- marginRight: theme.spacing(4),
- fontFamily: [
- '-apple-system',
- 'BlinkMacSystemFont',
- '"Segoe UI"',
- 'Roboto',
- '"Helvetica Neue"',
- 'Arial',
- 'sans-serif',
- '"Apple Color Emoji"',
- '"Segoe UI Emoji"',
- '"Segoe UI Symbol"',
- ].join(','),
- '&:hover': {
- color: '#3f51b5',
- opacity: 1,
- },
- '&$selected': {
- color: '#3f51b5',
- fontWeight: theme.typography.fontWeightMedium,
- },
- '&:focus': {
- color: '#3f51b5',
- },
- },
- selected: {},
- }),
- )((props: StyledTabProps) => );
+ function TabPanel(props: TabPanelProps) {
+ const { children, value, index, ...other } = props
return (
-
+
+ {value === index && (
+
+ {children}
+
+ )}
+
)
+ }
+
+ const AntTabs = withStyles({
+ root: {
+ borderBottom: '1px solid #e8e8e8',
+ },
+ indicator: {
+ backgroundColor: '#3f51b5',
+ },
+ })(Tabs)
+
+ interface StyledTabProps {
+ label: string
+ }
+
+ const AntTab = withStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ textTransform: 'none',
+ minWidth: 72,
+ backgroundColor: 'transparent',
+ fontWeight: theme.typography.fontWeightRegular,
+ marginRight: theme.spacing(4),
+ fontFamily: [
+ '-apple-system',
+ 'BlinkMacSystemFont',
+ '"Segoe UI"',
+ 'Roboto',
+ '"Helvetica Neue"',
+ 'Arial',
+ 'sans-serif',
+ '"Apple Color Emoji"',
+ '"Segoe UI Emoji"',
+ '"Segoe UI Symbol"',
+ ].join(','),
+ '&:hover': {
+ color: '#3f51b5',
+ opacity: 1,
+ },
+ '&$selected': {
+ color: '#3f51b5',
+ fontWeight: theme.typography.fontWeightMedium,
+ },
+ '&:focus': {
+ color: '#3f51b5',
+ },
+ },
+ selected: {},
+ }),
+ )((props: StyledTabProps) => )
+
+ return (
+
+ )
}
diff --git a/src/components/ConnectToHost.tsx b/src/components/ConnectToHost.tsx
index 9dc1e49..15ddfab 100644
--- a/src/components/ConnectToHost.tsx
+++ b/src/components/ConnectToHost.tsx
@@ -1,48 +1,62 @@
-import React, { useState } from 'react';
-import { TextField, Button, CircularProgress, Container } from '@material-ui/core';
+import React, { ReactElement, useState } from 'react'
+import { TextField, Button, CircularProgress, Container } from '@material-ui/core'
-interface IProps {
- defaultHost?: string,
- hostName: string,
+interface Props {
+ defaultHost?: string
+ hostName: string
}
-export default function ConnectToHost(props: IProps) {
- const [hostInputVisible, toggleHostInputVisibility] = useState(false)
- const [connectingToHost, setConnectingToHost] = useState(false)
- const [host, setHost] = useState('')
+export default function ConnectToHost(props: Props): ReactElement {
+ const [hostInputVisible, toggleHostInputVisibility] = useState(false)
+ const [connectingToHost, setConnectingToHost] = useState(false)
+ const [host, setHost] = useState('')
- const handleNewHostConnection = () => {
- if (host) {
- setConnectingToHost(true)
- sessionStorage.setItem(props.hostName, host)
- toggleHostInputVisibility(!hostInputVisible)
- window.location.reload();
- }
+ const handleNewHostConnection = () => {
+ if (host) {
+ setConnectingToHost(true)
+ sessionStorage.setItem(props.hostName, host)
+ toggleHostInputVisibility(!hostInputVisible)
+ window.location.reload()
}
+ }
- return (
-
- {hostInputVisible ?
-
- setHost(e.target.value)}
- style={{marginRight:'15px', minWidth:'300px'}}
- />
- handleNewHostConnection()} size='small' variant="outlined">Connect
- toggleHostInputVisibility(!hostInputVisible)} size='small'>Cancel
-
- :
- connectingToHost ?
-
-
-
- :
-
toggleHostInputVisibility(!hostInputVisible)} size='small' variant="outlined">Change host
- }
-
- )
+ return (
+
+ {
+ // FIXME: this should be broken up
+ /* eslint-disable no-nested-ternary */
+ hostInputVisible ? (
+
+ setHost(e.target.value)}
+ style={{ marginRight: '15px', minWidth: '300px' }}
+ />
+ handleNewHostConnection()} size="small" variant="outlined">
+ Connect
+
+ toggleHostInputVisibility(!hostInputVisible)}
+ size="small"
+ >
+ Cancel
+
+
+ ) : connectingToHost ? (
+
+
+
+ ) : (
+
toggleHostInputVisibility(!hostInputVisible)} size="small" variant="outlined">
+ Change host
+
+ )
+ /* eslint-enable no-nested-ternary */
+ }
+
+ )
}
diff --git a/src/components/DepositModal.tsx b/src/components/DepositModal.tsx
index 51edb98..ed12007 100644
--- a/src/components/DepositModal.tsx
+++ b/src/components/DepositModal.tsx
@@ -1,77 +1,69 @@
-import React from 'react';
-import Button from '@material-ui/core/Button';
-import Input from '@material-ui/core/Input';
-import Dialog from '@material-ui/core/Dialog';
-import DialogActions from '@material-ui/core/DialogActions';
-import DialogContent from '@material-ui/core/DialogContent';
-import DialogContentText from '@material-ui/core/DialogContentText';
-import DialogTitle from '@material-ui/core/DialogTitle';
-import { Snackbar } from '@material-ui/core';
+import React, { ReactElement } from 'react'
+import Button from '@material-ui/core/Button'
+import Input from '@material-ui/core/Input'
+import Dialog from '@material-ui/core/Dialog'
+import DialogActions from '@material-ui/core/DialogActions'
+import DialogContent from '@material-ui/core/DialogContent'
+import DialogContentText from '@material-ui/core/DialogContentText'
+import DialogTitle from '@material-ui/core/DialogTitle'
+import { Snackbar } from '@material-ui/core'
-import { beeDebugApi } from '../services/bee';
+import { beeDebugApi } from '../services/bee'
-export default function DepositModal() {
- const [open, setOpen] = React.useState(false);
- const [amount, setAmount] = React.useState(BigInt(0));
- const [showToast, setToastVisibility] = React.useState(false);
- const [toastContent, setToastContent] = React.useState('');
+export default function DepositModal(): ReactElement {
+ const [open, setOpen] = React.useState(false)
+ const [amount, setAmount] = React.useState(BigInt(0))
+ const [showToast, setToastVisibility] = React.useState(false)
+ const [toastContent, setToastContent] = React.useState('')
const handleClickOpen = () => {
- setOpen(true);
- };
+ setOpen(true)
+ }
const handleClose = () => {
- setOpen(false);
- };
+ setOpen(false)
+ }
const handleWithdraw = () => {
if (amount > 0) {
- beeDebugApi.chequebook.deposit(amount)
+ beeDebugApi.chequebook
+ .deposit(amount)
.then(res => {
- setOpen(false);
- handleToast(`Successful Deposit. Transaction ${res.transactionHash}`)
+ setOpen(false)
+ handleToast(`Successful Deposit. Transaction ${res.transactionHash}`)
})
- .catch(error => {
- handleToast('Error with Deposit')
+ .catch(() => {
+ handleToast('Error with Deposit')
})
} else {
- handleToast('Must be amount of greater than 0')
+ handleToast('Must be amount of greater than 0')
}
- };
+ }
const handleToast = (text: string) => {
setToastContent(text)
- setToastVisibility(true);
- setTimeout(
- () => setToastVisibility(false),
- 7000
- );
- };
+ setToastVisibility(true)
+ setTimeout(() => setToastVisibility(false), 7000)
+ }
return (
-
+
Deposit
-
+
Deposit Funds
-
- Specify the amount you would like to deposit to your node.
-
+ Specify the amount you would like to deposit to your node.
setAmount(BigInt(e.target.value))}
+ onChange={e => setAmount(BigInt(e.target.value))}
/>
@@ -84,5 +76,5 @@ export default function DepositModal() {
- );
+ )
}
diff --git a/src/components/EthereumAddress.tsx b/src/components/EthereumAddress.tsx
index e34a1ac..e43c6ea 100644
--- a/src/components/EthereumAddress.tsx
+++ b/src/components/EthereumAddress.tsx
@@ -1,54 +1,57 @@
-import React from 'react';
+import { Typography } from '@material-ui/core/'
+import QRCodeModal from './QRCodeModal'
+import ClipboardCopy from './ClipboardCopy'
-import { Typography } from '@material-ui/core/';
-import QRCodeModal from './QRCodeModal';
-import ClipboardCopy from './ClipboardCopy';
+import Identicon from 'react-identicons'
+import { ReactElement } from 'react'
-// @ts-ignore
-import Identicon from 'react-identicons';
-
-interface IProps {
- address: string | undefined,
- network?: string,
- hideBlockie?: boolean,
- transaction?: boolean,
- truncate?: boolean,
+interface Props {
+ address: string | undefined
+ network?: string
+ hideBlockie?: boolean
+ transaction?: boolean
+ truncate?: boolean
}
-export default function EthereumAddress(props: IProps) {
- return (
-
- {props.address ?
-
- {props.hideBlockie ?
- null
- :
-
-
-
}
-
-
-
+export default function EthereumAddress(props: Props): ReactElement {
+ return (
+
+ {props.address ? (
+
+ {props.hideBlockie ? null : (
+
+
- : '-' }
-
- )
+ )}
+
+
+
+
+ ) : (
+ '-'
+ )}
+
+ )
}
diff --git a/src/components/EthereumAddressCard.tsx b/src/components/EthereumAddressCard.tsx
index c08a470..6e0f7e0 100644
--- a/src/components/EthereumAddressCard.tsx
+++ b/src/components/EthereumAddressCard.tsx
@@ -1,14 +1,14 @@
-import React from 'react'
+import React, { ReactElement } from 'react'
-import { Theme, createStyles, makeStyles } from '@material-ui/core/styles';
-import { Card, CardContent, Typography } from '@material-ui/core/';
+import { createStyles, makeStyles } from '@material-ui/core/styles'
+import { Card, CardContent, Typography } from '@material-ui/core/'
-import EthereumAddress from '../components/EthereumAddress';
-import { Skeleton } from '@material-ui/lab';
+import EthereumAddress from '../components/EthereumAddress'
+import { Skeleton } from '@material-ui/lab'
-import type { ChequebookAddressResponse, NodeAddresses } from '@ethersphere/bee-js';
+import type { ChequebookAddressResponse, NodeAddresses } from '@ethersphere/bee-js'
-const useStyles = makeStyles((theme: Theme) =>
+const useStyles = makeStyles(() =>
createStyles({
root: {
display: 'flex',
@@ -22,58 +22,58 @@ const useStyles = makeStyles((theme: Theme) =>
flex: '1 0 auto',
},
status: {
- color: '#fff',
- backgroundColor: '#76a9fa',
- }
+ color: '#fff',
+ backgroundColor: '#76a9fa',
+ },
}),
-);
+)
-interface IProps{
- nodeAddresses: NodeAddresses | null,
- isLoadingNodeAddresses: boolean,
- chequebookAddress: ChequebookAddressResponse | null,
- isLoadingChequebookAddress: boolean,
+interface Props {
+ nodeAddresses: NodeAddresses | null
+ isLoadingNodeAddresses: boolean
+ chequebookAddress: ChequebookAddressResponse | null
+ isLoadingChequebookAddress: boolean
}
-function EthereumAddressCard(props: IProps) {
- const classes = useStyles();
+function EthereumAddressCard(props: Props): ReactElement {
+ const classes = useStyles()
- return (
-
-
- {props.isLoadingNodeAddresses ?
-
-
-
-
- :
-
-
- Ethereum Address
-
-
-
}
- {props.isLoadingChequebookAddress ?
-
-
-
-
- :
-
-
- Chequebook Contract Address
-
-
-
}
-
-
- )
+ return (
+
+
+ {props.isLoadingNodeAddresses ? (
+
+
+
+
+ ) : (
+
+
+
+ Ethereum Address
+
+
+
+
+ )}
+ {props.isLoadingChequebookAddress ? (
+
+
+
+
+ ) : (
+
+
+
+ Chequebook Contract Address
+
+
+
+
+ )}
+
+
+ )
}
export default EthereumAddressCard
diff --git a/src/components/NavBar.tsx b/src/components/NavBar.tsx
index d373171..eb1fee4 100644
--- a/src/components/NavBar.tsx
+++ b/src/components/NavBar.tsx
@@ -1,30 +1,31 @@
-import React, { useState } from 'react';
+import { useState, ReactElement } from 'react'
-import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
-import { Toolbar, Chip, IconButton } from '@material-ui/core/';
+import { createStyles, makeStyles } from '@material-ui/core/styles'
+import { Toolbar, Chip, IconButton } from '@material-ui/core/'
-import { Sun, Moon } from 'react-feather';
+import { Sun, Moon } from 'react-feather'
-const drawerWidth = 240;
+const drawerWidth = 240
-const useStyles = makeStyles((theme: Theme) =>
+const useStyles = makeStyles(() =>
createStyles({
appBar: {
width: `calc(100% - ${drawerWidth}px)`,
marginLeft: drawerWidth,
},
- network: {
-
- }
+ network: {},
}),
-);
+)
+interface Props {
+ themeMode: string
+}
-
-export default function SideBar(props: any) {
- const [darkMode, toggleDarkMode] = useState(false);
+export default function SideBar(props: Props): ReactElement {
+ const [darkMode, toggleDarkMode] = useState(false)
const switchTheme = () => {
- let theme = localStorage.getItem('theme')
+ const theme = localStorage.getItem('theme')
+
if (theme) {
localStorage.setItem('theme', theme === 'light' ? 'dark' : 'light')
} else {
@@ -35,26 +36,17 @@ export default function SideBar(props: any) {
window.location.reload()
}
- const classes = useStyles();
+ const classes = useStyles()
return (
-
+
-
+
switchTheme()}>
- {props.themeMode === 'dark' ?
-
- :
-
- }
+ {props.themeMode === 'dark' ? : }
{/*
- );
+ )
}
diff --git a/src/components/QRCodeModal.tsx b/src/components/QRCodeModal.tsx
index 0140b8e..8acb322 100644
--- a/src/components/QRCodeModal.tsx
+++ b/src/components/QRCodeModal.tsx
@@ -1,43 +1,43 @@
-import React,{ useState } from 'react';
-import QRCode from 'qrcode.react';
-import { IconButton, Dialog, DialogTitle } from '@material-ui/core';
-import { FilterCenterFocusSharp } from '@material-ui/icons';
+import { ReactElement, useState } from 'react'
+import QRCode from 'qrcode.react'
+import { IconButton, Dialog, DialogTitle } from '@material-ui/core'
+import { FilterCenterFocusSharp } from '@material-ui/icons'
-interface IProps {
- value: string,
- label: string,
+interface Props {
+ value: string
+ label: string
}
-export default function QRCodeModal(props: IProps) {
- const [open, setOpen] = useState(false);
-
- const handleOpen = () => {
- setOpen(true);
- };
-
- const handleClose = () => {
- setOpen(false);
- };
-
- return (
-
-
-
-
-
-
- { props.label }
-
-
-
-
- );
+export default function QRCodeModal(props: Props): ReactElement {
+ const [open, setOpen] = useState(false)
+
+ const handleOpen = () => {
+ setOpen(true)
}
+
+ const handleClose = () => {
+ setOpen(false)
+ }
+
+ return (
+
+
+
+
+
+
+ {props.label}
+
+
+
+
+ )
+}
diff --git a/src/components/SearchBar.tsx b/src/components/SearchBar.tsx
index db0cd1f..5851bd3 100644
--- a/src/components/SearchBar.tsx
+++ b/src/components/SearchBar.tsx
@@ -1,8 +1,8 @@
-import React from 'react';
+import React from 'react'
-import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
-import { Paper, InputBase, IconButton } from '@material-ui/core';
-import { Search } from '@material-ui/icons';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'
+import { Paper, InputBase, IconButton } from '@material-ui/core'
+import { Search } from '@material-ui/icons'
const useStyles = makeStyles((theme: Theme) =>
createStyles({
@@ -24,27 +24,23 @@ const useStyles = makeStyles((theme: Theme) =>
margin: 4,
},
}),
-);
+)
-interface IProps {
+export default function SearchBar() {
+ const classes = useStyles()
-}
-
-export default function SearchBar(props: IProps) {
- const classes = useStyles();
-
- return (
-
- )
+ return (
+
+ )
}
diff --git a/src/components/SideBar.tsx b/src/components/SideBar.tsx
index 5be4057..a8c6c27 100644
--- a/src/components/SideBar.tsx
+++ b/src/components/SideBar.tsx
@@ -1,46 +1,47 @@
-import React from 'react';
-import { Link } from 'react-router-dom';
+import { ReactElement } from 'react'
+import { Link, RouteComponentProps } from 'react-router-dom'
-import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
-import { ListItemText, ListItemIcon, ListItem, Divider, List, Drawer, Link as MUILink } from '@material-ui/core';
-import { OpenInNewSharp } from '@material-ui/icons';
-import { Activity, FileText, DollarSign, Share2, Settings } from 'react-feather';
+import { createStyles, Theme, makeStyles } from '@material-ui/core/styles'
+import { ListItemText, ListItemIcon, ListItem, Divider, List, Drawer, Link as MUILink } from '@material-ui/core'
+import { OpenInNewSharp } from '@material-ui/icons'
+import { Activity, FileText, DollarSign, Share2, Settings } from 'react-feather'
import SwarmLogoOrange from '../assets/swarm-logo-orange.svg'
+import { Health } from '@ethersphere/bee-js'
-const drawerWidth = 240;
+const drawerWidth = 240
const navBarItems = [
{
- 'label': 'Status',
- 'id': 'status',
- 'path': '/',
- 'icon': 'activity'
+ label: 'Status',
+ id: 'status',
+ path: '/',
+ icon: Activity,
},
{
- 'label': 'Files',
- 'id': 'files',
- 'path': '/files/',
- 'icon': 'file-text'
+ label: 'Files',
+ id: 'files',
+ path: '/files/',
+ icon: FileText,
},
{
- 'label': 'Accounting',
- 'id': 'accounting',
- 'path': '/accounting/',
- 'icon': 'dollar-sign'
+ label: 'Accounting',
+ id: 'accounting',
+ path: '/accounting/',
+ icon: DollarSign,
},
{
- 'label': 'Peers',
- 'id': 'peers',
- 'path': '/peers/',
- 'icon': 'share-2'
+ label: 'Peers',
+ id: 'peers',
+ path: '/peers/',
+ icon: Share2,
},
{
- 'label': 'Settings',
- 'id': 'settings',
- 'path': '/settings/',
- 'icon': 'settings'
- }
+ label: 'Settings',
+ id: 'settings',
+ path: '/settings/',
+ icon: Settings,
+ },
]
const useStyles = makeStyles((theme: Theme) =>
@@ -68,29 +69,20 @@ const useStyles = makeStyles((theme: Theme) =>
},
activeSideBarItem: {
borderLeft: '4px solid #dd7700',
- backgroundColor: 'inherit !important'
+ backgroundColor: 'inherit !important',
},
toolbar: theme.mixins.toolbar,
}),
-);
+)
-const getIcon = (iconPath: string) => {
- switch (iconPath) {
- case 'activity':
- return
- case 'file-text':
- return
- case 'dollar-sign':
- return
- case 'share-2':
- return
- case 'settings':
- return
- }
+interface Props extends RouteComponentProps {
+ themeMode: string
+ health: boolean
+ nodeHealth: Health | null
}
-export default function SideBar(props: any) {
- const classes = useStyles();
+export default function SideBar(props: Props): ReactElement {
+ const classes = useStyles()
return (
@@ -103,18 +95,30 @@ export default function SideBar(props: any) {
anchor="left"
>
-
-
+
+
{navBarItems.map(item => (
-
+
- {getIcon(item.icon)}
+
-
+
))}
@@ -131,16 +135,34 @@ export default function SideBar(props: any) {
- );
+ )
}
diff --git a/src/components/StatCard.tsx b/src/components/StatCard.tsx
index 760510c..13c1c52 100644
--- a/src/components/StatCard.tsx
+++ b/src/components/StatCard.tsx
@@ -1,53 +1,50 @@
-import React from 'react'
+import type { ReactElement } from 'react'
-import { makeStyles, } from '@material-ui/core/styles';
-import { Card, CardContent, Typography } from '@material-ui/core/';
-import { Skeleton } from '@material-ui/lab';
+import { makeStyles } from '@material-ui/core/styles'
+import { Card, CardContent, Typography } from '@material-ui/core/'
+import { Skeleton } from '@material-ui/lab'
const useStyles = makeStyles({
- root: {
- minWidth: 275,
- },
- title: {
- fontSize: 16,
- },
- pos: {
- marginBottom: 12,
- },
- });
+ root: {
+ minWidth: 275,
+ },
+ title: {
+ fontSize: 16,
+ },
+ pos: {
+ marginBottom: 12,
+ },
+})
-interface IProps {
- label: string
- statistic?: string
- loading?: boolean
+interface Props {
+ label: string
+ statistic?: string
+ loading?: boolean
}
-export default function StatCard({loading, label, statistic}: IProps) {
- const classes = useStyles();
+export default function StatCard({ loading, label, statistic }: Props): ReactElement {
+ const classes = useStyles()
-
- return (
-
-
- {loading && (
- <>
-
-
- >
- )
- }
- {!loading && (
- <>
-
- {label}
-
-
- {statistic}
-
- >
- )
- }
-
-
- )
+ return (
+
+
+ {loading && (
+ <>
+
+
+ >
+ )}
+ {!loading && (
+ <>
+
+ {label}
+
+
+ {statistic}
+
+ >
+ )}
+
+
+ )
}
diff --git a/src/components/TopologyStats.tsx b/src/components/TopologyStats.tsx
index c3ccec2..023ecfc 100644
--- a/src/components/TopologyStats.tsx
+++ b/src/components/TopologyStats.tsx
@@ -1,39 +1,28 @@
-import type { Topology } from '@ethersphere/bee-js';
-import { Grid } from '@material-ui/core/';
-import StatCard from './StatCard';
+import type { Topology } from '@ethersphere/bee-js'
+import { Grid } from '@material-ui/core/'
+import type { ReactElement } from 'react'
+import StatCard from './StatCard'
interface Props {
- isLoading: boolean
- topology: Topology | null
- error: Error | null // FIXME: should display error
+ isLoading: boolean
+ topology: Topology | null
+ error: Error | null // FIXME: should display error
}
-const TopologyStats = ({isLoading, topology, error}: Props) => (
-
-
-
-
-
-
-
-
-
-
-
-
+const TopologyStats = ({ isLoading, topology }: Props): ReactElement => (
+
+
+
+
+
+
+
+
+
+
+
+
)
export default TopologyStats
diff --git a/src/components/TroubleshootConnectionCard.tsx b/src/components/TroubleshootConnectionCard.tsx
index af261f2..43426cf 100644
--- a/src/components/TroubleshootConnectionCard.tsx
+++ b/src/components/TroubleshootConnectionCard.tsx
@@ -1,39 +1,47 @@
-import React from 'react';
-import { Link } from 'react-router-dom';
+import type { ReactElement } from 'react'
+import { Link } from 'react-router-dom'
-import { makeStyles, } from '@material-ui/core/styles';
-import { Card, CardContent, Typography } from '@material-ui/core/';
+import { makeStyles } from '@material-ui/core/styles'
+import { Card, CardContent, Typography } from '@material-ui/core/'
const useStyles = makeStyles({
- root: {
- flexGrow: 1,
- marginTop: '20px'
- },
- title: {
- textAlign:'center',
- fontSize: 26,
- },
- });
+ root: {
+ flexGrow: 1,
+ marginTop: '20px',
+ },
+ title: {
+ textAlign: 'center',
+ fontSize: 26,
+ },
+})
+export default function TroubleshootConnectionCard(): ReactElement {
+ const classes = useStyles()
-export default function TroubleshootConnectionCard() {
- const classes = useStyles();
+ return (
+
+
+
+ Looks like your node is not connected
+
+
+
+ Click to run status checks on your nodes connection or check out the{' '}
+
+ Swarm Bee Docs
+
+
+
- return (
-
-
-
- Looks like your node is not connected
-
-
-
Click to run status checks on your nodes connection or check out the Swarm Bee Docs
-
-
-
-
Still not working? Drop us a message on the Ethereum Swarm Discord
-
-
-
-
- )
+
+
+ Still not working? Drop us a message on the Ethereum Swarm{' '}
+
+ Discord
+
+
+
+
+
+ )
}
diff --git a/src/components/WithdrawlModal.tsx b/src/components/WithdrawlModal.tsx
index 154f330..c65a97d 100644
--- a/src/components/WithdrawlModal.tsx
+++ b/src/components/WithdrawlModal.tsx
@@ -1,77 +1,70 @@
-import React from 'react';
-import Button from '@material-ui/core/Button';
-import Input from '@material-ui/core/Input';
-import Dialog from '@material-ui/core/Dialog';
-import DialogActions from '@material-ui/core/DialogActions';
-import DialogContent from '@material-ui/core/DialogContent';
-import DialogContentText from '@material-ui/core/DialogContentText';
-import DialogTitle from '@material-ui/core/DialogTitle';
-import { Snackbar } from '@material-ui/core';
+import { ReactElement, useState } from 'react'
+import Button from '@material-ui/core/Button'
+import Input from '@material-ui/core/Input'
+import Dialog from '@material-ui/core/Dialog'
+import DialogActions from '@material-ui/core/DialogActions'
+import DialogContent from '@material-ui/core/DialogContent'
+import DialogContentText from '@material-ui/core/DialogContentText'
+import DialogTitle from '@material-ui/core/DialogTitle'
+import { Snackbar } from '@material-ui/core'
-import { beeDebugApi } from '../services/bee';
+import { beeDebugApi } from '../services/bee'
-export default function WithdrawlModal() {
- const [open, setOpen] = React.useState(false);
- const [amount, setAmount] = React.useState(BigInt(0));
- const [showToast, setToastVisibility] = React.useState(false);
- const [toastContent, setToastContent] = React.useState('');
+export default function WithdrawlModal(): ReactElement {
+ const [open, setOpen] = useState(false)
+ const [amount, setAmount] = useState(BigInt(0))
+ const [showToast, setToastVisibility] = useState(false)
+ const [toastContent, setToastContent] = useState('')
const handleClickOpen = () => {
- setOpen(true);
- };
+ setOpen(true)
+ }
const handleClose = () => {
- setOpen(false);
- };
+ setOpen(false)
+ }
const handleWithdraw = () => {
if (amount > 0) {
- beeDebugApi.chequebook.withdraw(amount)
+ beeDebugApi.chequebook
+ .withdraw(amount)
.then(res => {
- setOpen(false);
- handleToast(`Successful withdrawl. Transaction ${res.transactionHash}`)
+ setOpen(false)
+ handleToast(`Successful withdrawl. Transaction ${res.transactionHash}`)
})
- .catch(error => {
- handleToast('Error with withdrawl')
+ .catch(() => {
+ // FIXME: should probably detail the error
+ handleToast('Error with withdrawing')
})
} else {
- handleToast('Must be amount of greater than 0')
+ handleToast('Must be amount of greater than 0')
}
- };
+ }
const handleToast = (text: string) => {
setToastContent(text)
- setToastVisibility(true);
- setTimeout(
- () => setToastVisibility(false),
- 7000
- );
- };
+ setToastVisibility(true)
+ setTimeout(() => setToastVisibility(false), 7000)
+ }
return (
Withdraw
-
+
Withdraw Funds
-
- Specify the amount you would like to withdraw from your node.
-
+ Specify the amount you would like to withdraw from your node.
setAmount(BigInt(e.target.value))}
+ onChange={e => setAmount(BigInt(e.target.value))}
/>
@@ -84,5 +77,5 @@ export default function WithdrawlModal() {
- );
+ )
}
diff --git a/src/hooks/apiHooks.tsx b/src/hooks/apiHooks.tsx
index 827ed12..db67e6d 100644
--- a/src/hooks/apiHooks.tsx
+++ b/src/hooks/apiHooks.tsx
@@ -1,293 +1,393 @@
-import { useState, useEffect } from "react";
+import { useState, useEffect } from 'react'
-import { NodeAddresses, ChequebookAddressResponse, ChequebookBalanceResponse, BalanceResponse,
- LastChequesResponse, AllSettlements, LastCashoutActionResponse, Health, Peer, Topology, PingResponse, LastChequesForPeerResponse } from '@ethersphere/bee-js'
+import {
+ NodeAddresses,
+ ChequebookAddressResponse,
+ ChequebookBalanceResponse,
+ BalanceResponse,
+ LastChequesResponse,
+ AllSettlements,
+ LastCashoutActionResponse,
+ Health,
+ Peer,
+ Topology,
+ PingResponse,
+ LastChequesForPeerResponse,
+} from '@ethersphere/bee-js'
-import { beeDebugApi, beeApi } from '../services/bee';
+import { beeDebugApi, beeApi } from '../services/bee'
-export const useApiHealth = () => {
- const [health, setHealth] = useState(false)
- const [isLoadingHealth, setLoading] = useState(false)
- const [error, setError] = useState(null)
+export interface HealthHook {
+ health: boolean
+ isLoadingHealth: boolean
+ error: Error | null
+}
+export const useApiHealth = (): HealthHook => {
+ const [health, setHealth] = useState(false)
+ const [isLoadingHealth, setLoading] = useState(false)
+ const [error, setError] = useState(null)
- useEffect(() => {
- setLoading(true)
- beeApi.status.health()
- .then(res => {
- setHealth(res)
- })
- .catch(error => {
- setError(error)
- })
- .finally(() => {
- setLoading(false)
- })
- }, [])
+ useEffect(() => {
+ setLoading(true)
+ beeApi.status
+ .health()
+ .then(res => {
+ setHealth(res)
+ })
+ .catch(error => {
+ setError(error)
+ })
+ .finally(() => {
+ setLoading(false)
+ })
+ }, [])
- return { health, isLoadingHealth, error } ;
+ return { health, isLoadingHealth, error }
}
-export const useDebugApiHealth = () => {
- const [nodeHealth, setNodeHealth] = useState(null)
- const [isLoadingNodeHealth, setLoading] = useState(false)
- const [error, setError] = useState(null)
-
- useEffect(() => {
- setLoading(true)
- beeDebugApi.status.nodeHealth()
- .then(res => {
- setNodeHealth(res)
- })
- .catch(error => {
- setError(error)
- })
- .finally(() => {
- setLoading(false)
- })
- }, [])
-
- return { nodeHealth, isLoadingNodeHealth, error } ;
+export interface DebugHealthHook {
+ nodeHealth: Health | null
+ isLoadingNodeHealth: boolean
+ error: Error | null
}
-export const useApiNodeAddresses = () => {
- const [nodeAddresses, setNodeAddresses] = useState(null)
- const [isLoadingNodeAddresses, setLoading] = useState(false)
- const [error, setError] = useState(null)
+export const useDebugApiHealth = (): DebugHealthHook => {
+ const [nodeHealth, setNodeHealth] = useState(null)
+ const [isLoadingNodeHealth, setLoading] = useState(false)
+ const [error, setError] = useState(null)
- useEffect(() => {
- setLoading(true)
- beeDebugApi.connectivity.addresses()
- .then(res => {
- setNodeAddresses(res)
- })
- .catch(error => {
- setError(error)
- })
- .finally(() => {
- setLoading(false)
- })
- }, [])
+ useEffect(() => {
+ setLoading(true)
+ beeDebugApi.status
+ .nodeHealth()
+ .then(res => {
+ setNodeHealth(res)
+ })
+ .catch(error => {
+ setError(error)
+ })
+ .finally(() => {
+ setLoading(false)
+ })
+ }, [])
- return { nodeAddresses, isLoadingNodeAddresses, error } ;
+ return { nodeHealth, isLoadingNodeHealth, error }
}
-export const useApiNodeTopology = () => {
- const [topology, setNodeTopology] = useState(null)
- const [isLoading, setLoading] = useState(false)
- const [error, setError] = useState(null)
-
- useEffect(() => {
- setLoading(true)
- beeDebugApi.connectivity.topology()
- .then(res => {
- setNodeTopology(res)
- })
- .catch(error => {
- setError(error)
- })
- .finally(() => {
- setLoading(false)
- })
- }, [])
-
- return { topology, isLoading, error } ;
+export interface NodeAddressesHook {
+ nodeAddresses: NodeAddresses | null
+ isLoadingNodeAddresses: boolean
+ error: Error | null
}
-export const useApiChequebookAddress = () => {
- const [chequebookAddress, setChequebookAddress] = useState(null)
- const [isLoadingChequebookAddress, setLoading] = useState(false)
- const [error, setError] = useState(null)
+export const useApiNodeAddresses = (): NodeAddressesHook => {
+ const [nodeAddresses, setNodeAddresses] = useState(null)
+ const [isLoadingNodeAddresses, setLoading] = useState(false)
+ const [error, setError] = useState(null)
- useEffect(() => {
- setLoading(true)
- beeDebugApi.chequebook.address()
- .then(res => {
- setChequebookAddress(res)
- })
- .catch(error => {
- setError(error)
- })
- .finally(() => {
- setLoading(false)
- })
- }, [])
+ useEffect(() => {
+ setLoading(true)
+ beeDebugApi.connectivity
+ .addresses()
+ .then(res => {
+ setNodeAddresses(res)
+ })
+ .catch(error => {
+ setError(error)
+ })
+ .finally(() => {
+ setLoading(false)
+ })
+ }, [])
- return { chequebookAddress, isLoadingChequebookAddress, error };
+ return { nodeAddresses, isLoadingNodeAddresses, error }
}
-export const useApiNodePeers = () => {
- const [peers, setPeers] = useState(null)
- const [isLoading, setLoading] = useState(false)
- const [error, setError] = useState(null)
-
- useEffect(() => {
- setLoading(true)
- beeDebugApi.connectivity.listPeers()
- .then(res => {
- setPeers(res)
- })
- .catch(error => {
- setError(error)
- })
- .finally(() => {
- setLoading(false)
- })
- }, [])
-
- return { peers, isLoading, error };
+export interface NodeTopologyHook {
+ topology: Topology | null
+ isLoading: boolean
+ error: Error | null
}
-export const useApiChequebookBalance = () => {
- const [chequebookBalance, setChequebookBalance] = useState(null)
- const [isLoadingChequebookBalance, setLoading] = useState(false)
- const [error, setError] = useState(null)
+export const useApiNodeTopology = (): NodeTopologyHook => {
+ const [topology, setNodeTopology] = useState(null)
+ const [isLoading, setLoading] = useState(false)
+ const [error, setError] = useState(null)
- useEffect(() => {
- setLoading(true)
- beeDebugApi.chequebook.balance()
- .then(res => {
- setChequebookBalance(res)
- })
- .catch(error => {
- setError(error)
- })
- .finally(() => {
- setLoading(false)
- })
- }, [])
+ useEffect(() => {
+ setLoading(true)
+ beeDebugApi.connectivity
+ .topology()
+ .then(res => {
+ setNodeTopology(res)
+ })
+ .catch(error => {
+ setError(error)
+ })
+ .finally(() => {
+ setLoading(false)
+ })
+ }, [])
- return { chequebookBalance, isLoadingChequebookBalance, error };
+ return { topology, isLoading, error }
+}
+export interface ChequebookAddressHook {
+ chequebookAddress: ChequebookAddressResponse | null
+ isLoadingChequebookAddress: boolean
+ error: Error | null
}
-export const useApiPeerBalances = () => {
- const [peerBalances, setPeerBalances] = useState(null)
- const [isLoadingPeerBalances, setLoading] = useState(false)
- const [error, setError] = useState(null)
+export const useApiChequebookAddress = (): ChequebookAddressHook => {
+ const [chequebookAddress, setChequebookAddress] = useState(null)
+ const [isLoadingChequebookAddress, setLoading] = useState(false)
+ const [error, setError] = useState(null)
- useEffect(() => {
- setLoading(true)
- beeDebugApi.balance.balances()
- .then(res => {
- setPeerBalances(res)
- })
- .catch(error => {
- setError(error)
- })
- .finally(() => {
- setLoading(false)
- })
- }, [])
+ useEffect(() => {
+ setLoading(true)
+ beeDebugApi.chequebook
+ .address()
+ .then(res => {
+ setChequebookAddress(res)
+ })
+ .catch(error => {
+ setError(error)
+ })
+ .finally(() => {
+ setLoading(false)
+ })
+ }, [])
- return { peerBalances, isLoadingPeerBalances, error };
+ return { chequebookAddress, isLoadingChequebookAddress, error }
}
-export const useApiPeerCheques = () => {
- const [peerCheques, setPeerCheques] = useState(null)
- const [isLoadingPeerCheques, setLoading] = useState(false)
- const [error, setError] = useState(null)
-
- useEffect(() => {
- setLoading(true)
- beeDebugApi.chequebook.getLastCheques()
- .then(res => {
- setPeerCheques(res)
- })
- .catch(error => {
- setError(error)
- })
- .finally(() => {
- setLoading(false)
- })
- }, [])
-
- return { peerCheques, isLoadingPeerCheques, error };
+export interface NodePeersHook {
+ peers: Peer[] | null
+ isLoading: boolean
+ error: Error | null
}
-export const useApiPeerLastCheque = (peerId: string) => {
- const [peerCheque, setPeerCheque] = useState(null)
- const [isLoadingPeerCheque, setLoading] = useState(false)
- const [error, setError] = useState(null)
+export const useApiNodePeers = (): NodePeersHook => {
+ const [peers, setPeers] = useState(null)
+ const [isLoading, setLoading] = useState(false)
+ const [error, setError] = useState(null)
- useEffect(() => {
- setLoading(true)
- beeDebugApi.chequebook.getPeerLastCheques(peerId)
- .then(res => {
- setPeerCheque(res)
- })
- .catch(error => {
- setError(error)
- })
- .finally(() => {
- setLoading(false)
- })
- }, [peerId])
+ useEffect(() => {
+ setLoading(true)
+ beeDebugApi.connectivity
+ .listPeers()
+ .then(res => {
+ setPeers(res)
+ })
+ .catch(error => {
+ setError(error)
+ })
+ .finally(() => {
+ setLoading(false)
+ })
+ }, [])
- return { peerCheque, isLoadingPeerCheque, error };
+ return { peers, isLoading, error }
}
-export const useApiSettlements = () => {
- const [settlements, setSettlements] = useState(null)
- const [isLoadingSettlements, setLoading] = useState(false)
- const [error, setError] = useState(null)
-
- useEffect(() => {
- setLoading(true)
- beeDebugApi.settlements.getSettlements()
- .then(res => {
- setSettlements(res)
- })
- .catch(error => {
- setError(error)
- })
- .finally(() => {
- setLoading(false)
- })
- }, [])
-
- return { settlements, isLoadingSettlements, error };
+export interface ChequebookBalanceHook {
+ chequebookBalance: ChequebookBalanceResponse | null
+ isLoadingChequebookBalance: boolean
+ error: Error | null
}
+export const useApiChequebookBalance = (): ChequebookBalanceHook => {
+ const [chequebookBalance, setChequebookBalance] = useState(null)
+ const [isLoadingChequebookBalance, setLoading] = useState(false)
+ const [error, setError] = useState(null)
-export const useApiPingPeer = (peerId: string) => {
- const [peerRTP, setPeerRTP] = useState()
- const [isPingingPeer, setPingingPeer] = useState(false)
- const [error, setError] = useState(null)
+ useEffect(() => {
+ setLoading(true)
+ beeDebugApi.chequebook
+ .balance()
+ .then(res => {
+ setChequebookBalance(res)
+ })
+ .catch(error => {
+ setError(error)
+ })
+ .finally(() => {
+ setLoading(false)
+ })
+ }, [])
- useEffect(() => {
- setPingingPeer(true)
- beeDebugApi.connectivity.ping(peerId)
- .then(res => {
- setPeerRTP(res)
- })
- .catch(error => {
- setError(error)
- })
- .finally(() => {
- setPingingPeer(false)
- })
- }, [peerId])
-
- return { peerRTP, isPingingPeer, error };
+ return { chequebookBalance, isLoadingChequebookBalance, error }
}
-export const useApiPeerLastCashout = (peerId: string) => {
- const [peerCashout, setPeerCashout] = useState(null)
- const [isLoadingPeerCashout, setLoading] = useState(false)
- const [error, setError] = useState(null)
-
- useEffect(() => {
- setLoading(true)
- beeDebugApi.chequebook.getPeerLastCashout(peerId)
- .then(res => {
- setPeerCashout(res)
- })
- .catch(error => {
- setError(error)
- })
- .finally(() => {
- setLoading(false)
- })
- }, [peerId])
-
- return { peerCashout, isLoadingPeerCashout, error };
+export interface PeerBalanceHook {
+ peerBalances: BalanceResponse | null
+ isLoadingPeerBalances: boolean
+ error: Error | null
+}
+
+export const useApiPeerBalances = (): PeerBalanceHook => {
+ const [peerBalances, setPeerBalances] = useState(null)
+ const [isLoadingPeerBalances, setLoading] = useState(false)
+ const [error, setError] = useState(null)
+
+ useEffect(() => {
+ setLoading(true)
+ beeDebugApi.balance
+ .balances()
+ .then(res => {
+ setPeerBalances(res)
+ })
+ .catch(error => {
+ setError(error)
+ })
+ .finally(() => {
+ setLoading(false)
+ })
+ }, [])
+
+ return { peerBalances, isLoadingPeerBalances, error }
+}
+
+export interface PeerChequesHook {
+ peerCheques: LastChequesResponse | null
+ isLoadingPeerCheques: boolean
+ error: Error | null
+}
+
+export const useApiPeerCheques = (): PeerChequesHook => {
+ const [peerCheques, setPeerCheques] = useState(null)
+ const [isLoadingPeerCheques, setLoading] = useState(false)
+ const [error, setError] = useState(null)
+
+ useEffect(() => {
+ setLoading(true)
+ beeDebugApi.chequebook
+ .getLastCheques()
+ .then(res => {
+ setPeerCheques(res)
+ })
+ .catch(error => {
+ setError(error)
+ })
+ .finally(() => {
+ setLoading(false)
+ })
+ }, [])
+
+ return { peerCheques, isLoadingPeerCheques, error }
+}
+
+export interface PeerLastChequesHook {
+ peerCheque: LastChequesForPeerResponse | null
+ isLoadingPeerCheque: boolean
+ error: Error | null
+}
+
+export const useApiPeerLastCheque = (peerId: string): PeerLastChequesHook => {
+ const [peerCheque, setPeerCheque] = useState(null)
+ const [isLoadingPeerCheque, setLoading] = useState(false)
+ const [error, setError] = useState(null)
+
+ useEffect(() => {
+ setLoading(true)
+ beeDebugApi.chequebook
+ .getPeerLastCheques(peerId)
+ .then(res => {
+ setPeerCheque(res)
+ })
+ .catch(error => {
+ setError(error)
+ })
+ .finally(() => {
+ setLoading(false)
+ })
+ }, [peerId])
+
+ return { peerCheque, isLoadingPeerCheque, error }
+}
+
+export interface SettlementsHook {
+ settlements: AllSettlements | null
+ isLoadingSettlements: boolean
+ error: Error | null
+}
+
+export const useApiSettlements = (): SettlementsHook => {
+ const [settlements, setSettlements] = useState(null)
+ const [isLoadingSettlements, setLoading] = useState(false)
+ const [error, setError] = useState(null)
+
+ useEffect(() => {
+ setLoading(true)
+ beeDebugApi.settlements
+ .getSettlements()
+ .then(res => {
+ setSettlements(res)
+ })
+ .catch(error => {
+ setError(error)
+ })
+ .finally(() => {
+ setLoading(false)
+ })
+ }, [])
+
+ return { settlements, isLoadingSettlements, error }
+}
+
+export interface PingPeerHook {
+ peerRTP: PingResponse | null
+ isPingingPeer: boolean
+ error: Error | null
+}
+
+export const useApiPingPeer = (peerId: string): PingPeerHook => {
+ const [peerRTP, setPeerRTP] = useState(null)
+ const [isPingingPeer, setPingingPeer] = useState(false)
+ const [error, setError] = useState(null)
+
+ useEffect(() => {
+ setPingingPeer(true)
+ beeDebugApi.connectivity
+ .ping(peerId)
+ .then(res => {
+ setPeerRTP(res)
+ })
+ .catch(error => {
+ setError(error)
+ })
+ .finally(() => {
+ setPingingPeer(false)
+ })
+ }, [peerId])
+
+ return { peerRTP, isPingingPeer, error }
+}
+
+export interface PeerLastCashoutHook {
+ peerCashout: LastCashoutActionResponse | null
+ isLoadingPeerCashout: boolean
+ error: Error | null
+}
+
+export const useApiPeerLastCashout = (peerId: string): PeerLastCashoutHook => {
+ const [peerCashout, setPeerCashout] = useState(null)
+ const [isLoadingPeerCashout, setLoading] = useState(false)
+ const [error, setError] = useState(null)
+
+ useEffect(() => {
+ setLoading(true)
+ beeDebugApi.chequebook
+ .getPeerLastCashout(peerId)
+ .then(res => {
+ setPeerCashout(res)
+ })
+ .catch(error => {
+ setError(error)
+ })
+ .finally(() => {
+ setLoading(false)
+ })
+ }, [peerId])
+
+ return { peerCashout, isLoadingPeerCashout, error }
}
diff --git a/src/index.tsx b/src/index.tsx
index ef2edf8..68bf723 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,17 +1,17 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
-import './index.css';
-import App from './App';
-import reportWebVitals from './reportWebVitals';
+import React from 'react'
+import ReactDOM from 'react-dom'
+import './index.css'
+import App from './App'
+import reportWebVitals from './reportWebVitals'
ReactDOM.render(
,
- document.getElementById('root')
-);
+ document.getElementById('root'),
+)
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
-reportWebVitals();
+reportWebVitals()
diff --git a/src/layout/Dashboard.tsx b/src/layout/Dashboard.tsx
index c573dd0..fdea85c 100644
--- a/src/layout/Dashboard.tsx
+++ b/src/layout/Dashboard.tsx
@@ -1,12 +1,12 @@
-import React, { useState, useEffect } from 'react'
+import React, { useState, useEffect, ReactElement } from 'react'
-import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
+import { createStyles, Theme, makeStyles } from '@material-ui/core/styles'
-import SideBar from '../components/SideBar';
-import NavBar from '../components/NavBar';
-
-import { useApiHealth, useDebugApiHealth } from '../hooks/apiHooks';
+import SideBar from '../components/SideBar'
+import NavBar from '../components/NavBar'
+import { useApiHealth, useDebugApiHealth } from '../hooks/apiHooks'
+import { RouteComponentProps } from 'react-router'
const useStyles = makeStyles((theme: Theme) =>
createStyles({
@@ -16,7 +16,7 @@ const useStyles = makeStyles((theme: Theme) =>
flexGrow: 1,
backgroundColor: theme.palette.background.default,
padding: theme.spacing(3),
- paddingBottom:'65px',
+ paddingBottom: '65px',
},
footer: {
marginLeft: '240px',
@@ -24,55 +24,56 @@ const useStyles = makeStyles((theme: Theme) =>
position: 'fixed',
bottom: 0,
flexGrow: 1,
- width:'-webkit-fill-available',
+ width: '-webkit-fill-available',
padding: theme.spacing(2),
- textAlign:'center'
+ textAlign: 'center',
},
logo: {
height: '20px',
marginRight: '7px',
- }
+ },
}),
-);
+)
+interface Props extends RouteComponentProps {
+ children?: ReactElement
+}
-const Dashboard = (props: any) => {
- const classes = useStyles();
+const Dashboard = (props: Props): ReactElement => {
+ const classes = useStyles()
- const [themeMode, toggleThemeMode] = useState('light');
+ const [themeMode, toggleThemeMode] = useState('light')
- const { health, isLoadingHealth } = useApiHealth()
- const { nodeHealth, isLoadingNodeHealth } = useDebugApiHealth()
+ // FIXME: handle errrors and loading
+ const { health } = useApiHealth()
+ const { nodeHealth } = useDebugApiHealth()
- useEffect(() => {
- let theme = localStorage.getItem('theme')
+ useEffect(() => {
+ const theme = localStorage.getItem('theme')
- if (theme) {
- toggleThemeMode(String(localStorage.getItem('theme')))
- } else if (window?.matchMedia('(prefers-color-scheme: dark)')?.matches) {
- toggleThemeMode('dark')
- }
-
- window?.matchMedia('(prefers-color-scheme: dark)')?.addEventListener('change', e => {
- toggleThemeMode(e?.matches ? "dark" : "light")
- });
+ if (theme) {
+ toggleThemeMode(String(localStorage.getItem('theme')))
+ } else if (window?.matchMedia('(prefers-color-scheme: dark)')?.matches) {
+ toggleThemeMode('dark')
+ }
- return () => window?.matchMedia('(prefers-color-scheme: dark)')?.removeEventListener('change', e => {
- toggleThemeMode(e?.matches ? "dark" : "light")
+ window?.matchMedia('(prefers-color-scheme: dark)')?.addEventListener('change', e => {
+ toggleThemeMode(e?.matches ? 'dark' : 'light')
+ })
+
+ return () =>
+ window?.matchMedia('(prefers-color-scheme: dark)')?.removeEventListener('change', e => {
+ toggleThemeMode(e?.matches ? 'dark' : 'light')
})
- }, [])
+ }, [])
- let childrenInjectedWithProps = React.cloneElement(props.children, { health, nodeHealth, isLoadingHealth, isLoadingNodeHealth })
-
- return (
-
-
-
-
- {childrenInjectedWithProps}
-
-
- )
+ return (
+
+
+
+ {props.children}
+
+ )
}
export default Dashboard
diff --git a/src/pages/accounting/AccountCard.tsx b/src/pages/accounting/AccountCard.tsx
index 5e33af2..3a92811 100644
--- a/src/pages/accounting/AccountCard.tsx
+++ b/src/pages/accounting/AccountCard.tsx
@@ -1,17 +1,17 @@
-import React from 'react'
+import { ReactElement } from 'react'
-import { Theme, createStyles, makeStyles } from '@material-ui/core/styles';
-import { Card, CardContent, Typography, Grid } from '@material-ui/core/';
-import { Skeleton } from '@material-ui/lab';
-import WithdrawlModal from '../../components/WithdrawlModal';
-import DepositModal from '../../components/DepositModal';
-import CashoutModal from '../../components/CashoutModal';
+import { createStyles, makeStyles } from '@material-ui/core/styles'
+import { Card, CardContent, Typography, Grid } from '@material-ui/core/'
+import { Skeleton } from '@material-ui/lab'
+import WithdrawlModal from '../../components/WithdrawlModal'
+import DepositModal from '../../components/DepositModal'
+import CashoutModal from '../../components/CashoutModal'
-import { ConvertBalanceToBZZ } from '../../utils/common';
+import { ConvertBalanceToBZZ } from '../../utils/common'
-import type { ChequebookAddressResponse } from '@ethersphere/bee-js';
+import type { AllSettlements, ChequebookAddressResponse } from '@ethersphere/bee-js'
-const useStyles = makeStyles((theme: Theme) =>
+const useStyles = makeStyles(() =>
createStyles({
root: {
display: 'flex',
@@ -20,93 +20,107 @@ const useStyles = makeStyles((theme: Theme) =>
display: 'flex',
},
address: {
- color: 'grey',
- fontWeight: 400,
- },
+ color: 'grey',
+ fontWeight: 400,
+ },
content: {
- flexGrow: 1,
+ flexGrow: 1,
},
status: {
- color: '#fff',
- backgroundColor: '#76a9fa',
- }
+ color: '#fff',
+ backgroundColor: '#76a9fa',
+ },
}),
-);
-
+)
interface ChequebookBalance {
- totalBalance: number,
- availableBalance: number
+ totalBalance: number
+ availableBalance: number
}
-interface IProps{
- chequebookAddress: ChequebookAddressResponse | null,
- isLoadingChequebookAddress: boolean,
- chequebookBalance: ChequebookBalance | null,
- isLoadingChequebookBalance: boolean,
- settlements: any,
- isLoadingSettlements: boolean,
+interface Props {
+ chequebookAddress: ChequebookAddressResponse | null
+ isLoadingChequebookAddress: boolean
+ chequebookBalance: ChequebookBalance | null
+ isLoadingChequebookBalance: boolean
+ settlements: AllSettlements | null
+ isLoadingSettlements: boolean
}
+function AccountCard(props: Props): ReactElement {
+ const classes = useStyles()
-function AccountCard(props: IProps) {
- const classes = useStyles();
-
- return (
-
-
-
-
- { !props.isLoadingChequebookBalance && !props.isLoadingSettlements && props.chequebookBalance ?
-
-
-
-
-
- Total Balance
-
-
- {ConvertBalanceToBZZ(props.chequebookBalance.totalBalance)}
-
-
-
-
- Available Balance
-
-
- {ConvertBalanceToBZZ(props.chequebookBalance.availableBalance)}
-
-
-
-
- Total Sent / Received
-
-
- {ConvertBalanceToBZZ(props.settlements.totalsent)} / {ConvertBalanceToBZZ(props.settlements.totalreceived)}
- props.settlements.totalreceived ? '#c9201f' : '#32c48d' }}>({ConvertBalanceToBZZ(props.settlements.totalsent - props.settlements.totalreceived)})
-
-
-
-
-
- :
-
-
-
-
-
-
- }
-
+ return (
+
+
+
Accounting
+
+
+
+
- )
+
+
+
+ {!props.isLoadingChequebookBalance && !props.isLoadingSettlements && props.chequebookBalance ? (
+
+
+
+
+
+ Total Balance
+
+
+ {ConvertBalanceToBZZ(props.chequebookBalance.totalBalance)}
+
+
+
+
+ Available Balance
+
+
+ {ConvertBalanceToBZZ(props.chequebookBalance.availableBalance)}
+
+
+
+
+ Total Sent / Received
+
+
+
+ {ConvertBalanceToBZZ(props.settlements?.totalsent || 0)} /{' '}
+ {ConvertBalanceToBZZ(props.settlements?.totalreceived || 0)}
+
+ props.settlements?.totalreceived
+ ? '#c9201f'
+ : '#32c48d',
+ }}
+ >
+ (
+ {ConvertBalanceToBZZ(
+ (props.settlements && props.settlements?.totalsent - props.settlements?.totalreceived) || 0,
+ )}
+ )
+
+
+
+
+
+
+ ) : (
+
+
+
+
+
+
+ )}
+
+
+ )
}
-export default AccountCard;
+export default AccountCard
diff --git a/src/pages/accounting/BalancesTable.tsx b/src/pages/accounting/BalancesTable.tsx
index eb7ba0d..ac4b0c5 100644
--- a/src/pages/accounting/BalancesTable.tsx
+++ b/src/pages/accounting/BalancesTable.tsx
@@ -1,64 +1,80 @@
-import React from 'react';
-import { makeStyles } from '@material-ui/core/styles';
-import { Table, TableBody, TableCell, TableContainer, TableRow, TableHead, Paper, Container, CircularProgress } from '@material-ui/core';
+import type { ReactElement } from 'react'
+import { makeStyles } from '@material-ui/core/styles'
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableContainer,
+ TableRow,
+ TableHead,
+ Paper,
+ Container,
+ CircularProgress,
+} from '@material-ui/core'
-import { ConvertBalanceToBZZ } from '../../utils/common';
+import { ConvertBalanceToBZZ } from '../../utils/common'
const useStyles = makeStyles({
- table: {
- minWidth: 650,
- },
- });
+ table: {
+ minWidth: 650,
+ },
+})
interface PeerBalance {
- balance: number,
- peer: string,
+ balance: number
+ peer: string
}
interface PeerBalances {
- balances: Array
+ balances: Array
}
-interface IProps {
- peerBalances: PeerBalances | null,
- loading?: boolean,
-}
-
-function BalancesTable(props: IProps) {
- const classes = useStyles();
-
- return (
-
- {props.loading ?
-
-
-
- :
-
-
-
-
- Peer
- Balance (BZZ)
-
-
-
-
- {props.peerBalances?.balances.map((peerBalance: PeerBalance, idx: number) => (
-
- {peerBalance.peer}
- 0 ? '#32c48d' : '#c9201f', textAlign:'right', fontFamily: 'monospace, monospace' }}>
- {ConvertBalanceToBZZ(peerBalance.balance).toFixed(7).toLocaleString() }
-
-
-
-
- ))}
-
-
- }
-
- )
+interface Props {
+ peerBalances: PeerBalances | null
+ loading?: boolean
}
-export default BalancesTable;
+function BalancesTable(props: Props): ReactElement {
+ const classes = useStyles()
+
+ return (
+
+ {props.loading ? (
+
+
+
+ ) : (
+
+
+
+
+ Peer
+ Balance (BZZ)
+
+
+
+
+ {props.peerBalances?.balances.map((peerBalance: PeerBalance) => (
+
+ {peerBalance.peer}
+ 0 ? '#32c48d' : '#c9201f',
+ textAlign: 'right',
+ fontFamily: 'monospace, monospace',
+ }}
+ >
+ {ConvertBalanceToBZZ(peerBalance.balance).toFixed(7).toLocaleString()}
+
+
+
+ ))}
+
+
+
+ )}
+
+ )
+}
+
+export default BalancesTable
diff --git a/src/pages/accounting/ChequebookTable.tsx b/src/pages/accounting/ChequebookTable.tsx
index df5f9e5..3e35926 100644
--- a/src/pages/accounting/ChequebookTable.tsx
+++ b/src/pages/accounting/ChequebookTable.tsx
@@ -1,113 +1,125 @@
-import React from 'react';
-import { makeStyles } from '@material-ui/core/styles';
-import { Table, TableBody, TableCell, TableContainer, TableRow, TableHead, Paper, Container, CircularProgress } from '@material-ui/core';
+import React, { ReactElement } from 'react'
+import { makeStyles } from '@material-ui/core/styles'
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableContainer,
+ TableRow,
+ TableHead,
+ Paper,
+ Container,
+ CircularProgress,
+} from '@material-ui/core'
-import { ConvertBalanceToBZZ } from '../../utils/common';
-import EthereumAddress from '../../components/EthereumAddress';
-import ClipboardCopy from '../../components/ClipboardCopy';
-import PeerDetailDrawer from './PeerDetailDrawer';
+import { ConvertBalanceToBZZ } from '../../utils/common'
+import EthereumAddress from '../../components/EthereumAddress'
+import ClipboardCopy from '../../components/ClipboardCopy'
+import PeerDetailDrawer from './PeerDetailDrawer'
const useStyles = makeStyles({
- table: {
- minWidth: 650,
- },
- });
+ table: {
+ minWidth: 650,
+ },
+})
interface ChequeEvent {
- beneficiary: string,
- chequebook: string,
- payout: number,
+ beneficiary: string
+ chequebook: string
+ payout: number
}
interface PeerCheque {
- lastreceived?: ChequeEvent,
- lastsent?: ChequeEvent,
- peer: string,
+ lastreceived?: ChequeEvent
+ lastsent?: ChequeEvent
+ peer: string
}
interface PeerCheques {
- lastcheques: Array
+ lastcheques: Array
}
-interface IProps {
- peerCheques: PeerCheques | null,
- loading?: boolean,
+interface Props {
+ peerCheques: PeerCheques | null
+ loading?: boolean
}
-
-function ChequebookTable(props: IProps) {
- const classes = useStyles();
- return (
+function ChequebookTable(props: Props): ReactElement {
+ const classes = useStyles()
+
+ return (
+
+ {props.loading ? (
+
+
+
+ ) : (
- {props.loading ?
-
-
-
- :
-
-
-
-
-
- Peer
- Last Received
- Last Sent
-
-
-
-
- {props.peerCheques?.lastcheques.map((peerCheque: PeerCheque, idx: number) => (
-
-
-
-
-
-
-
- {peerCheque.lastreceived?.payout ?
- `${ConvertBalanceToBZZ(peerCheque.lastreceived?.payout).toFixed(7).toLocaleString()} from`
- : '-'}
-
- {peerCheque.lastreceived ?
- : null}
-
-
-
-
-
- {peerCheque.lastsent?.payout ? `${ConvertBalanceToBZZ(peerCheque.lastsent?.payout).toFixed(7).toLocaleString()} to` : '-'}
-
- {peerCheque.lastsent ?
- : null}
-
-
-
-
-
- ))}
-
-
-
-
}
+
+
+
+
+ Peer
+ Last Received
+ Last Sent
+
+
+
+
+ {props.peerCheques?.lastcheques.map((peerCheque: PeerCheque) => (
+
+
+
+
+
+
+
+ {peerCheque.lastreceived?.payout
+ ? `${ConvertBalanceToBZZ(peerCheque.lastreceived?.payout).toFixed(7).toLocaleString()} from`
+ : '-'}
+
+ {peerCheque.lastreceived ? (
+
+ ) : null}
+
+
+
+
+
+ {peerCheque.lastsent?.payout
+ ? `${ConvertBalanceToBZZ(peerCheque.lastsent?.payout).toFixed(7).toLocaleString()} to`
+ : '-'}
+
+ {peerCheque.lastsent ? (
+
+ ) : null}
+
+
+
+
+ ))}
+
+
+
- )
+ )}
+
+ )
}
-export default ChequebookTable;
+export default ChequebookTable
diff --git a/src/pages/accounting/PeerDetailDrawer.tsx b/src/pages/accounting/PeerDetailDrawer.tsx
index ac9b09a..c2c405d 100644
--- a/src/pages/accounting/PeerDetailDrawer.tsx
+++ b/src/pages/accounting/PeerDetailDrawer.tsx
@@ -1,188 +1,170 @@
-import React, { useState } from 'react'
-import { Paper, Container, Drawer, Button, Typography, CircularProgress, Grid } from '@material-ui/core';
-import ClipboardCopy from '../../components/ClipboardCopy';
-import { beeDebugApi } from '../../services/bee';
-import EthereumAddress from '../../components/EthereumAddress';
-import { ConvertBalanceToBZZ } from '../../utils/common';
+import React, { ReactElement, useState } from 'react'
+import { Paper, Container, Drawer, Button, Typography, CircularProgress, Grid } from '@material-ui/core'
+import ClipboardCopy from '../../components/ClipboardCopy'
+import { beeDebugApi } from '../../services/bee'
+import EthereumAddress from '../../components/EthereumAddress'
+import { ConvertBalanceToBZZ } from '../../utils/common'
+import { LastCashoutActionResponse, LastChequesForPeerResponse } from '@ethersphere/bee-js'
-function truncStringPortion(str: string, firstCharCount=10, endCharCount=10) {
- var convertedStr="";
- convertedStr+=str.substring(0, firstCharCount);
- convertedStr += ".".repeat(3);
- convertedStr+=str.substring(str.length-endCharCount, str.length);
- return convertedStr;
+function truncStringPortion(str: string, firstCharCount = 10, endCharCount = 10) {
+ let convertedStr = ''
+ convertedStr += str.substring(0, firstCharCount)
+ convertedStr += '.'.repeat(3)
+ convertedStr += str.substring(str.length - endCharCount, str.length)
+
+ return convertedStr
}
-export default function Index(props: any) {
- const [open, setOpen] = useState(false);
- const [peerCashout, setPeerCashout] = useState({ "peer": "",
- "chequebook": "",
- "cumulativePayout": 0,
- "beneficiary": "",
- "transactionHash": "",
- "result": {
- "recipient": "",
- "lastPayout": 0,
- "bounced": false
- }});
+interface Props {
+ peerId: string
+}
- const [peerCheque, setPeerCheque] = useState({
- lastreceived: { beneficiary: "", payout: 0, chequebook: "" },
- lastsent: { beneficiary: "", payout: 0, chequebook: "" },
- peer: ""
- })
+export default function Index(props: Props): ReactElement {
+ const [open, setOpen] = useState(false)
+ const [peerCashout, setPeerCashout] = useState(null)
+ const [peerCheque, setPeerCheque] = useState(null)
- const [isLoadingPeerCheque, setIsLoadingPeerCheque] = useState(false)
- const [isLoadingPeerCashout, setIsLoadingPeerCashout] = useState(false);
+ const [isLoadingPeerCheque, setIsLoadingPeerCheque] = useState(false)
+ const [isLoadingPeerCashout, setIsLoadingPeerCashout] = useState(false)
+ const handleClickOpen = (peerId: string) => {
+ setIsLoadingPeerCashout(true)
+ beeDebugApi.chequebook
+ .getPeerLastCashout(peerId)
+ .then(res => {
+ setPeerCashout(res)
+ })
+ .catch(() => {
+ // FIXME: handle the error
+ })
+ .finally(() => {
+ setIsLoadingPeerCashout(false)
+ })
- const handleClickOpen = (peerId: string) => {
- setIsLoadingPeerCashout(true)
- beeDebugApi.chequebook.getPeerLastCashout(peerId)
- .then(res => {
- setPeerCashout(res)
- })
- .catch(error => {
- })
- .finally(() => {
- setIsLoadingPeerCashout(false)
- })
+ setIsLoadingPeerCheque(true)
+ beeDebugApi.chequebook
+ .getPeerLastCheques(peerId)
+ .then(res => {
+ setPeerCheque(res)
+ })
+ .catch(() => {
+ // FIXME: handle the error
+ })
+ .finally(() => {
+ setIsLoadingPeerCheque(false)
+ })
- setIsLoadingPeerCheque(true)
- beeDebugApi.chequebook.getPeerLastCheques(peerId)
- .then(res => {
- setPeerCheque(res)
- })
- .catch(error => {
- })
- .finally(() => {
- setIsLoadingPeerCheque(false)
- })
+ setOpen(true)
+ }
- setOpen(true);
- }
-
- const handleClose = () => {
- setOpen(false);
- };
-
+ const handleClose = () => {
+ setOpen(false)
+ }
- return (
-
-
handleClickOpen(props.peerId)}>{truncStringPortion(props.peerId)}
-
-
-
- Peer: { truncStringPortion(props.peerId) }
-
-
-
- { isLoadingPeerCashout || isLoadingPeerCheque ?
-
-
-
- :
-
-
Last Cheque
-
-
- Last Sent
-
- Payout:
- {
- peerCheque.lastsent?.payout ? ConvertBalanceToBZZ(peerCheque.lastsent?.payout) : '-'
- }
-
- Beneficiary:
-
-
- Chequebook:
-
-
-
-
- Last Received
-
- Payout:
- {
- peerCheque.lastreceived?.payout ? ConvertBalanceToBZZ(peerCheque.lastreceived?.payout) : '-'}
-
- Beneficiary:
-
-
- Chequebook:
-
-
-
-
-
Last Cashout
- {peerCashout.cumulativePayout > 0 ?
-
-
- Cumulative Payout:
-
- {peerCashout.cumulativePayout ? ConvertBalanceToBZZ(peerCashout.cumulativePayout) : '-'}
-
-
-
- Last Payout:
- {
- peerCashout.result.lastPayout ? ConvertBalanceToBZZ(peerCashout.result.lastPayout) : '-'
- }
- {peerCashout.result.bounced ? 'Bounced' : ''}
-
-
Beneficiary:
-
-
-
Chequebook:
-
-
-
Recipient:
-
-
-
Transaction:
-
-
-
- : 'None'}
-
- }
-
-
-
+ return (
+
+
handleClickOpen(props.peerId)}>
+ {truncStringPortion(props.peerId)}
+
+
+
+
+ Peer: {truncStringPortion(props.peerId)}
+
+
+
+ {isLoadingPeerCashout || isLoadingPeerCheque ? (
+
+
+
+ ) : (
+
+
Last Cheque
+
+
+ Last Sent
+
+ Payout:
+
+ {' '}
+ {peerCheque?.lastsent?.payout ? ConvertBalanceToBZZ(peerCheque?.lastsent?.payout) : '-'}
+
+
+
+ Beneficiary:
+
+
+
+ Chequebook:
+
+
+
+
+ Last Received
+
+ Payout:
+
+ {' '}
+ {peerCheque?.lastreceived?.payout ? ConvertBalanceToBZZ(peerCheque?.lastreceived?.payout) : '-'}
+
+
+
+ Beneficiary:
+
+
+
+ Chequebook:
+
+
+
+
+
Last Cashout
+ {peerCashout && peerCashout?.cumulativePayout > 0 ? (
+
+
+ Cumulative Payout:
+
+ {peerCashout?.cumulativePayout ? ConvertBalanceToBZZ(peerCashout?.cumulativePayout) : '-'}
+
+
+
+ Last Payout:
+
+ {' '}
+ {peerCashout?.result.lastPayout ? ConvertBalanceToBZZ(peerCashout?.result.lastPayout) : '-'}
+
+ {peerCashout?.result.bounced ? 'Bounced' : ''}
+
+
+ Beneficiary:
+
+
+
+ Chequebook:
+
+
+
+ Recipient:
+
+
+
+ Transaction:
+
+
+
+ ) : (
+ 'None'
+ )}
+
+ )}
+
- )
+
+
+ )
}
diff --git a/src/pages/accounting/SettlementsTable.tsx b/src/pages/accounting/SettlementsTable.tsx
index f27e2df..1718334 100644
--- a/src/pages/accounting/SettlementsTable.tsx
+++ b/src/pages/accounting/SettlementsTable.tsx
@@ -1,59 +1,69 @@
-import React from 'react';
-import { makeStyles } from '@material-ui/core/styles';
-import { Table, TableBody, TableCell, TableContainer, TableRow, TableHead, Paper, Container, CircularProgress } from '@material-ui/core';
+import { ReactElement } from 'react'
+import { makeStyles } from '@material-ui/core/styles'
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableContainer,
+ TableRow,
+ TableHead,
+ Paper,
+ Container,
+ CircularProgress,
+} from '@material-ui/core'
-import { ConvertBalanceToBZZ } from '../../utils/common';
+import { ConvertBalanceToBZZ } from '../../utils/common'
import type { AllSettlements, Settlements } from '@ethersphere/bee-js'
const useStyles = makeStyles({
- table: {
- minWidth: 650,
- },
- });
+ table: {
+ minWidth: 650,
+ },
+})
-
-interface IProps {
- nodeSettlements: AllSettlements | null,
- loading?: boolean,
-}
-
-function SettlementsTable(props: IProps) {
- const classes = useStyles();
-
- return (
-
- {props.loading ?
-
-
-
- :
-
-
-
-
- Peer
- Received (BZZ)
- Sent (BZZ)
-
-
-
- {props.nodeSettlements?.settlements.map((item: Settlements, idx: number) => (
-
- {item.peer}
-
- {item.received > 0 ? ConvertBalanceToBZZ(item.received).toFixed(7).toLocaleString() : item.received}
-
-
- {item.sent > 0 ? ConvertBalanceToBZZ(item.sent).toFixed(7).toLocaleString() : item.sent}
-
-
- ))}
-
-
- }
-
- )
+interface Props {
+ nodeSettlements: AllSettlements | null
+ loading?: boolean
}
-export default SettlementsTable;
+function SettlementsTable(props: Props): ReactElement {
+ const classes = useStyles()
+
+ return (
+
+ {props.loading ? (
+
+
+
+ ) : (
+
+
+
+
+ Peer
+ Received (BZZ)
+ Sent (BZZ)
+
+
+
+ {props.nodeSettlements?.settlements.map((item: Settlements) => (
+
+ {item.peer}
+
+ {item.received > 0 ? ConvertBalanceToBZZ(item.received).toFixed(7).toLocaleString() : item.received}
+
+
+ {item.sent > 0 ? ConvertBalanceToBZZ(item.sent).toFixed(7).toLocaleString() : item.sent}
+
+
+ ))}
+
+
+
+ )}
+
+ )
+}
+
+export default SettlementsTable
diff --git a/src/pages/accounting/index.tsx b/src/pages/accounting/index.tsx
index cd8ba2a..c516217 100644
--- a/src/pages/accounting/index.tsx
+++ b/src/pages/accounting/index.tsx
@@ -1,166 +1,168 @@
-import React from 'react';
-import { withStyles, Theme, createStyles } from '@material-ui/core/styles';
-import { Tabs, Tab, Box, Typography, Container, CircularProgress } from '@material-ui/core';
+import { ReactElement, useState, ChangeEvent, ReactChild } from 'react'
+import { withStyles, Theme, createStyles } from '@material-ui/core/styles'
+import { Tabs, Tab, Box, Typography, Container, CircularProgress } from '@material-ui/core'
-import AccountCard from '../accounting/AccountCard';
-import BalancesTable from './BalancesTable';
-import ChequebookTable from './ChequebookTable';
-import SettlementsTable from './SettlementsTable';
-import EthereumAddressCard from '../../components/EthereumAddressCard';
-import TroubleshootConnectionCard from '../../components/TroubleshootConnectionCard';
+import AccountCard from '../accounting/AccountCard'
+import BalancesTable from './BalancesTable'
+import ChequebookTable from './ChequebookTable'
+import SettlementsTable from './SettlementsTable'
+import EthereumAddressCard from '../../components/EthereumAddressCard'
+import TroubleshootConnectionCard from '../../components/TroubleshootConnectionCard'
-import { useApiNodeAddresses, useApiChequebookAddress, useApiChequebookBalance, useApiPeerBalances, useApiPeerCheques, useApiSettlements } from '../../hooks/apiHooks';
+import {
+ useApiNodeAddresses,
+ useApiChequebookAddress,
+ useApiChequebookBalance,
+ useApiPeerBalances,
+ useApiPeerCheques,
+ useApiSettlements,
+ useApiHealth,
+ useDebugApiHealth,
+} from '../../hooks/apiHooks'
interface TabPanelProps {
- children?: React.ReactNode;
- index: any;
- value: any;
+ children?: ReactChild
+ index: number
+ value: number
}
-
-function a11yProps(index: any) {
- return {
- id: `simple-tab-${index}`,
- 'aria-controls': `simple-tabpanel-${index}`,
- };
+function a11yProps(index: number) {
+ return {
+ id: `simple-tab-${index}`,
+ 'aria-controls': `simple-tabpanel-${index}`,
+ }
}
-export default function Accounting(props: any) {
- const [value, setValue] = React.useState(0);
+export default function Accounting(): ReactElement {
+ const [value, setValue] = useState(0)
- const handleChange = (event: React.ChangeEvent<{}>, newValue: number) => {
- setValue(newValue);
- };
+ const handleChange = (event: ChangeEvent
, newValue: number) => {
+ setValue(newValue)
+ }
- const { chequebookAddress, isLoadingChequebookAddress } = useApiChequebookAddress()
- const { chequebookBalance, isLoadingChequebookBalance } = useApiChequebookBalance()
- const { peerBalances, isLoadingPeerBalances } = useApiPeerBalances()
- const { nodeAddresses, isLoadingNodeAddresses } = useApiNodeAddresses()
+ const { chequebookAddress, isLoadingChequebookAddress } = useApiChequebookAddress()
+ const { chequebookBalance, isLoadingChequebookBalance } = useApiChequebookBalance()
+ const { peerBalances, isLoadingPeerBalances } = useApiPeerBalances()
+ const { nodeAddresses, isLoadingNodeAddresses } = useApiNodeAddresses()
+ const { health, isLoadingHealth } = useApiHealth()
+ const { nodeHealth, isLoadingNodeHealth } = useDebugApiHealth()
- const { peerCheques, isLoadingPeerCheques } = useApiPeerCheques()
- const { settlements, isLoadingSettlements } = useApiSettlements()
+ const { peerCheques, isLoadingPeerCheques } = useApiPeerCheques()
+ const { settlements, isLoadingSettlements } = useApiSettlements()
+ function TabPanel(props: TabPanelProps) {
+ const { children, value, index, ...other } = props
- function TabPanel(props: TabPanelProps) {
- const { children, value, index, ...other } = props;
-
- return (
-
- {value === index && (
-
- {children}
-
- )}
-
- );
- }
-
- const AntTabs = withStyles({
- root: {
- borderBottom: '1px solid #e8e8e8',
- },
- indicator: {
- backgroundColor: '#3f51b5',
- },
- })(Tabs);
-
- interface StyledTabProps {
- label: string;
- }
-
- const AntTab = withStyles((theme: Theme) =>
- createStyles({
- root: {
- textTransform: 'none',
- minWidth: 72,
- backgroundColor: 'transparent',
- fontWeight: theme.typography.fontWeightRegular,
- marginRight: theme.spacing(4),
- fontFamily: [
- '-apple-system',
- 'BlinkMacSystemFont',
- '"Segoe UI"',
- 'Roboto',
- '"Helvetica Neue"',
- 'Arial',
- 'sans-serif',
- '"Apple Color Emoji"',
- '"Segoe UI Emoji"',
- '"Segoe UI Symbol"',
- ].join(','),
- '&:hover': {
- color: '#3f51b5',
- opacity: 1,
- },
- '&$selected': {
- color: '#3f51b5',
- fontWeight: theme.typography.fontWeightMedium,
- },
- '&:focus': {
- color: '#3f51b5',
- },
- },
- selected: {},
- }),
- )((props: StyledTabProps) => );
-
-
return (
-
- {props.nodeHealth?.status === 'ok' && props.health ?
+
+ {value === index && (
+
+ {children}
+
+ )}
+
+ )
+ }
+
+ const AntTabs = withStyles({
+ root: {
+ borderBottom: '1px solid #e8e8e8',
+ },
+ indicator: {
+ backgroundColor: '#3f51b5',
+ },
+ })(Tabs)
+
+ interface StyledTabProps {
+ label: string
+ }
+
+ const AntTab = withStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ textTransform: 'none',
+ minWidth: 72,
+ backgroundColor: 'transparent',
+ fontWeight: theme.typography.fontWeightRegular,
+ marginRight: theme.spacing(4),
+ fontFamily: [
+ '-apple-system',
+ 'BlinkMacSystemFont',
+ '"Segoe UI"',
+ 'Roboto',
+ '"Helvetica Neue"',
+ 'Arial',
+ 'sans-serif',
+ '"Apple Color Emoji"',
+ '"Segoe UI Emoji"',
+ '"Segoe UI Symbol"',
+ ].join(','),
+ '&:hover': {
+ color: '#3f51b5',
+ opacity: 1,
+ },
+ '&$selected': {
+ color: '#3f51b5',
+ fontWeight: theme.typography.fontWeightMedium,
+ },
+ '&:focus': {
+ color: '#3f51b5',
+ },
+ },
+ selected: {},
+ }),
+ )((props: StyledTabProps) =>
)
+
+ return (
+
+ {
+ // FIXME: this should be broken up
+ /* eslint-disable no-nested-ternary */
+ nodeHealth?.status === 'ok' && health ? (
-
-
-
-
+
+
+
-
+
-
+
-
+
-
- :
- props.isLoadingHealth || props.isLoadingNodeHealth ?
-
-
-
- :
-
- }
-
- )
+
+ ) : isLoadingHealth || isLoadingNodeHealth ? (
+
+
+
+ ) : (
+
+ ) /* eslint-enable no-nested-ternary */
+ }
+
+ )
}
diff --git a/src/pages/files/index.tsx b/src/pages/files/index.tsx
index 7286b69..84afcc5 100644
--- a/src/pages/files/index.tsx
+++ b/src/pages/files/index.tsx
@@ -1,14 +1,15 @@
-import React, { useState } from 'react';
-import { beeApi } from '../../services/bee';
+import { ReactElement, useState } from 'react'
+import { beeApi } from '../../services/bee'
-import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
-import { Paper, InputBase, IconButton, Button, Container, CircularProgress } from '@material-ui/core';
-import { Search } from '@material-ui/icons';
-import {DropzoneArea} from 'material-ui-dropzone'
-import ClipboardCopy from '../../components/ClipboardCopy';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'
+import { Paper, InputBase, IconButton, Button, Container, CircularProgress } from '@material-ui/core'
+import { Search } from '@material-ui/icons'
+import { DropzoneArea } from 'material-ui-dropzone'
+import ClipboardCopy from '../../components/ClipboardCopy'
-import TroubleshootConnectionCard from '../../components/TroubleshootConnectionCard';
-import { Data, FileData } from '@ethersphere/bee-js';
+import TroubleshootConnectionCard from '../../components/TroubleshootConnectionCard'
+import { Data, FileData } from '@ethersphere/bee-js'
+import { useApiHealth, useDebugApiHealth } from '../../hooks/apiHooks'
const useStyles = makeStyles((theme: Theme) =>
createStyles({
@@ -30,128 +31,138 @@ const useStyles = makeStyles((theme: Theme) =>
margin: 4,
},
}),
-);
+)
-export default function Files(props: any) {
- const classes = useStyles();
+export default function Files(): ReactElement {
+ const classes = useStyles()
- const [inputMode, setInputMode] = useState<'browse' | 'upload'>('browse');
- const [searchInput, setSearchInput] = useState('');
- const [searchResult, setSearchResult] = useState | null>(null);
- const [loadingSearch, setLoadingSearch] = useState(false);
+ const [inputMode, setInputMode] = useState<'browse' | 'upload'>('browse')
+ const [searchInput, setSearchInput] = useState('')
+ const [searchResult, setSearchResult] = useState | null>(null)
+ const [loadingSearch, setLoadingSearch] = useState(false)
+ const { health, isLoadingHealth } = useApiHealth()
+ const { nodeHealth, isLoadingNodeHealth } = useDebugApiHealth()
- const [files, setFiles] = useState([]);
- const [uploadReference, setUploadReference] = useState('');
- const [uploadingFile, setUploadingFile] = useState(false);
+ const [files, setFiles] = useState([])
+ const [uploadReference, setUploadReference] = useState('')
+ const [uploadingFile, setUploadingFile] = useState(false)
- const getFile = () => {
- setLoadingSearch(true)
- beeApi.files.downloadFile(searchInput)
- .then(res => {
- setSearchResult(res)
-
- const downloadUrl = window.URL.createObjectURL(new Blob([res.data]));
- const link = document.createElement('a');
- link.href = downloadUrl;
- link.setAttribute('download', 'file.zip'); //any other extension
- document.body.appendChild(link);
- link.click();
- link.remove();
- })
- .catch(error => {
- })
- .finally(() => {
- setLoadingSearch(false)
- })
+ const getFile = () => {
+ setLoadingSearch(true)
+ beeApi.files
+ .downloadFile(searchInput)
+ .then(res => {
+ setSearchResult(res)
+
+ const downloadUrl = window.URL.createObjectURL(new Blob([res.data]))
+ const link = document.createElement('a')
+ link.href = downloadUrl
+ link.setAttribute('download', 'file.zip') //any other extension
+ document.body.appendChild(link)
+ link.click()
+ link.remove()
+ })
+ .catch(() => {
+ // FIXME: handle the error
+ })
+ .finally(() => {
+ setLoadingSearch(false)
+ })
+ }
+
+ const uploadFile = () => {
+ setUploadingFile(true)
+ beeApi.files
+ .uploadFile(files[0])
+ .then(hash => {
+ setUploadReference(hash)
+ setFiles([])
+ })
+ .catch(() => {
+ // FIXME: handle the error
+ })
+ .finally(() => {
+ setUploadingFile(false)
+ })
+ }
+
+ const handleChange = (files?: File[]) => {
+ if (files) {
+ setFiles(files)
}
+ }
- const uploadFile = () => {
- setUploadingFile(true)
- beeApi.files.uploadFile(files[0])
- .then(hash => {
- setUploadReference(hash)
- setFiles([])
- })
- .catch(error => {
- })
- .finally(() => {
- setUploadingFile(false)
- })
- }
-
- const handleChange = (files: any) => {
- if (files) {
- setFiles(files)
- }
- }
-
- return (
-
- {props.nodeHealth?.status === 'ok' && props.health ?
-
-
- setInputMode('browse')}>Browse
- setInputMode('upload')}>Upload
-
- {inputMode === 'browse' ?
-
-
+ {
+ // FIXME: this should be broken up
+ /* eslint-disable no-nested-ternary */
+ nodeHealth?.status === 'ok' && health ? (
+
+
+ setInputMode('browse')}>
+ Browse
+
+ setInputMode('upload')}>
+ Upload
+
+
+ {inputMode === 'browse' ? (
+
+ setSearchInput(e.target.value)}
- />
- getFile()} className={classes.iconButton} aria-label="search">
-
-
+ onChange={e => setSearchInput(e.target.value)}
+ />
+ getFile()} className={classes.iconButton} aria-label="search">
+
+
- :
+ ) : (
- {uploadingFile ?
-
+ {uploadingFile ? (
+
-
- :
-
- {uploadReference ?
-
- {uploadReference}
-
-
- :
- null
- }
-
-
-
uploadFile()} className={classes.iconButton}>
+
+ ) : (
+
+ {uploadReference ? (
+
+ {uploadReference}
+
+
+ ) : null}
+
+
+ uploadFile()} className={classes.iconButton}>
Upload
-
+
+
- }
+ )}
- }
- {loadingSearch ?
-
-
-
- :
-
- {searchResult}
-
- }
-
- :
- props.isLoadingHealth || props.isLoadingNodeHealth ?
-
+ )}
+ {loadingSearch ? (
+
-
- :
- }
-
- )
+
+ ) : (
+ {searchResult}
+ )}
+
+ ) : isLoadingHealth || isLoadingNodeHealth ? (
+
+
+
+ ) : (
+
+ ) /* eslint-enable no-nested-ternary */
+ }
+
+ )
}
diff --git a/src/pages/peers/PeerTable.tsx b/src/pages/peers/PeerTable.tsx
index e1a1e53..8cb5e75 100644
--- a/src/pages/peers/PeerTable.tsx
+++ b/src/pages/peers/PeerTable.tsx
@@ -1,92 +1,113 @@
-import React, { useState } from 'react';
-import { makeStyles } from '@material-ui/core/styles';
-import { Table, TableBody, TableCell, TableContainer, TableRow, TableHead, Button, Paper, Tooltip, Container, CircularProgress } from '@material-ui/core';
-import { Autorenew } from '@material-ui/icons';
+import React, { ReactElement, useState } from 'react'
+import { makeStyles } from '@material-ui/core/styles'
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableContainer,
+ TableRow,
+ TableHead,
+ Button,
+ Paper,
+ Tooltip,
+ Container,
+ CircularProgress,
+} from '@material-ui/core'
+import { Autorenew } from '@material-ui/icons'
-import { beeDebugApi } from '../../services/bee';
-import type { Peer } from '@ethersphere/bee-js';
+import { beeDebugApi } from '../../services/bee'
+import type { Peer } from '@ethersphere/bee-js'
const useStyles = makeStyles({
- table: {
- minWidth: 650,
- },
- });
+ table: {
+ minWidth: 650,
+ },
+})
interface Props {
- peers: Peer[] | null
- isLoading: boolean
- error: Error | null
+ peers: Peer[] | null
+ isLoading: boolean
+ error: Error | null
}
-
-function PeerTable(props: Props) {
- const classes = useStyles();
+function PeerTable(props: Props): ReactElement {
+ const classes = useStyles()
- const [peerLatency, setPeerLatency] = useState([{ peerId: '', rtt: '', loading: false }]);
+ const [peerLatency, setPeerLatency] = useState([{ peerId: '', rtt: '', loading: false }])
- const PingPeer = async (peerId: string) => {
-
- setPeerLatency([...peerLatency, { peerId: peerId, rtt: '', loading: true }])
- beeDebugApi.connectivity.ping(peerId)
- .then(res => {
- setPeerLatency([...peerLatency, { peerId: peerId, rtt: res.rtt, loading: false }])
- })
- .catch(error => {
- setPeerLatency([...peerLatency, { peerId: peerId, rtt: 'error', loading: false }])
- })
- }
-
- if (props.isLoading) {
- return (
-
-
-
- )
- }
-
- if (props.error || props.peers === null) {
- return (
-
- Failed to load peers
-
- )
- }
+ const PingPeer = (peerId: string) => {
+ setPeerLatency([...peerLatency, { peerId: peerId, rtt: '', loading: true }])
+ beeDebugApi.connectivity
+ .ping(peerId)
+ .then(res => {
+ setPeerLatency([...peerLatency, { peerId: peerId, rtt: res.rtt, loading: false }])
+ })
+ .catch(() => {
+ setPeerLatency([...peerLatency, { peerId: peerId, rtt: 'error', loading: false }])
+ })
+ }
+ if (props.isLoading) {
return (
-
-
-
-
-
- Index
- Peer Id
- Actions
-
-
-
- {props.peers.map((peer: any, idx: number) => (
-
-
- {idx + 1}
-
- {peer.address}
-
-
- PingPeer(peer.address)} >
- {peerLatency.find(item => item.peerId === peer.address) ?
- peerLatency.filter(item => item.peerId === peer.address)[0].loading ? :
- peerLatency.filter(item => item.peerId === peer.address)[0].rtt :
- }
-
-
-
-
- ))}
-
-
-
-
+
+
+
)
+ }
+
+ if (props.error || props.peers === null) {
+ return (
+
+ Failed to load peers
+
+ )
+ }
+
+ return (
+
+
+
+
+
+ Index
+ Peer Id
+ Actions
+
+
+
+ {props.peers.map((peer: Peer, idx: number) => (
+
+
+ {idx + 1}
+
+ {peer.address}
+
+
+ PingPeer(peer.address)}>
+ {
+ // FIXME: this should be broken up
+ /* eslint-disable no-nested-ternary */
+ peerLatency.find(item => item.peerId === peer.address) ? (
+ peerLatency.filter(item => item.peerId === peer.address)[0].loading ? (
+
+ ) : (
+ peerLatency.filter(item => item.peerId === peer.address)[0].rtt
+ )
+ ) : (
+
+ )
+ /* eslint-enable no-nested-ternary */
+ }
+
+
+
+
+ ))}
+
+
+
+
+ )
}
export default PeerTable
diff --git a/src/pages/peers/index.tsx b/src/pages/peers/index.tsx
index c1c2749..000646c 100644
--- a/src/pages/peers/index.tsx
+++ b/src/pages/peers/index.tsx
@@ -1,31 +1,32 @@
-import { Container, CircularProgress } from '@material-ui/core/';
-import PeerTable from './PeerTable';
-import TroubleshootConnectionCard from '../../components/TroubleshootConnectionCard';
+import { Container, CircularProgress } from '@material-ui/core/'
+import PeerTable from './PeerTable'
+import TroubleshootConnectionCard from '../../components/TroubleshootConnectionCard'
-import { useApiNodeTopology, useApiNodePeers, useDebugApiHealth } from '../../hooks/apiHooks';
-import TopologyStats from '../../components/TopologyStats';
+import { useApiNodeTopology, useApiNodePeers, useDebugApiHealth } from '../../hooks/apiHooks'
+import TopologyStats from '../../components/TopologyStats'
+import { ReactElement } from 'react'
-export default function Peers() {
- const topology = useApiNodeTopology()
- const debugHealth = useDebugApiHealth()
- const peers = useApiNodePeers()
-
- if (debugHealth.isLoadingNodeHealth) {
- return (
-
-
-
- )
- }
-
- if (debugHealth.error) {
- return
- }
+export default function Peers(): ReactElement {
+ const topology = useApiNodeTopology()
+ const debugHealth = useDebugApiHealth()
+ const peers = useApiNodePeers()
+ if (debugHealth.isLoadingNodeHealth) {
return (
- <>
-
-
- >
+
+
+
)
+ }
+
+ if (debugHealth.error) {
+ return
+ }
+
+ return (
+ <>
+
+
+ >
+ )
}
diff --git a/src/pages/settings/index.tsx b/src/pages/settings/index.tsx
index cca3083..725e214 100644
--- a/src/pages/settings/index.tsx
+++ b/src/pages/settings/index.tsx
@@ -1,77 +1,86 @@
-import React, { useState } from 'react'
-import { Paper, Container, TextField, Typography, Button } from '@material-ui/core';
+import React, { ReactElement, useState } from 'react'
+import { Paper, Container, TextField, Typography, Button } from '@material-ui/core'
-export default function Settings() {
+export default function Settings(): ReactElement {
+ const [refreshVisibility, toggleRefreshVisibility] = useState(false)
+ const [host, setHost] = useState('')
+ const [debugHost, setDebugHost] = useState('')
- const [refreshVisibility, toggleRefreshVisibility] = useState(false)
- const [host, setHost] = useState('')
- const [debugHost, setDebugHost] = useState('')
-
- const handleNewHostConnection = () => {
- if (host) {
- sessionStorage.setItem('api_host', host)
- }
- if (debugHost) {
- sessionStorage.setItem('debug_api_host', debugHost)
- }
- if (host || debugHost) {
- toggleRefreshVisibility(!refreshVisibility)
- window.location.reload();
- }
+ const handleNewHostConnection = () => {
+ if (host) {
+ sessionStorage.setItem('api_host', host)
}
- return (
-
-
-
- Settings
-
-
- {
- setHost(e.target.value)
- toggleRefreshVisibility(true)
- }}
- variant="filled"
- />
-
-
- {
- setDebugHost(e.target.value)
- toggleRefreshVisibility(true)
- }}
- margin="normal"
- InputLabelProps={{
- shrink: true,
- }}
- variant="filled"
- />
-
- {refreshVisibility ?
-
- handleNewHostConnection()}>Save
-
- : null}
-
-
- )
+ if (debugHost) {
+ sessionStorage.setItem('debug_api_host', debugHost)
+ }
+
+ if (host || debugHost) {
+ toggleRefreshVisibility(!refreshVisibility)
+ window.location.reload()
+ }
+ }
+
+ return (
+
+
+
+ Settings
+
+
+ {
+ setHost(e.target.value)
+ toggleRefreshVisibility(true)
+ }}
+ variant="filled"
+ />
+
+
+ {
+ setDebugHost(e.target.value)
+ toggleRefreshVisibility(true)
+ }}
+ margin="normal"
+ InputLabelProps={{
+ shrink: true,
+ }}
+ variant="filled"
+ />
+
+ {refreshVisibility ? (
+
+ handleNewHostConnection()}>
+ Save
+
+
+ ) : null}
+
+
+ )
}
diff --git a/src/pages/status/NodeSetupWorkflow.tsx b/src/pages/status/NodeSetupWorkflow.tsx
index 2d8fa8d..fb9bd8a 100644
--- a/src/pages/status/NodeSetupWorkflow.tsx
+++ b/src/pages/status/NodeSetupWorkflow.tsx
@@ -1,15 +1,21 @@
-import React, { useEffect, useState } from 'react';
-import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
-import { Typography, Paper, Button, Step, StepLabel, StepContent, Stepper, StepButton } from '@material-ui/core/';
-import { CheckCircle, Error, Sync, ExpandLessSharp, ExpandMoreSharp } from '@material-ui/icons/';
-
-import DebugConnectionCheck from './SetupSteps/DebugConnectionCheck';
-import NodeConnectionCheck from './SetupSteps/NodeConnectionCheck';
-import VersionCheck from './SetupSteps/VersionCheck';
-import EthereumConnectionCheck from './SetupSteps/EthereumConnectionCheck';
-import ChequebookDeployFund from './SetupSteps/ChequebookDeployFund';
-import PeerConnection from './SetupSteps/PeerConnection';
+import { ReactElement, useEffect, useState } from 'react'
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'
+import { Typography, Paper, Button, Step, StepLabel, StepContent, Stepper, StepButton } from '@material-ui/core/'
+import { CheckCircle, Error, Sync, ExpandLessSharp, ExpandMoreSharp } from '@material-ui/icons/'
+import DebugConnectionCheck from './SetupSteps/DebugConnectionCheck'
+import NodeConnectionCheck from './SetupSteps/NodeConnectionCheck'
+import VersionCheck from './SetupSteps/VersionCheck'
+import EthereumConnectionCheck from './SetupSteps/EthereumConnectionCheck'
+import ChequebookDeployFund from './SetupSteps/ChequebookDeployFund'
+import PeerConnection from './SetupSteps/PeerConnection'
+import type {
+ ChequebookAddressResponse,
+ ChequebookBalanceResponse,
+ Health,
+ NodeAddresses,
+ Topology,
+} from '@ethersphere/bee-js'
const useStyles = makeStyles((theme: Theme) =>
createStyles({
@@ -27,50 +33,100 @@ const useStyles = makeStyles((theme: Theme) =>
padding: theme.spacing(5),
},
}),
-);
+)
function getSteps() {
return [
'Debug Connection Check',
- 'Version Check',
+ 'Version Check',
'Connect to Ethereum Blockchain',
'Deploy and Fund Chequebook',
- 'Node Connection Check',
+ 'Node Connection Check',
'Connect to Peers',
- ];
+ ]
+}
+interface Props {
+ nodeHealth: Health | null
+ nodeApiHealth: boolean
+ nodeAddresses: NodeAddresses | null
+ chequebookAddress: ChequebookAddressResponse | null
+ chequebookBalance: ChequebookBalanceResponse | null
+ beeRelease: LatestBeeRelease | null
+ nodeTopology: Topology | null
+ isLoadingBeeRelease: boolean
+ isLoadingNodeHealth: boolean
+ isLoadingNodeAddresses: boolean
+ isLoadingNodeTopology: boolean
+ isLoadingHealth: boolean
+ isLoadingChequebookAddress: boolean
+ isLoadingChequebookBalance: boolean
+ setStatusChecksVisible: (value: boolean) => void
+ apiHost: string
+ debugApiHost: string
}
-function getStepContent(step: number, props: any) {
-
+function getStepContent(step: number, props: Props) {
+ const {
+ nodeHealth,
+ debugApiHost,
+ beeRelease,
+ isLoadingBeeRelease,
+ nodeAddresses,
+ isLoadingNodeAddresses,
+ isLoadingChequebookBalance,
+ chequebookAddress,
+ chequebookBalance,
+ isLoadingChequebookAddress,
+ nodeApiHealth,
+ apiHost,
+ isLoadingNodeTopology,
+ nodeTopology,
+ } = props
switch (step) {
case 0:
- return ;
+ return
case 1:
- return ;
+ return
case 2:
- return ;
+ return
case 3:
- return ;
+ return (
+
+ )
case 4:
- return ;
+ return
default:
- return ;
+ return
}
}
-export default function NodeSetupWorkflow(props: any) {
- const {nodeHealth, nodeApiHealth, nodeAddresses, chequebookAddress, chequebookBalance, beeRelease, nodeTopology, setStatusChecksVisible} = props
- const classes = useStyles();
- const [activeStep, setActiveStep] = useState(0);
- const [completed, setCompleted] = useState<{ [k: number]: boolean }>({});
- const steps = getSteps();
+export default function NodeSetupWorkflow(props: Props): ReactElement {
+ const {
+ nodeHealth,
+ nodeApiHealth,
+ nodeAddresses,
+ chequebookAddress,
+ chequebookBalance,
+ beeRelease,
+ nodeTopology,
+ setStatusChecksVisible,
+ } = props
+ const classes = useStyles()
+ const [activeStep, setActiveStep] = useState(0)
+ const [completed, setCompleted] = useState<{ [k: number]: boolean }>({})
+ const steps = getSteps()
useEffect(() => {
const handleComplete = (index: number) => {
- const newCompleted = completed;
- newCompleted[index] = true;
- setCompleted(newCompleted);
- };
+ const newCompleted = completed
+ newCompleted[index] = true
+ setCompleted(newCompleted)
+ }
const evaluateNodeStatus = () => {
if (nodeHealth?.status === 'ok') {
@@ -88,7 +144,7 @@ export default function NodeSetupWorkflow(props: any) {
setActiveStep(3)
}
- if (chequebookAddress?.chequebookaddress && chequebookBalance.totalBalance > 0) {
+ if (chequebookAddress?.chequebookaddress && chequebookBalance && chequebookBalance.totalBalance > 0) {
handleComplete(3)
setActiveStep(4)
}
@@ -104,45 +160,62 @@ export default function NodeSetupWorkflow(props: any) {
}
}
evaluateNodeStatus()
- }, [nodeHealth, nodeApiHealth, nodeAddresses, chequebookAddress, beeRelease, chequebookBalance, nodeTopology, completed])
+ }, [
+ nodeHealth,
+ nodeApiHealth,
+ nodeAddresses,
+ chequebookAddress,
+ beeRelease,
+ chequebookBalance,
+ nodeTopology,
+ completed,
+ ])
const handleNext = () => {
- setActiveStep((prevActiveStep) => prevActiveStep + 1);
- };
+ setActiveStep(prevActiveStep => prevActiveStep + 1)
+ }
const handleBack = () => {
- setActiveStep((prevActiveStep) => prevActiveStep - 1);
- };
+ setActiveStep(prevActiveStep => prevActiveStep - 1)
+ }
const handleSetupComplete = () => {
setStatusChecksVisible(false)
- };
+ }
return (
Node Setup
-
- window.location.reload()}>Refresh Checks
+
+ window.location.reload()}>
+
+ Refresh Checks
+
{steps.map((label, index) => (
- setActiveStep(index === activeStep ? 6 : index)}
- StepIconComponent={() => {
- if(completed[index])
- return
- else {
- return
- }
- }}
+ setActiveStep(index === activeStep ? 6 : index)}
+ StepIconComponent={() => {
+ if (completed[index]) {
+ return
+ } else {
+ return
+ }
+ }}
>
- setActiveStep(index === activeStep ? 6 : index)} style={{justifyContent:'space-between'}}>
-
-
{label}
-
{index === activeStep ? : }
+
setActiveStep(index === activeStep ? 6 : index)}
+ style={{ justifyContent: 'space-between' }}
+ >
+
+
{label}
+
+ {index === activeStep ? : }
+
@@ -150,20 +223,11 @@ export default function NodeSetupWorkflow(props: any) {
{getStepContent(index, props)}
-
+
Back
-
- Next
+
+ Next
@@ -174,10 +238,7 @@ export default function NodeSetupWorkflow(props: any) {
{Object.values(completed).filter(value => value).length === 6 ? (
Bee setup complete! Welcome to the swarm and the internet of decentralized storage
-
+
Back
@@ -186,5 +247,5 @@ export default function NodeSetupWorkflow(props: any) {
) : null}
- );
+ )
}
diff --git a/src/pages/status/SetupSteps/ChequebookDeployFund.tsx b/src/pages/status/SetupSteps/ChequebookDeployFund.tsx
index 69b6641..528bd29 100644
--- a/src/pages/status/SetupSteps/ChequebookDeployFund.tsx
+++ b/src/pages/status/SetupSteps/ChequebookDeployFund.tsx
@@ -1,44 +1,57 @@
-import { Typography } from '@material-ui/core/';
-import { CheckCircle, Warning } from '@material-ui/icons/';
-import EthereumAddress from '../../../components/EthereumAddress';
-import DepositModal from '../../../components/DepositModal';
-import CodeBlockTabs from '../../../components/CodeBlockTabs';
+import { Typography } from '@material-ui/core/'
+import { CheckCircle, Warning } from '@material-ui/icons/'
+import EthereumAddress from '../../../components/EthereumAddress'
+import DepositModal from '../../../components/DepositModal'
+import CodeBlockTabs from '../../../components/CodeBlockTabs'
+import type { ChequebookAddressResponse, ChequebookBalanceResponse } from '@ethersphere/bee-js'
+import type { ReactElement } from 'react'
-export default function ChequebookDeployFund(props: any) {
- return (
-
-
- Deploy chequebook and fund with BZZ
- {props.chequebookAddress?.chequebookaddress ?
-
- : null }
-
-
- {props.chequebookAddress?.chequebookaddress && props.chequebookBalance && props.chequebookBalance?.totalBalance > 0 ?
-
-
- Your chequebook is deployed and funded!
-
- :
- props.loadingChequebookAddress || props.isLoadingChequebookBalance ?
- null
- :
-
-
- Your chequebook is either not deployed or funded. Run the below commands to get your address and deposit ETH. Then visit the BZZaar here https://bzz.ethswarm.org/?transaction=buy&amount=10&slippage=30&receiver=[ENTER_ADDRESS_HERE] to get BZZ
-
-
- }
-
-
Chequebook Address
-
-
- )
+interface Props {
+ chequebookAddress: ChequebookAddressResponse | null
+ chequebookBalance: ChequebookBalanceResponse | null
+ isLoadingChequebookAddress: boolean
+ isLoadingChequebookBalance: boolean
}
+
+const ChequebookDeployFund = (props: Props): ReactElement => (
+
+
+ Deploy chequebook and fund with BZZ
+ {props.chequebookAddress?.chequebookaddress ? : null}
+
+
+ {
+ // FIXME: this should be broken up
+ /* eslint-disable no-nested-ternary */
+ props.chequebookAddress?.chequebookaddress &&
+ props.chequebookBalance &&
+ props.chequebookBalance?.totalBalance > 0 ? (
+
+
+ Your chequebook is deployed and funded!
+
+ ) : props.isLoadingChequebookAddress || props.isLoadingChequebookBalance ? null : (
+
+
+
+ Your chequebook is either not deployed or funded. Run the below commands to get your address and deposit
+ ETH. Then visit the BZZaar here{' '}
+
+ https://bzz.ethswarm.org/?transaction=buy&amount=10&slippage=30&receiver=[ENTER_ADDRESS_HERE]
+ {' '}
+ to get BZZ
+
+
+
+ )
+ /* eslint-enable no-nested-ternary */
+ }
+
+
+ Chequebook Address
+
+
+
+)
+
+export default ChequebookDeployFund
diff --git a/src/pages/status/SetupSteps/DebugConnectionCheck.tsx b/src/pages/status/SetupSteps/DebugConnectionCheck.tsx
index 78ae987..aa8f7cd 100644
--- a/src/pages/status/SetupSteps/DebugConnectionCheck.tsx
+++ b/src/pages/status/SetupSteps/DebugConnectionCheck.tsx
@@ -1,76 +1,101 @@
-import React from 'react'
-import { Typography, Accordion, AccordionSummary, AccordionDetails } from '@material-ui/core/';
-import MuiAlert from '@material-ui/lab/Alert';
-import { CheckCircle, Error, ExpandMoreSharp } from '@material-ui/icons/';
+import type { ReactElement } from 'react'
+import { Typography, Accordion, AccordionSummary, AccordionDetails } from '@material-ui/core/'
+import MuiAlert from '@material-ui/lab/Alert'
+import { CheckCircle, Error, ExpandMoreSharp } from '@material-ui/icons/'
-import ConnectToHost from '../../../components/ConnectToHost';
+import ConnectToHost from '../../../components/ConnectToHost'
import CodeBlockTabs from '../../../components/CodeBlockTabs'
+import type { Health } from '@ethersphere/bee-js'
-export default function NodeConnectionCheck(props: any) {
- return (
+interface Props {
+ nodeHealth: Health | null
+ debugApiHost: string
+}
+
+export default function NodeConnectionCheck(props: Props): ReactElement {
+ return (
+
+
Connect to Bee Node Debug API
+
+
+ {props.nodeHealth?.status === 'ok' ? (
+
+ ) : (
+
+ )}
+
+ Debug API ({props.debugApiHost} )
+
+
+
-
Connect to Bee Node Debug API
-
-
- { props.nodeHealth?.status === 'ok' ?
-
- :
-
- }
- Debug API ({props.debugApiHost} )
-
-
-
- { props.nodeHealth?.status !== 'ok' ?
-
- We cannot connect to your nodes debug API at {props.debugApiHost} . Please check the following to troubleshoot your issue.
-
- }
- aria-controls="panel1a-content"
- id="panel1a-header"
- >
- Troubleshoot
-
-
-
+ {props.nodeHealth?.status !== 'ok' ? (
+
+ We cannot connect to your nodes debug API at{' '}
+ {props.debugApiHost} . Please check the following to troubleshoot
+ your issue.
+
+ } aria-controls="panel1a-content" id="panel1a-header">
+ Troubleshoot
+
+
+
- Check the status of your node by running the below command to see if your node is running.
+
+ Check the status of your node by running the below command to see if your node is running.
+
- If your node is running, check your firewall settings to make sure that port 1635 (or your custom specified port) is bound to localhost. If your node is not running try executing the below command to start your bee node
-
- Your debug node API should never be completely open to the internet. If you want to connect remotely, make sure your firewall settings are set to only allow specific trusted IP addresses and block all other ports. A simple google search for "what is my ip" will show you your computers public IP address to allow.
+
+ If your node is running, check your firewall settings to make sure that port 1635 (or your
+ custom specified port) is bound to localhost. If your node is not running try executing the
+ below command to start your bee node
+
+
+ Your debug node API should never be completely open to the internet. If you want to connect
+ remotely, make sure your firewall settings are set to only allow specific trusted IP addresses
+ and block all other ports. A simple google search for "what is my ip" will show you
+ your computers public IP address to allow.
Run the commands to validate your node is running and see the log output.
- Lastly, check your nodes configuration settings to validate the debug API is enabled and the Cross Origin Resource Sharing (CORS) setting is configured to allow your host. Config parameter debug-api-enable must be set to true and cors-allowed-origins must be set to your host domain or IP. If edits are made to the configuration run the restart command below for changes to take effect.
+
+ Lastly, check your nodes configuration settings to validate the debug API is enabled and the
+ Cross Origin Resource Sharing (CORS) setting is configured to allow your host. Config parameter{' '}
+ debug-api-enable must be set to true and{' '}
+ cors-allowed-origins must be set to your host domain or IP. If edits are made
+ to the configuration run the restart command below for changes to take effect.
+
-
-
-
-
- :
- null}
-
-
+
+
+
+
+ ) : null}
+
+
- )
-}
\ No newline at end of file
+ )
+}
diff --git a/src/pages/status/SetupSteps/EthereumConnectionCheck.tsx b/src/pages/status/SetupSteps/EthereumConnectionCheck.tsx
index 43026ea..57fe9ab 100644
--- a/src/pages/status/SetupSteps/EthereumConnectionCheck.tsx
+++ b/src/pages/status/SetupSteps/EthereumConnectionCheck.tsx
@@ -1,37 +1,56 @@
-import React from 'react';
-import { Typography } from '@material-ui/core/';
-import { CheckCircle, Warning } from '@material-ui/icons/';
-import EthereumAddress from '../../../components/EthereumAddress';
+import type { ReactElement } from 'react'
+import { Typography } from '@material-ui/core/'
+import { CheckCircle, Warning } from '@material-ui/icons/'
+import EthereumAddress from '../../../components/EthereumAddress'
+import type { NodeAddresses } from '@ethersphere/bee-js'
-export default function EthereumConnectionCheck(props: any) {
- return (
-
-
Connect to the ethereum blockchain.
-
- {props.nodeAddresses?.ethereum ?
-
-
- Your connected to the Ethereum network
-
- :
- props.loadingNodeAddresses ?
- null
- :
-
-
-
Your not connected to the Ethereum network.
-
Your Bee node must have access to the Ethereum blockchain, so that it can interact and deploy your chequebook contract. You can run your own Goerli node , or use a provider such as rpc.slock.it/goerli or Infura .
-
- By default, Bee expects a local Goerli node at http://localhost:8545. To use a provider instead, simply change your --swap-endpoint in your configuration file.
-
-
- }
-
-
Node Address
-
-
- )
+interface Props {
+ nodeAddresses: NodeAddresses | null
+ isLoadingNodeAddresses: boolean
+}
+
+export default function EthereumConnectionCheck(props: Props): ReactElement {
+ return (
+
+
Connect to the ethereum blockchain.
+
+ {
+ // FIXME: this should be broken up
+ /* eslint-disable no-nested-ternary */
+ props.nodeAddresses?.ethereum ? (
+
+
+ Your connected to the Ethereum network
+
+ ) : props.isLoadingNodeAddresses ? null : (
+
+
+
Your not connected to the Ethereum network.
+
+ Your Bee node must have access to the Ethereum blockchain, so that it can interact and deploy your
+ chequebook contract. You can run{' '}
+
+ your own Goerli node
+
+ , or use a provider such as{' '}
+
+ rpc.slock.it/goerli
+ {' '}
+ or{' '}
+
+ Infura
+
+ . By default, Bee expects a local Goerli node at http://localhost:8545. To use a provider instead,
+ simply change your --swap-endpoint in your configuration file.
+
+
+ ) /* eslint-enable no-nested-ternary */
+ }
+
+
+ Node Address
+
+
+
+ )
}
diff --git a/src/pages/status/SetupSteps/NodeConnectionCheck.tsx b/src/pages/status/SetupSteps/NodeConnectionCheck.tsx
index 19cf127..64cdc57 100644
--- a/src/pages/status/SetupSteps/NodeConnectionCheck.tsx
+++ b/src/pages/status/SetupSteps/NodeConnectionCheck.tsx
@@ -1,64 +1,71 @@
-import React from 'react'
-import { Typography, Accordion, AccordionSummary, AccordionDetails } from '@material-ui/core/';
-import { CheckCircle, Error, ExpandMoreSharp } from '@material-ui/icons/';
+import React, { ReactElement } from 'react'
+import { Typography, Accordion, AccordionSummary, AccordionDetails } from '@material-ui/core/'
+import { CheckCircle, Error, ExpandMoreSharp } from '@material-ui/icons/'
-import ConnectToHost from '../../../components/ConnectToHost';
+import ConnectToHost from '../../../components/ConnectToHost'
import CodeBlockTabs from '../../../components/CodeBlockTabs'
-export default function NodeConnectionCheck(props: any) {
- return (
-
-
Connect to Bee Node API
-
- { props.nodeApiHealth ?
-
- :
-
- }
- Node API ({props.apiHost} )
-
-
-
- { !props.nodeApiHealth ?
-
- We cannot connect to your nodes API at {props.apiHost} . Please check the following to troubleshoot your issue.
-
- }
- aria-controls="panel1a-content"
- id="panel1a-header"
- >
- Troubleshoot
-
-
-
-
- Check the status of your node by running the below command to see if your node is running.
-
- If your node is running, check your firewall settings to make sure that port 1633 (or your custom specified port) is exposed to the internet. If your node is not running try executing the below command to start your bee node
-
- Run the commands to validate your node is running and see the log output.
-
-
-
-
-
-
- :
- null}
-
-
- )
+interface Props {
+ nodeApiHealth: boolean
+ apiHost: string
+}
+
+export default function NodeConnectionCheck(props: Props): ReactElement {
+ return (
+
+
Connect to Bee Node API
+
+ {props.nodeApiHealth ? (
+
+ ) : (
+
+ )}
+
+ Node API ({props.apiHost} )
+
+
+
+
+ {!props.nodeApiHealth ? (
+
+ We cannot connect to your nodes API at {props.apiHost} . Please
+ check the following to troubleshoot your issue.
+
+ } aria-controls="panel1a-content" id="panel1a-header">
+ Troubleshoot
+
+
+
+
+ Check the status of your node by running the below command to see if your node is running.
+
+
+ If your node is running, check your firewall settings to make sure that port 1633 (or your custom
+ specified port) is exposed to the internet. If your node is not running try executing the below
+ command to start your bee node
+
+
+ Run the commands to validate your node is running and see the log output.
+
+
+
+
+
+
+ ) : null}
+
+
+ )
}
diff --git a/src/pages/status/SetupSteps/PeerConnection.tsx b/src/pages/status/SetupSteps/PeerConnection.tsx
index 7fb71d1..c38852b 100644
--- a/src/pages/status/SetupSteps/PeerConnection.tsx
+++ b/src/pages/status/SetupSteps/PeerConnection.tsx
@@ -1,45 +1,53 @@
-import React from 'react';
-import { Typography } from '@material-ui/core/';
-import { CheckCircle, Warning } from '@material-ui/icons/';
+import React, { ReactElement } from 'react'
+import { Typography } from '@material-ui/core/'
+import { CheckCircle, Warning } from '@material-ui/icons/'
+import { Topology } from '@ethersphere/bee-js'
-export default function PeerConnection(props: any) {
- return (
-
-
Connect to Peers
-
- {props.nodeTopology.connected && props.nodeTopology.connected > 0 ?
-
-
- Your connected to {props.nodeTopology.connected} peers!
-
- :
- props.loadingNodeTopology ?
- null
- :
-
-
- Your node is not connected to any peers
-
- }
-
-
-
-
- Connected Peers
-
-
- { props.nodeTopology.connected }
-
-
-
-
- Discovered Nodes
-
-
- { props.nodeTopology.population }
-
-
-
-
- )
+interface Props {
+ nodeTopology: Topology | null
+ isLoadingNodeTopology: boolean
+}
+
+export default function PeerConnection(props: Props): ReactElement {
+ return (
+
+
Connect to Peers
+
+ html_url
+ {
+ // FIXME: this should be broken up
+ /* eslint-disable no-nested-ternary */
+ props.nodeTopology?.connected && props.nodeTopology?.connected > 0 ? (
+
+
+ Your connected to {props.nodeTopology.connected} peers!
+
+ ) : props.isLoadingNodeTopology ? null : (
+
+
+ Your node is not connected to any peers
+
+ ) /* eslint-enable no-nested-ternary */
+ }
+
+
+
+
+ Connected Peers
+
+
+ {props.nodeTopology?.connected}
+
+
+
+
+ Discovered Nodes
+
+
+ {props.nodeTopology?.population}
+
+
+
+
+ )
}
diff --git a/src/pages/status/SetupSteps/VersionCheck.tsx b/src/pages/status/SetupSteps/VersionCheck.tsx
index 6b1f413..f0887b2 100644
--- a/src/pages/status/SetupSteps/VersionCheck.tsx
+++ b/src/pages/status/SetupSteps/VersionCheck.tsx
@@ -1,45 +1,81 @@
-import React from 'react';
-import { Typography } from '@material-ui/core/';
-import { CheckCircle, Warning } from '@material-ui/icons/';
-import CodeBlockTabs from '../../../components/CodeBlockTabs';
+import React, { ReactElement } from 'react'
+import { Typography } from '@material-ui/core/'
+import { CheckCircle, Warning } from '@material-ui/icons/'
+import CodeBlockTabs from '../../../components/CodeBlockTabs'
+import { Health } from '@ethersphere/bee-js'
-export default function VersionCheck(props: any) {
- return (
-
-
Check to make sure the latest version of Bee is running
- {props.beeRelease && props.beeRelease.name === `v${props.nodeReadiness?.version?.split('-')[0]}` ?
-
-
- Your running the latest version of Bee
-
- :
- props.loadingBeeRelease ?
- null
- :
-
-
-
Your Bee version is out of date. Please update to the latest before continuing. Rerun the installation script below to upgrade. Reference the docs for help with updating. Docs
-
-
- }
-
-
-
Current Version
-
- {props.nodeReadiness?.version ? ` v${props.nodeReadiness?.version?.split('-')[0]}` : '-'}
-
-
-
-
Latest Version
-
- {props.beeRelease && props.beeRelease.name ? props.beeRelease.name : '-'}
-
-
-
-
- )
+interface Props {
+ beeRelease: LatestBeeRelease | null
+ isLoadingBeeRelease: boolean
+ nodeHealth: Health | null
+}
+
+export default function VersionCheck(props: Props): ReactElement {
+ return (
+
+
+ Check to make sure the latest version of{' '}
+
+ Bee
+ {' '}
+ is running
+
+ {
+ // FIXME: this should be broken up
+ /* eslint-disable no-nested-ternary */
+ props.beeRelease && props.beeRelease.name === `v${props.nodeHealth?.version?.split('-')[0]}` ? (
+
+
+ Your running the latest version of Bee
+
+ ) : props.isLoadingBeeRelease ? null : (
+
+
+
+ Your Bee version is out of date. Please update to the{' '}
+
+ latest
+ {' '}
+ before continuing. Rerun the installation script below to upgrade. Reference the docs for help with
+ updating.{' '}
+
+ Docs
+
+
+
+
+ ) /* eslint-enable no-nested-ternary */
+ }
+
+
+
+ Current Version
+
+
+ {props.nodeHealth?.version ? ` v${props.nodeHealth?.version?.split('-')[0]}` : '-'}
+
+
+
+
+ Latest Version
+
+
+ {props.beeRelease && props.beeRelease.name ? props.beeRelease.name : '-'}
+
+
+
+
+ )
}
diff --git a/src/pages/status/StatusCard.tsx b/src/pages/status/StatusCard.tsx
index 0e34625..967189d 100644
--- a/src/pages/status/StatusCard.tsx
+++ b/src/pages/status/StatusCard.tsx
@@ -1,13 +1,13 @@
-import React, { useState } from 'react'
-import { Link } from 'react-router-dom';
+import { ReactElement, useState } from 'react'
+import { Link } from 'react-router-dom'
-import { Theme, createStyles, makeStyles } from '@material-ui/core/styles';
-import { Card, CardContent, Typography, Chip, Button } from '@material-ui/core/';
-import { CheckCircle, Error, ArrowRight, ArrowDropUp } from '@material-ui/icons/';
-import { Skeleton } from '@material-ui/lab';
-import type { Health, NodeAddresses, Topology } from '@ethersphere/bee-js';
+import { createStyles, makeStyles } from '@material-ui/core/styles'
+import { Card, CardContent, Typography, Chip, Button } from '@material-ui/core/'
+import { CheckCircle, Error, ArrowRight, ArrowDropUp } from '@material-ui/icons/'
+import { Skeleton } from '@material-ui/lab'
+import type { Health, NodeAddresses, Topology } from '@ethersphere/bee-js'
-const useStyles = makeStyles((theme: Theme) =>
+const useStyles = makeStyles(() =>
createStyles({
root: {
display: 'flex',
@@ -22,120 +22,132 @@ const useStyles = makeStyles((theme: Theme) =>
flex: '1 0 auto',
},
status: {
- color: '#2145a0',
- backgroundColor: '#e1effe',
- }
+ color: '#2145a0',
+ backgroundColor: '#e1effe',
+ },
}),
-);
+)
-interface IProps{
- nodeHealth: Health,
- loadingNodeHealth: boolean,
- beeRelease: any,
- loadingBeeRelease: boolean,
- nodeAddresses: NodeAddresses,
- nodeTopology: Topology,
- loadingNodeTopology: boolean,
- setStatusChecksVisible: any,
+interface Props {
+ nodeHealth: Health | null
+ loadingNodeHealth: boolean
+ beeRelease: LatestBeeRelease | null
+ loadingBeeRelease: boolean
+ nodeAddresses: NodeAddresses
+ nodeTopology: Topology
+ loadingNodeTopology: boolean
+ setStatusChecksVisible: (value: boolean) => void
}
-function StatusCard(props: IProps) {
- const classes = useStyles();
+function StatusCard(props: Props): ReactElement {
+ const classes = useStyles()
- const [underlayAddressesVisible, setUnderlayAddresessVisible] = useState(false)
+ const [underlayAddressesVisible, setUnderlayAddresessVisible] = useState(false)
- return (
-
-
- { !props.loadingNodeHealth && props.nodeHealth ?
-
-
-
- { props.nodeHealth.status === 'ok' ?
-
-
- Connected to Bee Node
-
- :
-
-
- Could not connect to Bee Node
-
- }
- props.setStatusChecksVisible(true)}>View Status Checks
-
-
- Discovered Nodes: { props.nodeTopology.population }
-
- Connected Peers:
-
- { props.nodeTopology.connected }
-
-
-
+ return (
+
+
+ {!props.loadingNodeHealth && props.nodeHealth ? (
+
+
+
+ {props.nodeHealth.status === 'ok' ? (
+
+
+ Connected to Bee Node
+
+ ) : (
+
+
+ Could not connect to Bee Node
+
+ )}
+ props.setStatusChecksVisible(true)}
+ >
+ View Status Checks
+
+
+
+ Discovered Nodes: {props.nodeTopology.population}
+
+ Connected Peers:
+ {props.nodeTopology.connected}
+
+
+
+
+ AGENT:
+
+ Bee
+
+ {props.nodeHealth?.version ? ` v${props.nodeHealth.version}` : '-'}
+ {
+ // FIXME: this should be broken up
+ /* eslint-disable no-nested-ternary */
+ props.beeRelease && props.beeRelease.name === `v${props.nodeHealth?.version?.split('-')[0]}` ? (
+
+ ) : props.loadingBeeRelease ? (
+ ''
+ ) : (
+ update
+ )
+ /* eslint-enable no-nested-ternary */
+ }
+
+
+ PUBLIC KEY:
+ {props.nodeAddresses.public_key ? props.nodeAddresses.public_key : '-'}
+
+
+ PSS PUBLIC KEY:
+ {props.nodeAddresses.pss_public_key ? props.nodeAddresses.pss_public_key : '-'}
+
+
+
+ OVERLAY ADDRESS (PEER ID):
+ {props.nodeAddresses.overlay ? props.nodeAddresses.overlay : '-'}
+
+ setUnderlayAddresessVisible(!underlayAddressesVisible)}>
+
+ {underlayAddressesVisible ? (
+
+ ) : (
+
+ )}
+ Underlay Addresses
+
+
+ {underlayAddressesVisible ? (
-
- AGENT:
- Bee
- {props.nodeHealth?.version ? ` v${props.nodeHealth.version}` : '-'}
- {props.beeRelease && props.beeRelease.name === `v${props.nodeHealth?.version?.split('-')[0]}` ?
-
- :
- props.loadingBeeRelease ?
- ''
- :
- update
- }
-
-
- PUBLIC KEY:
- { props.nodeAddresses.public_key ? props.nodeAddresses.public_key : '-' }
-
-
- PSS PUBLIC KEY:
- { props.nodeAddresses.pss_public_key ? props.nodeAddresses.pss_public_key : '-' }
-
-
-
- OVERLAY ADDRESS (PEER ID):
- { props.nodeAddresses.overlay ? props.nodeAddresses.overlay : '-' }
-
- setUnderlayAddresessVisible(!underlayAddressesVisible)}>
-
- { underlayAddressesVisible ?
- :
-
- }
- Underlay Addresses
-
-
- {underlayAddressesVisible ?
-
-
- { props.nodeAddresses.underlay ?
- props.nodeAddresses.underlay.map(item => (
{item} ))
- : '-' }
-
- : null}
-
+ {props.nodeAddresses.underlay
+ ? props.nodeAddresses.underlay.map(item =>
{item} )
+ : '-'}
-
-
- :
-
-
-
-
-
- }
-
-
- )
+ ) : null}
+
+
+
+
+ ) : (
+
+
+
+
+
+ )}
+
+
+ )
}
export default StatusCard
diff --git a/src/pages/status/index.tsx b/src/pages/status/index.tsx
index 12e6c44..151ecf8 100644
--- a/src/pages/status/index.tsx
+++ b/src/pages/status/index.tsx
@@ -1,135 +1,143 @@
-import React, { useState, useEffect } from 'react'
-import axios from 'axios';
-import { Container, CircularProgress } from '@material-ui/core';
+import { useState, useEffect, ReactElement } from 'react'
+import axios from 'axios'
+import { Container, CircularProgress } from '@material-ui/core'
-import NodeSetupWorkflow from './NodeSetupWorkflow';
-import StatusCard from './StatusCard';
-import EthereumAddressCard from '../../components/EthereumAddressCard';
-import { useApiHealth, useDebugApiHealth, useApiNodeAddresses, useApiChequebookAddress, useApiNodeTopology, useApiChequebookBalance } from '../../hooks/apiHooks';
+import NodeSetupWorkflow from './NodeSetupWorkflow'
+import StatusCard from './StatusCard'
+import EthereumAddressCard from '../../components/EthereumAddressCard'
+import {
+ useApiHealth,
+ useDebugApiHealth,
+ useApiNodeAddresses,
+ useApiChequebookAddress,
+ useApiNodeTopology,
+ useApiChequebookBalance,
+} from '../../hooks/apiHooks'
-export default function Status() {
- const [beeRelease, setBeeRelease] = useState({ name: ''});
- const [isLoadingBeeRelease, setIsLoadingBeeRelease] = useState(false);
+export default function Status(): ReactElement {
+ const [beeRelease, setBeeRelease] = useState(null)
+ const [isLoadingBeeRelease, setIsLoadingBeeRelease] = useState(false)
- const [apiHost, setApiHost] = useState('');
- const [debugApiHost, setDebugApiHost] = useState('');
+ const [apiHost, setApiHost] = useState('')
+ const [debugApiHost, setDebugApiHost] = useState('')
- const [statusChecksVisible, setStatusChecksVisible] = useState(false);
+ const [statusChecksVisible, setStatusChecksVisible] = useState(false)
- const { health, isLoadingHealth } = useApiHealth()
- const { nodeHealth, isLoadingNodeHealth } = useDebugApiHealth()
- const { nodeAddresses, isLoadingNodeAddresses } = useApiNodeAddresses()
- const { chequebookAddress, isLoadingChequebookAddress } = useApiChequebookAddress()
- const { topology: nodeTopology, isLoading: isLoadingNodeTopology } = useApiNodeTopology()
- const { chequebookBalance, isLoadingChequebookBalance } = useApiChequebookBalance()
+ const { health, isLoadingHealth } = useApiHealth()
+ const { nodeHealth, isLoadingNodeHealth } = useDebugApiHealth()
+ const { nodeAddresses, isLoadingNodeAddresses } = useApiNodeAddresses()
+ const { chequebookAddress, isLoadingChequebookAddress } = useApiChequebookAddress()
+ const { topology: nodeTopology, isLoading: isLoadingNodeTopology } = useApiNodeTopology()
+ const { chequebookBalance, isLoadingChequebookBalance } = useApiChequebookBalance()
+ const fetchLatestBeeRelease = () => {
+ setIsLoadingBeeRelease(true)
+ axios
+ .get(`${process.env.REACT_APP_BEE_GITHUB_REPO_URL}/releases/latest`)
+ .then(res => {
+ setBeeRelease(res.data)
+ })
+ .catch(() => {
+ // FIXME: should do something about the error
+ })
+ .finally(() => {
+ setIsLoadingBeeRelease(false)
+ })
+ }
- const fetchLatestBeeRelease = async () => {
- setIsLoadingBeeRelease(true)
- axios.get(`${process.env.REACT_APP_BEE_GITHUB_REPO_URL}/releases/latest`)
- .then(res => {
- setBeeRelease(res.data)
- })
- .catch(error => {
- console.log(error)
- })
- .finally(() => {
- setIsLoadingBeeRelease(false)
- })
+ const fetchApiHost = () => {
+ let apiHost
+
+ if (sessionStorage.getItem('api_host')) {
+ apiHost = String(sessionStorage.getItem('api_host') || '')
+ } else {
+ apiHost = String(process.env.REACT_APP_BEE_HOST)
}
+ setApiHost(apiHost)
+ }
- const fetchApiHost = () => {
- let apiHost
-
- if (sessionStorage.getItem('api_host')) {
- apiHost = String(sessionStorage.getItem('api_host') || '')
- } else {
- apiHost = String(process.env.REACT_APP_BEE_HOST)
- }
- setApiHost(apiHost)
+ const fetchDebugApiHost = () => {
+ let debugApiHost
+
+ if (sessionStorage.getItem('debug_api_host')) {
+ debugApiHost = String(sessionStorage.getItem('debug_api_host') || '')
+ } else {
+ debugApiHost = String(process.env.REACT_APP_BEE_DEBUG_HOST)
}
+ setDebugApiHost(debugApiHost)
+ }
- const fetchDebugApiHost = () => {
- let debugApiHost
-
- if (sessionStorage.getItem('debug_api_host')) {
- debugApiHost = String(sessionStorage.getItem('debug_api_host') || '')
- } else {
- debugApiHost = String(process.env.REACT_APP_BEE_DEBUG_HOST)
- }
- setDebugApiHost(debugApiHost)
- }
+ useEffect(() => {
+ fetchApiHost()
+ fetchDebugApiHost()
+ fetchLatestBeeRelease()
+ }, [])
- useEffect(() => {
- fetchApiHost()
- fetchDebugApiHost()
- fetchLatestBeeRelease()
- }, []);
-
- return (
+ // FIXME: this should be broken up
+ /* eslint-disable no-nested-ternary */
+ return (
+
+ {nodeHealth?.status === 'ok' &&
+ health &&
+ beeRelease &&
+ beeRelease.name === `v${nodeHealth?.version?.split('-')[0]}` &&
+ nodeAddresses?.ethereum &&
+ chequebookAddress?.chequebookaddress &&
+ chequebookBalance &&
+ chequebookBalance?.totalBalance > 0 &&
+ nodeTopology?.connected &&
+ nodeTopology?.connected > 0 &&
+ !statusChecksVisible ? (
- {nodeHealth?.status === 'ok' &&
- health &&
- beeRelease &&
- beeRelease.name === `v${nodeHealth?.version?.split('-')[0]}` &&
- nodeAddresses?.ethereum &&
- chequebookAddress?.chequebookaddress && chequebookBalance && chequebookBalance?.totalBalance > 0 &&
- nodeTopology?.connected && nodeTopology?.connected > 0 &&
- !statusChecksVisible ?
-
-
-
-
- :
- ( isLoadingNodeHealth || isLoadingHealth || isLoadingChequebookAddress ||
- isLoadingNodeTopology || isLoadingBeeRelease || isLoadingNodeAddresses || isLoadingBeeRelease || isLoadingChequebookBalance
- )
- ?
-
-
-
- :
-
- }
+
+
- )
+ ) : isLoadingNodeHealth ||
+ isLoadingHealth ||
+ isLoadingChequebookAddress ||
+ isLoadingNodeTopology ||
+ isLoadingBeeRelease ||
+ isLoadingNodeAddresses ||
+ isLoadingBeeRelease ||
+ isLoadingChequebookBalance ? (
+
+
+
+ ) : (
+
+ )}
+
+ )
}
diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts
index 6431bc5..b86041e 100644
--- a/src/react-app-env.d.ts
+++ b/src/react-app-env.d.ts
@@ -1 +1,6 @@
///
+
+interface LatestBeeRelease {
+ name: string
+ html_url: string
+}
diff --git a/src/reportWebVitals.ts b/src/reportWebVitals.ts
index 49a2a16..dfe2a4f 100644
--- a/src/reportWebVitals.ts
+++ b/src/reportWebVitals.ts
@@ -1,15 +1,15 @@
-import { ReportHandler } from 'web-vitals';
+import { ReportHandler } from 'web-vitals'
-const reportWebVitals = (onPerfEntry?: ReportHandler) => {
+const reportWebVitals = (onPerfEntry?: ReportHandler): void => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
- getCLS(onPerfEntry);
- getFID(onPerfEntry);
- getFCP(onPerfEntry);
- getLCP(onPerfEntry);
- getTTFB(onPerfEntry);
- });
+ getCLS(onPerfEntry)
+ getFID(onPerfEntry)
+ getFCP(onPerfEntry)
+ getLCP(onPerfEntry)
+ getTTFB(onPerfEntry)
+ })
}
-};
+}
-export default reportWebVitals;
+export default reportWebVitals
diff --git a/src/routes/AppRoute.jsx b/src/routes/AppRoute.jsx
deleted file mode 100644
index 6acfe41..0000000
--- a/src/routes/AppRoute.jsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import React from 'react';
-import { Route } from 'react-router-dom';
-
-
-const AppRoute = ( {component: Component, layout: Layout, ...rest }) => (
- (
-
-
-
- )} />
- )
-
-export default AppRoute;
\ No newline at end of file
diff --git a/src/routes/AppRoute.tsx b/src/routes/AppRoute.tsx
new file mode 100644
index 0000000..3f5327e
--- /dev/null
+++ b/src/routes/AppRoute.tsx
@@ -0,0 +1,23 @@
+import type { JSXElementConstructor, ReactElement } from 'react'
+import { Route, RouteComponentProps } from 'react-router-dom'
+
+interface Props {
+ component: JSXElementConstructor
+ layout: JSXElementConstructor
+ exact?: boolean
+ path: string
+}
+
+const AppRoute = ({ component: Component, layout: Layout, exact, path }: Props): ReactElement => (
+ (
+
+
+
+ )}
+ />
+)
+
+export default AppRoute
diff --git a/src/routes/routes.tsx b/src/routes/routes.tsx
index 8e53b5d..ae4ce78 100644
--- a/src/routes/routes.tsx
+++ b/src/routes/routes.tsx
@@ -1,27 +1,26 @@
-import React from 'react';
-import { Switch } from 'react-router-dom';
+import type { ReactElement } from 'react'
+import { Switch } from 'react-router-dom'
-import AppRoute from './AppRoute';
+import AppRoute from './AppRoute'
// layouts
-import Dashboard from '../layout/Dashboard';
+import Dashboard from '../layout/Dashboard'
// pages
-import Status from '../pages/status/index';
-import Files from '../pages/files/index';
-import Peers from '../pages/peers/index';
-import Accounting from '../pages/accounting/index';
-import Settings from '../pages/settings/index';
+import Status from '../pages/status/index'
+import Files from '../pages/files/index'
+import Peers from '../pages/peers/index'
+import Accounting from '../pages/accounting/index'
+import Settings from '../pages/settings/index'
+const BaseRouter = (): ReactElement => (
+
+
+
+
+
+
+
+)
-const BaseRouter = (props: any) => (
-
-
-
-
-
-
-
-);
-
-export default BaseRouter;
\ No newline at end of file
+export default BaseRouter
diff --git a/src/services/bee.tsx b/src/services/bee.tsx
index 3e3b715..63a3e10 100644
--- a/src/services/bee.tsx
+++ b/src/services/bee.tsx
@@ -1,95 +1,116 @@
-import { Bee, BeeDebug, Reference } from "@ethersphere/bee-js";
+import {
+ AllSettlements,
+ BalanceResponse,
+ Bee,
+ BeeDebug,
+ CashoutResponse,
+ ChequebookAddressResponse,
+ ChequebookBalanceResponse,
+ Data,
+ DepositTokensResponse,
+ FileData,
+ Health,
+ LastCashoutActionResponse,
+ LastChequesForPeerResponse,
+ LastChequesResponse,
+ NodeAddresses,
+ Peer,
+ PingResponse,
+ Reference,
+ Topology,
+ WithdrawTokensResponse,
+} from '@ethersphere/bee-js'
const beeJSClient = () => {
- let apiHost = process.env.REACT_APP_BEE_HOST || 'http://localhost:1633'
-
- if (sessionStorage.getItem('api_host')) {
- apiHost = String(sessionStorage.getItem('api_host'))
- }
+ let apiHost = process.env.REACT_APP_BEE_HOST || 'http://localhost:1633'
- return new Bee(apiHost)
+ if (sessionStorage.getItem('api_host')) {
+ apiHost = String(sessionStorage.getItem('api_host'))
+ }
+
+ return new Bee(apiHost)
}
const beeJSDebugClient = () => {
- let debugApiHost = process.env.REACT_APP_BEE_DEBUG_HOST || 'http://localhost:1635'
-
- if (sessionStorage.getItem('debug_api_host')) {
- debugApiHost = String(sessionStorage.getItem('debug_api_host'))
- }
+ let debugApiHost = process.env.REACT_APP_BEE_DEBUG_HOST || 'http://localhost:1635'
- return new BeeDebug(debugApiHost)
+ if (sessionStorage.getItem('debug_api_host')) {
+ debugApiHost = String(sessionStorage.getItem('debug_api_host'))
+ }
+
+ return new BeeDebug(debugApiHost)
}
export const beeApi = {
- status: {
- health() {
- return beeJSClient().isConnected()
- }
+ status: {
+ health(): Promise {
+ return beeJSClient().isConnected()
},
- files: {
- uploadFile(file: File) {
- return beeJSClient().uploadFile(file)
- },
- downloadFile(hash: string | Reference) {
- return beeJSClient().downloadFile(hash)
- },
+ },
+ files: {
+ uploadFile(file: File): Promise {
+ return beeJSClient().uploadFile(file)
},
+ downloadFile(hash: string | Reference): Promise> {
+ return beeJSClient().downloadFile(hash)
+ },
+ },
}
export const beeDebugApi = {
- status: {
- nodeHealth() {
- return beeJSDebugClient().getHealth()
- },
+ status: {
+ nodeHealth(): Promise {
+ return beeJSDebugClient().getHealth()
},
- connectivity: {
- addresses() {
- return beeJSDebugClient().getNodeAddresses()
- },
- listPeers() {
- return beeJSDebugClient().getPeers()
- },
- topology() {
- return beeJSDebugClient().getTopology()
- },
- ping(peerId: string) {
- return beeJSDebugClient().pingPeer(peerId)
- }
+ },
+ connectivity: {
+ addresses(): Promise {
+ return beeJSDebugClient().getNodeAddresses()
},
- balance: {
- balances() {
- return beeJSDebugClient().getAllBalances()
- }
+ listPeers(): Promise {
+ return beeJSDebugClient().getPeers()
},
- chequebook: {
- address() {
- return beeJSDebugClient().getChequebookAddress()
- },
- balance() {
- return beeJSDebugClient().getChequebookBalance()
- },
- getLastCheques() {
- return beeJSDebugClient().getLastCheques()
- },
- peerCashout(peerId: string) {
- return beeJSDebugClient().cashoutLastCheque(peerId)
- },
- getPeerLastCashout(peerId: string) {
- return beeJSDebugClient().getLastCashoutAction(peerId)
- },
- getPeerLastCheques(peerId: string) {
- return beeJSDebugClient().getLastChequesForPeer(peerId)
- },
- withdraw(amount: bigint) {
- return beeJSDebugClient().withdrawTokens(amount)
- },
- deposit(amount: bigint) {
- return beeJSDebugClient().depositTokens(amount)
- },
+ topology(): Promise {
+ return beeJSDebugClient().getTopology()
},
- settlements: {
- getSettlements() {
- return beeJSDebugClient().getAllSettlements()
- }
- }
-}
\ No newline at end of file
+ ping(peerId: string): Promise {
+ return beeJSDebugClient().pingPeer(peerId)
+ },
+ },
+ balance: {
+ balances(): Promise {
+ return beeJSDebugClient().getAllBalances()
+ },
+ },
+ chequebook: {
+ address(): Promise {
+ return beeJSDebugClient().getChequebookAddress()
+ },
+ balance(): Promise {
+ return beeJSDebugClient().getChequebookBalance()
+ },
+ getLastCheques(): Promise {
+ return beeJSDebugClient().getLastCheques()
+ },
+ peerCashout(peerId: string): Promise {
+ return beeJSDebugClient().cashoutLastCheque(peerId)
+ },
+ getPeerLastCashout(peerId: string): Promise {
+ return beeJSDebugClient().getLastCashoutAction(peerId)
+ },
+ getPeerLastCheques(peerId: string): Promise {
+ return beeJSDebugClient().getLastChequesForPeer(peerId)
+ },
+ withdraw(amount: bigint): Promise {
+ return beeJSDebugClient().withdrawTokens(amount)
+ },
+ deposit(amount: bigint): Promise {
+ return beeJSDebugClient().depositTokens(amount)
+ },
+ },
+ settlements: {
+ getSettlements(): Promise {
+ return beeJSDebugClient().getAllSettlements()
+ },
+ },
+}
diff --git a/src/setupTests.ts b/src/setupTests.ts
index 8f2609b..52aaef1 100644
--- a/src/setupTests.ts
+++ b/src/setupTests.ts
@@ -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';
+import '@testing-library/jest-dom'
diff --git a/src/theme.tsx b/src/theme.tsx
index 1e0296d..133f713 100644
--- a/src/theme.tsx
+++ b/src/theme.tsx
@@ -1,4 +1,4 @@
-import { createMuiTheme } from '@material-ui/core/styles';
+import { createMuiTheme } from '@material-ui/core/styles'
declare module '@material-ui/core/styles/createPalette' {
interface TypeBackground {
@@ -7,54 +7,38 @@ declare module '@material-ui/core/styles/createPalette' {
}
export const lightTheme = createMuiTheme({
- palette: {
- type: "light",
- background: {
- default: '#fafafa',
- },
- primary: {
- main: '#6a6a6a',
- },
- secondary: {
- main: '#333333',
- },
+ palette: {
+ type: 'light',
+ background: {
+ default: '#fafafa',
},
- typography: {
- fontFamily: [
- 'Work Sans',
- 'Montserrat',
- 'Nunito',
- 'Roboto',
- '"Helvetica Neue"',
- 'Arial',
- 'sans-serif'
- ].join(','),
- }
-});
-
+ primary: {
+ main: '#6a6a6a',
+ },
+ secondary: {
+ main: '#333333',
+ },
+ },
+ typography: {
+ fontFamily: ['Work Sans', 'Montserrat', 'Nunito', 'Roboto', '"Helvetica Neue"', 'Arial', 'sans-serif'].join(','),
+ },
+})
+
export const darkTheme = createMuiTheme({
- palette: {
- type: "dark",
- background: {
- default: '#0d1117',
- paper: '#161b22',
- },
- primary: {
- main: '#dd7700',
- },
- secondary: {
- main: '#1f2937',
- },
+ palette: {
+ type: 'dark',
+ background: {
+ default: '#0d1117',
+ paper: '#161b22',
},
- typography: {
- fontFamily: [
- 'Work Sans',
- 'Montserrat',
- 'Nunito',
- 'Roboto',
- '"Helvetica Neue"',
- 'Arial',
- 'sans-serif'
- ].join(','),
- }
-});
\ No newline at end of file
+ primary: {
+ main: '#dd7700',
+ },
+ secondary: {
+ main: '#1f2937',
+ },
+ },
+ typography: {
+ fontFamily: ['Work Sans', 'Montserrat', 'Nunito', 'Roboto', '"Helvetica Neue"', 'Arial', 'sans-serif'].join(','),
+ },
+})
diff --git a/src/utils/common.tsx b/src/utils/common.tsx
index 90baba2..0bf8696 100644
--- a/src/utils/common.tsx
+++ b/src/utils/common.tsx
@@ -1,4 +1,3 @@
-
-export const ConvertBalanceToBZZ = (amount: number) => {
- return amount / (10 ** 16)
-}
\ No newline at end of file
+export const ConvertBalanceToBZZ = (amount: number): number => {
+ return amount / 10 ** 16
+}