add vpn and delegates
This commit is contained in:
342
package-lock.json
generated
342
package-lock.json
generated
@@ -13,6 +13,7 @@
|
|||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"chart.js": "^3.5.0",
|
"chart.js": "^3.5.0",
|
||||||
"chartjs-adapter-moment": "^1.0.0",
|
"chartjs-adapter-moment": "^1.0.0",
|
||||||
|
"classnames": "^2.3.2",
|
||||||
"crypto-browserify": "^3.12.0",
|
"crypto-browserify": "^3.12.0",
|
||||||
"mobx": "^6.6.0",
|
"mobx": "^6.6.0",
|
||||||
"mobx-react-lite": "^3.4.0",
|
"mobx-react-lite": "^3.4.0",
|
||||||
@@ -20,7 +21,9 @@
|
|||||||
"net": "^1.0.2",
|
"net": "^1.0.2",
|
||||||
"os-browserify": "^0.3.0",
|
"os-browserify": "^0.3.0",
|
||||||
"path-browserify": "^1.0.1",
|
"path-browserify": "^1.0.1",
|
||||||
|
"prettier": "^2.8.0",
|
||||||
"process": "^0.11.10",
|
"process": "^0.11.10",
|
||||||
|
"qrcode.react": "^3.1.0",
|
||||||
"querystring-es3": "^0.2.1",
|
"querystring-es3": "^0.2.1",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
@@ -28,6 +31,7 @@
|
|||||||
"react-loader-spinner": "^5.2.0",
|
"react-loader-spinner": "^5.2.0",
|
||||||
"react-router-dom": "^6.2.1",
|
"react-router-dom": "^6.2.1",
|
||||||
"react-transition-group": "^4.4.1",
|
"react-transition-group": "^4.4.1",
|
||||||
|
"sodium-universal": "^3.1.0",
|
||||||
"stream-browserify": "^3.0.0",
|
"stream-browserify": "^3.0.0",
|
||||||
"url": "^0.11.0",
|
"url": "^0.11.0",
|
||||||
"util": "^0.12.4"
|
"util": "^0.12.4"
|
||||||
@@ -1932,6 +1936,17 @@
|
|||||||
"sodium-native": "3.2.1"
|
"sodium-native": "3.2.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@liskhq/lisk-cryptography/node_modules/sodium-native": {
|
||||||
|
"version": "3.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-3.2.1.tgz",
|
||||||
|
"integrity": "sha512-EgDZ/Z7PxL2kCasKk7wnRkV8W9kvwuIlHuHXAxkQm3FF0MgVsjyLBXGjSRGhjE6u7rhSpk3KaMfFM23bfMysIQ==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"ini": "^1.3.5",
|
||||||
|
"node-gyp-build": "^4.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@liskhq/lisk-passphrase": {
|
"node_modules/@liskhq/lisk-passphrase": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@liskhq/lisk-passphrase/-/lisk-passphrase-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@liskhq/lisk-passphrase/-/lisk-passphrase-3.1.1.tgz",
|
||||||
@@ -2618,6 +2633,11 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/b4a": {
|
||||||
|
"version": "1.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.1.tgz",
|
||||||
|
"integrity": "sha512-AsKjNhz72yxteo/0EtQEiwkMUgk/tGmycXlbG4g3Ard2/ULtNLUykGOkeK0egmN27h0xMAhb76jYccW+XTBExA=="
|
||||||
|
},
|
||||||
"node_modules/babel-loader": {
|
"node_modules/babel-loader": {
|
||||||
"version": "8.2.5",
|
"version": "8.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz",
|
||||||
@@ -2773,6 +2793,24 @@
|
|||||||
"randombytes": "^2.0.1"
|
"randombytes": "^2.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/blake2b": {
|
||||||
|
"version": "2.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/blake2b/-/blake2b-2.1.4.tgz",
|
||||||
|
"integrity": "sha512-AyBuuJNI64gIvwx13qiICz6H6hpmjvYS5DGkG6jbXMOT8Z3WUJ3V1X0FlhIoT1b/5JtHE3ki+xjtMvu1nn+t9A==",
|
||||||
|
"dependencies": {
|
||||||
|
"blake2b-wasm": "^2.4.0",
|
||||||
|
"nanoassert": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/blake2b-wasm": {
|
||||||
|
"version": "2.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/blake2b-wasm/-/blake2b-wasm-2.4.0.tgz",
|
||||||
|
"integrity": "sha512-S1kwmW2ZhZFFFOghcx73+ZajEfKBqhP82JMssxtLVMxlaPea1p9uoLiUZ5WYyHn0KddwbLc+0vh4wR0KBNoT5w==",
|
||||||
|
"dependencies": {
|
||||||
|
"b4a": "^1.0.1",
|
||||||
|
"nanoassert": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/bn.js": {
|
"node_modules/bn.js": {
|
||||||
"version": "5.2.1",
|
"version": "5.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
|
||||||
@@ -3085,6 +3123,14 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/chacha20-universal": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/chacha20-universal/-/chacha20-universal-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-/IOxdWWNa7nRabfe7+oF+jVkGjlr2xUL4J8l/OvzZhj+c9RpMqoo3Dq+5nU1j/BflRV4BKnaQ4+4oH1yBpQG1Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"nanoassert": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/chalk": {
|
"node_modules/chalk": {
|
||||||
"version": "2.4.2",
|
"version": "2.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||||
@@ -3156,6 +3202,11 @@
|
|||||||
"safe-buffer": "^5.0.1"
|
"safe-buffer": "^5.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/classnames": {
|
||||||
|
"version": "2.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz",
|
||||||
|
"integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw=="
|
||||||
|
},
|
||||||
"node_modules/clean-css": {
|
"node_modules/clean-css": {
|
||||||
"version": "5.3.0",
|
"version": "5.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.0.tgz",
|
||||||
@@ -5835,6 +5886,11 @@
|
|||||||
"multicast-dns": "cli.js"
|
"multicast-dns": "cli.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/nanoassert": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-7vO7n28+aYO4J+8w96AzhmU8G+Y/xpPDJz/se19ICsqj/momRbb9mh9ZUtkoJ5X3nTnPdhEJyc0qnM6yAsHBaA=="
|
||||||
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
"version": "3.3.4",
|
"version": "3.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
|
||||||
@@ -5886,10 +5942,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/node-gyp-build": {
|
"node_modules/node-gyp-build": {
|
||||||
"version": "4.4.0",
|
"version": "4.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz",
|
||||||
"integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==",
|
"integrity": "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==",
|
||||||
"optional": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"node-gyp-build": "bin.js",
|
"node-gyp-build": "bin.js",
|
||||||
"node-gyp-build-optional": "optional.js",
|
"node-gyp-build-optional": "optional.js",
|
||||||
@@ -6546,6 +6601,20 @@
|
|||||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
||||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
|
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/prettier": {
|
||||||
|
"version": "2.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.0.tgz",
|
||||||
|
"integrity": "sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA==",
|
||||||
|
"bin": {
|
||||||
|
"prettier": "bin-prettier.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.13.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/pretty-error": {
|
"node_modules/pretty-error": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz",
|
||||||
@@ -6628,6 +6697,14 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/qrcode.react": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/qrcode.react/-/qrcode.react-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-oyF+Urr3oAMUG/OiOuONL3HXM+53wvuH3mtIWQrYmsXoAq0DkvZp2RYUWFSMFtbdOpuS++9v+WAkzNVkMlNW6Q==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/qs": {
|
"node_modules/qs": {
|
||||||
"version": "6.10.3",
|
"version": "6.10.3",
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
|
||||||
@@ -7427,6 +7504,42 @@
|
|||||||
"sha.js": "bin.js"
|
"sha.js": "bin.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sha256-universal": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/sha256-universal/-/sha256-universal-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-ghn3muhdn1ailCQqqceNxRgkOeZSVfSE13RQWEg6njB+itsFzGVSJv+O//2hvNXZuxVIRyNzrgsZ37SPDdGJJw==",
|
||||||
|
"dependencies": {
|
||||||
|
"b4a": "^1.0.1",
|
||||||
|
"sha256-wasm": "^2.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sha256-wasm": {
|
||||||
|
"version": "2.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/sha256-wasm/-/sha256-wasm-2.2.2.tgz",
|
||||||
|
"integrity": "sha512-qKSGARvao+JQlFiA+sjJZhJ/61gmW/3aNLblB2rsgIxDlDxsJPHo8a1seXj12oKtuHVgJSJJ7QEGBUYQN741lQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"b4a": "^1.0.1",
|
||||||
|
"nanoassert": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sha512-universal": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/sha512-universal/-/sha512-universal-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-kehYuigMoRkIngCv7rhgruLJNNHDnitGTBdkcYbCbooL8Cidj/bS78MDxByIjcc69M915WxcQTgZetZ1JbeQTQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"b4a": "^1.0.1",
|
||||||
|
"sha512-wasm": "^2.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sha512-wasm": {
|
||||||
|
"version": "2.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/sha512-wasm/-/sha512-wasm-2.3.4.tgz",
|
||||||
|
"integrity": "sha512-akWoxJPGCB3aZCrZ+fm6VIFhJ/p8idBv7AWGFng/CZIrQo51oQNsvDbTSRXWAzIiZJvpy16oIDiCCPqTe21sKg==",
|
||||||
|
"dependencies": {
|
||||||
|
"b4a": "^1.0.1",
|
||||||
|
"nanoassert": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/shallow-clone": {
|
"node_modules/shallow-clone": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
|
||||||
@@ -7484,6 +7597,14 @@
|
|||||||
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
|
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/siphash24": {
|
||||||
|
"version": "1.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/siphash24/-/siphash24-1.3.1.tgz",
|
||||||
|
"integrity": "sha512-moemC3ZKiTzH29nbFo3Iw8fbemWWod4vNs/WgKbQ54oEs6mE6XVlguxvinYjB+UmaE0PThgyED9fUkWvirT8hA==",
|
||||||
|
"dependencies": {
|
||||||
|
"nanoassert": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/sockjs": {
|
"node_modules/sockjs": {
|
||||||
"version": "0.3.24",
|
"version": "0.3.24",
|
||||||
"resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
|
"resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
|
||||||
@@ -7495,15 +7616,44 @@
|
|||||||
"websocket-driver": "^0.7.4"
|
"websocket-driver": "^0.7.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/sodium-native": {
|
"node_modules/sodium-javascript": {
|
||||||
"version": "3.2.1",
|
"version": "0.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-3.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/sodium-javascript/-/sodium-javascript-0.8.0.tgz",
|
||||||
"integrity": "sha512-EgDZ/Z7PxL2kCasKk7wnRkV8W9kvwuIlHuHXAxkQm3FF0MgVsjyLBXGjSRGhjE6u7rhSpk3KaMfFM23bfMysIQ==",
|
"integrity": "sha512-rEBzR5mPxPES+UjyMDvKPIXy9ImF17KOJ32nJNi9uIquWpS/nfj+h6m05J5yLJaGXjgM72LmQoUbWZVxh/rmGg==",
|
||||||
"hasInstallScript": true,
|
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ini": "^1.3.5",
|
"blake2b": "^2.1.1",
|
||||||
"node-gyp-build": "^4.2.0"
|
"chacha20-universal": "^1.0.4",
|
||||||
|
"nanoassert": "^2.0.0",
|
||||||
|
"sha256-universal": "^1.1.0",
|
||||||
|
"sha512-universal": "^1.1.0",
|
||||||
|
"siphash24": "^1.0.1",
|
||||||
|
"xsalsa20": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sodium-native": {
|
||||||
|
"version": "3.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-3.4.1.tgz",
|
||||||
|
"integrity": "sha512-PaNN/roiFWzVVTL6OqjzYct38NSXewdl2wz8SRB51Br/MLIJPrbM3XexhVWkq7D3UWMysfrhKVf1v1phZq6MeQ==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"dependencies": {
|
||||||
|
"node-gyp-build": "^4.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sodium-universal": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/sodium-universal/-/sodium-universal-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-N2gxk68Kg2qZLSJ4h0NffEhp4BjgWHCHXVlDi1aG1hA3y+ZeWEmHqnpml8Hy47QzfL1xLy5nwr9LcsWAg2Ep0A==",
|
||||||
|
"dependencies": {
|
||||||
|
"blake2b": "^2.1.1",
|
||||||
|
"chacha20-universal": "^1.0.4",
|
||||||
|
"nanoassert": "^2.0.0",
|
||||||
|
"resolve": "^1.17.0",
|
||||||
|
"sha256-universal": "^1.1.0",
|
||||||
|
"sha512-universal": "^1.1.0",
|
||||||
|
"siphash24": "^1.0.1",
|
||||||
|
"sodium-javascript": "~0.8.0",
|
||||||
|
"sodium-native": "^3.2.0",
|
||||||
|
"xsalsa20": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/source-map": {
|
"node_modules/source-map": {
|
||||||
@@ -8659,6 +8809,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/xsalsa20": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/xsalsa20/-/xsalsa20-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-FIr/DEeoHfj7ftfylnoFt3rAIRoWXpx2AoDfrT2qD2wtp7Dp+COajvs/Icb7uHqRW9m60f5iXZwdsJJO3kvb7w=="
|
||||||
|
},
|
||||||
"node_modules/xtend": {
|
"node_modules/xtend": {
|
||||||
"version": "4.0.2",
|
"version": "4.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||||
@@ -10006,6 +10161,18 @@
|
|||||||
"sodium-native": "3.2.1",
|
"sodium-native": "3.2.1",
|
||||||
"tweetnacl": "1.0.3",
|
"tweetnacl": "1.0.3",
|
||||||
"varuint-bitcoin": "1.1.2"
|
"varuint-bitcoin": "1.1.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"sodium-native": {
|
||||||
|
"version": "3.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-3.2.1.tgz",
|
||||||
|
"integrity": "sha512-EgDZ/Z7PxL2kCasKk7wnRkV8W9kvwuIlHuHXAxkQm3FF0MgVsjyLBXGjSRGhjE6u7rhSpk3KaMfFM23bfMysIQ==",
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"ini": "^1.3.5",
|
||||||
|
"node-gyp-build": "^4.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@liskhq/lisk-passphrase": {
|
"@liskhq/lisk-passphrase": {
|
||||||
@@ -10587,6 +10754,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
|
||||||
"integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw=="
|
"integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw=="
|
||||||
},
|
},
|
||||||
|
"b4a": {
|
||||||
|
"version": "1.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.1.tgz",
|
||||||
|
"integrity": "sha512-AsKjNhz72yxteo/0EtQEiwkMUgk/tGmycXlbG4g3Ard2/ULtNLUykGOkeK0egmN27h0xMAhb76jYccW+XTBExA=="
|
||||||
|
},
|
||||||
"babel-loader": {
|
"babel-loader": {
|
||||||
"version": "8.2.5",
|
"version": "8.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz",
|
||||||
@@ -10702,6 +10874,24 @@
|
|||||||
"randombytes": "^2.0.1"
|
"randombytes": "^2.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"blake2b": {
|
||||||
|
"version": "2.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/blake2b/-/blake2b-2.1.4.tgz",
|
||||||
|
"integrity": "sha512-AyBuuJNI64gIvwx13qiICz6H6hpmjvYS5DGkG6jbXMOT8Z3WUJ3V1X0FlhIoT1b/5JtHE3ki+xjtMvu1nn+t9A==",
|
||||||
|
"requires": {
|
||||||
|
"blake2b-wasm": "^2.4.0",
|
||||||
|
"nanoassert": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"blake2b-wasm": {
|
||||||
|
"version": "2.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/blake2b-wasm/-/blake2b-wasm-2.4.0.tgz",
|
||||||
|
"integrity": "sha512-S1kwmW2ZhZFFFOghcx73+ZajEfKBqhP82JMssxtLVMxlaPea1p9uoLiUZ5WYyHn0KddwbLc+0vh4wR0KBNoT5w==",
|
||||||
|
"requires": {
|
||||||
|
"b4a": "^1.0.1",
|
||||||
|
"nanoassert": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"bn.js": {
|
"bn.js": {
|
||||||
"version": "5.2.1",
|
"version": "5.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
|
||||||
@@ -10942,6 +11132,14 @@
|
|||||||
"integrity": "sha512-Sd6pjJHF27LzCB7pT7qs+kuX2ndurzCzkpJl6Qct7LPSZ9jn0bkOA8mdgMgmqnQAWLVOOGjLpc+66V57eLtb1g==",
|
"integrity": "sha512-Sd6pjJHF27LzCB7pT7qs+kuX2ndurzCzkpJl6Qct7LPSZ9jn0bkOA8mdgMgmqnQAWLVOOGjLpc+66V57eLtb1g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"chacha20-universal": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/chacha20-universal/-/chacha20-universal-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-/IOxdWWNa7nRabfe7+oF+jVkGjlr2xUL4J8l/OvzZhj+c9RpMqoo3Dq+5nU1j/BflRV4BKnaQ4+4oH1yBpQG1Q==",
|
||||||
|
"requires": {
|
||||||
|
"nanoassert": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"chalk": {
|
"chalk": {
|
||||||
"version": "2.4.2",
|
"version": "2.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||||
@@ -10993,6 +11191,11 @@
|
|||||||
"safe-buffer": "^5.0.1"
|
"safe-buffer": "^5.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"classnames": {
|
||||||
|
"version": "2.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz",
|
||||||
|
"integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw=="
|
||||||
|
},
|
||||||
"clean-css": {
|
"clean-css": {
|
||||||
"version": "5.3.0",
|
"version": "5.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.0.tgz",
|
||||||
@@ -12981,6 +13184,11 @@
|
|||||||
"thunky": "^1.0.2"
|
"thunky": "^1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nanoassert": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-7vO7n28+aYO4J+8w96AzhmU8G+Y/xpPDJz/se19ICsqj/momRbb9mh9ZUtkoJ5X3nTnPdhEJyc0qnM6yAsHBaA=="
|
||||||
|
},
|
||||||
"nanoid": {
|
"nanoid": {
|
||||||
"version": "3.3.4",
|
"version": "3.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
|
||||||
@@ -13020,10 +13228,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node-gyp-build": {
|
"node-gyp-build": {
|
||||||
"version": "4.4.0",
|
"version": "4.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz",
|
||||||
"integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==",
|
"integrity": "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg=="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"node-releases": {
|
"node-releases": {
|
||||||
"version": "2.0.5",
|
"version": "2.0.5",
|
||||||
@@ -13464,6 +13671,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
||||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
|
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
|
||||||
},
|
},
|
||||||
|
"prettier": {
|
||||||
|
"version": "2.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.0.tgz",
|
||||||
|
"integrity": "sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA=="
|
||||||
|
},
|
||||||
"pretty-error": {
|
"pretty-error": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz",
|
||||||
@@ -13538,6 +13750,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
||||||
},
|
},
|
||||||
|
"qrcode.react": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/qrcode.react/-/qrcode.react-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-oyF+Urr3oAMUG/OiOuONL3HXM+53wvuH3mtIWQrYmsXoAq0DkvZp2RYUWFSMFtbdOpuS++9v+WAkzNVkMlNW6Q==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"qs": {
|
"qs": {
|
||||||
"version": "6.10.3",
|
"version": "6.10.3",
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
|
||||||
@@ -14134,6 +14352,42 @@
|
|||||||
"safe-buffer": "^5.0.1"
|
"safe-buffer": "^5.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"sha256-universal": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/sha256-universal/-/sha256-universal-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-ghn3muhdn1ailCQqqceNxRgkOeZSVfSE13RQWEg6njB+itsFzGVSJv+O//2hvNXZuxVIRyNzrgsZ37SPDdGJJw==",
|
||||||
|
"requires": {
|
||||||
|
"b4a": "^1.0.1",
|
||||||
|
"sha256-wasm": "^2.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sha256-wasm": {
|
||||||
|
"version": "2.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/sha256-wasm/-/sha256-wasm-2.2.2.tgz",
|
||||||
|
"integrity": "sha512-qKSGARvao+JQlFiA+sjJZhJ/61gmW/3aNLblB2rsgIxDlDxsJPHo8a1seXj12oKtuHVgJSJJ7QEGBUYQN741lQ==",
|
||||||
|
"requires": {
|
||||||
|
"b4a": "^1.0.1",
|
||||||
|
"nanoassert": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sha512-universal": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/sha512-universal/-/sha512-universal-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-kehYuigMoRkIngCv7rhgruLJNNHDnitGTBdkcYbCbooL8Cidj/bS78MDxByIjcc69M915WxcQTgZetZ1JbeQTQ==",
|
||||||
|
"requires": {
|
||||||
|
"b4a": "^1.0.1",
|
||||||
|
"sha512-wasm": "^2.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sha512-wasm": {
|
||||||
|
"version": "2.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/sha512-wasm/-/sha512-wasm-2.3.4.tgz",
|
||||||
|
"integrity": "sha512-akWoxJPGCB3aZCrZ+fm6VIFhJ/p8idBv7AWGFng/CZIrQo51oQNsvDbTSRXWAzIiZJvpy16oIDiCCPqTe21sKg==",
|
||||||
|
"requires": {
|
||||||
|
"b4a": "^1.0.1",
|
||||||
|
"nanoassert": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"shallow-clone": {
|
"shallow-clone": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
|
||||||
@@ -14179,6 +14433,14 @@
|
|||||||
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
|
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"siphash24": {
|
||||||
|
"version": "1.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/siphash24/-/siphash24-1.3.1.tgz",
|
||||||
|
"integrity": "sha512-moemC3ZKiTzH29nbFo3Iw8fbemWWod4vNs/WgKbQ54oEs6mE6XVlguxvinYjB+UmaE0PThgyED9fUkWvirT8hA==",
|
||||||
|
"requires": {
|
||||||
|
"nanoassert": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"sockjs": {
|
"sockjs": {
|
||||||
"version": "0.3.24",
|
"version": "0.3.24",
|
||||||
"resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
|
"resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
|
||||||
@@ -14190,14 +14452,43 @@
|
|||||||
"websocket-driver": "^0.7.4"
|
"websocket-driver": "^0.7.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sodium-native": {
|
"sodium-javascript": {
|
||||||
"version": "3.2.1",
|
"version": "0.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-3.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/sodium-javascript/-/sodium-javascript-0.8.0.tgz",
|
||||||
"integrity": "sha512-EgDZ/Z7PxL2kCasKk7wnRkV8W9kvwuIlHuHXAxkQm3FF0MgVsjyLBXGjSRGhjE6u7rhSpk3KaMfFM23bfMysIQ==",
|
"integrity": "sha512-rEBzR5mPxPES+UjyMDvKPIXy9ImF17KOJ32nJNi9uIquWpS/nfj+h6m05J5yLJaGXjgM72LmQoUbWZVxh/rmGg==",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"ini": "^1.3.5",
|
"blake2b": "^2.1.1",
|
||||||
"node-gyp-build": "^4.2.0"
|
"chacha20-universal": "^1.0.4",
|
||||||
|
"nanoassert": "^2.0.0",
|
||||||
|
"sha256-universal": "^1.1.0",
|
||||||
|
"sha512-universal": "^1.1.0",
|
||||||
|
"siphash24": "^1.0.1",
|
||||||
|
"xsalsa20": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sodium-native": {
|
||||||
|
"version": "3.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-3.4.1.tgz",
|
||||||
|
"integrity": "sha512-PaNN/roiFWzVVTL6OqjzYct38NSXewdl2wz8SRB51Br/MLIJPrbM3XexhVWkq7D3UWMysfrhKVf1v1phZq6MeQ==",
|
||||||
|
"requires": {
|
||||||
|
"node-gyp-build": "^4.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sodium-universal": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/sodium-universal/-/sodium-universal-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-N2gxk68Kg2qZLSJ4h0NffEhp4BjgWHCHXVlDi1aG1hA3y+ZeWEmHqnpml8Hy47QzfL1xLy5nwr9LcsWAg2Ep0A==",
|
||||||
|
"requires": {
|
||||||
|
"blake2b": "^2.1.1",
|
||||||
|
"chacha20-universal": "^1.0.4",
|
||||||
|
"nanoassert": "^2.0.0",
|
||||||
|
"resolve": "^1.17.0",
|
||||||
|
"sha256-universal": "^1.1.0",
|
||||||
|
"sha512-universal": "^1.1.0",
|
||||||
|
"siphash24": "^1.0.1",
|
||||||
|
"sodium-javascript": "~0.8.0",
|
||||||
|
"sodium-native": "^3.2.0",
|
||||||
|
"xsalsa20": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"source-map": {
|
"source-map": {
|
||||||
@@ -15006,6 +15297,11 @@
|
|||||||
"integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==",
|
"integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==",
|
||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
|
"xsalsa20": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/xsalsa20/-/xsalsa20-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-FIr/DEeoHfj7ftfylnoFt3rAIRoWXpx2AoDfrT2qD2wtp7Dp+COajvs/Icb7uHqRW9m60f5iXZwdsJJO3kvb7w=="
|
||||||
|
},
|
||||||
"xtend": {
|
"xtend": {
|
||||||
"version": "4.0.2",
|
"version": "4.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"chart.js": "^3.5.0",
|
"chart.js": "^3.5.0",
|
||||||
"chartjs-adapter-moment": "^1.0.0",
|
"chartjs-adapter-moment": "^1.0.0",
|
||||||
|
"classnames": "^2.3.2",
|
||||||
"crypto-browserify": "^3.12.0",
|
"crypto-browserify": "^3.12.0",
|
||||||
"mobx": "^6.6.0",
|
"mobx": "^6.6.0",
|
||||||
"mobx-react-lite": "^3.4.0",
|
"mobx-react-lite": "^3.4.0",
|
||||||
@@ -19,7 +20,9 @@
|
|||||||
"net": "^1.0.2",
|
"net": "^1.0.2",
|
||||||
"os-browserify": "^0.3.0",
|
"os-browserify": "^0.3.0",
|
||||||
"path-browserify": "^1.0.1",
|
"path-browserify": "^1.0.1",
|
||||||
|
"prettier": "^2.8.0",
|
||||||
"process": "^0.11.10",
|
"process": "^0.11.10",
|
||||||
|
"qrcode.react": "^3.1.0",
|
||||||
"querystring-es3": "^0.2.1",
|
"querystring-es3": "^0.2.1",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
@@ -27,6 +30,7 @@
|
|||||||
"react-loader-spinner": "^5.2.0",
|
"react-loader-spinner": "^5.2.0",
|
||||||
"react-router-dom": "^6.2.1",
|
"react-router-dom": "^6.2.1",
|
||||||
"react-transition-group": "^4.4.1",
|
"react-transition-group": "^4.4.1",
|
||||||
|
"sodium-universal": "^3.1.0",
|
||||||
"stream-browserify": "^3.0.0",
|
"stream-browserify": "^3.0.0",
|
||||||
"url": "^0.11.0",
|
"url": "^0.11.0",
|
||||||
"util": "^0.12.4"
|
"util": "^0.12.4"
|
||||||
|
|||||||
47
src/App.jsx
47
src/App.jsx
@@ -1,44 +1,40 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from "react";
|
||||||
import {
|
import { Routes, Route, useLocation } from "react-router-dom";
|
||||||
Routes,
|
|
||||||
Route,
|
|
||||||
useLocation,
|
|
||||||
} from 'react-router-dom';
|
|
||||||
|
|
||||||
import './css/style.scss';
|
import "./css/style.scss";
|
||||||
|
|
||||||
// Import pages
|
// Import pages
|
||||||
import ProfileId from './pages/digitalId/ProfileId';
|
import ProfileId from "./pages/digitalId/ProfileId";
|
||||||
import Validate from './pages/digitalId/Validate';
|
import ValidationLog from "./pages/digitalId/ValidationLog";
|
||||||
import ValidationLog from './pages/digitalId/ValidationLog';
|
import Verify from "./pages/digitalId/Verify";
|
||||||
import Verify from './pages/digitalId/Verify';
|
|
||||||
import Onboarding1 from "./pages/Onboarding1";
|
import Onboarding1 from "./pages/Onboarding1";
|
||||||
import Onboarding2 from "./pages/Onboarding2";
|
import Onboarding2 from "./pages/Onboarding2";
|
||||||
import Onboarding3 from "./pages/Onboarding3";
|
import Onboarding3 from "./pages/Onboarding3";
|
||||||
import Onboarding4 from "./pages/Onboarding4";
|
import Onboarding4 from "./pages/Onboarding4";
|
||||||
import SharedData from "./pages/SharedData";
|
import SharedData from "./pages/SharedData";
|
||||||
import ResetPassword from "./pages/ResetPassword";
|
|
||||||
import SignIn from "./pages/SignIn";
|
import SignIn from "./pages/SignIn";
|
||||||
import {LoadingOverlay} from './components/LoadingOverlay';
|
import { LoadingOverlay } from "./components/LoadingOverlay";
|
||||||
import {store} from './store/store';
|
import { store } from "./store/store";
|
||||||
import {observer} from 'mobx-react-lite';
|
import { observer } from "mobx-react-lite";
|
||||||
|
import Delegates from "./pages/services/Delegates";
|
||||||
|
import VPNServers from "./pages/services/VPNServers";
|
||||||
|
import VPNPrepare from "./pages/services/VPNPrepare";
|
||||||
|
|
||||||
const App = observer(() => {
|
const App = observer(() => {
|
||||||
|
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
useEffect(()=> {
|
useEffect(() => {
|
||||||
localStorage.setItem('svgAvatar', '')
|
localStorage.setItem("svgAvatar", "");
|
||||||
},[])
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.querySelector('html').style.scrollBehavior = 'auto'
|
document.querySelector("html").style.scrollBehavior = "auto";
|
||||||
window.scroll({ top: 0 })
|
window.scroll({ top: 0 });
|
||||||
document.querySelector('html').style.scrollBehavior = ''
|
document.querySelector("html").style.scrollBehavior = "";
|
||||||
}, [location.pathname]); // triggered on route change
|
}, [location.pathname]); // triggered on route change
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{ store.loading && <LoadingOverlay /> }
|
{store.loading && <LoadingOverlay />}
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route exact path="/" element={<Onboarding1 />} />
|
<Route exact path="/" element={<Onboarding1 />} />
|
||||||
<Route path="/digitalId/profile-id" element={<ProfileId />} />
|
<Route path="/digitalId/profile-id" element={<ProfileId />} />
|
||||||
@@ -48,11 +44,14 @@ const App = observer(() => {
|
|||||||
<Route path="/onboarding-2" element={<Onboarding2 />} />
|
<Route path="/onboarding-2" element={<Onboarding2 />} />
|
||||||
<Route path="/onboarding-3" element={<Onboarding3 />} />
|
<Route path="/onboarding-3" element={<Onboarding3 />} />
|
||||||
<Route path="/onboarding-4" element={<Onboarding4 />} />
|
<Route path="/onboarding-4" element={<Onboarding4 />} />
|
||||||
|
<Route path="/services/delegates" element={<Delegates />} />
|
||||||
|
<Route path="/services/vpn" element={<VPNPrepare />} />
|
||||||
|
<Route path="/services/vpn/servers" element={<VPNServers />} />
|
||||||
<Route path="/shared-data/:id" element={<SharedData />} />
|
<Route path="/shared-data/:id" element={<SharedData />} />
|
||||||
<Route path="/signIn" element={<SignIn />} />
|
<Route path="/signIn" element={<SignIn />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
})
|
});
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|||||||
104
src/components/DropdownTransaction.jsx
Normal file
104
src/components/DropdownTransaction.jsx
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
import React, { useState, useRef, useEffect } from "react";
|
||||||
|
import Transition from "../utils/Transition";
|
||||||
|
|
||||||
|
function DropdownTransaction({ align, value, onChange }) {
|
||||||
|
const [dropdownOpen, setDropdownOpen] = useState(false);
|
||||||
|
|
||||||
|
const trigger = useRef(null);
|
||||||
|
const dropdown = useRef(null);
|
||||||
|
|
||||||
|
const changeValue = (val) => {
|
||||||
|
setDropdownOpen(false);
|
||||||
|
onChange(val);
|
||||||
|
};
|
||||||
|
|
||||||
|
// close on click outside
|
||||||
|
useEffect(() => {
|
||||||
|
const clickHandler = ({ target }) => {
|
||||||
|
if (!dropdown.current) return;
|
||||||
|
if (
|
||||||
|
!dropdownOpen ||
|
||||||
|
dropdown.current.contains(target) ||
|
||||||
|
trigger.current.contains(target)
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
setDropdownOpen(false);
|
||||||
|
};
|
||||||
|
document.addEventListener("click", clickHandler);
|
||||||
|
return () => document.removeEventListener("click", clickHandler);
|
||||||
|
});
|
||||||
|
|
||||||
|
// close if the esc key is pressed
|
||||||
|
useEffect(() => {
|
||||||
|
const keyHandler = ({ keyCode }) => {
|
||||||
|
if (!dropdownOpen || keyCode !== 27) return;
|
||||||
|
setDropdownOpen(false);
|
||||||
|
};
|
||||||
|
document.addEventListener("keydown", keyHandler);
|
||||||
|
return () => document.removeEventListener("keydown", keyHandler);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="relative inline-flex">
|
||||||
|
<button
|
||||||
|
ref={trigger}
|
||||||
|
className="inline-flex justify-center items-center group"
|
||||||
|
aria-haspopup="true"
|
||||||
|
aria-expanded={dropdownOpen}
|
||||||
|
onClick={() => setDropdownOpen(!dropdownOpen)}
|
||||||
|
>
|
||||||
|
<div className="flex items-center truncate">
|
||||||
|
<span className="truncate font-medium text-indigo-500 group-hover:text-indigo-600">
|
||||||
|
{value}
|
||||||
|
</span>
|
||||||
|
<svg
|
||||||
|
className="w-3 h-3 shrink-0 ml-1 fill-current text-slate-400"
|
||||||
|
viewBox="0 0 12 12"
|
||||||
|
>
|
||||||
|
<path d="M5.9 11.4L.5 6l1.4-1.4 4 4 4-4L11.3 6z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<Transition
|
||||||
|
className={`origin-top-right z-10 absolute top-full min-w-44 bg-white border border-slate-200 py-1.5 rounded shadow-lg overflow-hidden mt-1 ${
|
||||||
|
align === "right" ? "right-0" : "left-0"
|
||||||
|
}`}
|
||||||
|
show={dropdownOpen}
|
||||||
|
enter="transition ease-out duration-200 transform"
|
||||||
|
enterStart="opacity-0 -translate-y-2"
|
||||||
|
enterEnd="opacity-100 translate-y-0"
|
||||||
|
leave="transition ease-out duration-200"
|
||||||
|
leaveStart="opacity-100"
|
||||||
|
leaveEnd="opacity-0"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
ref={dropdown}
|
||||||
|
onFocus={() => setDropdownOpen(true)}
|
||||||
|
onBlur={() => setDropdownOpen(false)}
|
||||||
|
>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<span
|
||||||
|
className="font-medium text-sm text-slate-600 hover:text-slate-800 flex items-center py-1 px-3 cursor-pointer"
|
||||||
|
onClick={() => changeValue("Voiting")}
|
||||||
|
>
|
||||||
|
Voiting
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span
|
||||||
|
className="font-medium text-sm text-slate-600 hover:text-slate-800 flex items-center py-1 px-3 cursor-pointer"
|
||||||
|
onClick={() => changeValue("Unvoiting")}
|
||||||
|
>
|
||||||
|
Unvoiting
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</Transition>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DropdownTransaction;
|
||||||
31
src/components/Filters.js
Normal file
31
src/components/Filters.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export const Filters = ({ value, onChange, values = [] }) => {
|
||||||
|
return (
|
||||||
|
<div className="mb-5">
|
||||||
|
<ul className="flex flex-wrap -m-1">
|
||||||
|
{values.map((e) =>
|
||||||
|
e === value ? (
|
||||||
|
<li className="m-1" key={e}>
|
||||||
|
<button
|
||||||
|
className="inline-flex items-center justify-center text-sm font-medium leading-5 rounded-full px-3 py-1 border border-transparent shadow-sm bg-indigo-500 text-white duration-150 ease-in-out"
|
||||||
|
onClick={() => onChange(e)}
|
||||||
|
>
|
||||||
|
{e}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
) : (
|
||||||
|
<li className="m-1" key={e}>
|
||||||
|
<button
|
||||||
|
className="inline-flex items-center justify-center text-sm font-medium leading-5 rounded-full px-3 py-1 border border-slate-200 hover:border-slate-300 shadow-sm bg-white text-slate-500 duration-150 ease-in-out"
|
||||||
|
onClick={() => onChange(e)}
|
||||||
|
>
|
||||||
|
{e}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
39
src/components/PaginationClassic.jsx
Normal file
39
src/components/PaginationClassic.jsx
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import cn from 'classnames'
|
||||||
|
|
||||||
|
function PaginationClassic({count, limit, offset, onNextPage, onPrevPage}) {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between">
|
||||||
|
<nav className="mb-4 sm:mb-0 sm:order-1" role="navigation" aria-label="Navigation">
|
||||||
|
<ul className="flex justify-center">
|
||||||
|
<li className="ml-3 first:ml-0">
|
||||||
|
<button
|
||||||
|
className={
|
||||||
|
cn(
|
||||||
|
"btn bg-white border-slate-200 text-indigo-500",
|
||||||
|
{'cursor-not-allowed text-slate-300': offset === 0},
|
||||||
|
{'hover:border-slate-300' : offset !== 0}
|
||||||
|
)}
|
||||||
|
disabled={offset === 0}
|
||||||
|
onClick={onPrevPage}><- Previous</button>
|
||||||
|
</li>
|
||||||
|
<li className="ml-3 first:ml-0">
|
||||||
|
<button
|
||||||
|
className={cn(
|
||||||
|
"btn bg-white border-slate-200 text-indigo-500",
|
||||||
|
{'cursor-not-allowed text-slate-300': offset + limit >= count},
|
||||||
|
{'hover:border-slate-300' : offset + limit < count}
|
||||||
|
)}
|
||||||
|
disabled={offset + limit >= count}
|
||||||
|
onClick={onNextPage}>Next -></button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
<div className="text-sm text-slate-500 text-center sm:text-left">
|
||||||
|
Showing <span className="font-medium text-slate-600">{offset + 1}</span> to <span className="font-medium text-slate-600">{offset+limit}</span> of <span className="font-medium text-slate-600">{count}</span> results
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PaginationClassic;
|
||||||
BIN
src/images/service_icon.png
Normal file
BIN
src/images/service_icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 912 B |
BIN
src/images/vpn_server_icon.png
Normal file
BIN
src/images/vpn_server_icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 623 B |
BIN
src/images/vpn_service.png
Normal file
BIN
src/images/vpn_service.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.8 KiB |
@@ -5,6 +5,7 @@ import { HashRouter as Router } from 'react-router-dom'
|
|||||||
import App from './App'
|
import App from './App'
|
||||||
import {store} from './store/store';
|
import {store} from './store/store';
|
||||||
|
|
||||||
|
|
||||||
globalThis.Buffer = Buffer
|
globalThis.Buffer = Buffer
|
||||||
|
|
||||||
window.store = store;
|
window.store = store;
|
||||||
|
|||||||
105
src/pages/services/Delegates.jsx
Normal file
105
src/pages/services/Delegates.jsx
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
import Sidebar from "../../partials/Sidebar";
|
||||||
|
import Header from "../../partials/Header";
|
||||||
|
import DropdownTransaction from "../../components/DropdownTransaction";
|
||||||
|
import TransactionsTable from "../../partials/finance/TransactionsTable";
|
||||||
|
import PaginationClassic from "../../components/PaginationClassic";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
import TransactionPanel from "../../partials/finance/TransactionPanel";
|
||||||
|
import { Filters } from "../../components/Filters";
|
||||||
|
|
||||||
|
const filters = {
|
||||||
|
"View All": "",
|
||||||
|
Voted: "Unvote",
|
||||||
|
Pending: "Pending",
|
||||||
|
};
|
||||||
|
|
||||||
|
const Delegates = observer(() => {
|
||||||
|
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||||
|
const [currentDelegate, setCurrentDelegate] = useState(null);
|
||||||
|
const [currentFilter, setCurrentFilter] = useState("View All");
|
||||||
|
|
||||||
|
const [lockedFor, setLockedFor] = useState("Voiting");
|
||||||
|
|
||||||
|
const lockedLabel = Object.values(
|
||||||
|
lockedFor === "Voiting" ? store.processedVotes : store.accountLockedVotes
|
||||||
|
)
|
||||||
|
.reduce((sum, e) => sum + e, 0n)
|
||||||
|
.toString();
|
||||||
|
|
||||||
|
const [fetchOffset, setFetchOffset] = useState(0);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
store.fetchDelegates(fetchOffset);
|
||||||
|
}, [fetchOffset]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex h-screen overflow-hidden">
|
||||||
|
{/* Sidebar */}
|
||||||
|
<Sidebar sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} />
|
||||||
|
|
||||||
|
{/* Content area */}
|
||||||
|
<div className="relative flex flex-col flex-1 overflow-y-auto overflow-x-hidden bg-white">
|
||||||
|
{/* Site header */}
|
||||||
|
<Header sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} />
|
||||||
|
|
||||||
|
<main className="overflow-auto">
|
||||||
|
{/* Content */}
|
||||||
|
<div className="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
|
||||||
|
{/* Page header */}
|
||||||
|
<div className="sm:flex sm:justify-between sm:items-center mb-4 md:mb-2">
|
||||||
|
{/* Left: Title */}
|
||||||
|
<div className="mb-4 sm:mb-0">
|
||||||
|
<h1 className="text-2xl md:text-3xl text-slate-800 font-bold">
|
||||||
|
{lockedLabel}
|
||||||
|
/idn
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-5">
|
||||||
|
<span>Locked for </span>
|
||||||
|
<DropdownTransaction value={lockedFor} onChange={setLockedFor} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Filters */}
|
||||||
|
<Filters
|
||||||
|
value={currentFilter}
|
||||||
|
values={Object.keys(filters)}
|
||||||
|
onChange={setCurrentFilter}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Table */}
|
||||||
|
<TransactionsTable
|
||||||
|
data={store.delegates}
|
||||||
|
rowClick={(delegate) => setCurrentDelegate(delegate)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Pagination */}
|
||||||
|
<div className="mt-8">
|
||||||
|
<PaginationClassic
|
||||||
|
count={store.delegatesMeta.count}
|
||||||
|
limit={store.delegatesMeta.limit}
|
||||||
|
offset={store.delegatesMeta.offset}
|
||||||
|
onNextPage={() => setFetchOffset((prev) => prev + 10)}
|
||||||
|
onPrevPage={() => setFetchOffset((prev) => prev - 10)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<TransactionPanel
|
||||||
|
transactionPanelOpen={!!currentDelegate}
|
||||||
|
onClose={() => setCurrentDelegate(null)}
|
||||||
|
delegate={currentDelegate || {}}
|
||||||
|
postTransaction={(address, amount) =>
|
||||||
|
store.pushVoteTransaction(address, amount)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default Delegates;
|
||||||
103
src/pages/services/VPNPrepare.jsx
Normal file
103
src/pages/services/VPNPrepare.jsx
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import Sidebar from "../../partials/Sidebar";
|
||||||
|
import Header from "../../partials/Header";
|
||||||
|
import VPNServiceImg from "../../images/vpn_service.png";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
|
const VPNPrepare = observer(() => {
|
||||||
|
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
store.fetchVPNServers();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const canVote = store.accountBalance > 20;
|
||||||
|
|
||||||
|
const clickButton = () => {
|
||||||
|
if (canVote) navigate("/services/delegates");
|
||||||
|
else window.open("https://testnet.idntty.org/faucet", "_blank");
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (store.canVPN) navigate("/services/vpn/servers");
|
||||||
|
}, [store.canVPN]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex h-screen overflow-hidden">
|
||||||
|
{/* Sidebar */}
|
||||||
|
<Sidebar sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} />
|
||||||
|
|
||||||
|
{/* Content area */}
|
||||||
|
<div className="relative flex flex-col flex-1 overflow-y-auto overflow-x-hidden bg-white">
|
||||||
|
{/* Site header */}
|
||||||
|
<Header sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} />
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<div className="lg:relative lg:flex border-b border-slate-200">
|
||||||
|
{/* Content */}
|
||||||
|
<div className="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
|
||||||
|
{/* Page header */}
|
||||||
|
<div className="sm:flex sm:justify-between sm:items-center">
|
||||||
|
{/* Left: Title */}
|
||||||
|
<div className="mb-4 sm:mb-0">
|
||||||
|
<h1 className="text-2xl md:text-3xl text-slate-800 font-bold">
|
||||||
|
VPN Service✨
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex justify-center py-16">
|
||||||
|
<div className="flex w-2/4 flex-col gap-2 justify-center items-center">
|
||||||
|
<img
|
||||||
|
width="64"
|
||||||
|
height="64"
|
||||||
|
src={VPNServiceImg}
|
||||||
|
alt="VPN service"
|
||||||
|
/>
|
||||||
|
<h2 className="text-xl md:text-2xl text-slate-800 font-bold text-center">
|
||||||
|
{canVote
|
||||||
|
? "Vote for VPN delegate to get service"
|
||||||
|
: "You cannot get the VPN service, sorry 😢"}
|
||||||
|
</h2>
|
||||||
|
<p className="text-gray-600 text-center">
|
||||||
|
{canVote ? (
|
||||||
|
"The tokens used for voting are locked, which means that they still belong to you but they cannot be used for transactions. The funds are locked for as long as you are voting using these tokens and you are able to unlock them any time you want, by removing them from the votes."
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
Only users who can vote for a VPN delegate using{" "}
|
||||||
|
<b>at least 19.9 tokens</b> can use this service.
|
||||||
|
Unfortunately, your account currently has{" "}
|
||||||
|
<b>only {store.accountBalance} tokens</b>, which is not
|
||||||
|
enough to vote.
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
className="btn bg-indigo-500 hover:bg-indigo-600 text-white max-w-fit"
|
||||||
|
onClick={clickButton}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
className="w-4 h-4 fill-current opacity-50 shrink-0"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
>
|
||||||
|
<path d="M15 7H9V1c0-.6-.4-1-1-1S7 .4 7 1v6H1c-.6 0-1 .4-1 1s.4 1 1 1h6v6c0 .6.4 1 1 1s1-.4 1-1V9h6c.6 0 1-.4 1-1s-.4-1-1-1z" />
|
||||||
|
</svg>
|
||||||
|
<span className="hidden xs:block mx-6">
|
||||||
|
{canVote ? "Vote" : "Get It"}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default VPNPrepare;
|
||||||
226
src/pages/services/VPNServers.jsx
Normal file
226
src/pages/services/VPNServers.jsx
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
|
|
||||||
|
import Sidebar from "../../partials/Sidebar";
|
||||||
|
import Header from "../../partials/Header";
|
||||||
|
import { QRCodeSVG } from "qrcode.react";
|
||||||
|
|
||||||
|
import VPNServeIcon from "../../images/vpn_server_icon.png";
|
||||||
|
import { Filters } from "../../components/Filters";
|
||||||
|
|
||||||
|
const filters = {
|
||||||
|
"View All": "",
|
||||||
|
Active: "Active",
|
||||||
|
Offline: "Offline",
|
||||||
|
};
|
||||||
|
|
||||||
|
function VPNServers() {
|
||||||
|
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||||
|
const [selectedServer, setSelectedServer] = useState(0);
|
||||||
|
const [currentFilter, setCurrentFilter] = useState("View All");
|
||||||
|
|
||||||
|
const qrContent = useMemo(
|
||||||
|
() => `
|
||||||
|
[Interface]
|
||||||
|
PrivateKey = ${store.vpnPrivateKey}
|
||||||
|
Address = ${store.vpnServers?.[selectedServer]?.address}
|
||||||
|
DNS = ${store.vpnServers?.[selectedServer]?.dns}
|
||||||
|
|
||||||
|
[Peer]
|
||||||
|
PublicKey = ${store.vpnServers?.[selectedServer]?.publicKey}
|
||||||
|
AllowedIPs = 0.0.0.0/0
|
||||||
|
Endpoint = ${store.vpnServers?.[selectedServer]?.endpoint}
|
||||||
|
`,
|
||||||
|
[store.vpnServers, store.vpnPrivateKey]
|
||||||
|
);
|
||||||
|
|
||||||
|
const downloadTxtFile = () => {
|
||||||
|
const element = document.createElement("a");
|
||||||
|
const file = new Blob([qrContent], { type: "text/plain" });
|
||||||
|
element.href = URL.createObjectURL(file);
|
||||||
|
element.download = "vpnConfig.conf";
|
||||||
|
document.body.appendChild(element); // Required for this to work in FireFox
|
||||||
|
element.click();
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
store.fetchVPNServers();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex h-screen overflow-hidden">
|
||||||
|
{/* Sidebar */}
|
||||||
|
<Sidebar sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} />
|
||||||
|
|
||||||
|
{/* Content area */}
|
||||||
|
<div className="relative flex flex-col flex-1 overflow-y-auto overflow-x-hidden bg-white">
|
||||||
|
{/* Site header */}
|
||||||
|
<Header sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} />
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<div className="lg:relative lg:flex">
|
||||||
|
{/* Content */}
|
||||||
|
<div className="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
|
||||||
|
{/* Page header */}
|
||||||
|
<div className="sm:flex sm:justify-between sm:items-center mb-5">
|
||||||
|
{/* Left: Title */}
|
||||||
|
<div className="mb-4 sm:mb-0">
|
||||||
|
<h1 className="text-2xl md:text-3xl text-slate-800 font-bold">
|
||||||
|
Servers ✨
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Filters */}
|
||||||
|
<Filters
|
||||||
|
value={currentFilter}
|
||||||
|
values={Object.keys(filters)}
|
||||||
|
onChange={setCurrentFilter}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Credit cards */}
|
||||||
|
<div className="space-y-2">
|
||||||
|
{store.vpnServers?.map((e, i) => (
|
||||||
|
<label
|
||||||
|
className="relative block cursor-pointer text-left w-full"
|
||||||
|
onClick={() => setSelectedServer(i)}
|
||||||
|
key={e.publicKey}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="radio-buttons"
|
||||||
|
className="peer sr-only"
|
||||||
|
checked={i === selectedServer}
|
||||||
|
onChange={() => {}}
|
||||||
|
/>
|
||||||
|
<div className="p-4 rounded border border-slate-200 hover:border-slate-300 shadow-sm duration-150 ease-in-out">
|
||||||
|
<div className="grid grid-cols-12 items-center gap-x-2">
|
||||||
|
{/* Card */}
|
||||||
|
<div className="col-span-6 order-1 sm:order-none sm:col-span-3 flex items-center space-x-4 lg:sidebar-expanded:col-span-6 xl:sidebar-expanded:col-span-3">
|
||||||
|
<img
|
||||||
|
src={VPNServeIcon}
|
||||||
|
width="36"
|
||||||
|
height="36"
|
||||||
|
alt="VPN Country"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<div className="text-sm font-medium text-slate-800">
|
||||||
|
{e.endpoint}
|
||||||
|
</div>
|
||||||
|
<div className="text-xs">{e.publicKey}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* Card limits */}
|
||||||
|
<div className="col-span-6 order-1 sm:order-none sm:col-span-4 text-right sm:text-center lg:sidebar-expanded:col-span-6 xl:sidebar-expanded:col-span-6">
|
||||||
|
<div className="text-sm">4673,00 Mb / 473,00 Mb</div>
|
||||||
|
</div>
|
||||||
|
{/* Card status */}
|
||||||
|
<div className="col-span-6 order-2 sm:order-none sm:col-span-2 text-right lg:sidebar-expanded:hidden xl:sidebar-expanded:block">
|
||||||
|
<div className="text-xs inline-flex font-medium bg-emerald-100 text-emerald-600 rounded-full text-center px-2.5 py-1">
|
||||||
|
Active
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="absolute inset-0 border-2 border-transparent peer-checked:border-indigo-400 rounded pointer-events-none"
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Sidebar */}
|
||||||
|
<div>
|
||||||
|
<div className="lg:sticky lg:top-16 bg-slate-50 lg:overflow-x-hidden lg:overflow-y-auto no-scrollbar lg:shrink-0 border-t lg:border-t-0 lg:border-l border-slate-200 lg:w-[390px] lg:h-[calc(100vh-64px)]">
|
||||||
|
<div className="py-8 px-4 lg:px-8 h-full">
|
||||||
|
<div className="max-w-sm mx-auto lg:max-w-none flex flex-col justify-between h-full">
|
||||||
|
<div>
|
||||||
|
<div className="text-slate-800 font-semibold text-center mb-6">
|
||||||
|
Physical Metal Card
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Credit Card */}
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<QRCodeSVG
|
||||||
|
value={qrContent}
|
||||||
|
size={200}
|
||||||
|
includeMargin
|
||||||
|
level="L"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Details */}
|
||||||
|
<div className="mt-6">
|
||||||
|
<div className="text-sm font-semibold text-slate-800 mb-1">
|
||||||
|
Details
|
||||||
|
</div>
|
||||||
|
<ul>
|
||||||
|
<li className="flex items-center justify-between py-3 border-b border-slate-200">
|
||||||
|
<div className="text-sm">Server address</div>
|
||||||
|
<div className="text-sm font-medium text-slate-800 ml-2">
|
||||||
|
{store.vpnServers?.[selectedServer]?.endpoint}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li className="flex items-center justify-between py-3 border-b border-slate-200">
|
||||||
|
<div className="text-sm">Status</div>
|
||||||
|
<div className="flex items-center whitespace-nowrap">
|
||||||
|
<div className="w-2 h-2 rounded-full bg-emerald-500 mr-2" />
|
||||||
|
<div className="text-sm font-medium text-slate-800">
|
||||||
|
Active
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Payment Limits */}
|
||||||
|
<div className="mt-6">
|
||||||
|
<div className="text-sm font-semibold text-slate-800 mb-4">
|
||||||
|
Transfer
|
||||||
|
</div>
|
||||||
|
<div className="pb-4 border-b border-slate-200">
|
||||||
|
<div className="flex justify-between text-sm mb-2">
|
||||||
|
<div>Spent This Month</div>
|
||||||
|
<div className="italic">
|
||||||
|
4673,00 Mb{" "}
|
||||||
|
<span className="text-slate-400">/</span> 46730,00
|
||||||
|
Mb
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="relative w-full h-2 bg-slate-300">
|
||||||
|
<div
|
||||||
|
className="absolute inset-0 bg-indigo-500"
|
||||||
|
aria-hidden="true"
|
||||||
|
style={{ width: "10%" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className="btn w-full border-slate-200 hover:border-slate-300 text-slate-600"
|
||||||
|
onClick={downloadTxtFile}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
className="w-4 h-4 fill-current text-slate-400 shrink-0 rotate-180"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path d="M8 4c-.3 0-.5.1-.7.3L1.6 10 3 11.4l4-4V16h2V7.4l4 4 1.4-1.4-5.7-5.7C8.5 4.1 8.3 4 8 4ZM1 2h14V0H1v2Z" />
|
||||||
|
</svg>
|
||||||
|
<span className="ml-2">Download</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default VPNServers;
|
||||||
@@ -1,31 +1,34 @@
|
|||||||
import React, { useState, useEffect, useRef } from 'react';
|
import React, { useState, useEffect, useRef } from "react";
|
||||||
import { NavLink, useLocation } from 'react-router-dom';
|
import { NavLink, useLocation } from "react-router-dom";
|
||||||
import Logo from '../images/logo.png';
|
import Logo from "../images/logo.png";
|
||||||
|
|
||||||
import SidebarLinkGroup from './SidebarLinkGroup';
|
import SidebarLinkGroup from "./SidebarLinkGroup";
|
||||||
|
|
||||||
function Sidebar({
|
|
||||||
sidebarOpen,
|
|
||||||
setSidebarOpen
|
|
||||||
}) {
|
|
||||||
|
|
||||||
|
function Sidebar({ sidebarOpen, setSidebarOpen }) {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const { pathname } = location;
|
const { pathname } = location;
|
||||||
|
|
||||||
const trigger = useRef(null);
|
const trigger = useRef(null);
|
||||||
const sidebar = useRef(null);
|
const sidebar = useRef(null);
|
||||||
const storedSidebarExpanded = localStorage.getItem('sidebar-expanded');
|
const storedSidebarExpanded = localStorage.getItem("sidebar-expanded");
|
||||||
const [sidebarExpanded, setSidebarExpanded] = useState(storedSidebarExpanded === null ? false : storedSidebarExpanded === 'true');
|
const [sidebarExpanded, setSidebarExpanded] = useState(
|
||||||
|
storedSidebarExpanded === null ? false : storedSidebarExpanded === "true"
|
||||||
|
);
|
||||||
|
|
||||||
// close on click outside
|
// close on click outside
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const clickHandler = ({ target }) => {
|
const clickHandler = ({ target }) => {
|
||||||
if (!sidebar.current || !trigger.current) return;
|
if (!sidebar.current || !trigger.current) return;
|
||||||
if (!sidebarOpen || sidebar.current.contains(target) || trigger.current.contains(target)) return;
|
if (
|
||||||
|
!sidebarOpen ||
|
||||||
|
sidebar.current.contains(target) ||
|
||||||
|
trigger.current.contains(target)
|
||||||
|
)
|
||||||
|
return;
|
||||||
setSidebarOpen(false);
|
setSidebarOpen(false);
|
||||||
};
|
};
|
||||||
document.addEventListener('click', clickHandler);
|
document.addEventListener("click", clickHandler);
|
||||||
return () => document.removeEventListener('click', clickHandler);
|
return () => document.removeEventListener("click", clickHandler);
|
||||||
});
|
});
|
||||||
|
|
||||||
// close if the esc key is pressed
|
// close if the esc key is pressed
|
||||||
@@ -34,16 +37,16 @@ function Sidebar({
|
|||||||
if (!sidebarOpen || keyCode !== 27) return;
|
if (!sidebarOpen || keyCode !== 27) return;
|
||||||
setSidebarOpen(false);
|
setSidebarOpen(false);
|
||||||
};
|
};
|
||||||
document.addEventListener('keydown', keyHandler);
|
document.addEventListener("keydown", keyHandler);
|
||||||
return () => document.removeEventListener('keydown', keyHandler);
|
return () => document.removeEventListener("keydown", keyHandler);
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
localStorage.setItem('sidebar-expanded', sidebarExpanded);
|
localStorage.setItem("sidebar-expanded", sidebarExpanded);
|
||||||
if (sidebarExpanded) {
|
if (sidebarExpanded) {
|
||||||
document.querySelector('body').classList.add('sidebar-expanded');
|
document.querySelector("body").classList.add("sidebar-expanded");
|
||||||
} else {
|
} else {
|
||||||
document.querySelector('body').classList.remove('sidebar-expanded');
|
document.querySelector("body").classList.remove("sidebar-expanded");
|
||||||
}
|
}
|
||||||
}, [sidebarExpanded]);
|
}, [sidebarExpanded]);
|
||||||
|
|
||||||
@@ -52,7 +55,7 @@ function Sidebar({
|
|||||||
{/* Sidebar backdrop (mobile only) */}
|
{/* Sidebar backdrop (mobile only) */}
|
||||||
<div
|
<div
|
||||||
className={`fixed inset-0 bg-slate-900 bg-opacity-30 z-40 lg:hidden lg:z-auto transition-opacity duration-200 ${
|
className={`fixed inset-0 bg-slate-900 bg-opacity-30 z-40 lg:hidden lg:z-auto transition-opacity duration-200 ${
|
||||||
sidebarOpen ? 'opacity-100' : 'opacity-0 pointer-events-none'
|
sidebarOpen ? "opacity-100" : "opacity-0 pointer-events-none"
|
||||||
}`}
|
}`}
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></div>
|
></div>
|
||||||
@@ -62,7 +65,7 @@ function Sidebar({
|
|||||||
id="sidebar"
|
id="sidebar"
|
||||||
ref={sidebar}
|
ref={sidebar}
|
||||||
className={`flex flex-col absolute z-40 left-0 top-0 lg:static lg:left-auto lg:top-auto lg:translate-x-0 transform h-screen overflow-y-scroll lg:overflow-y-auto no-scrollbar w-64 lg:w-20 lg:sidebar-expanded:!w-64 2xl:!w-64 shrink-0 bg-slate-800 p-4 transition-all duration-200 ease-in-out ${
|
className={`flex flex-col absolute z-40 left-0 top-0 lg:static lg:left-auto lg:top-auto lg:translate-x-0 transform h-screen overflow-y-scroll lg:overflow-y-auto no-scrollbar w-64 lg:w-20 lg:sidebar-expanded:!w-64 2xl:!w-64 shrink-0 bg-slate-800 p-4 transition-all duration-200 ease-in-out ${
|
||||||
sidebarOpen ? 'translate-x-0' : '-translate-x-64'
|
sidebarOpen ? "translate-x-0" : "-translate-x-64"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{/* Sidebar header */}
|
{/* Sidebar header */}
|
||||||
@@ -76,13 +79,17 @@ function Sidebar({
|
|||||||
aria-expanded={sidebarOpen}
|
aria-expanded={sidebarOpen}
|
||||||
>
|
>
|
||||||
<span className="sr-only">Close sidebar</span>
|
<span className="sr-only">Close sidebar</span>
|
||||||
<svg className="w-6 h-6 fill-current" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
<svg
|
||||||
|
className="w-6 h-6 fill-current"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
<path d="M10.7 18.7l1.4-1.4L7.8 13H20v-2H7.8l4.3-4.3-1.4-1.4L4 12z" />
|
<path d="M10.7 18.7l1.4-1.4L7.8 13H20v-2H7.8l4.3-4.3-1.4-1.4L4 12z" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
{/* Logo */}
|
{/* Logo */}
|
||||||
<NavLink end to="/digitalId/profile-id" className="block">
|
<NavLink end to="/digitalId/profile-id" className="block">
|
||||||
<img alt='logo' src={Logo} width="89" height="32"/>
|
<img alt="logo" src={Logo} width="89" height="32" />
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -91,44 +98,68 @@ function Sidebar({
|
|||||||
{/* Pages group */}
|
{/* Pages group */}
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-xs uppercase text-slate-500 font-semibold pl-3">
|
<h3 className="text-xs uppercase text-slate-500 font-semibold pl-3">
|
||||||
<span className="hidden lg:block lg:sidebar-expanded:hidden 2xl:hidden text-center w-6" aria-hidden="true">
|
<span
|
||||||
|
className="hidden lg:block lg:sidebar-expanded:hidden 2xl:hidden text-center w-6"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
•••
|
•••
|
||||||
</span>
|
</span>
|
||||||
<span className="lg:hidden lg:sidebar-expanded:block 2xl:block">Pages</span>
|
<span className="lg:hidden lg:sidebar-expanded:block 2xl:block">
|
||||||
|
Pages
|
||||||
|
</span>
|
||||||
</h3>
|
</h3>
|
||||||
<ul className="mt-3">
|
<ul className="mt-3">
|
||||||
{/* digitalId */}
|
{/* digitalId */}
|
||||||
<SidebarLinkGroup activecondition={pathname.includes('digitalId')}>
|
<SidebarLinkGroup
|
||||||
|
activecondition={pathname.includes("digitalId")}
|
||||||
|
>
|
||||||
{(handleClick, open) => {
|
{(handleClick, open) => {
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<a
|
<a
|
||||||
href="#0"
|
|
||||||
className={`block text-slate-200 hover:text-white truncate transition duration-150 ${
|
className={`block text-slate-200 hover:text-white truncate transition duration-150 ${
|
||||||
pathname.includes('digitalId') && 'hover:text-slate-200'
|
pathname.includes("digitalId") &&
|
||||||
|
"hover:text-slate-200"
|
||||||
}`}
|
}`}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
sidebarExpanded ? handleClick() : setSidebarExpanded(true);
|
sidebarExpanded
|
||||||
|
? handleClick()
|
||||||
|
: setSidebarExpanded(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<svg className="shrink-0 h-6 w-6" viewBox="0 0 24 24">
|
<svg
|
||||||
|
className="shrink-0 h-6 w-6"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
<path
|
<path
|
||||||
className={`fill-current text-slate-600 ${pathname.includes('digitalId') && 'text-indigo-500'}`}
|
className={`fill-current text-slate-600 ${
|
||||||
|
pathname.includes("digitalId") &&
|
||||||
|
"text-indigo-500"
|
||||||
|
}`}
|
||||||
d="M19.714 14.7l-7.007 7.007-1.414-1.414 7.007-7.007c-.195-.4-.298-.84-.3-1.286a3 3 0 113 3 2.969 2.969 0 01-1.286-.3z"
|
d="M19.714 14.7l-7.007 7.007-1.414-1.414 7.007-7.007c-.195-.4-.298-.84-.3-1.286a3 3 0 113 3 2.969 2.969 0 01-1.286-.3z"
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
className={`fill-current text-slate-400 ${pathname.includes('digitalId') && 'text-indigo-300'}`}
|
className={`fill-current text-slate-400 ${
|
||||||
|
pathname.includes("digitalId") &&
|
||||||
|
"text-indigo-300"
|
||||||
|
}`}
|
||||||
d="M10.714 18.3c.4-.195.84-.298 1.286-.3a3 3 0 11-3 3c.002-.446.105-.885.3-1.286l-6.007-6.007 1.414-1.414 6.007 6.007z"
|
d="M10.714 18.3c.4-.195.84-.298 1.286-.3a3 3 0 11-3 3c.002-.446.105-.885.3-1.286l-6.007-6.007 1.414-1.414 6.007 6.007z"
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
className={`fill-current text-slate-600 ${pathname.includes('digitalId') && 'text-indigo-500'}`}
|
className={`fill-current text-slate-600 ${
|
||||||
|
pathname.includes("digitalId") &&
|
||||||
|
"text-indigo-500"
|
||||||
|
}`}
|
||||||
d="M5.7 10.714c.195.4.298.84.3 1.286a3 3 0 11-3-3c.446.002.885.105 1.286.3l7.007-7.007 1.414 1.414L5.7 10.714z"
|
d="M5.7 10.714c.195.4.298.84.3 1.286a3 3 0 11-3-3c.446.002.885.105 1.286.3l7.007-7.007 1.414 1.414L5.7 10.714z"
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
className={`fill-current text-slate-400 ${pathname.includes('digitalId') && 'text-indigo-300'}`}
|
className={`fill-current text-slate-400 ${
|
||||||
|
pathname.includes("digitalId") &&
|
||||||
|
"text-indigo-300"
|
||||||
|
}`}
|
||||||
d="M19.707 9.292a3.012 3.012 0 00-1.415 1.415L13.286 5.7c-.4.195-.84.298-1.286.3a3 3 0 113-3 2.969 2.969 0 01-.3 1.286l5.007 5.006z"
|
d="M19.707 9.292a3.012 3.012 0 00-1.415 1.415L13.286 5.7c-.4.195-.84.298-1.286.3a3 3 0 113-3 2.969 2.969 0 01-.3 1.286l5.007 5.006z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
@@ -139,7 +170,9 @@ function Sidebar({
|
|||||||
{/* Icon */}
|
{/* Icon */}
|
||||||
<div className="flex shrink-0 ml-2">
|
<div className="flex shrink-0 ml-2">
|
||||||
<svg
|
<svg
|
||||||
className={`w-3 h-3 shrink-0 ml-1 fill-current text-slate-400 ${open && 'transform rotate-180'}`}
|
className={`w-3 h-3 shrink-0 ml-1 fill-current text-slate-400 ${
|
||||||
|
open && "transform rotate-180"
|
||||||
|
}`}
|
||||||
viewBox="0 0 12 12"
|
viewBox="0 0 12 12"
|
||||||
>
|
>
|
||||||
<path d="M5.9 11.4L.5 6l1.4-1.4 4 4 4-4L11.3 6z" />
|
<path d="M5.9 11.4L.5 6l1.4-1.4 4 4 4-4L11.3 6z" />
|
||||||
@@ -148,13 +181,14 @@ function Sidebar({
|
|||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<div className="lg:hidden lg:sidebar-expanded:block 2xl:block">
|
<div className="lg:hidden lg:sidebar-expanded:block 2xl:block">
|
||||||
<ul className={`pl-9 mt-1 ${!open && 'hidden'}`}>
|
<ul className={`pl-9 mt-1 ${!open && "hidden"}`}>
|
||||||
<li className="mb-1 last:mb-0">
|
<li className="mb-1 last:mb-0">
|
||||||
<NavLink
|
<NavLink
|
||||||
end
|
end
|
||||||
to="/digitalId/profile-id"
|
to="/digitalId/profile-id"
|
||||||
className={({ isActive }) =>
|
className={({ isActive }) =>
|
||||||
'block text-slate-400 hover:text-slate-200 transition duration-150 truncate ' + (isActive ? '!text-indigo-500' : '')
|
"block text-slate-400 hover:text-slate-200 transition duration-150 truncate " +
|
||||||
|
(isActive ? "!text-indigo-500" : "")
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<span className="text-sm font-medium lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">
|
<span className="text-sm font-medium lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">
|
||||||
@@ -180,7 +214,8 @@ function Sidebar({
|
|||||||
end
|
end
|
||||||
to="/digitalId/validation-log"
|
to="/digitalId/validation-log"
|
||||||
className={({ isActive }) =>
|
className={({ isActive }) =>
|
||||||
'block text-slate-400 hover:text-slate-200 transition duration-150 truncate ' + (isActive ? '!text-indigo-500' : '')
|
"block text-slate-400 hover:text-slate-200 transition duration-150 truncate " +
|
||||||
|
(isActive ? "!text-indigo-500" : "")
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<span className="text-sm font-medium lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">
|
<span className="text-sm font-medium lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">
|
||||||
@@ -193,7 +228,8 @@ function Sidebar({
|
|||||||
end
|
end
|
||||||
to="/digitalId/verify"
|
to="/digitalId/verify"
|
||||||
className={({ isActive }) =>
|
className={({ isActive }) =>
|
||||||
'block text-slate-400 hover:text-slate-200 transition duration-150 truncate ' + (isActive ? '!text-indigo-500' : '')
|
"block text-slate-400 hover:text-slate-200 transition duration-150 truncate " +
|
||||||
|
(isActive ? "!text-indigo-500" : "")
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<span className="text-sm font-medium lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">
|
<span className="text-sm font-medium lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">
|
||||||
@@ -207,6 +243,118 @@ function Sidebar({
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</SidebarLinkGroup>
|
</SidebarLinkGroup>
|
||||||
|
<SidebarLinkGroup activecondition={pathname.includes("services")}>
|
||||||
|
{(handleClick, open) => {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<a
|
||||||
|
className={`block text-slate-200 hover:text-white truncate transition duration-150 ${
|
||||||
|
pathname.includes("services") &&
|
||||||
|
"hover:text-slate-200"
|
||||||
|
}`}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
sidebarExpanded
|
||||||
|
? handleClick()
|
||||||
|
: setSidebarExpanded(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<svg
|
||||||
|
className="shrink-0 h-6 w-6"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<circle
|
||||||
|
className={`fill-current text-slate-400 ${
|
||||||
|
pathname.includes("services") &&
|
||||||
|
"text-indigo-300"
|
||||||
|
}`}
|
||||||
|
cx="18.5"
|
||||||
|
cy="5.5"
|
||||||
|
r="4.5"
|
||||||
|
/>
|
||||||
|
<circle
|
||||||
|
className={`fill-current text-slate-600 ${
|
||||||
|
pathname.includes("services") &&
|
||||||
|
"text-indigo-500"
|
||||||
|
}`}
|
||||||
|
cx="5.5"
|
||||||
|
cy="5.5"
|
||||||
|
r="4.5"
|
||||||
|
/>
|
||||||
|
<circle
|
||||||
|
className={`fill-current text-slate-600 ${
|
||||||
|
pathname.includes("services") &&
|
||||||
|
"text-indigo-500"
|
||||||
|
}`}
|
||||||
|
cx="18.5"
|
||||||
|
cy="18.5"
|
||||||
|
r="4.5"
|
||||||
|
/>
|
||||||
|
<circle
|
||||||
|
className={`fill-current text-slate-400 ${
|
||||||
|
pathname.includes("services") &&
|
||||||
|
"text-indigo-300"
|
||||||
|
}`}
|
||||||
|
cx="5.5"
|
||||||
|
cy="18.5"
|
||||||
|
r="4.5"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span className="text-sm font-medium ml-3 lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">
|
||||||
|
Services
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/* Icon */}
|
||||||
|
<div className="flex shrink-0 ml-2">
|
||||||
|
<svg
|
||||||
|
className={`w-3 h-3 shrink-0 ml-1 fill-current text-slate-400 ${
|
||||||
|
open && "transform rotate-180"
|
||||||
|
}`}
|
||||||
|
viewBox="0 0 12 12"
|
||||||
|
>
|
||||||
|
<path d="M5.9 11.4L.5 6l1.4-1.4 4 4 4-4L11.3 6z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<div className="lg:hidden lg:sidebar-expanded:block 2xl:block">
|
||||||
|
<ul className={`pl-9 mt-1 ${!open && "hidden"}`}>
|
||||||
|
<li className="mb-1 last:mb-0">
|
||||||
|
<NavLink
|
||||||
|
end
|
||||||
|
to="/services/delegates"
|
||||||
|
className={({ isActive }) =>
|
||||||
|
"block text-slate-400 hover:text-slate-200 transition duration-150 truncate " +
|
||||||
|
(isActive ? "!text-indigo-500" : "")
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span className="text-sm font-medium lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">
|
||||||
|
Delegates
|
||||||
|
</span>
|
||||||
|
</NavLink>
|
||||||
|
</li>
|
||||||
|
<li className="mb-1 last:mb-0">
|
||||||
|
<NavLink
|
||||||
|
end
|
||||||
|
to="/services/vpn"
|
||||||
|
className={({ isActive }) =>
|
||||||
|
"block text-slate-400 hover:text-slate-200 transition duration-150 truncate " +
|
||||||
|
(isActive ? "!text-indigo-500" : "")
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span className="text-sm font-medium lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">
|
||||||
|
VPN
|
||||||
|
</span>
|
||||||
|
</NavLink>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</SidebarLinkGroup>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -216,8 +364,14 @@ function Sidebar({
|
|||||||
<div className="px-3 py-2">
|
<div className="px-3 py-2">
|
||||||
<button onClick={() => setSidebarExpanded(!sidebarExpanded)}>
|
<button onClick={() => setSidebarExpanded(!sidebarExpanded)}>
|
||||||
<span className="sr-only">Expand / collapse sidebar</span>
|
<span className="sr-only">Expand / collapse sidebar</span>
|
||||||
<svg className="w-6 h-6 fill-current sidebar-expanded:rotate-180" viewBox="0 0 24 24">
|
<svg
|
||||||
<path className="text-slate-400" d="M19.586 11l-5-5L16 4.586 23.414 12 16 19.414 14.586 18l5-5H7v-2z" />
|
className="w-6 h-6 fill-current sidebar-expanded:rotate-180"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
className="text-slate-400"
|
||||||
|
d="M19.586 11l-5-5L16 4.586 23.414 12 16 19.414 14.586 18l5-5H7v-2z"
|
||||||
|
/>
|
||||||
<path className="text-slate-600" d="M3 23H1V1h2z" />
|
<path className="text-slate-600" d="M3 23H1V1h2z" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
216
src/partials/finance/TransactionPanel.jsx
Normal file
216
src/partials/finance/TransactionPanel.jsx
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
|
import Image from "../../images/transactions-image-04.svg";
|
||||||
|
import moment from "moment";
|
||||||
|
import { formatAddressBig } from "../../utils/Utils";
|
||||||
|
import { generateSvgAvatar } from "../../images/GenerateOnboardingSvg/GenerateSvg";
|
||||||
|
import { store } from "../../store/store";
|
||||||
|
import UserAvatar from "../../images/user-avatar-32.png";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
|
||||||
|
const TransactionPanel = observer(
|
||||||
|
({ transactionPanelOpen, onClose, delegate, postTransaction }) => {
|
||||||
|
const closeBtn = useRef(null);
|
||||||
|
const panelContent = useRef(null);
|
||||||
|
|
||||||
|
const [amount, setAmount] = useState(0);
|
||||||
|
|
||||||
|
const statusColor = () => {
|
||||||
|
switch (delegate.status) {
|
||||||
|
case "Vote":
|
||||||
|
return "bg-emerald-100 text-emerald-600";
|
||||||
|
case "Unvote":
|
||||||
|
return "bg-rose-100 text-rose-500";
|
||||||
|
default:
|
||||||
|
return "bg-slate-100 text-slate-500";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const amountLabel =
|
||||||
|
delegate.status === "Vote" ? "Voiting amount" : "Unvoiting amount";
|
||||||
|
|
||||||
|
// close if the esc key is pressed
|
||||||
|
useEffect(() => {
|
||||||
|
const keyHandler = ({ keyCode }) => {
|
||||||
|
if (!transactionPanelOpen || keyCode !== 27) return;
|
||||||
|
onClose();
|
||||||
|
};
|
||||||
|
document.addEventListener("keydown", keyHandler);
|
||||||
|
return () => document.removeEventListener("keydown", keyHandler);
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const status = delegate.status;
|
||||||
|
|
||||||
|
if (status === "Unvote") {
|
||||||
|
setAmount(store.accountSentVotes[delegate.address].toString());
|
||||||
|
}
|
||||||
|
}, [delegate]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={panelContent}
|
||||||
|
className={`absolute inset-0 sm:left-auto z-20 transform shadow-xl transition-transform duration-200 ease-in-out ${
|
||||||
|
transactionPanelOpen ? "translate-x-" : "translate-x-full"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="sticky top-16 bg-slate-50 overflow-x-hidden overflow-y-auto no-scrollbar shrink-0 border-l border-slate-200 w-full sm:w-[390px] h-[calc(100vh-64px)]">
|
||||||
|
<button
|
||||||
|
ref={closeBtn}
|
||||||
|
onClick={() => onClose()}
|
||||||
|
className="absolute top-0 right-0 mt-6 mr-6 group p-2"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
className="w-4 h-4 fill-slate-400 group-hover:fill-slate-600 pointer-events-none"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path d="m7.95 6.536 4.242-4.243a1 1 0 1 1 1.415 1.414L9.364 7.95l4.243 4.242a1 1 0 1 1-1.415 1.415L7.95 9.364l-4.243 4.243a1 1 0 0 1-1.414-1.415L6.536 7.95 2.293 3.707a1 1 0 0 1 1.414-1.414L7.95 6.536Z" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div className="py-8 px-4 lg:px-8">
|
||||||
|
<div className="max-w-sm mx-auto lg:max-w-none">
|
||||||
|
<div className="text-slate-800 font-semibold text-center mb-1">
|
||||||
|
Vote Transaction
|
||||||
|
</div>
|
||||||
|
<div className="text-sm text-center italic">
|
||||||
|
{moment().format("DD/MM/YYYY hh:mm A")}
|
||||||
|
</div>
|
||||||
|
{/* Details */}
|
||||||
|
<div className="drop-shadow-lg mt-12">
|
||||||
|
{/* Top */}
|
||||||
|
<div className="bg-white rounded-t-xl px-5 pb-2.5 text-center">
|
||||||
|
<div className="mb-3 text-center">
|
||||||
|
<img
|
||||||
|
className="inline-flex w-12 h-12 rounded-full -mt-6"
|
||||||
|
src={Image}
|
||||||
|
width="48"
|
||||||
|
height="48"
|
||||||
|
alt="Transaction 04"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={`text-2xl font-semibold mb-1 ${statusColor()} bg-transparent`}
|
||||||
|
>
|
||||||
|
{amount}/idn
|
||||||
|
</div>
|
||||||
|
<div className="text-sm font-medium text-slate-800 mb-3">
|
||||||
|
{delegate?.dpos?.delegate?.username ||
|
||||||
|
formatAddressBig(delegate.address || "")}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={`text-xs inline-flex font-medium rounded-full text-center px-2.5 py-1 ${statusColor()} justify-center`}
|
||||||
|
style={{ minWidth: "84px" }}
|
||||||
|
>
|
||||||
|
{delegate.status}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* Divider */}
|
||||||
|
<div
|
||||||
|
className="flex justify-between items-center"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
className="w-5 h-5 fill-white"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path d="M0 20c5.523 0 10-4.477 10-10S5.523 0 0 0h20v20H0Z" />
|
||||||
|
</svg>
|
||||||
|
<div className="grow w-full h-5 bg-white flex flex-col justify-center">
|
||||||
|
<div className="h-px w-full border-t border-dashed border-slate-200" />
|
||||||
|
</div>
|
||||||
|
<svg
|
||||||
|
className="w-5 h-5 fill-white rotate-180"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path d="M0 20c5.523 0 10-4.477 10-10S5.523 0 0 0h20v20H0Z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
{/* Bottom */}
|
||||||
|
<div className="bg-white rounded-b-xl p-5 pt-2.5 text-sm space-y-3">
|
||||||
|
<div className="flex justify-between space-x-1">
|
||||||
|
<span className="italic">ADDRESS:</span>
|
||||||
|
<span className="font-medium text-slate-700 text-right">
|
||||||
|
{formatAddressBig(delegate.address || "")}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between space-x-1">
|
||||||
|
<span className="italic">FEE:</span>
|
||||||
|
<span className="font-medium text-slate-700 text-right">
|
||||||
|
145/idn
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between space-x-1">
|
||||||
|
<span className="italic">Nonce:</span>
|
||||||
|
<span className="font-medium text-slate-700 text-right">
|
||||||
|
{delegate?.sequence?.nonce}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between space-x-1">
|
||||||
|
<span className="italic">Sender:</span>
|
||||||
|
<span className="font-medium text-slate-700 text-right">
|
||||||
|
{formatAddressBig(store.address)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* Receipts */}
|
||||||
|
<div className="mt-6">
|
||||||
|
<label
|
||||||
|
className="block text-sm font-medium mb-1"
|
||||||
|
htmlFor="mandatory"
|
||||||
|
>
|
||||||
|
{amountLabel} <span className="text-rose-500">*</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="amount"
|
||||||
|
className="form-input w-full"
|
||||||
|
type="number"
|
||||||
|
required
|
||||||
|
onChange={(e) => setAmount(e.target.value)}
|
||||||
|
value={amount}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/* Notes */}
|
||||||
|
<div className="mt-6">
|
||||||
|
<div className="text-sm font-semibold text-slate-800 mb-2">
|
||||||
|
Transaction details
|
||||||
|
</div>
|
||||||
|
<div className="flex p-2 justify-between items-center border border-slate-300 rounded-md">
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<img
|
||||||
|
className="w-8 h-8 rounded-full"
|
||||||
|
src={generateSvgAvatar(store.pubKey) || UserAvatar}
|
||||||
|
width="32"
|
||||||
|
height="32"
|
||||||
|
alt="User"
|
||||||
|
/>
|
||||||
|
<div className="flex items-center text-sm text-slate-700">
|
||||||
|
Balance
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center text-sm text-slate-700">
|
||||||
|
{store.accountBalance}/idn
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center space-x-3 mt-6">
|
||||||
|
<button
|
||||||
|
className="btn bg-indigo-500 hover:bg-indigo-600 text-white w-full"
|
||||||
|
onClick={() => {
|
||||||
|
postTransaction(delegate.address, BigInt(amount));
|
||||||
|
onClose();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className="hidden xs:block">Post Transaction</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export default TransactionPanel;
|
||||||
64
src/partials/finance/TransactionsTable.jsx
Normal file
64
src/partials/finance/TransactionsTable.jsx
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import React from "react";
|
||||||
|
import TransactionItem from "./TransactionsTableItem";
|
||||||
|
|
||||||
|
import Image01 from "../../images/transactions-image-01.svg";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
|
||||||
|
const TransactionsTable = observer(({ data, rowClick }) => {
|
||||||
|
return (
|
||||||
|
<div className="bg-white">
|
||||||
|
<div>
|
||||||
|
{/* Table */}
|
||||||
|
<div className="overflow-x-auto">
|
||||||
|
<table className="table-auto w-full">
|
||||||
|
{/* Table header */}
|
||||||
|
<thead className="text-xs font-semibold uppercase text-slate-500 border-t border-b border-slate-200">
|
||||||
|
<tr>
|
||||||
|
<th className="px-4 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
|
||||||
|
<div className="font-semibold text-left">Delegate</div>
|
||||||
|
</th>
|
||||||
|
<th className="px-4 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
|
||||||
|
<div className="font-semibold text-center">Service</div>
|
||||||
|
</th>
|
||||||
|
<th className="px-4 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
|
||||||
|
<div className="font-semibold text-center">Balance</div>
|
||||||
|
</th>
|
||||||
|
<th className="px-4 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
|
||||||
|
<div className="font-semibold text-center">Voted Total</div>
|
||||||
|
</th>
|
||||||
|
<th className="px-4 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
|
||||||
|
<div className="font-semibold text-center"></div>
|
||||||
|
</th>
|
||||||
|
<th className="px-4 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
|
||||||
|
<div className="font-semibold text-center">Sent Votes</div>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
{/* Table body */}
|
||||||
|
<tbody className="text-sm divide-y divide-slate-200 border-b border-slate-200">
|
||||||
|
{data.map((delegate) => {
|
||||||
|
return (
|
||||||
|
<TransactionItem
|
||||||
|
key={delegate.address}
|
||||||
|
id={delegate.address}
|
||||||
|
image={Image01}
|
||||||
|
balance={delegate.token.balance}
|
||||||
|
name={delegate.dpos.delegate.username || delegate.address}
|
||||||
|
total={delegate.dpos.delegate.totalVotesReceived}
|
||||||
|
hasSevice
|
||||||
|
date={delegate.date}
|
||||||
|
status={delegate.status}
|
||||||
|
amount={store.accountSentVotes[delegate.address] || 0}
|
||||||
|
handleClick={() => rowClick(delegate)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default TransactionsTable;
|
||||||
96
src/partials/finance/TransactionsTableItem.jsx
Normal file
96
src/partials/finance/TransactionsTableItem.jsx
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import ServiceImage from "../../images/service_icon.png";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
|
||||||
|
const TransactionsTableItem = observer((props) => {
|
||||||
|
const statusColor = () => {
|
||||||
|
switch (props.status) {
|
||||||
|
case "Vote":
|
||||||
|
return "bg-emerald-100 text-emerald-600";
|
||||||
|
case "Unvote":
|
||||||
|
return "bg-rose-100 text-rose-500";
|
||||||
|
default:
|
||||||
|
return "bg-slate-100 text-slate-500";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const amountColor = () => {
|
||||||
|
switch (props.status === "Unvote") {
|
||||||
|
case "+":
|
||||||
|
return "text-emerald-500";
|
||||||
|
default:
|
||||||
|
return "text-slate-700";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const clickReturn = (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
store.pushUnlockTransaction(props.id);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<tr className="cursor-pointer" onClick={() => props.handleClick()}>
|
||||||
|
<td className="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap md:w-1/2">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<div className="w-9 h-9 shrink-0 mr-2 sm:mr-3">
|
||||||
|
<img
|
||||||
|
className="rounded-full"
|
||||||
|
src={props.image}
|
||||||
|
width="36"
|
||||||
|
height="36"
|
||||||
|
alt={props.name}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="font-medium text-slate-800">{props.name}</div>
|
||||||
|
{store.accountLockedVotesCanReturn[props.id] && (
|
||||||
|
<span
|
||||||
|
className="truncate font-medium text-indigo-500 group-hover:text-indigo-600 ml-2"
|
||||||
|
onClick={clickReturn}
|
||||||
|
>
|
||||||
|
Return votes
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td className="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
|
||||||
|
<div className="flex items-center justify-center">
|
||||||
|
<div className="w-9 h-9 shrink-0">
|
||||||
|
{props.hasSevice && (
|
||||||
|
<img
|
||||||
|
className="rounded-full"
|
||||||
|
src={ServiceImage}
|
||||||
|
width="36"
|
||||||
|
height="36"
|
||||||
|
alt="service"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td className="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
|
||||||
|
<div className="text-center">{props.balance}/idn</div>
|
||||||
|
</td>
|
||||||
|
<td className="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
|
||||||
|
<div className="text-center">{props.total}/idn</div>
|
||||||
|
</td>
|
||||||
|
<td className="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
|
||||||
|
<div className="text-center">
|
||||||
|
<div
|
||||||
|
className={`text-xs inline-flex font-medium rounded-full justify-center px-2.5 py-1 ${statusColor()}`}
|
||||||
|
style={{ minWidth: "84px" }}
|
||||||
|
>
|
||||||
|
{props.status}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td className="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap w-px">
|
||||||
|
<div className={`text-center font-medium ${amountColor()}`}>
|
||||||
|
{props.amount.toString()}/idn
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default TransactionsTableItem;
|
||||||
@@ -1,18 +1,29 @@
|
|||||||
import { reaction, makeAutoObservable, onBecomeObserved, onBecomeUnobserved } from 'mobx';
|
import {
|
||||||
import { cryptography } from '@liskhq/lisk-client';
|
reaction,
|
||||||
import { passphrase } from '@liskhq/lisk-client';
|
makeAutoObservable,
|
||||||
import { getNodeInfo } from '../api/node';
|
onBecomeObserved,
|
||||||
import { fetchWrapper } from '../shared/fetchWrapper';
|
onBecomeUnobserved,
|
||||||
import { labelMap } from '../shared/labelMap';
|
} from "mobx";
|
||||||
|
import { cryptography } from "@liskhq/lisk-client";
|
||||||
|
import { passphrase } from "@liskhq/lisk-client";
|
||||||
|
import { getNodeInfo } from "../api/node";
|
||||||
|
import { fetchWrapper } from "../shared/fetchWrapper";
|
||||||
|
import { labelMap } from "../shared/labelMap";
|
||||||
import { statusMap } from "../shared/statusMap";
|
import { statusMap } from "../shared/statusMap";
|
||||||
import { generateSvgAvatar } from '../images/GenerateOnboardingSvg/GenerateSvg';
|
import { generateSvgAvatar } from "../images/GenerateOnboardingSvg/GenerateSvg";
|
||||||
import {decryptedData} from "../utils/decryptedData";
|
import { decryptedData } from "../utils/decryptedData";
|
||||||
import {encryptAccountData, encryptSharedData, generateTransaction, hashAccountData} from '../utils/Utils';
|
import {
|
||||||
|
encryptAccountData,
|
||||||
|
encryptSharedData,
|
||||||
|
generateTransaction,
|
||||||
|
hashAccountData,
|
||||||
|
} from "../utils/Utils";
|
||||||
|
import sodium from "sodium-universal";
|
||||||
|
|
||||||
class Store {
|
class Store {
|
||||||
_accountData = [];
|
_accountData = [];
|
||||||
|
|
||||||
_passPhrase = '';
|
_passPhrase = "";
|
||||||
|
|
||||||
_nodeInfo = {};
|
_nodeInfo = {};
|
||||||
|
|
||||||
@@ -28,6 +39,19 @@ class Store {
|
|||||||
|
|
||||||
_tempTransactions = [];
|
_tempTransactions = [];
|
||||||
|
|
||||||
|
_vpnServers = [];
|
||||||
|
|
||||||
|
_canVPN = false;
|
||||||
|
|
||||||
|
_delegates = {
|
||||||
|
data: [],
|
||||||
|
meta: {
|
||||||
|
count: 0,
|
||||||
|
limit: 0,
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
makeAutoObservable(this, {});
|
makeAutoObservable(this, {});
|
||||||
|
|
||||||
@@ -39,121 +63,147 @@ class Store {
|
|||||||
() => this.address,
|
() => this.address,
|
||||||
() => this.fetchAccountInfo()
|
() => this.fetchAccountInfo()
|
||||||
);
|
);
|
||||||
onBecomeObserved(this, 'decryptedAccountData', () => this.fetchNewAccountData());
|
onBecomeObserved(this, "decryptedAccountData", () =>
|
||||||
onBecomeUnobserved(this, 'decryptedAccountData', () => this.unobservedAccountData())
|
this.fetchNewAccountData()
|
||||||
onBecomeObserved(this, 'sharedData', () => this.fetchKeysArray());
|
);
|
||||||
onBecomeUnobserved(this, 'sharedData', () => this.unobservedSharedData());
|
onBecomeUnobserved(this, "decryptedAccountData", () =>
|
||||||
onBecomeObserved(this, 'transactionsInfo', () => this.fetchTransactionsInfo());
|
this.unobservedAccountData()
|
||||||
onBecomeUnobserved(this, 'transactionsInfo', () => this.unobservedTransactionsInfo());
|
);
|
||||||
|
onBecomeObserved(this, "sharedData", () => this.fetchKeysArray());
|
||||||
|
onBecomeUnobserved(this, "sharedData", () => this.unobservedSharedData());
|
||||||
|
onBecomeObserved(this, "transactionsInfo", () =>
|
||||||
|
this.fetchTransactionsInfo()
|
||||||
|
);
|
||||||
|
onBecomeUnobserved(this, "transactionsInfo", () =>
|
||||||
|
this.unobservedTransactionsInfo()
|
||||||
|
);
|
||||||
|
|
||||||
this.fetchNodeInfo();
|
this.fetchNodeInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fetchVPNServers() {
|
||||||
|
fetchWrapper
|
||||||
|
.getAuth("vpn/servers")
|
||||||
|
.then((r) => this.fetchVPNServersSuccess(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchDelegates(offset = 0, limit = 10) {
|
||||||
|
fetchWrapper
|
||||||
|
.getAuth(`delegates?limit=${limit}&offset=${offset}`)
|
||||||
|
.then((r) => this.fetchDelegatesSuccess(r));
|
||||||
|
}
|
||||||
|
|
||||||
fetchNewAccountData() {
|
fetchNewAccountData() {
|
||||||
getNodeInfo()
|
getNodeInfo()
|
||||||
.then((info) => {
|
.then((info) => {
|
||||||
this.fetchNodeInfoSuccess(info);
|
this.fetchNodeInfoSuccess(info);
|
||||||
fetchWrapper
|
fetchWrapper
|
||||||
.getAuth('data/private', {
|
.getAuth("data/private", {
|
||||||
networkIdentifier: this.nodeInfo.networkIdentifier,
|
networkIdentifier: this.nodeInfo.networkIdentifier,
|
||||||
lastBlockID: this.nodeInfo.lastBlockID,
|
lastBlockID: this.nodeInfo.lastBlockID,
|
||||||
|
})
|
||||||
|
.then((res) => this.accountDataFetchChange(res))
|
||||||
|
.catch((err) => this.throwError(err));
|
||||||
})
|
})
|
||||||
.then((res) => this.accountDataFetchChange(res))
|
|
||||||
.catch((err) => this.throwError(err));
|
.catch((err) => this.throwError(err));
|
||||||
})
|
|
||||||
.catch((err) => this.throwError(err));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchAccountInfo() {
|
fetchAccountInfo() {
|
||||||
fetchWrapper
|
fetchWrapper
|
||||||
.get(`accounts/${this.address}`)
|
.get(`accounts/${this.address}`)
|
||||||
.then((res) => this.fetchAccountInfoSuccess(res))
|
.then((res) => this.fetchAccountInfoSuccess(res))
|
||||||
.catch((err) => this.throwError(err));
|
.catch((err) => this.throwError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchKeysArray() {
|
fetchKeysArray() {
|
||||||
getNodeInfo()
|
getNodeInfo()
|
||||||
.then((info) => {
|
.then((info) => {
|
||||||
this.fetchNodeInfoSuccess(info);
|
this.fetchNodeInfoSuccess(info);
|
||||||
fetchWrapper
|
fetchWrapper
|
||||||
.getAuth('data/shared/', {
|
.getAuth("data/shared/", {
|
||||||
networkIdentifier: this.nodeInfo.networkIdentifier,
|
networkIdentifier: this.nodeInfo.networkIdentifier,
|
||||||
lastBlockID: this.nodeInfo.lastBlockID,
|
lastBlockID: this.nodeInfo.lastBlockID,
|
||||||
|
})
|
||||||
|
.then((res) => this.keysArrayFetchChange(res));
|
||||||
})
|
})
|
||||||
.then((res) => this.keysArrayFetchChange(res));
|
.catch((err) => this.throwError(err));
|
||||||
})
|
|
||||||
.catch((err) => this.throwError(err));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchTransactionsInfo() {
|
fetchTransactionsInfo() {
|
||||||
fetchWrapper
|
fetchWrapper
|
||||||
.get(`account/transactions/${this.address}`, {
|
.get(`account/transactions/${this.address}`, {
|
||||||
networkIdentifier: this.nodeInfo.networkIdentifier,
|
networkIdentifier: this.nodeInfo.networkIdentifier,
|
||||||
lastBlockID: this.nodeInfo.lastBlockID,
|
lastBlockID: this.nodeInfo.lastBlockID,
|
||||||
})
|
})
|
||||||
.then((res) => this.saveInfoTransactions(res))
|
.then((res) => this.saveInfoTransactions(res))
|
||||||
.catch((err) => this.throwError(err));
|
.catch((err) => this.throwError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchTempTransactions() {
|
fetchTempTransactions() {
|
||||||
fetchWrapper
|
fetchWrapper
|
||||||
.get('node/transactions')
|
.get("node/transactions")
|
||||||
.then((res) => this.fetchTempTransactionsSuccess(res))
|
.then((res) => this.fetchTempTransactionsSuccess(res))
|
||||||
.catch((err) => this.throwError(err));
|
.catch((err) => this.throwError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchPassPhrase() {
|
fetchPassPhrase() {
|
||||||
this._passPhrase = sessionStorage.getItem('passPhrase') || '';
|
this._passPhrase = sessionStorage.getItem("passPhrase") || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchSharedData() {
|
fetchSharedData() {
|
||||||
this._keysArray.forEach((elem) => {
|
this._keysArray.forEach((elem) => {
|
||||||
fetchWrapper
|
fetchWrapper
|
||||||
.get(`data/shared/${elem}`)
|
.get(`data/shared/${elem}`)
|
||||||
.then((res) => this.changeSharedData(res, elem))
|
.then((res) => this.changeSharedData(res, elem))
|
||||||
.catch((err) => this.throwError(err))
|
.catch((err) => this.throwError(err));
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchNodeInfo() {
|
fetchNodeInfo() {
|
||||||
getNodeInfo()
|
getNodeInfo()
|
||||||
.then((info) => this.fetchNodeInfoSuccess(info))
|
.then((info) => this.fetchNodeInfoSuccess(info))
|
||||||
.catch((err) => this.throwError(err));
|
.catch((err) => this.throwError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
pushSharedData(data, pubKey = this.pubKey) {
|
pushSharedData(data, pubKey = this.pubKey) {
|
||||||
data=data.filter(item=>item.status!==statusMap.blockchained)
|
data = data.filter((item) => item.status !== statusMap.blockchained);
|
||||||
if(data.length>0) {
|
if (data.length > 0) {
|
||||||
fetchWrapper
|
fetchWrapper
|
||||||
.postAuth(
|
.postAuth(
|
||||||
'data/shared',
|
"data/shared",
|
||||||
{
|
{
|
||||||
networkIdentifier: this.nodeInfo.networkIdentifier,
|
networkIdentifier: this.nodeInfo.networkIdentifier,
|
||||||
lastBlockID: this.nodeInfo.lastBlockID,
|
lastBlockID: this.nodeInfo.lastBlockID,
|
||||||
},
|
},
|
||||||
{publickey: this.pubKey, shared: encryptSharedData(data, this.passPhrase, pubKey)}
|
{
|
||||||
)
|
publickey: this.pubKey,
|
||||||
.catch((err) => this.throwError(err));
|
shared: encryptSharedData(data, this.passPhrase, pubKey),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((err) => this.throwError(err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pushAccountData(data = this.accountData) {
|
pushAccountData(data = this.accountData) {
|
||||||
fetchWrapper
|
fetchWrapper
|
||||||
.postAuth(
|
.postAuth(
|
||||||
'data/private',
|
"data/private",
|
||||||
{
|
{
|
||||||
networkIdentifier: this.nodeInfo.networkIdentifier,
|
networkIdentifier: this.nodeInfo.networkIdentifier,
|
||||||
lastBlockID: this.nodeInfo.lastBlockID,
|
lastBlockID: this.nodeInfo.lastBlockID,
|
||||||
},
|
},
|
||||||
[...encryptAccountData(data, this.passPhrase, this.pubKey)]
|
[...encryptAccountData(data, this.passPhrase, this.pubKey)]
|
||||||
)
|
)
|
||||||
.then(() => this.fetchNewAccountData())
|
.then(() => this.fetchNewAccountData())
|
||||||
.catch((err) => this.throwError(err));
|
.catch((err) => this.throwError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
pushAccountDataToBlockchain(data = this.decryptedAccountData) {
|
pushAccountDataToBlockchain(data = this.decryptedAccountData) {
|
||||||
const [removed, changed] = hashAccountData(data, this.decryptedAccountData, this.accountFeaturesMap);
|
const [removed, changed] = hashAccountData(
|
||||||
|
data,
|
||||||
|
this.decryptedAccountData,
|
||||||
|
this.accountFeaturesMap
|
||||||
|
);
|
||||||
const builder = generateTransaction(
|
const builder = generateTransaction(
|
||||||
BigInt(this.accountInfo?.sequence?.nonce || 0),
|
BigInt(this.accountInfo?.sequence?.nonce || 0),
|
||||||
this.addressAndPubKey.publicKey,
|
this.addressAndPubKey.publicKey,
|
||||||
@@ -167,21 +217,63 @@ class Store {
|
|||||||
|
|
||||||
if (changed.length !== 0) signedTx = builder.update(changed);
|
if (changed.length !== 0) signedTx = builder.update(changed);
|
||||||
if (signedTx) {
|
if (signedTx) {
|
||||||
fetchWrapper.post('transactions', {}, signedTx)
|
fetchWrapper
|
||||||
.then(() => this.fetchTempTransactions())
|
.post("transactions", {}, signedTx)
|
||||||
.catch((err) => this.throwError(err));
|
.then(() => this.fetchTempTransactions())
|
||||||
|
.catch((err) => this.throwError(err));
|
||||||
|
this.accountInfo.sequence.nonce++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pushVoteTransaction(delegateAddress, amount) {
|
||||||
|
const builder = generateTransaction(
|
||||||
|
BigInt(this.accountInfo?.sequence?.nonce || 0),
|
||||||
|
this.addressAndPubKey.publicKey,
|
||||||
|
this.nodeInfo.networkIdentifier,
|
||||||
|
this.passPhrase
|
||||||
|
);
|
||||||
|
|
||||||
|
const signedTx = builder.vote(delegateAddress, amount);
|
||||||
|
|
||||||
|
if (signedTx) {
|
||||||
|
fetchWrapper
|
||||||
|
.post("transactions", {}, signedTx)
|
||||||
|
.then(() => this.fetchTempTransactions())
|
||||||
|
.catch((err) => this.throwError(err));
|
||||||
|
this.accountInfo.sequence.nonce++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pushUnlockTransaction(delegateAddress) {
|
||||||
|
const builder = generateTransaction(
|
||||||
|
BigInt(this.accountInfo?.sequence?.nonce || 0),
|
||||||
|
this.addressAndPubKey.publicKey,
|
||||||
|
this.nodeInfo.networkIdentifier,
|
||||||
|
this.passPhrase
|
||||||
|
);
|
||||||
|
|
||||||
|
const { amount, unvoteHeight } =
|
||||||
|
this.accountLockedVotesCanReturn[delegateAddress];
|
||||||
|
|
||||||
|
const signedTx = builder.unlock(delegateAddress, amount, unvoteHeight);
|
||||||
|
|
||||||
|
if (signedTx) {
|
||||||
|
fetchWrapper
|
||||||
|
.post("transactions", {}, signedTx)
|
||||||
|
.then(() => this.fetchTempTransactions())
|
||||||
|
.catch((err) => this.throwError(err));
|
||||||
this.accountInfo.sequence.nonce++;
|
this.accountInfo.sequence.nonce++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
generatePassPhrase() {
|
generatePassPhrase() {
|
||||||
this._passPhrase = passphrase.Mnemonic.generateMnemonic();
|
this._passPhrase = passphrase.Mnemonic.generateMnemonic();
|
||||||
sessionStorage.setItem('passPhrase', this._passPhrase);
|
sessionStorage.setItem("passPhrase", this._passPhrase);
|
||||||
}
|
}
|
||||||
|
|
||||||
savePastPassPhrase(phrase) {
|
savePastPassPhrase(phrase) {
|
||||||
this._passPhrase = phrase;
|
this._passPhrase = phrase;
|
||||||
sessionStorage.setItem('passPhrase', this._passPhrase);
|
sessionStorage.setItem("passPhrase", this._passPhrase);
|
||||||
}
|
}
|
||||||
|
|
||||||
unobservedTransactionsInfo() {
|
unobservedTransactionsInfo() {
|
||||||
@@ -193,13 +285,13 @@ class Store {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unobservedAccountData() {
|
unobservedAccountData() {
|
||||||
this._accountData=[]
|
this._accountData = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
changeSharedData(incomingData, id) {
|
changeSharedData(incomingData, id) {
|
||||||
this._sharedData.push({
|
this._sharedData.push({
|
||||||
data: incomingData.data,
|
data: incomingData.data,
|
||||||
id
|
id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,6 +318,26 @@ class Store {
|
|||||||
this._keysArray = res.data;
|
this._keysArray = res.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fetchVPNServersSuccess() {
|
||||||
|
const res = {
|
||||||
|
servers: [
|
||||||
|
{
|
||||||
|
endpoint: "3.71.169.233:137",
|
||||||
|
publicKey: "LEcqxygHtVlYWoQ6kZld9FbWxjb+fAqctMMFFJD6XU4=",
|
||||||
|
address: "10.1.0.6/32",
|
||||||
|
dns: "1.1.1.1",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
meta: true,
|
||||||
|
};
|
||||||
|
this._canVPN = res.meta;
|
||||||
|
this._vpnServers = res.servers;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchDelegatesSuccess(res) {
|
||||||
|
this._delegates = res;
|
||||||
|
}
|
||||||
|
|
||||||
fetchNodeInfoSuccess(info) {
|
fetchNodeInfoSuccess(info) {
|
||||||
this._nodeInfo = info.data;
|
this._nodeInfo = info.data;
|
||||||
this.fetchPassPhrase();
|
this.fetchPassPhrase();
|
||||||
@@ -234,7 +346,8 @@ class Store {
|
|||||||
fetchAccountInfoSuccess(res) {
|
fetchAccountInfoSuccess(res) {
|
||||||
this._accountInfo = res.data;
|
this._accountInfo = res.data;
|
||||||
if (this.accountInfo?.sequence?.nonce)
|
if (this.accountInfo?.sequence?.nonce)
|
||||||
this.accountInfo.sequence.nonce = parseInt(this.accountInfo.sequence.nonce) || 0;
|
this.accountInfo.sequence.nonce =
|
||||||
|
parseInt(this.accountInfo.sequence.nonce) || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchTempTransactionsSuccess(res) {
|
fetchTempTransactionsSuccess(res) {
|
||||||
@@ -251,7 +364,7 @@ class Store {
|
|||||||
label: labelMap[item.label] || item.label,
|
label: labelMap[item.label] || item.label,
|
||||||
value: item.value,
|
value: item.value,
|
||||||
})),
|
})),
|
||||||
id: elem.id
|
id: elem.id,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,7 +372,9 @@ class Store {
|
|||||||
return this._transactionsInfo.map((item) => {
|
return this._transactionsInfo.map((item) => {
|
||||||
return {
|
return {
|
||||||
id: item.id,
|
id: item.id,
|
||||||
sender_avatar: item.asset.recipientAddress && generateSvgAvatar(item.senderPublicKey),
|
sender_avatar:
|
||||||
|
item.asset.recipientAddress &&
|
||||||
|
generateSvgAvatar(item.senderPublicKey),
|
||||||
avatar_size: 24,
|
avatar_size: 24,
|
||||||
transaction: item.asset.features.map((asset) => {
|
transaction: item.asset.features.map((asset) => {
|
||||||
return {
|
return {
|
||||||
@@ -267,7 +382,9 @@ class Store {
|
|||||||
address:
|
address:
|
||||||
item.asset.recipientAddress &&
|
item.asset.recipientAddress &&
|
||||||
cryptography.bufferToHex(
|
cryptography.bufferToHex(
|
||||||
cryptography.getAddressFromPublicKey(cryptography.hexToBuffer(item.senderPublicKey))
|
cryptography.getAddressFromPublicKey(
|
||||||
|
cryptography.hexToBuffer(item.senderPublicKey)
|
||||||
|
)
|
||||||
),
|
),
|
||||||
value: asset.value,
|
value: asset.value,
|
||||||
label: labelMap[asset.label] || asset.label,
|
label: labelMap[asset.label] || asset.label,
|
||||||
@@ -277,15 +394,23 @@ class Store {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
get decryptedAccountData() {
|
get decryptedAccountData() {
|
||||||
return decryptedData(this._accountData, this.accountFeatures, this.passPhrase, this.pubKey, this.processedFeatures)
|
return decryptedData(
|
||||||
|
this._accountData,
|
||||||
|
this.accountFeatures,
|
||||||
|
this.passPhrase,
|
||||||
|
this.pubKey,
|
||||||
|
this.processedFeatures
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get firstName() {
|
get firstName() {
|
||||||
return this.decryptedAccountData.find((item) => item.key === 'firstname')?.value;
|
return this.decryptedAccountData.find((item) => item.key === "firstname")
|
||||||
|
?.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
get lastName() {
|
get lastName() {
|
||||||
return this.decryptedAccountData.find((item) => item.key === 'secondname')?.value;
|
return this.decryptedAccountData.find((item) => item.key === "secondname")
|
||||||
|
?.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
get accountName() {
|
get accountName() {
|
||||||
@@ -316,19 +441,36 @@ class Store {
|
|||||||
return cryptography.getAddressAndPublicKeyFromPassphrase(this.passPhrase);
|
return cryptography.getAddressAndPublicKeyFromPassphrase(this.passPhrase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get privateKey() {
|
||||||
|
return cryptography.getPrivateAndPublicKeyFromPassphrase(this.passPhrase)
|
||||||
|
?.privateKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
get vpnPrivateKey() {
|
||||||
|
let x25519_sk = Buffer.alloc(sodium.crypto_box_SECRETKEYBYTES);
|
||||||
|
sodium.crypto_sign_ed25519_sk_to_curve25519(
|
||||||
|
x25519_sk,
|
||||||
|
Buffer.from(this.privateKey, "hex")
|
||||||
|
);
|
||||||
|
return x25519_sk.toString("Base64");
|
||||||
|
}
|
||||||
|
|
||||||
get pubKey() {
|
get pubKey() {
|
||||||
return this.addressAndPubKey.publicKey.toString('hex');
|
return this.addressAndPubKey.publicKey.toString("hex");
|
||||||
}
|
}
|
||||||
|
|
||||||
get address() {
|
get address() {
|
||||||
return this.addressAndPubKey.address.toString('hex');
|
return this.addressAndPubKey.address.toString("hex");
|
||||||
}
|
}
|
||||||
|
|
||||||
get tokenKey() {
|
get tokenKey() {
|
||||||
const stringToSign = this.nodeInfo.networkIdentifier + this.nodeInfo.lastBlockID;
|
const stringToSign =
|
||||||
if (!stringToSign) return '';
|
this.nodeInfo.networkIdentifier + this.nodeInfo.lastBlockID;
|
||||||
const sign = cryptography.signDataWithPassphrase(Buffer.from(stringToSign, 'hex'), this.passPhrase).toString('hex');
|
if (!stringToSign) return "";
|
||||||
return this.pubKey + ':' + sign;
|
const sign = cryptography
|
||||||
|
.signDataWithPassphrase(Buffer.from(stringToSign, "hex"), this.passPhrase)
|
||||||
|
.toString("hex");
|
||||||
|
return this.pubKey + ":" + sign;
|
||||||
}
|
}
|
||||||
|
|
||||||
get accountIdentity() {
|
get accountIdentity() {
|
||||||
@@ -339,6 +481,51 @@ class Store {
|
|||||||
return this.accountIdentity?.features || [];
|
return this.accountIdentity?.features || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get accountBalance() {
|
||||||
|
return (
|
||||||
|
BigInt(this.accountInfo?.token?.balance || 0) / 100000000n
|
||||||
|
).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
get accountSentVotes() {
|
||||||
|
return (this.accountInfo?.dpos?.sentVotes || []).reduce(
|
||||||
|
(acc, e) => ({
|
||||||
|
...acc,
|
||||||
|
[e.delegateAddress]:
|
||||||
|
BigInt(e.amount || 0) / 100000000n + (acc[e.delegateAddress] || 0n),
|
||||||
|
}),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
get accountLockedVotes() {
|
||||||
|
return (this.accountInfo?.dpos?.unlocking || []).reduce(
|
||||||
|
(acc, e) => ({
|
||||||
|
...acc,
|
||||||
|
[e.delegateAddress]:
|
||||||
|
BigInt(e.amount || 0) / 100000000n + (acc[e.delegateAddress] || 0n),
|
||||||
|
}),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
get accountLockedVotesCanReturn() {
|
||||||
|
return (this.accountInfo?.dpos?.unlocking || [])
|
||||||
|
.filter((e) => this.nodeInfo.height - e.unvoteHeight > 2000)
|
||||||
|
.reduce(
|
||||||
|
(acc, e) => ({
|
||||||
|
...acc,
|
||||||
|
[e.delegateAddress]: {
|
||||||
|
amount:
|
||||||
|
BigInt(e.amount || 0) / 100000000n +
|
||||||
|
(acc[e.delegateAddress]?.amount || 0n),
|
||||||
|
unvoteHeight: e.unvoteHeight,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
get accountFeaturesMap() {
|
get accountFeaturesMap() {
|
||||||
return this.accountFeatures.reduce(
|
return this.accountFeatures.reduce(
|
||||||
(acc, item) => ({
|
(acc, item) => ({
|
||||||
@@ -363,14 +550,103 @@ class Store {
|
|||||||
|
|
||||||
get processedFeatures() {
|
get processedFeatures() {
|
||||||
return this.tempTransactions
|
return this.tempTransactions
|
||||||
.filter(item => item.senderPublicKey === this.pubKey)
|
.filter((item) => item.senderPublicKey === this.pubKey)
|
||||||
.reduce((acc, item) => {
|
.reduce((acc, item) => {
|
||||||
const { features } = item.asset;
|
const { features } = item.asset;
|
||||||
return {
|
return {
|
||||||
...acc,
|
...acc,
|
||||||
...features.reduce((obj, feature) => ({...obj, [feature.label]: true}), {})
|
...(features?.reduce(
|
||||||
}
|
(obj, feature) => ({ ...obj, [feature.label]: true }),
|
||||||
}, {})
|
{}
|
||||||
|
) || {}),
|
||||||
|
};
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
get processedVotes() {
|
||||||
|
return this.tempTransactions
|
||||||
|
.filter((item) => item.senderPublicKey === this.pubKey)
|
||||||
|
.reduce((acc, item) => {
|
||||||
|
const { votes } = item.asset;
|
||||||
|
return {
|
||||||
|
...acc,
|
||||||
|
...(votes?.reduce(
|
||||||
|
(obj, vote) => ({
|
||||||
|
...obj,
|
||||||
|
[vote.delegateAddress]:
|
||||||
|
BigInt(vote.amount) / 100000000n +
|
||||||
|
(obj[vote.delegateAddress] || 0n),
|
||||||
|
}),
|
||||||
|
{}
|
||||||
|
) || {}),
|
||||||
|
};
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
get processedUnlocking() {
|
||||||
|
return this.tempTransactions
|
||||||
|
.filter((item) => item.senderPublicKey === this.pubKey)
|
||||||
|
.reduce((acc, item) => {
|
||||||
|
const { unlockObjects } = item.asset;
|
||||||
|
return {
|
||||||
|
...acc,
|
||||||
|
...(unlockObjects?.reduce(
|
||||||
|
(obj, vote) => ({
|
||||||
|
...obj,
|
||||||
|
[vote.delegateAddress]:
|
||||||
|
BigInt(vote.amount) / 100000000n +
|
||||||
|
(obj[vote.delegateAddress] || 0n),
|
||||||
|
}),
|
||||||
|
{}
|
||||||
|
) || {}),
|
||||||
|
};
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
get vpnServers() {
|
||||||
|
return this._vpnServers;
|
||||||
|
}
|
||||||
|
|
||||||
|
get canVPN() {
|
||||||
|
return this._canVPN;
|
||||||
|
}
|
||||||
|
|
||||||
|
get delegates() {
|
||||||
|
const getStatus = (delegate) => {
|
||||||
|
const { address } = delegate;
|
||||||
|
|
||||||
|
let amount = this.processedVotes[address];
|
||||||
|
|
||||||
|
if (amount) return "Pending";
|
||||||
|
|
||||||
|
amount = this.accountSentVotes[address];
|
||||||
|
|
||||||
|
if (amount) return "Unvote";
|
||||||
|
|
||||||
|
return "Vote";
|
||||||
|
};
|
||||||
|
|
||||||
|
return this._delegates.data.map((delegate) => ({
|
||||||
|
...delegate,
|
||||||
|
status: getStatus(delegate),
|
||||||
|
token: {
|
||||||
|
...delegate.token,
|
||||||
|
balance: Number(BigInt(delegate.token.balance) / 100000000n).toString(),
|
||||||
|
},
|
||||||
|
dpos: {
|
||||||
|
...delegate.dpos,
|
||||||
|
delegate: {
|
||||||
|
...delegate.dpos.delegate,
|
||||||
|
totalVotesReceived: Number(
|
||||||
|
BigInt(delegate.dpos.delegate.totalVotesReceived) / 100000000n
|
||||||
|
).toString(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
get delegatesMeta() {
|
||||||
|
return this._delegates.meta;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,127 +1,200 @@
|
|||||||
export const IdentityModuleSchema = {
|
export const IdentityModuleSchema = {
|
||||||
$id: 'idntty/identity/module',
|
$id: "idntty/identity/module",
|
||||||
title: 'Identity module account schema',
|
title: "Identity module account schema",
|
||||||
type: 'object',
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
features: {
|
features: {
|
||||||
fieldNumber: 1,
|
fieldNumber: 1,
|
||||||
type: 'array',
|
type: "array",
|
||||||
maxItems: 256,
|
maxItems: 256,
|
||||||
items: {
|
items: {
|
||||||
type: 'object',
|
type: "object",
|
||||||
required: ['label', 'value'],
|
required: ["label", "value"],
|
||||||
properties: {
|
properties: {
|
||||||
label: { fieldNumber: 1, dataType: 'string'},
|
label: { fieldNumber: 1, dataType: "string" },
|
||||||
value: { fieldNumber: 2, dataType: 'bytes'},
|
value: { fieldNumber: 2, dataType: "bytes" },
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
verifications: {
|
verifications: {
|
||||||
fieldNumber: 2,
|
fieldNumber: 2,
|
||||||
type: 'array',
|
type: "array",
|
||||||
items: {
|
items: {
|
||||||
type: 'object',
|
type: "object",
|
||||||
required: ['label', 'account', 'tx'],
|
required: ["label", "account", "tx"],
|
||||||
properties: {
|
properties: {
|
||||||
label: { fieldNumber: 1, dataType: 'string'},
|
label: { fieldNumber: 1, dataType: "string" },
|
||||||
account: { fieldNumber: 2, dataType: 'bytes'},
|
account: { fieldNumber: 2, dataType: "bytes" },
|
||||||
tx: { fieldNumber: 3, dataType: 'bytes'},
|
tx: { fieldNumber: 3, dataType: "bytes" },
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
default: {features: [], verifications: []}
|
default: { features: [], verifications: [] },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const setFeatureAssetSchema = {
|
export const setFeatureAssetSchema = {
|
||||||
$id: 'idntty/identity/setfeature',
|
$id: "idntty/identity/setfeature",
|
||||||
title: 'Asset schema to set or update account features for identity module',
|
title: "Asset schema to set or update account features for identity module",
|
||||||
type: 'object',
|
type: "object",
|
||||||
required: ['features'],
|
required: ["features"],
|
||||||
properties: {
|
properties: {
|
||||||
features: {
|
features: {
|
||||||
fieldNumber: 1,
|
fieldNumber: 1,
|
||||||
type: 'array',
|
type: "array",
|
||||||
minItems: 1,
|
minItems: 1,
|
||||||
maxItems: 16,
|
maxItems: 16,
|
||||||
items: {
|
items: {
|
||||||
type: 'object',
|
type: "object",
|
||||||
required: ['label','value'],
|
required: ["label", "value"],
|
||||||
properties: {
|
properties: {
|
||||||
label: { fieldNumber: 1, dataType: 'string', maxLength: 16},
|
label: { fieldNumber: 1, dataType: "string", maxLength: 16 },
|
||||||
value: { fieldNumber: 2, dataType: 'bytes', maxLength: 32},
|
value: { fieldNumber: 2, dataType: "bytes", maxLength: 32 },
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const removeFeatureAssetSchema = {
|
export const removeFeatureAssetSchema = {
|
||||||
$id: 'idntty/identity/removefeature',
|
$id: "idntty/identity/removefeature",
|
||||||
title: 'Asset schema to remove account features for identity module',
|
title: "Asset schema to remove account features for identity module",
|
||||||
type: 'object',
|
type: "object",
|
||||||
required: ['features'],
|
required: ["features"],
|
||||||
properties: {
|
properties: {
|
||||||
features: {
|
features: {
|
||||||
fieldNumber: 1,
|
fieldNumber: 1,
|
||||||
type: 'array',
|
type: "array",
|
||||||
minItems: 1,
|
minItems: 1,
|
||||||
maxItems: 16,
|
maxItems: 16,
|
||||||
items: {
|
items: {
|
||||||
type: 'object',
|
type: "object",
|
||||||
required: ['label'],
|
required: ["label"],
|
||||||
properties: {
|
properties: {
|
||||||
label: { fieldNumber: 1, dataType: 'string', maxLength: 16},
|
label: { fieldNumber: 1, dataType: "string", maxLength: 16 },
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const validateFeatureAssetSchema = {
|
export const validateFeatureAssetSchema = {
|
||||||
$id: 'idntty/identity/validatefeature',
|
$id: "idntty/identity/validatefeature",
|
||||||
title: 'Asset schema to validate account features for identity module',
|
title: "Asset schema to validate account features for identity module",
|
||||||
type: 'object',
|
type: "object",
|
||||||
required: ['recipientAddress','features'],
|
required: ["recipientAddress", "features"],
|
||||||
properties: {
|
properties: {
|
||||||
recipientAddress: {fieldNumber: 1, dataType: 'bytes', minLength: 20, maxLength: 20},
|
recipientAddress: {
|
||||||
|
fieldNumber: 1,
|
||||||
|
dataType: "bytes",
|
||||||
|
minLength: 20,
|
||||||
|
maxLength: 20,
|
||||||
|
},
|
||||||
features: {
|
features: {
|
||||||
fieldNumber: 2,
|
fieldNumber: 2,
|
||||||
type: 'array',
|
type: "array",
|
||||||
minItems: 1,
|
minItems: 1,
|
||||||
maxItems: 16,
|
maxItems: 16,
|
||||||
items: {
|
items: {
|
||||||
type: 'object',
|
type: "object",
|
||||||
required: ['label', 'value'],
|
required: ["label", "value"],
|
||||||
properties: {
|
properties: {
|
||||||
label: { fieldNumber: 1, dataType: 'string', maxLength: 16},
|
label: { fieldNumber: 1, dataType: "string", maxLength: 16 },
|
||||||
value: { fieldNumber: 2, dataType: 'bytes', maxLength: 32},
|
value: { fieldNumber: 2, dataType: "bytes", maxLength: 32 },
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const invalidateFeatureAssetSchema = {
|
export const invalidateFeatureAssetSchema = {
|
||||||
$id: 'idntty/identity/invalidatefeature',
|
$id: "idntty/identity/invalidatefeature",
|
||||||
title: 'Asset schema to invalidate account features for identity module',
|
title: "Asset schema to invalidate account features for identity module",
|
||||||
type: 'object',
|
type: "object",
|
||||||
required: ['recipientAddress','features'],
|
required: ["recipientAddress", "features"],
|
||||||
properties: {
|
properties: {
|
||||||
recipientAddress: {fieldNumber: 1, dataType: 'bytes', minLength: 20, maxLength: 20},
|
recipientAddress: {
|
||||||
|
fieldNumber: 1,
|
||||||
|
dataType: "bytes",
|
||||||
|
minLength: 20,
|
||||||
|
maxLength: 20,
|
||||||
|
},
|
||||||
features: {
|
features: {
|
||||||
fieldNumber: 2,
|
fieldNumber: 2,
|
||||||
type: 'array',
|
type: "array",
|
||||||
minItems: 1,
|
minItems: 1,
|
||||||
maxItems: 16,
|
maxItems: 16,
|
||||||
items: {
|
items: {
|
||||||
type: 'object',
|
type: "object",
|
||||||
required: ['label'],
|
required: ["label"],
|
||||||
properties: {
|
properties: {
|
||||||
label: { fieldNumber: 1, dataType: 'string', maxLength: 16},
|
label: { fieldNumber: 1, dataType: "string", maxLength: 16 },
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const voteDelegateAssetSchema = {
|
||||||
|
$id: "lisk/dpos/vote",
|
||||||
|
type: "object",
|
||||||
|
required: ["votes"],
|
||||||
|
properties: {
|
||||||
|
votes: {
|
||||||
|
type: "array",
|
||||||
|
minItems: 1,
|
||||||
|
maxItems: 20,
|
||||||
|
items: {
|
||||||
|
type: "object",
|
||||||
|
required: ["delegateAddress", "amount"],
|
||||||
|
properties: {
|
||||||
|
delegateAddress: {
|
||||||
|
dataType: "bytes",
|
||||||
|
fieldNumber: 1,
|
||||||
|
minLength: 20,
|
||||||
|
maxLength: 20,
|
||||||
|
},
|
||||||
|
amount: {
|
||||||
|
dataType: "sint64",
|
||||||
|
fieldNumber: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fieldNumber: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const unlockDelegateAssetSchema = {
|
||||||
|
$id: "lisk/dpos/unlock",
|
||||||
|
type: "object",
|
||||||
|
required: ["unlockObjects"],
|
||||||
|
properties: {
|
||||||
|
unlockObjects: {
|
||||||
|
type: "array",
|
||||||
|
minItems: 1,
|
||||||
|
maxItems: 20,
|
||||||
|
items: {
|
||||||
|
type: "object",
|
||||||
|
required: ["delegateAddress", "amount", "unvoteHeight"],
|
||||||
|
properties: {
|
||||||
|
delegateAddress: {
|
||||||
|
dataType: "bytes",
|
||||||
|
fieldNumber: 1,
|
||||||
|
minLength: 20,
|
||||||
|
maxLength: 20,
|
||||||
|
},
|
||||||
|
amount: {
|
||||||
|
dataType: "uint64",
|
||||||
|
fieldNumber: 2,
|
||||||
|
},
|
||||||
|
unvoteHeight: {
|
||||||
|
dataType: "uint32",
|
||||||
|
fieldNumber: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fieldNumber: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
import resolveConfig from 'tailwindcss/resolveConfig';
|
import resolveConfig from "tailwindcss/resolveConfig";
|
||||||
import {cryptography, transactions} from '@liskhq/lisk-client';
|
import { cryptography, transactions } from "@liskhq/lisk-client";
|
||||||
import {
|
import {
|
||||||
removeFeatureAssetSchema,
|
removeFeatureAssetSchema,
|
||||||
setFeatureAssetSchema,
|
setFeatureAssetSchema,
|
||||||
|
unlockDelegateAssetSchema,
|
||||||
validateFeatureAssetSchema,
|
validateFeatureAssetSchema,
|
||||||
} from './Schemas';
|
voteDelegateAssetSchema,
|
||||||
import {statusMap} from "../shared/statusMap";
|
} from "./Schemas";
|
||||||
|
import { statusMap } from "../shared/statusMap";
|
||||||
|
|
||||||
export const tailwindConfig = () => {
|
export const tailwindConfig = () => {
|
||||||
// Tailwind config
|
// Tailwind config
|
||||||
return resolveConfig('./src/tailwind.config.js')
|
return resolveConfig("./src/tailwind.config.js");
|
||||||
}
|
};
|
||||||
|
|
||||||
export const hexToRGB = (h) => {
|
export const hexToRGB = (h) => {
|
||||||
let r = 0;
|
let r = 0;
|
||||||
@@ -28,179 +30,378 @@ export const hexToRGB = (h) => {
|
|||||||
return `${+r},${+g},${+b}`;
|
return `${+r},${+g},${+b}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const formatValue = (value) => Intl.NumberFormat('en-US', {
|
export const formatValue = (value) =>
|
||||||
style: 'currency',
|
Intl.NumberFormat("en-US", {
|
||||||
currency: 'USD',
|
style: "currency",
|
||||||
maximumSignificantDigits: 3,
|
currency: "USD",
|
||||||
notation: 'compact',
|
maximumSignificantDigits: 3,
|
||||||
}).format(value);
|
notation: "compact",
|
||||||
|
}).format(value);
|
||||||
|
|
||||||
export const formatThousands = (value) => Intl.NumberFormat('en-US', {
|
export const formatThousands = (value) =>
|
||||||
maximumSignificantDigits: 3,
|
Intl.NumberFormat("en-US", {
|
||||||
notation: 'compact',
|
maximumSignificantDigits: 3,
|
||||||
}).format(value);
|
notation: "compact",
|
||||||
|
}).format(value);
|
||||||
|
|
||||||
export const encryptAccountData = (data = [], passPhrase = '', pubKey = '') => {
|
export const formatAddressBig = (address) =>
|
||||||
return data.filter(item=>item.status!==statusMap.blockchained).map((item) => {
|
`${address.slice(0, 4)} ${address.slice(4, 8)} ****** ${address.slice(
|
||||||
let value = cryptography.encryptMessageWithPassphrase(item.seed + ":" + item.value, passPhrase, pubKey);
|
address.length - 8,
|
||||||
|
address.length - 4
|
||||||
|
)} ${address.slice(address.length - 4)}`;
|
||||||
|
|
||||||
|
export const encryptAccountData = (data = [], passPhrase = "", pubKey = "") => {
|
||||||
|
return data
|
||||||
|
.filter((item) => item.status !== statusMap.blockchained)
|
||||||
|
.map((item) => {
|
||||||
|
let value = cryptography.encryptMessageWithPassphrase(
|
||||||
|
item.seed + ":" + item.value,
|
||||||
|
passPhrase,
|
||||||
|
pubKey
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
label: item.key,
|
||||||
|
value: value.encryptedMessage,
|
||||||
|
value_nonce: value.nonce,
|
||||||
|
seed: item.seed,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const encryptSharedData = (data = [], passPhrase = "", pubKey = "") => {
|
||||||
|
return data.map((item) => {
|
||||||
|
let value = cryptography.encryptMessageWithPassphrase(
|
||||||
|
item.seed + ":" + item.value,
|
||||||
|
passPhrase,
|
||||||
|
Buffer.from(pubKey, "hex")
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
label: item.key,
|
label: item.key,
|
||||||
value: value.encryptedMessage,
|
value: value.encryptedMessage,
|
||||||
value_nonce: value.nonce,
|
value_nonce: value.nonce,
|
||||||
seed: item.seed,
|
};
|
||||||
}
|
});
|
||||||
})
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export const encryptSharedData = (data = [], passPhrase = '', pubKey = '') => {
|
|
||||||
return data.map((item)=> {
|
|
||||||
let value = cryptography.encryptMessageWithPassphrase(item.seed + ":" + item.value, passPhrase, Buffer.from(pubKey, 'hex'));
|
|
||||||
return {
|
|
||||||
label: item.key,
|
|
||||||
value: value.encryptedMessage,
|
|
||||||
value_nonce: value.nonce,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export const hashAccountData = (data = [], oldData = [], hashMap = {}) => {
|
export const hashAccountData = (data = [], oldData = [], hashMap = {}) => {
|
||||||
const accountMap = data.reduce((acc, item) => ({
|
const accountMap = data.reduce(
|
||||||
...acc,
|
(acc, item) => ({
|
||||||
[item.label]: item.value
|
...acc,
|
||||||
}), {})
|
[item.label]: item.value,
|
||||||
|
}),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
const oldAccountMap = oldData.reduce((acc, item) => ({
|
const oldAccountMap = oldData.reduce(
|
||||||
...acc,
|
(acc, item) => ({
|
||||||
[item.label]: item.value
|
...acc,
|
||||||
}), {})
|
[item.label]: item.value,
|
||||||
|
}),
|
||||||
|
{}
|
||||||
|
);
|
||||||
const removed = oldData.reduce((acc, item) => {
|
const removed = oldData.reduce((acc, item) => {
|
||||||
if(!accountMap[item.label] && !data.find(elem=>elem.label===item.label))
|
if (
|
||||||
return [...acc, {label: item.label}];
|
!accountMap[item.label] &&
|
||||||
return acc
|
!data.find((elem) => elem.label === item.label)
|
||||||
}, [])
|
)
|
||||||
|
return [...acc, { label: item.label }];
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
|
||||||
const changed = data.reduce((acc, item) => {
|
const changed = data.reduce((acc, item) => {
|
||||||
if(!oldAccountMap[item.label])
|
if (!oldAccountMap[item.label]) return [...acc, item];
|
||||||
return [ ...acc, item ]
|
|
||||||
const oldValue = hashMap[item.key];
|
const oldValue = hashMap[item.key];
|
||||||
const newValue = hashValue(item.value, item.seed).toString('hex')
|
const newValue = hashValue(item.value, item.seed).toString("hex");
|
||||||
if(oldValue !== newValue && item.status==='new')
|
if (oldValue !== newValue && item.status === "new") return [...acc, item];
|
||||||
return [ ...acc, item ]
|
|
||||||
return acc;
|
return acc;
|
||||||
}, [])
|
}, []);
|
||||||
return [
|
return [
|
||||||
removed,
|
removed,
|
||||||
changed.map((item) => {
|
changed.map((item) => {
|
||||||
const value = hashValue(item.value, item.seed);
|
const value = hashValue(item.value, item.seed);
|
||||||
return {
|
return {
|
||||||
label: item.key,
|
label: item.key,
|
||||||
value
|
value,
|
||||||
}
|
};
|
||||||
})
|
}),
|
||||||
]
|
];
|
||||||
}
|
};
|
||||||
|
|
||||||
export const jsonReplacer = (key, value) => {
|
export const jsonReplacer = (key, value) => {
|
||||||
if (key === 'big') {
|
if (key === "big") {
|
||||||
return value.toString();
|
return value.toString();
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const hashValue = (value = '', seed = '') => cryptography.hash(Buffer.concat([Buffer.from(seed, 'utf8'), cryptography.hash(value, 'utf8')]));
|
export const hashValue = (value = "", seed = "") =>
|
||||||
|
cryptography.hash(
|
||||||
|
Buffer.concat([Buffer.from(seed, "utf8"), cryptography.hash(value, "utf8")])
|
||||||
|
);
|
||||||
|
|
||||||
export const generateTransaction = (nonce = BigInt(0), senderPublicKey = '', networkIdentifier = '', passPhrase = '', fee = BigInt(500000),) => {
|
export const generateTransaction = (
|
||||||
|
nonce = BigInt(0),
|
||||||
|
senderPublicKey = "",
|
||||||
|
networkIdentifier = "",
|
||||||
|
passPhrase = "",
|
||||||
|
fee = BigInt(500000)
|
||||||
|
) => {
|
||||||
return {
|
return {
|
||||||
update: (features) => generateSetTransaction(features, nonce, senderPublicKey, networkIdentifier, passPhrase, fee),
|
update: (features) =>
|
||||||
remove: (features) => generateRemoveTransaction(features, nonce, senderPublicKey, networkIdentifier, passPhrase, fee),
|
generateSetTransaction(
|
||||||
validate: (features, recipientAddress) => generateValidateTransaction(features, nonce, senderPublicKey, networkIdentifier, passPhrase, fee, recipientAddress),
|
features,
|
||||||
}
|
nonce,
|
||||||
}
|
senderPublicKey,
|
||||||
|
networkIdentifier,
|
||||||
|
passPhrase,
|
||||||
|
fee
|
||||||
|
),
|
||||||
|
remove: (features) =>
|
||||||
|
generateRemoveTransaction(
|
||||||
|
features,
|
||||||
|
nonce,
|
||||||
|
senderPublicKey,
|
||||||
|
networkIdentifier,
|
||||||
|
passPhrase,
|
||||||
|
fee
|
||||||
|
),
|
||||||
|
validate: (features, recipientAddress) =>
|
||||||
|
generateValidateTransaction(
|
||||||
|
features,
|
||||||
|
nonce,
|
||||||
|
senderPublicKey,
|
||||||
|
networkIdentifier,
|
||||||
|
passPhrase,
|
||||||
|
fee,
|
||||||
|
recipientAddress
|
||||||
|
),
|
||||||
|
vote: (delegateAddress, amount) =>
|
||||||
|
generateVoteTransaction(
|
||||||
|
nonce,
|
||||||
|
senderPublicKey,
|
||||||
|
networkIdentifier,
|
||||||
|
passPhrase,
|
||||||
|
fee,
|
||||||
|
delegateAddress,
|
||||||
|
amount
|
||||||
|
),
|
||||||
|
unlock: (delegateAddress, amount, unvoteHeight) =>
|
||||||
|
generateUnlockTransaction(
|
||||||
|
nonce,
|
||||||
|
senderPublicKey,
|
||||||
|
networkIdentifier,
|
||||||
|
passPhrase,
|
||||||
|
fee,
|
||||||
|
delegateAddress,
|
||||||
|
amount,
|
||||||
|
unvoteHeight
|
||||||
|
),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const generateSetTransaction = (features, nonce = BigInt(0), senderPublicKey = '', networkIdentifier = '', passPhrase = '', fee = BigInt(500000)) => {
|
export const generateSetTransaction = (
|
||||||
|
features,
|
||||||
|
nonce = BigInt(0),
|
||||||
|
senderPublicKey = "",
|
||||||
|
networkIdentifier = "",
|
||||||
|
passPhrase = "",
|
||||||
|
fee = BigInt(500000)
|
||||||
|
) => {
|
||||||
const tx = {
|
const tx = {
|
||||||
"moduleID": 1001,
|
moduleID: 1001,
|
||||||
"assetID": 1,
|
assetID: 1,
|
||||||
nonce,
|
nonce,
|
||||||
senderPublicKey,
|
senderPublicKey,
|
||||||
fee,
|
fee,
|
||||||
"asset": {
|
asset: {
|
||||||
features
|
features,
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
if(features.length === 0)
|
if (features.length === 0) return;
|
||||||
return;
|
|
||||||
|
|
||||||
const signedTx = transactions.signTransaction(setFeatureAssetSchema,
|
const signedTx = transactions.signTransaction(
|
||||||
tx, Buffer.from(networkIdentifier, "hex"),
|
setFeatureAssetSchema,
|
||||||
passPhrase)
|
tx,
|
||||||
|
Buffer.from(networkIdentifier, "hex"),
|
||||||
|
passPhrase
|
||||||
|
);
|
||||||
|
|
||||||
signedTx.senderPublicKey = signedTx.senderPublicKey.toString("hex");
|
signedTx.senderPublicKey = signedTx.senderPublicKey.toString("hex");
|
||||||
signedTx.signatures[0] = signedTx.signatures[0].toString("hex");
|
signedTx.signatures[0] = signedTx.signatures[0].toString("hex");
|
||||||
signedTx.asset.features = signedTx.asset.features.map(feature => ({
|
signedTx.asset.features = signedTx.asset.features.map((feature) => ({
|
||||||
...feature,
|
...feature,
|
||||||
value: feature.value.toString("hex")
|
value: feature.value.toString("hex"),
|
||||||
}))
|
}));
|
||||||
|
|
||||||
delete signedTx.id;
|
delete signedTx.id;
|
||||||
|
|
||||||
return signedTx;
|
return signedTx;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const generateRemoveTransaction = (features, nonce = BigInt(0), senderPublicKey = '', networkIdentifier = '', passPhrase = '', fee = BigInt(500000)) => {
|
export const generateRemoveTransaction = (
|
||||||
|
features,
|
||||||
|
nonce = BigInt(0),
|
||||||
|
senderPublicKey = "",
|
||||||
|
networkIdentifier = "",
|
||||||
|
passPhrase = "",
|
||||||
|
fee = BigInt(500000)
|
||||||
|
) => {
|
||||||
const tx = {
|
const tx = {
|
||||||
"moduleID": 1001,
|
moduleID: 1001,
|
||||||
"assetID": 2,
|
assetID: 2,
|
||||||
nonce,
|
nonce,
|
||||||
senderPublicKey,
|
senderPublicKey,
|
||||||
fee,
|
fee,
|
||||||
"asset": {
|
asset: {
|
||||||
features
|
features,
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
const signedTx = transactions.signTransaction(removeFeatureAssetSchema,
|
const signedTx = transactions.signTransaction(
|
||||||
tx, Buffer.from(networkIdentifier, "hex"),
|
removeFeatureAssetSchema,
|
||||||
passPhrase)
|
tx,
|
||||||
|
Buffer.from(networkIdentifier, "hex"),
|
||||||
|
passPhrase
|
||||||
|
);
|
||||||
|
|
||||||
signedTx.senderPublicKey = signedTx.senderPublicKey.toString(
|
signedTx.senderPublicKey = signedTx.senderPublicKey.toString("hex");
|
||||||
"hex");
|
|
||||||
signedTx.signatures[0] = signedTx.signatures[0].toString("hex");
|
signedTx.signatures[0] = signedTx.signatures[0].toString("hex");
|
||||||
|
|
||||||
delete signedTx.id;
|
delete signedTx.id;
|
||||||
|
|
||||||
return signedTx;
|
return signedTx;
|
||||||
}
|
};
|
||||||
|
|
||||||
const generateValidateTransaction = (features, nonce = BigInt(0), senderPublicKey = '', networkIdentifier = '', passPhrase = '', fee = BigInt(500000), recipientAddress='') => {
|
const generateValidateTransaction = (
|
||||||
|
features,
|
||||||
|
nonce = BigInt(0),
|
||||||
|
senderPublicKey = "",
|
||||||
|
networkIdentifier = "",
|
||||||
|
passPhrase = "",
|
||||||
|
fee = BigInt(500000),
|
||||||
|
recipientAddress = ""
|
||||||
|
) => {
|
||||||
const tx = {
|
const tx = {
|
||||||
"moduleID": 1001,
|
moduleID: 1001,
|
||||||
"assetID": 11,
|
assetID: 11,
|
||||||
nonce,
|
nonce,
|
||||||
senderPublicKey: Buffer.from(senderPublicKey, "hex"),
|
senderPublicKey: Buffer.from(senderPublicKey, "hex"),
|
||||||
fee,
|
fee,
|
||||||
"asset": {
|
asset: {
|
||||||
features,
|
features,
|
||||||
recipientAddress: Buffer.from(recipientAddress, "hex")
|
recipientAddress: Buffer.from(recipientAddress, "hex"),
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
if(features.length === 0)
|
if (features.length === 0) return;
|
||||||
return;
|
|
||||||
|
|
||||||
const signedTx = transactions.signTransaction(validateFeatureAssetSchema,
|
const signedTx = transactions.signTransaction(
|
||||||
tx, Buffer.from(networkIdentifier, "hex"),
|
validateFeatureAssetSchema,
|
||||||
passPhrase)
|
tx,
|
||||||
|
Buffer.from(networkIdentifier, "hex"),
|
||||||
|
passPhrase
|
||||||
|
);
|
||||||
|
|
||||||
signedTx.senderPublicKey = signedTx.senderPublicKey.toString("hex");
|
signedTx.senderPublicKey = signedTx.senderPublicKey.toString("hex");
|
||||||
signedTx.asset.recipientAddress = signedTx.asset.recipientAddress.toString("hex");
|
signedTx.asset.recipientAddress =
|
||||||
|
signedTx.asset.recipientAddress.toString("hex");
|
||||||
signedTx.signatures[0] = signedTx.signatures[0].toString("hex");
|
signedTx.signatures[0] = signedTx.signatures[0].toString("hex");
|
||||||
signedTx.asset.features = signedTx.asset.features.map(feature => ({
|
signedTx.asset.features = signedTx.asset.features.map((feature) => ({
|
||||||
...feature,
|
...feature,
|
||||||
value: feature.value.toString("hex")
|
value: feature.value.toString("hex"),
|
||||||
}))
|
}));
|
||||||
|
|
||||||
delete signedTx.id;
|
delete signedTx.id;
|
||||||
|
|
||||||
return signedTx;
|
return signedTx;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
const generateVoteTransaction = (
|
||||||
|
nonce = BigInt(0),
|
||||||
|
senderPublicKey = "",
|
||||||
|
networkIdentifier = "",
|
||||||
|
passPhrase = "",
|
||||||
|
fee = BigInt(500000),
|
||||||
|
delegateAddress = "",
|
||||||
|
amount = 0n
|
||||||
|
) => {
|
||||||
|
const tx = {
|
||||||
|
moduleID: 5,
|
||||||
|
assetID: 1,
|
||||||
|
nonce,
|
||||||
|
senderPublicKey: Buffer.from(senderPublicKey, "hex"),
|
||||||
|
fee,
|
||||||
|
asset: {
|
||||||
|
votes: [
|
||||||
|
{
|
||||||
|
delegateAddress: Buffer.from(delegateAddress, "hex"),
|
||||||
|
amount: amount * 100000000n,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const signedTx = transactions.signTransaction(
|
||||||
|
voteDelegateAssetSchema,
|
||||||
|
tx,
|
||||||
|
Buffer.from(networkIdentifier, "hex"),
|
||||||
|
passPhrase
|
||||||
|
);
|
||||||
|
|
||||||
|
signedTx.senderPublicKey = signedTx.senderPublicKey.toString("hex");
|
||||||
|
signedTx.signatures[0] = signedTx.signatures[0].toString("hex");
|
||||||
|
signedTx.asset.votes = signedTx.asset.votes.map((vote) => ({
|
||||||
|
...vote,
|
||||||
|
delegateAddress: vote.delegateAddress.toString("hex"),
|
||||||
|
}));
|
||||||
|
|
||||||
|
delete signedTx.id;
|
||||||
|
|
||||||
|
return signedTx;
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateUnlockTransaction = (
|
||||||
|
nonce = BigInt(0),
|
||||||
|
senderPublicKey = "",
|
||||||
|
networkIdentifier = "",
|
||||||
|
passPhrase = "",
|
||||||
|
fee = BigInt(500000),
|
||||||
|
delegateAddress = "",
|
||||||
|
amount = 0n,
|
||||||
|
unvoteHeight = 0
|
||||||
|
) => {
|
||||||
|
const tx = {
|
||||||
|
moduleID: 5,
|
||||||
|
assetID: 2,
|
||||||
|
nonce,
|
||||||
|
senderPublicKey: Buffer.from(senderPublicKey, "hex"),
|
||||||
|
fee,
|
||||||
|
asset: {
|
||||||
|
unlockObjects: [
|
||||||
|
{
|
||||||
|
delegateAddress: Buffer.from(delegateAddress, "hex"),
|
||||||
|
amount: amount * 100000000n,
|
||||||
|
unvoteHeight,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const signedTx = transactions.signTransaction(
|
||||||
|
unlockDelegateAssetSchema,
|
||||||
|
tx,
|
||||||
|
Buffer.from(networkIdentifier, "hex"),
|
||||||
|
passPhrase
|
||||||
|
);
|
||||||
|
|
||||||
|
signedTx.senderPublicKey = signedTx.senderPublicKey.toString("hex");
|
||||||
|
signedTx.signatures[0] = signedTx.signatures[0].toString("hex");
|
||||||
|
signedTx.asset.unlockObjects = signedTx.asset.unlockObjects.map((vote) => ({
|
||||||
|
...vote,
|
||||||
|
delegateAddress: vote.delegateAddress.toString("hex"),
|
||||||
|
}));
|
||||||
|
|
||||||
|
delete signedTx.id;
|
||||||
|
|
||||||
|
return signedTx;
|
||||||
|
};
|
||||||
|
|||||||
31
src/utils/test.js
Normal file
31
src/utils/test.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import {cryptography, passphrase} from "@liskhq/lisk-client";
|
||||||
|
import sodium from 'sodium-universal';
|
||||||
|
|
||||||
|
let passphrase1 = passphrase.Mnemonic.generateMnemonic();
|
||||||
|
const keys = cryptography.getPrivateAndPublicKeyFromPassphrase(passphrase1);
|
||||||
|
console.log('IDNTTY Public & Private keys(hex):');
|
||||||
|
console.log('publicKey:', keys.publicKey.length, keys.publicKey.toString('hex'));
|
||||||
|
console.log('privateKey:', keys.privateKey.length, keys.privateKey.toString('hex'));
|
||||||
|
|
||||||
|
console.log('');
|
||||||
|
console.log('SODIUM Public & Private keys(hex):');
|
||||||
|
|
||||||
|
let pk = Buffer.alloc(sodium.crypto_sign_PUBLICKEYBYTES);
|
||||||
|
let sk = Buffer.alloc(sodium.crypto_sign_SECRETKEYBYTES);
|
||||||
|
|
||||||
|
let x25519_sk = Buffer.alloc(sodium.crypto_box_SECRETKEYBYTES);
|
||||||
|
let x25519_pk = Buffer.alloc(sodium.crypto_box_PUBLICKEYBYTES);
|
||||||
|
|
||||||
|
sodium.crypto_sign_seed_keypair(pk, sk, cryptography.hash(Buffer.from(passphrase1, 'UTF-8')));
|
||||||
|
|
||||||
|
sodium.crypto_sign_ed25519_sk_to_curve25519(x25519_sk, sk);
|
||||||
|
sodium.crypto_sign_ed25519_pk_to_curve25519(x25519_pk, pk)
|
||||||
|
|
||||||
|
console.log('Public & Private keys(hex):');
|
||||||
|
console.log('publicKey:', pk.length, pk.toString('hex'));
|
||||||
|
console.log('privateKey:', sk.length, sk.toString('hex'));
|
||||||
|
console.log('');
|
||||||
|
|
||||||
|
console.log('x25519_sk privateKey:', x25519_sk.length, x25519_sk.toString('Base64'));
|
||||||
|
console.log('x25519_pk publicKey:', x25519_pk.length, x25519_pk.toString('Base64'));
|
||||||
|
|
||||||
@@ -1,101 +1,107 @@
|
|||||||
const path = require("path");
|
const path = require("path");
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||||
const webpack = require('webpack');
|
const webpack = require("webpack");
|
||||||
|
|
||||||
const plugins = [
|
const plugins = [
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
favicon: './public/favicon.ico',
|
favicon: "./public/favicon.ico",
|
||||||
template: './public/index.html',
|
template: "./public/index.html",
|
||||||
}),
|
}),
|
||||||
new webpack.ProvidePlugin({
|
new webpack.ProvidePlugin({
|
||||||
Buffer: ['buffer', 'Buffer'],
|
Buffer: ["buffer", "Buffer"],
|
||||||
}),
|
}),
|
||||||
new webpack.ProvidePlugin({
|
new webpack.ProvidePlugin({
|
||||||
process: 'process/browser',
|
process: "process/browser",
|
||||||
|
}),
|
||||||
|
require("tailwindcss"),
|
||||||
|
new webpack.ContextReplacementPlugin(/sodium/, (data) => {
|
||||||
|
delete data.dependencies[0].critical;
|
||||||
|
return data;
|
||||||
}),
|
}),
|
||||||
require('tailwindcss')
|
|
||||||
];
|
];
|
||||||
|
|
||||||
module.exports = (env, argv) => ( {
|
module.exports = (env, argv) => ({
|
||||||
entry: './src/main.jsx',
|
entry: "./src/main.jsx",
|
||||||
mode: argv.mode || 'development',
|
mode: argv.mode || "development",
|
||||||
devtool: argv.mode === 'production' ? false : 'eval-source-map',
|
devtool: argv.mode === "production" ? false : "eval-source-map",
|
||||||
plugins,
|
plugins,
|
||||||
output: {
|
output: {
|
||||||
clean: true,
|
clean: true,
|
||||||
path: path.resolve(__dirname, 'build'),
|
path: path.resolve(__dirname, "build"),
|
||||||
assetModuleFilename: 'assets/[fullhash:12][ext]',
|
assetModuleFilename: "assets/[fullhash:12][ext]",
|
||||||
filename: 'main.[fullhash:8].js',
|
filename: "main.[fullhash:8].js",
|
||||||
},
|
},
|
||||||
devServer: {
|
devServer: {
|
||||||
open: true,
|
open: true,
|
||||||
static: {
|
static: {
|
||||||
directory: path.join(__dirname, 'public'),
|
directory: path.join(__dirname, "public"),
|
||||||
},
|
},
|
||||||
compress: true,
|
compress: true,
|
||||||
port: 'auto',
|
port: "auto",
|
||||||
hot: true,
|
hot: true,
|
||||||
client: {
|
client: {
|
||||||
progress: true,
|
progress: true,
|
||||||
},
|
},
|
||||||
proxy: {
|
proxy: {
|
||||||
'/api/**': {
|
"/api/**": {
|
||||||
target: 'http://3.125.47.101',
|
target: "https://tn-alpha.idntty.org:8080/",
|
||||||
secure: false,
|
secure: false,
|
||||||
changeOrigin: true
|
changeOrigin: true,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
ignoreWarnings: [() => false],
|
||||||
|
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{ test: /\.(html)$/, use: ['html-loader'] },
|
{ test: /\.(html)$/, use: ["html-loader"] },
|
||||||
{
|
{
|
||||||
test: /\.m?jsx?$/,
|
test: /\.m?jsx?$/,
|
||||||
exclude: /(node_modules|bower_components)/,
|
exclude: /(node_modules|bower_components)/,
|
||||||
use: {
|
use: {
|
||||||
loader: 'babel-loader',
|
loader: "babel-loader",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.scss$/,
|
test: /\.scss$/,
|
||||||
use: [
|
use: [
|
||||||
{
|
{
|
||||||
loader: 'style-loader'
|
loader: "style-loader",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loader: 'css-loader'
|
loader: "css-loader",
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
loader: 'postcss-loader'
|
loader: "postcss-loader",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loader: 'sass-loader'
|
loader: "sass-loader",
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(png|svg|jpg|gif)$/,
|
test: /\.(png|svg|jpg|gif)$/,
|
||||||
loader: 'file-loader',
|
loader: "file-loader",
|
||||||
options: {
|
options: {
|
||||||
outputPath: 'assets',
|
outputPath: "assets",
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.js', '.jsx'],
|
extensions: [".js", ".jsx"],
|
||||||
fallback: {
|
fallback: {
|
||||||
"path": require.resolve("path-browserify"),
|
path: require.resolve("path-browserify"),
|
||||||
"os": require.resolve("os-browserify/browser"),
|
os: require.resolve("os-browserify/browser"),
|
||||||
"querystring": require.resolve("querystring-es3"),
|
querystring: require.resolve("querystring-es3"),
|
||||||
"crypto": require.resolve("crypto-browserify"),
|
crypto: require.resolve("crypto-browserify"),
|
||||||
"util": require.resolve("util/"),
|
util: require.resolve("util/"),
|
||||||
"stream": require.resolve("stream-browserify"),
|
stream: require.resolve("stream-browserify"),
|
||||||
"url": require.resolve("url/"),
|
url: require.resolve("url/"),
|
||||||
"buffer": require.resolve("buffer/"),
|
buffer: require.resolve("buffer/"),
|
||||||
"fs": false
|
fs: false,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
Reference in New Issue
Block a user