mirror of
https://github.com/Qortal/q-trade.git
synced 2025-06-18 12:11:21 +00:00
fixes
This commit is contained in:
parent
bbfd29e8fb
commit
f32cd68554
59
package-lock.json
generated
59
package-lock.json
generated
@ -19,7 +19,7 @@
|
|||||||
"jotai": "^2.12.3",
|
"jotai": "^2.12.3",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"qapp-core": "^1.0.24",
|
"qapp-core": "^1.0.25",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-countdown-circle-timer": "^3.2.1",
|
"react-countdown-circle-timer": "^3.2.1",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
@ -3128,6 +3128,7 @@
|
|||||||
"version": "3.13.6",
|
"version": "3.13.6",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.13.6.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.13.6.tgz",
|
||||||
"integrity": "sha512-WT7nWs8ximoQ0CDx/ngoFP7HbQF9Q2wQe4nh2NB+u2486eX3nZRE40P9g6ccCVq7ZfTSH5gFOuCoVH5DLNS/aA==",
|
"integrity": "sha512-WT7nWs8ximoQ0CDx/ngoFP7HbQF9Q2wQe4nh2NB+u2486eX3nZRE40P9g6ccCVq7ZfTSH5gFOuCoVH5DLNS/aA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tanstack/virtual-core": "3.13.6"
|
"@tanstack/virtual-core": "3.13.6"
|
||||||
},
|
},
|
||||||
@ -3144,6 +3145,7 @@
|
|||||||
"version": "3.13.6",
|
"version": "3.13.6",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.13.6.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.13.6.tgz",
|
||||||
"integrity": "sha512-cnQUeWnhNP8tJ4WsGcYiX24Gjkc9ALstLbHcBj1t3E7EimN6n6kHH+DPV4PpDnuw00NApQp+ViojMj1GRdwYQg==",
|
"integrity": "sha512-cnQUeWnhNP8tJ4WsGcYiX24Gjkc9ALstLbHcBj1t3E7EimN6n6kHH+DPV4PpDnuw00NApQp+ViojMj1GRdwYQg==",
|
||||||
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
"url": "https://github.com/sponsors/tannerlinsley"
|
"url": "https://github.com/sponsors/tannerlinsley"
|
||||||
@ -3254,7 +3256,8 @@
|
|||||||
"node_modules/@types/seedrandom": {
|
"node_modules/@types/seedrandom": {
|
||||||
"version": "3.0.8",
|
"version": "3.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-3.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-3.0.8.tgz",
|
||||||
"integrity": "sha512-TY1eezMU2zH2ozQoAFAQFOPpvP15g+ZgSfTZt31AUUH/Rxtnz3H+A/Sv1Snw2/amp//omibc+AEkTaA8KUeOLQ=="
|
"integrity": "sha512-TY1eezMU2zH2ozQoAFAQFOPpvP15g+ZgSfTZt31AUUH/Rxtnz3H+A/Sv1Snw2/amp//omibc+AEkTaA8KUeOLQ==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/semver": {
|
"node_modules/@types/semver": {
|
||||||
"version": "7.5.8",
|
"version": "7.5.8",
|
||||||
@ -3661,6 +3664,7 @@
|
|||||||
"version": "2.2.5",
|
"version": "2.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.5.tgz",
|
||||||
"integrity": "sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ==",
|
"integrity": "sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
@ -3762,6 +3766,7 @@
|
|||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
|
||||||
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
|
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.6.0"
|
"node": ">= 0.6.0"
|
||||||
}
|
}
|
||||||
@ -3783,7 +3788,8 @@
|
|||||||
"type": "consulting",
|
"type": "consulting",
|
||||||
"url": "https://feross.org/support"
|
"url": "https://feross.org/support"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/binary-extensions": {
|
"node_modules/binary-extensions": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
@ -3800,6 +3806,7 @@
|
|||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/bloom-filters/-/bloom-filters-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/bloom-filters/-/bloom-filters-3.0.4.tgz",
|
||||||
"integrity": "sha512-BdnPWo2OpYhlvuP2fRzJBdioMCkm7Zp0HCf8NJgF5Mbyqy7VQ/CnTiVWMMyq4EZCBHwj0Kq6098gW2/3RsZsrA==",
|
"integrity": "sha512-BdnPWo2OpYhlvuP2fRzJBdioMCkm7Zp0HCf8NJgF5Mbyqy7VQ/CnTiVWMMyq4EZCBHwj0Kq6098gW2/3RsZsrA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/seedrandom": "^3.0.8",
|
"@types/seedrandom": "^3.0.8",
|
||||||
"base64-arraybuffer": "^1.0.2",
|
"base64-arraybuffer": "^1.0.2",
|
||||||
@ -3817,7 +3824,8 @@
|
|||||||
"node_modules/blueimp-canvas-to-blob": {
|
"node_modules/blueimp-canvas-to-blob": {
|
||||||
"version": "3.29.0",
|
"version": "3.29.0",
|
||||||
"resolved": "https://registry.npmjs.org/blueimp-canvas-to-blob/-/blueimp-canvas-to-blob-3.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/blueimp-canvas-to-blob/-/blueimp-canvas-to-blob-3.29.0.tgz",
|
||||||
"integrity": "sha512-0pcSSGxC0QxT+yVkivxIqW0Y4VlO2XSDPofBAqoJ1qJxgH9eiUDLv50Rixij2cDuEfx4M6DpD9UGZpRhT5Q8qg=="
|
"integrity": "sha512-0pcSSGxC0QxT+yVkivxIqW0Y4VlO2XSDPofBAqoJ1qJxgH9eiUDLv50Rixij2cDuEfx4M6DpD9UGZpRhT5Q8qg==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/brace-expansion": {
|
"node_modules/brace-expansion": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
@ -3889,6 +3897,7 @@
|
|||||||
"url": "https://feross.org/support"
|
"url": "https://feross.org/support"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"base64-js": "^1.3.1",
|
"base64-js": "^1.3.1",
|
||||||
"ieee754": "^1.2.1"
|
"ieee754": "^1.2.1"
|
||||||
@ -4066,6 +4075,7 @@
|
|||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/compressorjs/-/compressorjs-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/compressorjs/-/compressorjs-1.2.1.tgz",
|
||||||
"integrity": "sha512-+geIjeRnPhQ+LLvvA7wxBQE5ddeLU7pJ3FsKFWirDw6veY3s9iLxAQEw7lXGHnhCJvBujEQWuNnGzZcvCvdkLQ==",
|
"integrity": "sha512-+geIjeRnPhQ+LLvvA7wxBQE5ddeLU7pJ3FsKFWirDw6veY3s9iLxAQEw7lXGHnhCJvBujEQWuNnGzZcvCvdkLQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"blueimp-canvas-to-blob": "^3.29.0",
|
"blueimp-canvas-to-blob": "^3.29.0",
|
||||||
"is-blob": "^2.1.0"
|
"is-blob": "^2.1.0"
|
||||||
@ -4128,7 +4138,8 @@
|
|||||||
"node_modules/crypto-js": {
|
"node_modules/crypto-js": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
|
||||||
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
|
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/crypto-random-string": {
|
"node_modules/crypto-random-string": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
@ -4167,7 +4178,8 @@
|
|||||||
"node_modules/cuint": {
|
"node_modules/cuint": {
|
||||||
"version": "0.2.2",
|
"version": "0.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz",
|
||||||
"integrity": "sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw=="
|
"integrity": "sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/data-view-buffer": {
|
"node_modules/data-view-buffer": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
@ -4223,7 +4235,8 @@
|
|||||||
"node_modules/dayjs": {
|
"node_modules/dayjs": {
|
||||||
"version": "1.11.13",
|
"version": "1.11.13",
|
||||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
|
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
|
||||||
"integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg=="
|
"integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "4.3.7",
|
"version": "4.3.7",
|
||||||
@ -4342,6 +4355,7 @@
|
|||||||
"version": "3.2.5",
|
"version": "3.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.5.tgz",
|
||||||
"integrity": "sha512-mLPd29uoRe9HpvwP2TxClGQBzGXeEC/we/q+bFlmPPmj2p2Ugl3r6ATu/UU1v77DXNcehiBg9zsr1dREyA/dJQ==",
|
"integrity": "sha512-mLPd29uoRe9HpvwP2TxClGQBzGXeEC/we/q+bFlmPPmj2p2Ugl3r6ATu/UU1v77DXNcehiBg9zsr1dREyA/dJQ==",
|
||||||
|
"license": "(MPL-2.0 OR Apache-2.0)",
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@types/trusted-types": "^2.0.7"
|
"@types/trusted-types": "^2.0.7"
|
||||||
}
|
}
|
||||||
@ -4944,6 +4958,7 @@
|
|||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/file-selector/-/file-selector-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/file-selector/-/file-selector-2.1.2.tgz",
|
||||||
"integrity": "sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig==",
|
"integrity": "sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.7.0"
|
"tslib": "^2.7.0"
|
||||||
},
|
},
|
||||||
@ -4954,7 +4969,8 @@
|
|||||||
"node_modules/file-selector/node_modules/tslib": {
|
"node_modules/file-selector/node_modules/tslib": {
|
||||||
"version": "2.8.1",
|
"version": "2.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
|
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||||
|
"license": "0BSD"
|
||||||
},
|
},
|
||||||
"node_modules/filelist": {
|
"node_modules/filelist": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
@ -5292,6 +5308,7 @@
|
|||||||
"version": "2.1.16",
|
"version": "2.1.16",
|
||||||
"resolved": "https://registry.npmjs.org/goober/-/goober-2.1.16.tgz",
|
"resolved": "https://registry.npmjs.org/goober/-/goober-2.1.16.tgz",
|
||||||
"integrity": "sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==",
|
"integrity": "sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==",
|
||||||
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"csstype": "^3.0.10"
|
"csstype": "^3.0.10"
|
||||||
}
|
}
|
||||||
@ -5435,7 +5452,8 @@
|
|||||||
"type": "consulting",
|
"type": "consulting",
|
||||||
"url": "https://feross.org/support"
|
"url": "https://feross.org/support"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
},
|
},
|
||||||
"node_modules/ignore": {
|
"node_modules/ignore": {
|
||||||
"version": "5.3.1",
|
"version": "5.3.1",
|
||||||
@ -5553,6 +5571,7 @@
|
|||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-blob/-/is-blob-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-blob/-/is-blob-2.1.0.tgz",
|
||||||
"integrity": "sha512-SZ/fTft5eUhQM6oF/ZaASFDEdbFVe89Imltn9uZr03wdKMcWNVYSMjQPFtg05QuNkt5l5c135ElvXEQG0rk4tw==",
|
"integrity": "sha512-SZ/fTft5eUhQM6oF/ZaASFDEdbFVe89Imltn9uZr03wdKMcWNVYSMjQPFtg05QuNkt5l5c135ElvXEQG0rk4tw==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
},
|
},
|
||||||
@ -5594,6 +5613,7 @@
|
|||||||
"url": "https://feross.org/support"
|
"url": "https://feross.org/support"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
@ -6162,7 +6182,8 @@
|
|||||||
"node_modules/long": {
|
"node_modules/long": {
|
||||||
"version": "5.3.2",
|
"version": "5.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
|
||||||
"integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="
|
"integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
|
||||||
|
"license": "Apache-2.0"
|
||||||
},
|
},
|
||||||
"node_modules/loose-envify": {
|
"node_modules/loose-envify": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
@ -6581,9 +6602,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/qapp-core": {
|
"node_modules/qapp-core": {
|
||||||
"version": "1.0.24",
|
"version": "1.0.25",
|
||||||
"resolved": "https://registry.npmjs.org/qapp-core/-/qapp-core-1.0.24.tgz",
|
"resolved": "https://registry.npmjs.org/qapp-core/-/qapp-core-1.0.25.tgz",
|
||||||
"integrity": "sha512-KnrwiysaHlTR1rUnPGwN79gQgcjvtLr4xRH3EGGQcbXKCcbrklV7lv4KLUfFR4UwhskbgOXpJY5PECWdrlGXSw==",
|
"integrity": "sha512-JhdQliLPjapgzbCjkuSpR5hAk8ewT0FbQxIW+oxVWJyT1e0swAKXJqvX1PHQzTbiV5IQI12nbIxy6SjBam3K2A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tanstack/react-virtual": "^3.13.2",
|
"@tanstack/react-virtual": "^3.13.2",
|
||||||
@ -6675,6 +6696,7 @@
|
|||||||
"version": "14.3.8",
|
"version": "14.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.3.8.tgz",
|
||||||
"integrity": "sha512-sBgODnq+lcA4P296DY4wacOZz3JFpD99fp+hb//iBO2HHnyeZU3FwWyXJ6salNpqQdsZrgMrotuko/BdJMV8Ug==",
|
"integrity": "sha512-sBgODnq+lcA4P296DY4wacOZz3JFpD99fp+hb//iBO2HHnyeZU3FwWyXJ6salNpqQdsZrgMrotuko/BdJMV8Ug==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"attr-accept": "^2.2.4",
|
"attr-accept": "^2.2.4",
|
||||||
"file-selector": "^2.1.0",
|
"file-selector": "^2.1.0",
|
||||||
@ -6696,6 +6718,7 @@
|
|||||||
"version": "2.5.2",
|
"version": "2.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.5.2.tgz",
|
||||||
"integrity": "sha512-Tun3BbCxzmXXM7C+NI4qiv6lT0uwGh4oAfeJyNOjYUejTsm35mK9iCaYLGv8cBz9L5YxZLx/2ii7zsIwPtPUdw==",
|
"integrity": "sha512-Tun3BbCxzmXXM7C+NI4qiv6lT0uwGh4oAfeJyNOjYUejTsm35mK9iCaYLGv8cBz9L5YxZLx/2ii7zsIwPtPUdw==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"csstype": "^3.1.3",
|
"csstype": "^3.1.3",
|
||||||
"goober": "^2.1.16"
|
"goober": "^2.1.16"
|
||||||
@ -6712,6 +6735,7 @@
|
|||||||
"version": "9.16.0",
|
"version": "9.16.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.16.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.16.0.tgz",
|
||||||
"integrity": "sha512-w9nJSEp+DrW9KmQmeWHQyfaP6b03v+TdXynaoA964Wxt7mdR3An11z4NNCQgL4gKSK7y1ver2Fq+JKH6CWEzUA==",
|
"integrity": "sha512-w9nJSEp+DrW9KmQmeWHQyfaP6b03v+TdXynaoA964Wxt7mdR3An11z4NNCQgL4gKSK7y1ver2Fq+JKH6CWEzUA==",
|
||||||
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||||
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
@ -6836,7 +6860,8 @@
|
|||||||
"node_modules/reflect-metadata": {
|
"node_modules/reflect-metadata": {
|
||||||
"version": "0.1.14",
|
"version": "0.1.14",
|
||||||
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz",
|
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz",
|
||||||
"integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A=="
|
"integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==",
|
||||||
|
"license": "Apache-2.0"
|
||||||
},
|
},
|
||||||
"node_modules/regenerate": {
|
"node_modules/regenerate": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.2",
|
||||||
@ -7122,7 +7147,8 @@
|
|||||||
"node_modules/seedrandom": {
|
"node_modules/seedrandom": {
|
||||||
"version": "3.0.5",
|
"version": "3.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz",
|
||||||
"integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg=="
|
"integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/semver": {
|
"node_modules/semver": {
|
||||||
"version": "7.6.0",
|
"version": "7.6.0",
|
||||||
@ -7906,6 +7932,7 @@
|
|||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz",
|
||||||
"integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==",
|
"integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==",
|
||||||
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
}
|
}
|
||||||
@ -8434,6 +8461,7 @@
|
|||||||
"version": "0.2.2",
|
"version": "0.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz",
|
||||||
"integrity": "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==",
|
"integrity": "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cuint": "^0.2.2"
|
"cuint": "^0.2.2"
|
||||||
}
|
}
|
||||||
@ -8468,6 +8496,7 @@
|
|||||||
"version": "4.5.6",
|
"version": "4.5.6",
|
||||||
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.6.tgz",
|
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.6.tgz",
|
||||||
"integrity": "sha512-ibr/n1hBzLLj5Y+yUcU7dYw8p6WnIVzdJbnX+1YpaScvZVF2ziugqHs+LAmHw4lWO9c/zRj+K1ncgWDQuthEdQ==",
|
"integrity": "sha512-ibr/n1hBzLLj5Y+yUcU7dYw8p6WnIVzdJbnX+1YpaScvZVF2ziugqHs+LAmHw4lWO9c/zRj+K1ncgWDQuthEdQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"use-sync-external-store": "^1.2.2"
|
"use-sync-external-store": "^1.2.2"
|
||||||
},
|
},
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
"jotai": "^2.12.3",
|
"jotai": "^2.12.3",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"qapp-core": "^1.0.24",
|
"qapp-core": "^1.0.25",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-countdown-circle-timer": "^3.2.1",
|
"react-countdown-circle-timer": "^3.2.1",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
|
@ -61,6 +61,7 @@ import CloseIcon from "@mui/icons-material/Close";
|
|||||||
import ContentCopyIcon from "@mui/icons-material/ContentCopy";
|
import ContentCopyIcon from "@mui/icons-material/ContentCopy";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { RequestQueueWithPromise } from "qapp-core";
|
import { RequestQueueWithPromise } from "qapp-core";
|
||||||
|
import { useUpdateFee } from "../../hooks/useUpdateFee";
|
||||||
|
|
||||||
const copyToClipboard = (text: string) => {
|
const copyToClipboard = (text: string) => {
|
||||||
navigator.clipboard.writeText(text);
|
navigator.clipboard.writeText(text);
|
||||||
@ -91,6 +92,7 @@ export const autoSizeStrategy: SizeColumnsToContentStrategy = {
|
|||||||
export const TradeOffers: React.FC<any> = ({
|
export const TradeOffers: React.FC<any> = ({
|
||||||
foreignCoinBalance,
|
foreignCoinBalance,
|
||||||
fee,
|
fee,
|
||||||
|
setFee
|
||||||
}: any) => {
|
}: any) => {
|
||||||
const [offers, setOffers] = useState<any[]>([]);
|
const [offers, setOffers] = useState<any[]>([]);
|
||||||
const [signedUnlockingFees, setSignedUnlockingFees] = useState(null);
|
const [signedUnlockingFees, setSignedUnlockingFees] = useState(null);
|
||||||
@ -105,6 +107,7 @@ export const TradeOffers: React.FC<any> = ({
|
|||||||
} = useContext(gameContext);
|
} = useContext(gameContext);
|
||||||
const isRemoveOrdersWithoutUnlockingFees = useRef(false);
|
const isRemoveOrdersWithoutUnlockingFees = useRef(false);
|
||||||
const [isRemoveOrders, setIsRemoveOrders] = useState('remove');
|
const [isRemoveOrders, setIsRemoveOrders] = useState('remove');
|
||||||
|
const updateFee = useUpdateFee({setFee, selectedCoin})
|
||||||
const listOfOngoingTradesAts = useMemo(() => {
|
const listOfOngoingTradesAts = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
onGoingTrades
|
onGoingTrades
|
||||||
@ -128,6 +131,14 @@ export const TradeOffers: React.FC<any> = ({
|
|||||||
message: messageTradesUnknownFee,
|
message: messageTradesUnknownFee,
|
||||||
} = useModal();
|
} = useModal();
|
||||||
|
|
||||||
|
const {
|
||||||
|
isShow: isShowAskToUpdateFee,
|
||||||
|
onCancel: onCancelAskToUpdateFee,
|
||||||
|
onOk: onOkAskToUpdateFee,
|
||||||
|
show: showAskToUpdateFee,
|
||||||
|
message: messageAskToUpdateFee,
|
||||||
|
} = useModal();
|
||||||
|
|
||||||
const offersWithoutOngoing = useMemo(() => {
|
const offersWithoutOngoing = useMemo(() => {
|
||||||
return offers.filter(
|
return offers.filter(
|
||||||
(item) => !listOfOngoingTradesAts.includes(item.qortalAtAddress)
|
(item) => !listOfOngoingTradesAts.includes(item.qortalAtAddress)
|
||||||
@ -228,6 +239,20 @@ export const TradeOffers: React.FC<any> = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const rowTooltip = (params) => {
|
||||||
|
let selectable = true;
|
||||||
|
const hasSignedFee = signedUnlockingFees?.find(
|
||||||
|
(item) => item?.atAddress === params.data.qortalAtAddress
|
||||||
|
);
|
||||||
|
if (!hasSignedFee) selectable = true;
|
||||||
|
|
||||||
|
if (hasSignedFee && hasSignedFee?.fee > feeRef.current)
|
||||||
|
selectable = false;
|
||||||
|
if(!selectable)return 'Your unlocking fee is to low to buy this order, Increase your fee to purchase'
|
||||||
|
|
||||||
|
return ''
|
||||||
|
};
|
||||||
|
|
||||||
const columnDefs: ColDef[] = useMemo(() => {
|
const columnDefs: ColDef[] = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@ -239,7 +264,7 @@ export const TradeOffers: React.FC<any> = ({
|
|||||||
pinned: "left", // Optional, to pin this column on the left
|
pinned: "left", // Optional, to pin this column on the left
|
||||||
resizable: false,
|
resizable: false,
|
||||||
suppressRowClickSelection: true,
|
suppressRowClickSelection: true,
|
||||||
|
tooltipValueGetter: rowTooltip,
|
||||||
cellRenderer: (params) => (
|
cellRenderer: (params) => (
|
||||||
<SelectWithInfoCell
|
<SelectWithInfoCell
|
||||||
{...params}
|
{...params}
|
||||||
@ -265,6 +290,7 @@ export const TradeOffers: React.FC<any> = ({
|
|||||||
flex: 1, // Flex makes this column responsive
|
flex: 1, // Flex makes this column responsive
|
||||||
minWidth: 150, // Ensure it doesn't shrink too much
|
minWidth: 150, // Ensure it doesn't shrink too much
|
||||||
resizable: true,
|
resizable: true,
|
||||||
|
tooltipValueGetter: rowTooltip
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headerName: `${getCoinLabel()}/QORT`,
|
headerName: `${getCoinLabel()}/QORT`,
|
||||||
@ -275,6 +301,7 @@ export const TradeOffers: React.FC<any> = ({
|
|||||||
flex: 1, // Flex makes this column responsive
|
flex: 1, // Flex makes this column responsive
|
||||||
minWidth: 150, // Ensure it doesn't shrink too much
|
minWidth: 150, // Ensure it doesn't shrink too much
|
||||||
resizable: true,
|
resizable: true,
|
||||||
|
tooltipValueGetter: rowTooltip
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headerName: `Total ${getCoinLabel()} Value`,
|
headerName: `Total ${getCoinLabel()} Value`,
|
||||||
@ -282,12 +309,14 @@ export const TradeOffers: React.FC<any> = ({
|
|||||||
flex: 1, // Flex makes this column responsive
|
flex: 1, // Flex makes this column responsive
|
||||||
minWidth: 150, // Ensure it doesn't shrink too much
|
minWidth: 150, // Ensure it doesn't shrink too much
|
||||||
resizable: true,
|
resizable: true,
|
||||||
|
tooltipValueGetter: rowTooltip
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headerName: `Unlocking fee`,
|
headerName: `Unlocking fee`,
|
||||||
flex: 1, // Flex makes this column responsive
|
flex: 1, // Flex makes this column responsive
|
||||||
minWidth: 150, // Ensure it doesn't shrink too much
|
minWidth: 150, // Ensure it doesn't shrink too much
|
||||||
resizable: true,
|
resizable: true,
|
||||||
|
tooltipValueGetter: rowTooltip,
|
||||||
valueGetter: (params) => {
|
valueGetter: (params) => {
|
||||||
if (params?.data?.qortalAtAddress) {
|
if (params?.data?.qortalAtAddress) {
|
||||||
const hasSignedFee = signedUnlockingFees?.find(
|
const hasSignedFee = signedUnlockingFees?.find(
|
||||||
@ -304,6 +333,7 @@ export const TradeOffers: React.FC<any> = ({
|
|||||||
flex: 1, // Flex makes this column responsive
|
flex: 1, // Flex makes this column responsive
|
||||||
minWidth: 300, // Ensure it doesn't shrink too much
|
minWidth: 300, // Ensure it doesn't shrink too much
|
||||||
resizable: true,
|
resizable: true,
|
||||||
|
tooltipValueGetter: rowTooltip,
|
||||||
valueGetter: (params) => {
|
valueGetter: (params) => {
|
||||||
if (params?.data?.qortalCreator) {
|
if (params?.data?.qortalCreator) {
|
||||||
if (qortalNames[params?.data?.qortalCreator]) {
|
if (qortalNames[params?.data?.qortalCreator]) {
|
||||||
@ -660,6 +690,20 @@ export const TradeOffers: React.FC<any> = ({
|
|||||||
offersWithKnownFees = selectedOffers;
|
offersWithKnownFees = selectedOffers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const highestFee = offersWithKnownFees.length
|
||||||
|
? Math.max(
|
||||||
|
...offersWithKnownFees
|
||||||
|
.filter(o => typeof o.fee === 'number')
|
||||||
|
.map(o => o.fee as number)
|
||||||
|
)
|
||||||
|
: 0;
|
||||||
|
if(highestFee < fee){
|
||||||
|
|
||||||
|
await showAskToUpdateFee({
|
||||||
|
message: highestFee
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
setIsShowBuyInProgress({ status: "buying" });
|
setIsShowBuyInProgress({ status: "buying" });
|
||||||
|
|
||||||
@ -864,6 +908,7 @@ export const TradeOffers: React.FC<any> = ({
|
|||||||
onGridReady={onGridReady}
|
onGridReady={onGridReady}
|
||||||
// domLayout='autoHeight'
|
// domLayout='autoHeight'
|
||||||
getRowId={(params) => params.data.qortalAtAddress} // Ensure rows have unique IDs
|
getRowId={(params) => params.data.qortalAtAddress} // Ensure rows have unique IDs
|
||||||
|
enableBrowserTooltips={true}
|
||||||
gridOptions={{
|
gridOptions={{
|
||||||
isRowSelectable: (params) => {
|
isRowSelectable: (params) => {
|
||||||
let selectable = true;
|
let selectable = true;
|
||||||
@ -1001,7 +1046,7 @@ export const TradeOffers: React.FC<any> = ({
|
|||||||
</Button>
|
</Button>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button variant="contained" onClick={onOkInfo} autoFocus>
|
<Button variant="outlined" onClick={onOkInfo} autoFocus>
|
||||||
Close
|
Close
|
||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
@ -1012,9 +1057,19 @@ export const TradeOffers: React.FC<any> = ({
|
|||||||
open={isShowTradesUnknownFee}
|
open={isShowTradesUnknownFee}
|
||||||
aria-labelledby="alert-dialog-title"
|
aria-labelledby="alert-dialog-title"
|
||||||
aria-describedby="alert-dialog-description"
|
aria-describedby="alert-dialog-description"
|
||||||
|
PaperProps={{
|
||||||
|
style: {
|
||||||
|
backgroundColor: "rgb(39, 40, 44)",
|
||||||
|
background: "rgb(39, 40, 44)",
|
||||||
|
},
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<DialogTitle id="alert-dialog-title">Warning</DialogTitle>
|
<DialogTitle sx={{
|
||||||
<DialogContent>
|
|
||||||
|
background: "rgb(39, 40, 44)"
|
||||||
|
|
||||||
|
}} id="alert-dialog-title">Warning</DialogTitle>
|
||||||
|
<DialogContent sx={{ borderColor: "#333" }}>
|
||||||
<DialogContentText
|
<DialogContentText
|
||||||
id="alert-dialog-description"
|
id="alert-dialog-description"
|
||||||
sx={{ color: "white" }}
|
sx={{ color: "white" }}
|
||||||
@ -1076,16 +1131,18 @@ export const TradeOffers: React.FC<any> = ({
|
|||||||
|
|
||||||
|
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions sx={{
|
||||||
|
background: "rgb(39, 40, 44)",
|
||||||
|
}}>
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="outlined"
|
||||||
onClick={onCancelTradesUnknownFee}
|
onClick={onCancelTradesUnknownFee}
|
||||||
autoFocus
|
autoFocus
|
||||||
>
|
>
|
||||||
Close
|
Close
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="outlined"
|
||||||
onClick={onOkTradesUnknownFee}
|
onClick={onOkTradesUnknownFee}
|
||||||
autoFocus
|
autoFocus
|
||||||
>
|
>
|
||||||
@ -1094,6 +1151,61 @@ export const TradeOffers: React.FC<any> = ({
|
|||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{isShowAskToUpdateFee && (
|
||||||
|
<Dialog
|
||||||
|
open={isShowAskToUpdateFee}
|
||||||
|
aria-labelledby="alert-dialog-title"
|
||||||
|
aria-describedby="alert-dialog-description"
|
||||||
|
PaperProps={{
|
||||||
|
style: {
|
||||||
|
backgroundColor: "rgb(39, 40, 44)",
|
||||||
|
background: "rgb(39, 40, 44)",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DialogTitle sx={{
|
||||||
|
background: "rgb(39, 40, 44)",
|
||||||
|
}} id="alert-dialog-title">Suggestion</DialogTitle>
|
||||||
|
<DialogContent sx={{ borderColor: "#333" }}>
|
||||||
|
<DialogContentText
|
||||||
|
id="alert-dialog-description"
|
||||||
|
sx={{ color: "white" }}
|
||||||
|
>
|
||||||
|
Your current unlocking fee is higher than necessary. You can lower it to match the highest required fee and reduce costs.
|
||||||
|
</DialogContentText>
|
||||||
|
<Spacer height="20px" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions sx={{
|
||||||
|
background: "rgb(39, 40, 44)",
|
||||||
|
}}>
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
onClick={onOkAskToUpdateFee}
|
||||||
|
|
||||||
|
>
|
||||||
|
Continue without updating
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
onClick={async (e)=> {
|
||||||
|
try {
|
||||||
|
await updateFee(messageAskToUpdateFee.message)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
onOkAskToUpdateFee(e)
|
||||||
|
}}
|
||||||
|
|
||||||
|
>
|
||||||
|
Lower fee
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
)}
|
||||||
{isShowBuyInProgress && (
|
{isShowBuyInProgress && (
|
||||||
<Dialog
|
<Dialog
|
||||||
open={isShowBuyInProgress}
|
open={isShowBuyInProgress}
|
||||||
|
@ -30,7 +30,11 @@ import { usePublish, Service, QortalGetMetadata } from "qapp-core";
|
|||||||
import { SetLeftFeature } from "ag-grid-community";
|
import { SetLeftFeature } from "ag-grid-community";
|
||||||
import { formatTimestampForum } from "../../utils/formatTime";
|
import { formatTimestampForum } from "../../utils/formatTime";
|
||||||
import { useAtom } from "jotai/react";
|
import { useAtom } from "jotai/react";
|
||||||
import { isEnabledCustomLockingFeeAtom, selectedFeePublisherAtom } from "../../global/state";
|
import {
|
||||||
|
isEnabledCustomLockingFeeAtom,
|
||||||
|
selectedFeePublisherAtom,
|
||||||
|
} from "../../global/state";
|
||||||
|
import { useRecommendedFees } from "../../hooks/useRecommendedFees";
|
||||||
|
|
||||||
type FeeEstimate = {
|
type FeeEstimate = {
|
||||||
height: number;
|
height: number;
|
||||||
@ -39,15 +43,15 @@ type FeeEstimate = {
|
|||||||
medium_fee_per_kb: number;
|
medium_fee_per_kb: number;
|
||||||
high_fee_per_kb: number;
|
high_fee_per_kb: number;
|
||||||
};
|
};
|
||||||
function isValidFeeEstimate(obj: any): obj is FeeEstimate {
|
export function isValidFeeEstimate(obj: any): obj is FeeEstimate {
|
||||||
return (
|
return (
|
||||||
typeof obj === 'object' &&
|
typeof obj === "object" &&
|
||||||
obj !== null &&
|
obj !== null &&
|
||||||
typeof obj.height === 'number' &&
|
typeof obj.height === "number" &&
|
||||||
typeof obj.time === 'number' &&
|
typeof obj.time === "number" &&
|
||||||
typeof obj.low_fee_per_kb === 'number' &&
|
typeof obj.low_fee_per_kb === "number" &&
|
||||||
typeof obj.medium_fee_per_kb === 'number' &&
|
typeof obj.medium_fee_per_kb === "number" &&
|
||||||
typeof obj.high_fee_per_kb === 'number'
|
typeof obj.high_fee_per_kb === "number"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,9 +60,9 @@ function calculateFeeFromRate(feePerKb, sizeInBytes) {
|
|||||||
return fee?.toFixed(0);
|
return fee?.toFixed(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculateRateFromFee(totalFee, sizeInBytes) {
|
export function calculateRateFromFee(totalFee, sizeInBytes) {
|
||||||
const fee = (totalFee / sizeInBytes) * 1000;
|
const fee = (totalFee / sizeInBytes) * 1000;
|
||||||
return fee.toFixed(0)
|
return fee.toFixed(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FeeManager = ({ selectedCoin, setFee, fee }) => {
|
export const FeeManager = ({ selectedCoin, setFee, fee }) => {
|
||||||
@ -68,12 +72,19 @@ export const FeeManager = ({ selectedCoin, setFee, fee }) => {
|
|||||||
service: "JSON",
|
service: "JSON",
|
||||||
});
|
});
|
||||||
const { resource } = usePublish(3, "JSON", feeLocation);
|
const { resource } = usePublish(3, "JSON", feeLocation);
|
||||||
const [selectedFeePublisher, setSelectedFeePublisher] = useAtom(selectedFeePublisherAtom)
|
const [selectedFeePublisher, setSelectedFeePublisher] = useAtom(
|
||||||
const [isEnabledCustomLockingFee, setIsEnabledCustomLockingFee] = useAtom(isEnabledCustomLockingFeeAtom)
|
selectedFeePublisherAtom
|
||||||
|
);
|
||||||
|
const [isEnabledCustomLockingFee, setIsEnabledCustomLockingFee] = useAtom(
|
||||||
|
isEnabledCustomLockingFeeAtom
|
||||||
|
);
|
||||||
|
|
||||||
const [editFee, setEditFee] = useState("");
|
const [editFee, setEditFee] = useState("");
|
||||||
const [openModal, setOpenModal] = useState(false);
|
const [openModal, setOpenModal] = useState(false);
|
||||||
const [recommendedFee, setRecommendedFee] = useState("m");
|
const [recommendedFee, setRecommendedFee] = useState("medium_fee_per_kb");
|
||||||
|
|
||||||
|
const {hideRecommendations, recommendedFeeDisplay} = useRecommendedFees({selectedCoin, recommendedFee})
|
||||||
|
|
||||||
const [openAlert, setOpenAlert] = useState(false);
|
const [openAlert, setOpenAlert] = useState(false);
|
||||||
const [info, setInfo] = useState<any>(null);
|
const [info, setInfo] = useState<any>(null);
|
||||||
const { getCoinLabel } = useContext(gameContext);
|
const { getCoinLabel } = useContext(gameContext);
|
||||||
@ -89,16 +100,18 @@ export const FeeManager = ({ selectedCoin, setFee, fee }) => {
|
|||||||
setInfo(null);
|
setInfo(null);
|
||||||
};
|
};
|
||||||
const coin = useMemo(() => {
|
const coin = useMemo(() => {
|
||||||
const coinLabel = getCoinLabel(selectedCoin)
|
const coinLabel = getCoinLabel(selectedCoin);
|
||||||
if(typeof coinLabel !== 'string') return null
|
if (typeof coinLabel !== "string") return null;
|
||||||
return coinLabel?.toLowerCase();
|
return coinLabel?.toLowerCase();
|
||||||
}, [selectedCoin, getCoinLabel]);
|
}, [selectedCoin, getCoinLabel]);
|
||||||
|
|
||||||
|
const feeTimestamp = useMemo(() => {
|
||||||
const feeTimestamp = useMemo(()=> {
|
if (
|
||||||
if(!resource?.qortalMetadata?.identifier?.includes(`${coin.toUpperCase()}`)) return
|
!resource?.qortalMetadata?.identifier?.includes(`${coin.toUpperCase()}`)
|
||||||
return resource?.data?.time || null
|
)
|
||||||
}, [resource, coin])
|
return;
|
||||||
|
return resource?.data?.time || null;
|
||||||
|
}, [resource, coin]);
|
||||||
const establishUpdateFeeForm = useCallback(async (coin) => {
|
const establishUpdateFeeForm = useCallback(async (coin) => {
|
||||||
setFee("");
|
setFee("");
|
||||||
// if the coin or type is not set, then abort
|
// if the coin or type is not set, then abort
|
||||||
@ -117,10 +130,9 @@ export const FeeManager = ({ selectedCoin, setFee, fee }) => {
|
|||||||
},
|
},
|
||||||
1800000
|
1800000
|
||||||
);
|
);
|
||||||
if ((response !== null && response !== undefined) && !isNaN(+response)) {
|
if (response !== null && response !== undefined && !isNaN(+response)) {
|
||||||
setFee(response);
|
setFee(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setFee("");
|
setFee("");
|
||||||
console.error(error);
|
console.error(error);
|
||||||
@ -131,42 +143,29 @@ export const FeeManager = ({ selectedCoin, setFee, fee }) => {
|
|||||||
establishUpdateFeeForm(coin);
|
establishUpdateFeeForm(coin);
|
||||||
}, [coin, establishUpdateFeeForm]);
|
}, [coin, establishUpdateFeeForm]);
|
||||||
|
|
||||||
const recommendedFeeData = useMemo(() => {
|
|
||||||
if(!resource?.qortalMetadata?.identifier?.includes(`${coin.toUpperCase()}`)) return
|
|
||||||
if (!resource?.data) return null;
|
|
||||||
const isValid = isValidFeeEstimate(resource.data)
|
|
||||||
if(!isValid) return null
|
|
||||||
return resource.data;
|
|
||||||
}, [resource, coin]);
|
|
||||||
|
|
||||||
const recommendedFeeDisplay = useMemo(() => {
|
|
||||||
if (!recommendedFeeData) return null;
|
|
||||||
|
|
||||||
if(!recommendedFeeData) return null
|
|
||||||
return recommendedFeeData[recommendedFee] || null;
|
|
||||||
}, [recommendedFeeData, recommendedFee]);
|
|
||||||
|
|
||||||
const hideRecommendations = useMemo(()=> {
|
|
||||||
if(recommendedFeeData) return false
|
|
||||||
return true
|
|
||||||
}, [recommendedFeeData])
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(()=> {
|
|
||||||
if(hideRecommendations){
|
|
||||||
setRecommendedFee('custom')
|
useEffect(() => {
|
||||||
|
if (hideRecommendations) {
|
||||||
|
setRecommendedFee("custom");
|
||||||
}
|
}
|
||||||
}, [hideRecommendations])
|
}, [hideRecommendations]);
|
||||||
|
|
||||||
const updateFee = async () => {
|
const updateFee = async () => {
|
||||||
const typeRequest = "feerequired";
|
const typeRequest = "feerequired";
|
||||||
const typeRequestLocking = "feekb";
|
const typeRequestLocking = "feekb";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let feeToSave = editFee
|
|
||||||
if(recommendedFee !== 'custom'){
|
let feeToSave = editFee;
|
||||||
feeToSave = calculateFeeFromRate(recommendedFeeDisplay, 300)
|
if (recommendedFee !== "custom") {
|
||||||
}
|
feeToSave = calculateFeeFromRate(recommendedFeeDisplay, 300);
|
||||||
|
}
|
||||||
|
if(+fee === +feeToSave){
|
||||||
|
return
|
||||||
|
}
|
||||||
const response = await qortalRequestWithTimeout(
|
const response = await qortalRequestWithTimeout(
|
||||||
{
|
{
|
||||||
action: "UPDATE_FOREIGN_FEE",
|
action: "UPDATE_FOREIGN_FEE",
|
||||||
@ -177,8 +176,8 @@ export const FeeManager = ({ selectedCoin, setFee, fee }) => {
|
|||||||
1800000
|
1800000
|
||||||
);
|
);
|
||||||
|
|
||||||
if(!isEnabledCustomLockingFee){
|
if (!isEnabledCustomLockingFee) {
|
||||||
await qortalRequestWithTimeout(
|
await qortalRequestWithTimeout(
|
||||||
{
|
{
|
||||||
action: "UPDATE_FOREIGN_FEE",
|
action: "UPDATE_FOREIGN_FEE",
|
||||||
coin: coin,
|
coin: coin,
|
||||||
@ -187,7 +186,6 @@ export const FeeManager = ({ selectedCoin, setFee, fee }) => {
|
|||||||
},
|
},
|
||||||
1800000
|
1800000
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response && !isNaN(+response)) {
|
if (response && !isNaN(+response)) {
|
||||||
@ -212,34 +210,11 @@ export const FeeManager = ({ selectedCoin, setFee, fee }) => {
|
|||||||
event: React.MouseEvent<HTMLElement>,
|
event: React.MouseEvent<HTMLElement>,
|
||||||
newAlignment: string
|
newAlignment: string
|
||||||
) => {
|
) => {
|
||||||
if(newAlignment){
|
if (newAlignment) {
|
||||||
setRecommendedFee(newAlignment);
|
setRecommendedFee(newAlignment);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const getLatestFees = useCallback(async () => {
|
|
||||||
try {
|
|
||||||
const coinLabel = getCoinLabel(selectedCoin)
|
|
||||||
if(typeof coinLabel !== 'string') return
|
|
||||||
const coin = coinLabel?.toUpperCase();
|
|
||||||
const identifier = `coinInfo-${coin}`
|
|
||||||
const res = await fetch(
|
|
||||||
`/arbitrary/resources/searchsimple?service=JSON&identifier=${identifier}&name=${selectedFeePublisher}&prefix=true&limit=1&reverse=true`
|
|
||||||
);
|
|
||||||
const data = await res.json();
|
|
||||||
if (data && data?.length > 0) {
|
|
||||||
setFeeLocation(data[0]);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
}
|
|
||||||
}, [selectedFeePublisher, selectedCoin]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
getLatestFees();
|
|
||||||
}, [getLatestFees]);
|
|
||||||
|
|
||||||
|
|
||||||
if (fee === null || fee === undefined) return;
|
if (fee === null || fee === undefined) return;
|
||||||
@ -281,12 +256,12 @@ export const FeeManager = ({ selectedCoin, setFee, fee }) => {
|
|||||||
open={openModal}
|
open={openModal}
|
||||||
backdrop
|
backdrop
|
||||||
styles={{
|
styles={{
|
||||||
width: '450px',
|
width: "450px",
|
||||||
maxWidth: '95vw',
|
maxWidth: "95vw",
|
||||||
padding: '15px'
|
padding: "15px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CoinActionContainer >
|
<CoinActionContainer>
|
||||||
<CoinActionRow>
|
<CoinActionRow>
|
||||||
<HeaderRow>
|
<HeaderRow>
|
||||||
<Typography
|
<Typography
|
||||||
@ -301,59 +276,83 @@ export const FeeManager = ({ selectedCoin, setFee, fee }) => {
|
|||||||
</CoinActionRow>
|
</CoinActionRow>
|
||||||
<CoinActionRow>
|
<CoinActionRow>
|
||||||
<HeaderRow>
|
<HeaderRow>
|
||||||
<Box sx={{
|
<Box
|
||||||
width: '100%'
|
sx={{
|
||||||
}}>
|
width: "100%",
|
||||||
<Box sx={{
|
}}
|
||||||
width: '100%',
|
>
|
||||||
display: 'flex',
|
<Box
|
||||||
flexDirection: 'column',
|
sx={{
|
||||||
alignItems: 'center'
|
width: "100%",
|
||||||
}}>
|
display: "flex",
|
||||||
<CustomLabel sx={{
|
flexDirection: "column",
|
||||||
fontSize: '16px'
|
alignItems: "center",
|
||||||
}} htmlFor="standard-adornment-name">
|
}}
|
||||||
Recommended fee selection (in sats)
|
|
||||||
</CustomLabel>
|
|
||||||
|
|
||||||
<Spacer height="10px" />
|
|
||||||
<ToggleButtonGroup
|
|
||||||
color="primary"
|
|
||||||
value={recommendedFee}
|
|
||||||
exclusive
|
|
||||||
onChange={handleChange}
|
|
||||||
aria-label="Platform"
|
|
||||||
>
|
>
|
||||||
{!hideRecommendations && (
|
<CustomLabel
|
||||||
|
sx={{
|
||||||
|
fontSize: "16px",
|
||||||
|
}}
|
||||||
|
htmlFor="standard-adornment-name"
|
||||||
|
>
|
||||||
|
Recommended fee selection (in sats)
|
||||||
|
</CustomLabel>
|
||||||
|
|
||||||
|
<Spacer height="10px" />
|
||||||
|
<ToggleButtonGroup
|
||||||
|
color="primary"
|
||||||
|
value={recommendedFee}
|
||||||
|
exclusive
|
||||||
|
onChange={handleChange}
|
||||||
|
aria-label="Platform"
|
||||||
|
>
|
||||||
|
{!hideRecommendations && (
|
||||||
<>
|
<>
|
||||||
<ToggleButton value="low_fee_per_kb">Low</ToggleButton>
|
<ToggleButton value="low_fee_per_kb">
|
||||||
<ToggleButton value="medium_fee_per_kb">Medium</ToggleButton>
|
Low
|
||||||
<ToggleButton value="high_fee_per_kb">High</ToggleButton>
|
</ToggleButton>
|
||||||
|
<ToggleButton value="medium_fee_per_kb">
|
||||||
|
Medium
|
||||||
|
</ToggleButton>
|
||||||
|
<ToggleButton value="high_fee_per_kb">
|
||||||
|
High
|
||||||
|
</ToggleButton>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<ToggleButton value="custom">Custom</ToggleButton>
|
<ToggleButton value="custom">Custom</ToggleButton>
|
||||||
</ToggleButtonGroup>
|
</ToggleButtonGroup>
|
||||||
</Box>
|
</Box>
|
||||||
{recommendedFeeDisplay && (
|
{recommendedFeeDisplay && (
|
||||||
<>
|
<>
|
||||||
<Spacer height="15px" />
|
<Spacer height="15px" />
|
||||||
<Box sx={{
|
<Box
|
||||||
width: '100%',
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center'
|
|
||||||
}}>
|
|
||||||
<Typography
|
|
||||||
sx={{
|
sx={{
|
||||||
color: "white",
|
width: "100%",
|
||||||
fontSize: "18px",
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span style={{
|
<Typography
|
||||||
fontWeight: 'bold'
|
sx={{
|
||||||
}}> New fee:</span>{" "}
|
color: "white",
|
||||||
{calculateFeeFromRate(recommendedFeeDisplay, 300)} sats
|
fontSize: "18px",
|
||||||
</Typography>
|
}}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
fontWeight: "bold",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{" "}
|
||||||
|
New fee:
|
||||||
|
</span>{" "}
|
||||||
|
{calculateFeeFromRate(
|
||||||
|
recommendedFeeDisplay,
|
||||||
|
300
|
||||||
|
)}{" "}
|
||||||
|
sats
|
||||||
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<Spacer height="10px" />
|
<Spacer height="10px" />
|
||||||
<Box
|
<Box
|
||||||
@ -376,11 +375,10 @@ export const FeeManager = ({ selectedCoin, setFee, fee }) => {
|
|||||||
>
|
>
|
||||||
This recommended fee is derived from{" "}
|
This recommended fee is derived from{" "}
|
||||||
{recommendedFeeDisplay} per kb, for a transaction that
|
{recommendedFeeDisplay} per kb, for a transaction that
|
||||||
is approximately 300 kB in size.
|
is approximately 300 bytes in size.
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<Spacer height="10px"/>
|
<Spacer height="10px" />
|
||||||
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
@ -408,7 +406,7 @@ export const FeeManager = ({ selectedCoin, setFee, fee }) => {
|
|||||||
|
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
onClick={updateFee}
|
onClick={updateFee}
|
||||||
disabled={(recommendedFee === 'custom' && !editFee)}
|
disabled={recommendedFee === "custom" && !editFee}
|
||||||
sx={{
|
sx={{
|
||||||
minHeight: "42px",
|
minHeight: "42px",
|
||||||
border: "1px solid gray",
|
border: "1px solid gray",
|
||||||
@ -431,10 +429,15 @@ export const FeeManager = ({ selectedCoin, setFee, fee }) => {
|
|||||||
<Typography>Update fee</Typography>
|
<Typography>Update fee</Typography>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
{!hideRecommendations && feeTimestamp && (
|
{!hideRecommendations && feeTimestamp && (
|
||||||
<CustomLabel sx={{
|
<CustomLabel
|
||||||
textAlign: 'center'
|
sx={{
|
||||||
}}>*Recommended fees last updated: {formatTimestampForum(feeTimestamp)}</CustomLabel>
|
textAlign: "center",
|
||||||
)}
|
}}
|
||||||
|
>
|
||||||
|
*Recommended fees last updated:{" "}
|
||||||
|
{formatTimestampForum(feeTimestamp)}
|
||||||
|
</CustomLabel>
|
||||||
|
)}
|
||||||
</CoinActionContainer>
|
</CoinActionContainer>
|
||||||
</ReusableModal>
|
</ReusableModal>
|
||||||
)}
|
)}
|
||||||
|
@ -39,20 +39,34 @@ import { SetLeftFeature } from "ag-grid-community";
|
|||||||
import { formatTimestampForum } from "../../utils/formatTime";
|
import { formatTimestampForum } from "../../utils/formatTime";
|
||||||
import { SelectRow } from "../header/Header";
|
import { SelectRow } from "../header/Header";
|
||||||
import { useAtom } from "jotai/react";
|
import { useAtom } from "jotai/react";
|
||||||
import { isEnabledCustomLockingFeeAtom, selectedFeePublisherAtom } from "../../global/state";
|
import {
|
||||||
|
isEnabledCustomLockingFeeAtom,
|
||||||
|
selectedFeePublisherAtom,
|
||||||
|
} from "../../global/state";
|
||||||
|
import { useRecommendedFees } from "../../hooks/useRecommendedFees";
|
||||||
|
|
||||||
export const Settings = () => {
|
export const Settings = () => {
|
||||||
const saveDataLocal = useGlobal().persistentOperations.saveData
|
const saveDataLocal = useGlobal().persistentOperations.saveData;
|
||||||
const getDataLocal = useGlobal().persistentOperations.getData
|
const getDataLocal = useGlobal().persistentOperations.getData;
|
||||||
const [openModal, setOpenModal] = useState(false);
|
const [openModal, setOpenModal] = useState(false);
|
||||||
const [lockingFee, setLockingFee] = useState("");
|
const [lockingFee, setLockingFee] = useState("");
|
||||||
|
const [recommendedFee, setRecommendedFee] = useState("medium_fee_per_kb");
|
||||||
|
const [selectedCoin, setSelectedCoin] = useState("LITECOIN");
|
||||||
|
|
||||||
|
const { hideRecommendations, recommendedFeeDisplay, coin } = useRecommendedFees({
|
||||||
|
selectedCoin,
|
||||||
|
recommendedFee
|
||||||
|
});
|
||||||
|
|
||||||
const [editLockingFee, setEditLockingFee] = useState("");
|
const [editLockingFee, setEditLockingFee] = useState("");
|
||||||
const [openAlert, setOpenAlert] = useState(false);
|
const [openAlert, setOpenAlert] = useState(false);
|
||||||
const [info, setInfo] = useState<any>(null);
|
const [info, setInfo] = useState<any>(null);
|
||||||
const [selectedCoin, setSelectedCoin] = useState("LTC");
|
const [selectedFeePublisher, setSelectedFeePublisher] = useAtom(
|
||||||
const [selectedFeePublisher, setSelectedFeePublisher] = useAtom(selectedFeePublisherAtom)
|
selectedFeePublisherAtom
|
||||||
const [isEnabledCustomLockingFee, setIsEnabledCustomLockingFee] = useAtom(isEnabledCustomLockingFeeAtom)
|
);
|
||||||
|
const [isEnabledCustomLockingFee, setIsEnabledCustomLockingFee] = useAtom(
|
||||||
|
isEnabledCustomLockingFeeAtom
|
||||||
|
);
|
||||||
const handleCloseAlert = (
|
const handleCloseAlert = (
|
||||||
event?: React.SyntheticEvent | Event,
|
event?: React.SyntheticEvent | Event,
|
||||||
reason?: SnackbarCloseReason
|
reason?: SnackbarCloseReason
|
||||||
@ -69,12 +83,14 @@ export const Settings = () => {
|
|||||||
const typeRequest = "feekb";
|
const typeRequest = "feekb";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const feeToSave = editLockingFee;
|
let feeToSave = editLockingFee;
|
||||||
|
if (recommendedFee !== "custom") {
|
||||||
|
feeToSave = recommendedFeeDisplay
|
||||||
|
}
|
||||||
const response = await qortalRequestWithTimeout(
|
const response = await qortalRequestWithTimeout(
|
||||||
{
|
{
|
||||||
action: "UPDATE_FOREIGN_FEE",
|
action: "UPDATE_FOREIGN_FEE",
|
||||||
coin: selectedCoin,
|
coin: coin,
|
||||||
type: typeRequest,
|
type: typeRequest,
|
||||||
value: feeToSave,
|
value: feeToSave,
|
||||||
},
|
},
|
||||||
@ -102,7 +118,16 @@ export const Settings = () => {
|
|||||||
|
|
||||||
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
setIsEnabledCustomLockingFee(event.target.checked);
|
setIsEnabledCustomLockingFee(event.target.checked);
|
||||||
saveDataLocal('isEnabledCustomLockingFee', event.target.checked)
|
saveDataLocal("isEnabledCustomLockingFee", event.target.checked);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChangeRecommended = (
|
||||||
|
event: React.MouseEvent<HTMLElement>,
|
||||||
|
newAlignment: string
|
||||||
|
) => {
|
||||||
|
if (newAlignment) {
|
||||||
|
setRecommendedFee(newAlignment);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const establishUpdateFeeForm = useCallback(async (coin) => {
|
const establishUpdateFeeForm = useCallback(async (coin) => {
|
||||||
@ -136,27 +161,33 @@ export const Settings = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(!openModal) return
|
if (!openModal) return;
|
||||||
establishUpdateFeeForm(selectedCoin);
|
establishUpdateFeeForm(coin);
|
||||||
}, [selectedCoin, establishUpdateFeeForm, openModal]);
|
}, [coin, establishUpdateFeeForm, openModal]);
|
||||||
|
|
||||||
useEffect(()=> {
|
useEffect(() => {
|
||||||
const getSavedSelectedPublisher = async ()=> {
|
const getSavedSelectedPublisher = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await getDataLocal('selectedFeePublisher')
|
const res = await getDataLocal("selectedFeePublisher");
|
||||||
if(res){
|
if (res) {
|
||||||
setSelectedFeePublisher(res)
|
setSelectedFeePublisher(res);
|
||||||
}
|
}
|
||||||
const res2 = await getDataLocal('isEnabledCustomLockingFee')
|
const res2 = await getDataLocal("isEnabledCustomLockingFee");
|
||||||
if(res2){
|
if (res2) {
|
||||||
setIsEnabledCustomLockingFee(res)
|
setIsEnabledCustomLockingFee(res);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
getSavedSelectedPublisher()
|
getSavedSelectedPublisher();
|
||||||
}, [])
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (hideRecommendations) {
|
||||||
|
setRecommendedFee("custom");
|
||||||
|
}
|
||||||
|
}, [hideRecommendations]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -187,18 +218,33 @@ export const Settings = () => {
|
|||||||
}}
|
}}
|
||||||
open={openModal}
|
open={openModal}
|
||||||
>
|
>
|
||||||
<CoinActionContainer sx={{
|
<CoinActionContainer
|
||||||
border: '1px solid #3F3F3F',
|
sx={{
|
||||||
borderRadius: '5px',
|
border: "1px solid #3F3F3F",
|
||||||
padding: '5px'
|
borderRadius: "5px",
|
||||||
}}>
|
padding: "5px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Typography>Locking fees</Typography>
|
<Typography>Locking fees</Typography>
|
||||||
<FormControlLabel control={<Checkbox checked={isEnabledCustomLockingFee} onChange={handleChange} />} label="Enable custom locking fee" />
|
<FormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={isEnabledCustomLockingFee}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="Enable custom locking fee"
|
||||||
|
/>
|
||||||
|
|
||||||
{isEnabledCustomLockingFee && (
|
{isEnabledCustomLockingFee && (
|
||||||
<CoinSelectRow sx={{
|
<>
|
||||||
gap: '20px'
|
<CoinSelectRow
|
||||||
}}>
|
sx={{
|
||||||
|
gap: "20px",
|
||||||
|
width: '100%',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Select
|
<Select
|
||||||
size="small"
|
size="small"
|
||||||
value={selectedCoin}
|
value={selectedCoin}
|
||||||
@ -208,25 +254,119 @@ export const Settings = () => {
|
|||||||
setSelectedCoin(e.target.value);
|
setSelectedCoin(e.target.value);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<MenuItem value={"LTC"}>
|
<MenuItem value={"LITECOIN"}>
|
||||||
<SelectRow coin="LTC" />
|
<SelectRow coin="LTC" />
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem value={"DOGE"}>
|
<MenuItem value={"DOGECOIN"}>
|
||||||
<SelectRow coin="DOGE" />
|
<SelectRow coin="DOGE" />
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem value={"BTC"}>
|
<MenuItem value={"BITCOIN"}>
|
||||||
<SelectRow coin="BTC" />
|
<SelectRow coin="BTC" />
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem value={"DGB"}>
|
<MenuItem value={"DIGIBYTE"}>
|
||||||
<SelectRow coin="DGB" />
|
<SelectRow coin="DGB" />
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem value={"RVN"}>
|
<MenuItem value={"RAVENCOIN"}>
|
||||||
<SelectRow coin="RVN" />
|
<SelectRow coin="RVN" />
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
<MenuItem value={"PIRATECHAIN"}>
|
||||||
|
<SelectRow coin="ARRR" />
|
||||||
|
</MenuItem>
|
||||||
</Select>
|
</Select>
|
||||||
<Box>
|
<Box>
|
||||||
|
|
||||||
|
</Box>
|
||||||
|
</CoinSelectRow>
|
||||||
|
<CoinActionRow>
|
||||||
|
<HeaderRow>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: "100%",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CustomLabel
|
||||||
|
sx={{
|
||||||
|
fontSize: "16px",
|
||||||
|
}}
|
||||||
|
htmlFor="standard-adornment-name"
|
||||||
|
>
|
||||||
|
Recommended fee selection (in sats per kb)
|
||||||
|
</CustomLabel>
|
||||||
|
|
||||||
|
<Spacer height="10px" />
|
||||||
|
<ToggleButtonGroup
|
||||||
|
color="primary"
|
||||||
|
value={recommendedFee}
|
||||||
|
exclusive
|
||||||
|
onChange={handleChangeRecommended}
|
||||||
|
aria-label="Platform"
|
||||||
|
>
|
||||||
|
{!hideRecommendations && (
|
||||||
|
<>
|
||||||
|
<ToggleButton value="low_fee_per_kb">
|
||||||
|
Low
|
||||||
|
</ToggleButton>
|
||||||
|
<ToggleButton value="medium_fee_per_kb">
|
||||||
|
Medium
|
||||||
|
</ToggleButton>
|
||||||
|
<ToggleButton value="high_fee_per_kb">
|
||||||
|
High
|
||||||
|
</ToggleButton>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<ToggleButton value="custom">Custom</ToggleButton>
|
||||||
|
</ToggleButtonGroup>
|
||||||
|
</Box>
|
||||||
|
{recommendedFeeDisplay && (
|
||||||
|
<>
|
||||||
|
<Spacer height="15px" />
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: "100%",
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
color: "white",
|
||||||
|
fontSize: "18px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
fontWeight: "bold",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{" "}
|
||||||
|
New fee:
|
||||||
|
</span>{" "}
|
||||||
|
{recommendedFeeDisplay}{" "}
|
||||||
|
sats per kb
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Spacer height="10px" />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</HeaderRow>
|
||||||
|
</CoinActionRow>
|
||||||
|
{recommendedFee === "custom" && (
|
||||||
|
<CoinActionRow>
|
||||||
|
<HeaderRow>
|
||||||
|
<Box>
|
||||||
<CustomLabel htmlFor="standard-adornment-name">
|
<CustomLabel htmlFor="standard-adornment-name">
|
||||||
Locking fee for {selectedCoin} (sats per kb)
|
Custom fee
|
||||||
</CustomLabel>
|
</CustomLabel>
|
||||||
<Spacer height="5px" />
|
<Spacer height="5px" />
|
||||||
<CustomInput
|
<CustomInput
|
||||||
@ -237,13 +377,16 @@ export const Settings = () => {
|
|||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</CoinSelectRow>
|
</HeaderRow>
|
||||||
|
</CoinActionRow>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
onClick={updateLockingFee}
|
onClick={updateLockingFee}
|
||||||
disabled={!editLockingFee}
|
disabled={recommendedFee === "custom" && !editLockingFee}
|
||||||
sx={{
|
sx={{
|
||||||
minHeight: "42px",
|
minHeight: "42px",
|
||||||
border: "1px solid gray",
|
border: "1px solid gray",
|
||||||
@ -266,32 +409,33 @@ export const Settings = () => {
|
|||||||
<Typography>Update locking fee</Typography>
|
<Typography>Update locking fee</Typography>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
</CoinActionContainer>
|
</CoinActionContainer>
|
||||||
<Spacer height="20px"/>
|
<Spacer height="20px" />
|
||||||
<CoinActionContainer sx={{
|
<CoinActionContainer
|
||||||
border: '1px solid #3F3F3F',
|
sx={{
|
||||||
borderRadius: '5px',
|
border: "1px solid #3F3F3F",
|
||||||
padding: '5px'
|
borderRadius: "5px",
|
||||||
}}>
|
padding: "5px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Typography>Fee publisher</Typography>
|
<Typography>Fee publisher</Typography>
|
||||||
<Select
|
<Select
|
||||||
size="small"
|
size="small"
|
||||||
value={selectedFeePublisher}
|
value={selectedFeePublisher}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
if(e.target.value){
|
if (e.target.value) {
|
||||||
setSelectedFeePublisher(e.target.value);
|
setSelectedFeePublisher(e.target.value);
|
||||||
saveDataLocal('selectedFeePublisher', e.target.value)
|
saveDataLocal("selectedFeePublisher", e.target.value);
|
||||||
}
|
}
|
||||||
|
}}
|
||||||
}}
|
>
|
||||||
>
|
<MenuItem value={"Foreign-Fee-Publisher"}>
|
||||||
<MenuItem value={"Foreign-Fee-Publisher"}>
|
<SelectRow coin="Foreign-Fee-Publisher" />
|
||||||
<SelectRow coin="Foreign-Fee-Publisher" />
|
</MenuItem>
|
||||||
</MenuItem>
|
<MenuItem value={"Ice.JSON"}>
|
||||||
<MenuItem value={"Ice.JSON"}>
|
<SelectRow coin="Ice.JSON" />
|
||||||
<SelectRow coin="Ice.JSON" />
|
</MenuItem>
|
||||||
</MenuItem>
|
</Select>
|
||||||
</Select>
|
</CoinActionContainer>
|
||||||
</CoinActionContainer>
|
|
||||||
</ReusableModal>
|
</ReusableModal>
|
||||||
)}
|
)}
|
||||||
<Snackbar
|
<Snackbar
|
||||||
|
76
src/hooks/useRecommendedFees.tsx
Normal file
76
src/hooks/useRecommendedFees.tsx
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react'
|
||||||
|
import gameContext from '../contexts/gameContext';
|
||||||
|
import { QortalGetMetadata, usePublish } from 'qapp-core';
|
||||||
|
import { useAtom } from 'jotai/react';
|
||||||
|
import { selectedFeePublisherAtom } from '../global/state';
|
||||||
|
import { isValidFeeEstimate } from '../components/sell/FeeManager';
|
||||||
|
|
||||||
|
export const useRecommendedFees = ({selectedCoin, recommendedFee}) => {
|
||||||
|
const { getCoinLabel } = useContext(gameContext);
|
||||||
|
const [selectedFeePublisher, setSelectedFeePublisher] = useAtom(
|
||||||
|
selectedFeePublisherAtom
|
||||||
|
);
|
||||||
|
|
||||||
|
const [feeLocation, setFeeLocation] = useState<QortalGetMetadata>({
|
||||||
|
name: "",
|
||||||
|
identifier: "",
|
||||||
|
service: "JSON",
|
||||||
|
});
|
||||||
|
const { resource } = usePublish(3, "JSON", feeLocation);
|
||||||
|
|
||||||
|
const coin = useMemo(() => {
|
||||||
|
const coinLabel = getCoinLabel(selectedCoin);
|
||||||
|
if (typeof coinLabel !== "string") return null;
|
||||||
|
return coinLabel?.toLowerCase();
|
||||||
|
}, [selectedCoin, getCoinLabel]);
|
||||||
|
|
||||||
|
const getLatestFees = useCallback(async () => {
|
||||||
|
try {
|
||||||
|
const coinLabel = getCoinLabel(selectedCoin);
|
||||||
|
if (typeof coinLabel !== "string") return;
|
||||||
|
const coin = coinLabel?.toUpperCase();
|
||||||
|
const identifier = `coinInfo-${coin}`;
|
||||||
|
const res = await fetch(
|
||||||
|
`/arbitrary/resources/searchsimple?service=JSON&identifier=${identifier}&name=${selectedFeePublisher}&prefix=true&limit=1&reverse=true`
|
||||||
|
);
|
||||||
|
const data = await res.json();
|
||||||
|
if (data && data?.length > 0) {
|
||||||
|
setFeeLocation(data[0]);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}, [selectedFeePublisher, selectedCoin]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getLatestFees();
|
||||||
|
}, [getLatestFees]);
|
||||||
|
|
||||||
|
const recommendedFeeData = useMemo(() => {
|
||||||
|
if (
|
||||||
|
!resource?.qortalMetadata?.identifier?.includes(`${coin.toUpperCase()}`)
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
if (!resource?.data) return null;
|
||||||
|
const isValid = isValidFeeEstimate(resource.data);
|
||||||
|
if (!isValid) return null;
|
||||||
|
return resource.data;
|
||||||
|
}, [resource, coin]);
|
||||||
|
|
||||||
|
const recommendedFeeDisplay = useMemo(() => {
|
||||||
|
if (!recommendedFeeData) return null;
|
||||||
|
|
||||||
|
if (!recommendedFeeData) return null;
|
||||||
|
return recommendedFeeData[recommendedFee] || null;
|
||||||
|
}, [recommendedFeeData, recommendedFee]);
|
||||||
|
|
||||||
|
const hideRecommendations = useMemo(() => {
|
||||||
|
if (recommendedFeeData) return false;
|
||||||
|
return true;
|
||||||
|
}, [recommendedFeeData]);
|
||||||
|
return {
|
||||||
|
hideRecommendations,
|
||||||
|
recommendedFeeDisplay,
|
||||||
|
coin
|
||||||
|
}
|
||||||
|
}
|
61
src/hooks/useUpdateFee.tsx
Normal file
61
src/hooks/useUpdateFee.tsx
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import { useAtom } from 'jotai/react';
|
||||||
|
import React, { useCallback, useContext, useMemo } from 'react'
|
||||||
|
import { calculateRateFromFee } from '../components/sell/FeeManager';
|
||||||
|
import { isEnabledCustomLockingFeeAtom } from '../global/state';
|
||||||
|
import gameContext from '../contexts/gameContext';
|
||||||
|
|
||||||
|
export const useUpdateFee = ({setFee, selectedCoin}) => {
|
||||||
|
const [isEnabledCustomLockingFee, setIsEnabledCustomLockingFee] = useAtom(
|
||||||
|
isEnabledCustomLockingFeeAtom
|
||||||
|
);
|
||||||
|
|
||||||
|
const {
|
||||||
|
|
||||||
|
getCoinLabel,
|
||||||
|
|
||||||
|
} = useContext(gameContext);
|
||||||
|
|
||||||
|
|
||||||
|
const coin = useMemo(() => {
|
||||||
|
const coinLabel = getCoinLabel(selectedCoin);
|
||||||
|
if (typeof coinLabel !== "string") return null;
|
||||||
|
return coinLabel?.toLowerCase();
|
||||||
|
}, [selectedCoin, getCoinLabel]);
|
||||||
|
const updateFee = useCallback(async (suggestedFee ) => {
|
||||||
|
const typeRequest = "feerequired";
|
||||||
|
const typeRequestLocking = "feekb";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const feeToSave = +suggestedFee
|
||||||
|
|
||||||
|
const response = await qortalRequestWithTimeout(
|
||||||
|
{
|
||||||
|
action: "UPDATE_FOREIGN_FEE",
|
||||||
|
coin: coin,
|
||||||
|
type: typeRequest,
|
||||||
|
value: feeToSave,
|
||||||
|
},
|
||||||
|
1800000
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isEnabledCustomLockingFee) {
|
||||||
|
await qortalRequestWithTimeout(
|
||||||
|
{
|
||||||
|
action: "UPDATE_FOREIGN_FEE",
|
||||||
|
coin: coin,
|
||||||
|
type: typeRequestLocking,
|
||||||
|
value: calculateRateFromFee(feeToSave, 300),
|
||||||
|
},
|
||||||
|
1800000
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response && !isNaN(+response)) {
|
||||||
|
setFee(response);
|
||||||
|
return response
|
||||||
|
} else throw new Error("Unable to update fee");
|
||||||
|
|
||||||
|
}, [coin, isEnabledCustomLockingFee, setFee]);
|
||||||
|
return updateFee
|
||||||
|
}
|
@ -113,8 +113,8 @@ export const HomePage = () => {
|
|||||||
</TextTableTitle>
|
</TextTableTitle>
|
||||||
</Box>
|
</Box>
|
||||||
<Spacer height="10px" />
|
<Spacer height="10px" />
|
||||||
<TradeOffers fee={fee}
|
<TradeOffers setFee={setFee} fee={fee}
|
||||||
setFee={setFee} foreignCoinBalance={foreignCoinBalance} />
|
foreignCoinBalance={foreignCoinBalance} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<CreateSell show={mode === "sell"} qortAddress={userInfo?.address} />
|
<CreateSell show={mode === "sell"} qortAddress={userInfo?.address} />
|
||||||
|
Loading…
x
Reference in New Issue
Block a user