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